1. Если вы только начинаете программировать на ассемблере и не знаете с чего начать, тогда попробуйте среду разработки ASM Visual IDE
    (c) на правах рекламы
    Скрыть объявление

Аналоговые часы GDI+

Тема в разделе "WASM.GUI", создана пользователем Orbit, 8 окт 2017.

  1. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
    Добрый вечер! В программировании я новичок.
    Хочу скрафтать аналоговые часы. С помощью Бога и Mikl___ создал окошко. Что делать дальше?
    Да-да... видел примеры часов на C но не совсем разобрался с порядком функций и их назначением.
    Если кто в теме объясните пожалуйста порядок действий.
     
  2. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    669
    Orbit, рисовать лучше наверное через GDI+ - там и антиалиасинг и полупрозрачность поддерживается в отличии от GDI. Если есть желание и интерес то можно Direct2D/3D заюзать.
    Для GDI+ следующие функции для рисования:

    GdiplusStartup/GdiplusShutdown
    GdipCreateFromHDC/GdipCreateFromHWND/GdipDeleteGraphics
    GdipGraphicsClear
    GdipSetSmoothingMode
    GdipCreatePen1/GdipDeletePen/GdipDeletePen
    GdipCreateSolidFill/GdipCreateHatchBrush/GdipCreateLineBrush/GdipCreateTexture/GdipDeleteBrush
    GdipDrawLine/GdipDrawLineI
    GdipDrawEllipse/GdipDrawEllipseI
    GdipStringFormatGetGenericDefault/GdipDeleteStringFormat
    GdipSetTextRenderingHint
    GdipCreateFontFromDC/GdipDeleteFont
    GdipMeasureString
    GdipDrawString
     
  3. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
    Подскажите библиотека работает только со спрайтами или я могу с помощью нее начертить круг и условно разделить его допустим на 12 частей?
     
  4. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.488
    Как рекомендация посмотрите пури(purebasic). Там это всё просто чудесно реализовано и как обучалка годная весьма. Собирается его скрипт асм компилером.
     
  5. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    669
    Чертить круг (эллипс) - GdipDrawEllipse/GdipDrawEllipseI.
     
  6. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
    Простите пытался изобрести велосипед. Нагугли что меня пока устроит... но вопрос остается открытым
     
  7. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    1
    Регистрация:
    11 июн 2004
    Сообщения:
    3.474
    Адрес:
    Russia
    Забудьте про библиотеку. Читайте "Компьютерную графику" Борескова.
    И еще - еще 1 ссылка типа той, что была в посте #6 - улетите в бан.
     
  8. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
    Пытаюсь инициализировать библиотеку. Программа вываливается. То ли что то с размерами аргументов структуры то ли что-то другое :dntknw: в каком месте программы начинать использование библиотеки?

    Код (ASM):
    1.  
    2. format PE64 GUI 6.0
    3. entry start
    4. include 'win64a.inc'
    5.  
    6. section '.code' code readable executable
    7. ;-----------------------------------------------------------------------
    8. start:
    9.   sub  rsp,8  ; Make stack dqword aligned
    10.   invoke GetModuleHandle,0
    11.   mov [wc.hInstance],rax
    12.   mov [wc.cbSize],sizeof.WNDCLASSEX
    13.   mov [wc.style],CS_HREDRAW or CS_VREDRAW
    14.   mov [wc.lpfnWndProc],WindowProc
    15.   mov [wc.cbClsExtra],0
    16.   invoke LoadIcon,0,IDI_APPLICATION
    17.   mov [wc.hIcon],rax
    18.   mov [wc.hIconSm],rax
    19.   invoke LoadCursor,0,IDC_ARROW
    20.   mov [wc.hCursor],rax
    21.   mov [wc.hbrBackground],COLOR_WINDOW+1
    22.   mov [wc.lpszMenuName],NULL
    23.   mov [wc.lpszClassName],szTitle
    24.   invoke RegisterClassEx,wc
    25.   invoke CreateWindowEx,0,szTitle,szTitle,WS_VISIBLE + WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,444,444,NULL,NULL,[wc.hInstance],NULL
    26.  
    27.   mov  [GdiplusStartupInput.GdiplusVersion],1
    28.   mov  [GdiplusStartupInput.DebugEventCallback],0
    29.   mov  [GdiplusStartupInput.SuppressBackgroundThread],0
    30.   mov  [GdiplusStartupInput.SuppressExternalCodecs],0
    31.  
    32. msg_loop:
    33.   invoke  GetMessage,msg,NULL,0,0
    34.   or  rax,rax
    35.   je  exit
    36.   invoke  TranslateMessage,msg
    37.   invoke  DispatchMessage,msg
    38.   jmp  msg_loop
    39.   exit:
    40.   invoke ExitProcess,[msg.wParam]
    41. ;--------------------------------------------------------------------------------
    42. proc WindowProc hwnd,wmsg,wparam,lparam
    43.   mov [hwnd],rcx
    44.   mov [wmsg],rdx
    45.   mov [wparam],r8
    46.   mov [lparam],r9
    47.   cmp [wmsg],WM_DESTROY
    48.   jne .defwndproc
    49.   invoke PostQuitMessage,0
    50.   ret
    51.   .defwndproc:
    52.   invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
    53.   ret
    54. endp
    55. ;----------------------------------------------------------------------
    56. section '.data' data readable writeable
    57.  
    58. szTitle db 'CLOCK',0
    59.  
    60. struct GdiplusStartupInput
    61.   GdiplusVersion  dd ?
    62.   DebugEventCallback  dq ?
    63.   SuppressBackgroundThread  dd ?
    64.   SuppressExternalCodecs  dd ?
    65. ends
    66.  
    67. wc WNDCLASSEX
    68. msg MSG
    69. ;----------------------------------------------------------------------
    70.  
    71. section '.idata' import data readable writeable
    72.  
    73.   library kernel,'KERNEL32.DLL',\
    74.   user,'USER32.DLL',\
    75.   gdiplus,'GDIPLUS.DLL'
    76.  
    77.   import kernel,\
    78.   ExitProcess,'ExitProcess',\
    79.   GetModuleHandle,'GetModuleHandleA'
    80.  
    81.   import user,\
    82.   PostQuitMessage,'PostQuitMessage',\
    83.   LoadIcon,'LoadIconA',\
    84.   LoadCursor,'LoadCursorA',\
    85.   RegisterClassEx,'RegisterClassExA',\
    86.   CreateWindowEx,'CreateWindowExA',\
    87.   DefWindowProc,'DefWindowProcA',\
    88.   GetMessage,'GetMessageA',\
    89.   TranslateMessage,'TranslateMessage',\
    90.   DispatchMessage,'DispatchMessageA'
    91.  
     
  9. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
  10. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    1
    Регистрация:
    11 июн 2004
    Сообщения:
    3.474
    Адрес:
    Russia
    cmp [wmsg],WM_PAINT
    и далее по контексту.
     
  11. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.179
    Orbit,
    начни с WinAPI, а к GDIPlus перейдешь чуть погодя. Вот псевдо-код для WinAPI движение секундной стрелки по кругу. Значение в Sec увеличивай с приходом сообщения WM_TIMER
    Код (Text):
    1. Rectangle(150, 100, 750, 500);
    2.       Ellipse(250, 100, 650, 500);
    3.       MoveTo(450, 300);
    4.       LineTo(Round(450-200*Cos((Sec*6+90)/180*Pi)), Round(300-200*Sin((Sec*6+90)/180*Pi)));
    5.       Ellipse(443, 293, 457, 307);
     
  12. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
    Для меня пока тяжеловато, нужно разобраться с сообщениями окну. WM_TIMER приходит постоянно это понятно. а WM_PAINT один раз после запуска программы?
     
  13. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.179
    Нужно расширить WindowProc
    Код (ASM):
    1. cmp [wmsg],WM_CREATE
    2. je wmCREATE
    3. cmp [wmsg],WM_PAINT
    4. je wmPAINT
    5. cmp [wmsg],WM_TIMER
    6. je wmTIMER
    7. cmp [wmsg],WM_DESTROY
    8.  jne .defwndproc
    9.   invoke PostQuitMessage,0
    10.  jmp wmBYE
    11.  .defwndproc:
    12.   invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
    13.  ret
    14. wmCREATE:
    15. ...
    16. jmp wmBYE
    17. wmPAINT:
    18. ...
    19. jmp wmBYE
    20. wmTIMER:
    21.  ...
    22. wmBYE: ret
    Движение по кругу посмотри в Глава шестая. Вращающийся текст WM_TIMER будет вызывать сообщение WM_PAINT чтобы перерисовать часовую, минутную и секундную стрелки на новом месте. Разберись пока с секундной стрелкой...
     
  14. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
    Спасибо, хорошо, я понял, наклон по градусам.. буду вникать. Но неплохо было бы увидеть как это происходит на живую :)

    Код (ASM):
    1.  
    2. format PE64 GUI 6.0
    3. entry start
    4. include 'win64a.inc'
    5.  
    6. section '.code' code readable executable
    7. ;----------------------------------------------------------------------
    8. start:
    9.   sub  rsp,8  ; Make stack dqword aligned
    10.   invoke GetModuleHandle,0
    11.   mov [wc.hInstance],rax
    12.   mov [wc.cbSize],sizeof.WNDCLASSEX
    13.   mov [wc.style],CS_HREDRAW or CS_VREDRAW
    14.   mov [wc.lpfnWndProc],WindowProc
    15.   mov [wc.cbClsExtra],0
    16.   invoke LoadIcon,0,IDI_APPLICATION
    17.   mov [wc.hIcon],rax
    18.   mov [wc.hIconSm],rax
    19.   invoke LoadCursor,0,IDC_ARROW
    20.   mov [wc.hCursor],rax
    21.   mov [wc.hbrBackground],COLOR_WINDOW+1
    22.   mov [wc.lpszMenuName],NULL
    23.   mov [wc.lpszClassName],szTitle
    24.   invoke RegisterClassEx,wc
    25.   invoke CreateWindowEx,0,szTitle,szTitle,WS_OVERLAPPED + WS_VISIBLE + WS_CAPTION + WS_SYSMENU + WS_MINIMIZEBOX ,CW_USEDEFAULT,CW_USEDEFAULT,444,444,NULL,NULL,[wc.hInstance],NULL
    26.  
    27. msg_loop:
    28.   invoke  GetMessage,msg,NULL,0,0
    29.   or  rax,rax
    30.   je  exit
    31.   invoke  TranslateMessage,msg
    32.   invoke  DispatchMessage,msg
    33.   jmp  msg_loop
    34.   exit:
    35.   invoke ExitProcess,[msg.wParam]
    36. ;----------------------------------------------------------------------
    37. proc WindowProc hwnd,wmsg,wparam,lparam
    38.   mov [hwnd],rcx
    39.   mov [wmsg],rdx
    40.   mov [wparam],r8
    41.   mov [lparam],r9
    42.  
    43.   cmp [wmsg],WM_CREATE
    44.   je .create
    45.  
    46.  
    47.   cmp [wmsg],WM_TIMER
    48.   je .timer
    49.  
    50.   cmp [wmsg],WM_PAINT
    51.   je .paint
    52.  
    53.   cmp [wmsg],WM_DESTROY
    54.   jne .defwndproc
    55.  
    56.   invoke PostQuitMessage,0
    57.   jmp .exit
    58.  
    59.   .defwndproc:
    60.   invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
    61.   ret
    62.  
    63.   .create:
    64.   ;mov  [GdiplusStartupInput.GdiplusVersion],1
    65.   ;mov  [GdiplusStartupInput.DebugEventCallback],0
    66.   ;mov  [GdiplusStartupInput.SuppressBackgroundThread],0
    67.   ;mov  [GdiplusStartupInput.SuppressExternalCodecs],0
    68.  
    69.   .timer:
    70.  
    71.   .paint:
    72.  
    73.   .exit:
    74.   ret
    75. endp
    76. ;----------------------------------------------------------------------
    77. section '.data' data readable writeable
    78.  
    79. szTitle db 'CLOCK',0
    80.  
    81. struct GdiplusStartupInput
    82.   GdiplusVersion  dd ?
    83.   DebugEventCallback  dq ?
    84.   SuppressBackgroundThread  dd ?
    85.   SuppressExternalCodecs  dd ?
    86. ends
    87.  
    88. wc WNDCLASSEX
    89. msg MSG
    90. ;----------------------------------------------------------------------
    91.  
    92. section '.idata' import data readable writeable
    93.  
    94.   library kernel,'KERNEL32.DLL',\
    95.   user,'USER32.DLL',\
    96.   gdiplus,'GDIPLUS.DLL'
    97.  
    98.   import kernel,\
    99.   ExitProcess,'ExitProcess',\
    100.   GetModuleHandle,'GetModuleHandleA'
    101.  
    102.   import user,\
    103.   PostQuitMessage,'PostQuitMessage',\
    104.   LoadIcon,'LoadIconA',\
    105.   LoadCursor,'LoadCursorA',\
    106.   RegisterClassEx,'RegisterClassExA',\
    107.   CreateWindowEx,'CreateWindowExA',\
    108.   DefWindowProc,'DefWindowProcA',\
    109.   GetMessage,'GetMessageA',\
    110.   TranslateMessage,'TranslateMessage',\
    111.   DispatchMessage,'DispatchMessageA'  
    112.  
     
  15. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.179
    Предлагаешь кому-то написать за тебя курсовую? Для этого есть раздел WASM.COMMERCE Перенести топик?
     
  16. Orbit

    Orbit Member

    Публикаций:
    0
    Регистрация:
    13 дек 2016
    Сообщения:
    109
    Адрес:
    г. Москва
    Это не курсовая, пишу для себя...

    Код (ASM):
    1.  
    2. format PE64 GUI 6.0
    3. entry start
    4. include 'win64a.inc'
    5.  
    6. section '.code' code readable executable
    7. ;----------------------------------------------------------------------
    8. start:
    9.   sub  rsp,8  ; Make stack dqword aligned
    10.   invoke GetModuleHandle,0
    11.   mov [wc.hInstance],rax
    12.   mov [wc.cbSize],sizeof.WNDCLASSEX
    13.   mov [wc.style],CS_HREDRAW or CS_VREDRAW
    14.   mov [wc.lpfnWndProc],WindowProc
    15.   mov [wc.cbClsExtra],0
    16.   invoke LoadIcon,0,IDI_APPLICATION
    17.   mov [wc.hIcon],rax
    18.   mov [wc.hIconSm],rax
    19.   invoke LoadCursor,0,IDC_ARROW
    20.   mov [wc.hCursor],rax
    21.   mov [wc.hbrBackground],COLOR_WINDOW+1
    22.   mov [wc.lpszMenuName],NULL
    23.   mov [wc.lpszClassName],szTitle
    24.   invoke RegisterClassEx,wc
    25.   invoke CreateWindowEx,0,szTitle,szTitle,WS_OVERLAPPED + WS_VISIBLE + WS_CAPTION + WS_SYSMENU + WS_MINIMIZEBOX ,CW_USEDEFAULT,CW_USEDEFAULT,444,444,NULL,NULL,[wc.hInstance],NULL
    26.  
    27. msg_loop:
    28.   invoke  GetMessage,msg,NULL,0,0
    29.   or  rax,rax
    30.   je  exit
    31.   invoke  TranslateMessage,msg
    32.   invoke  DispatchMessage,msg
    33.   jmp  msg_loop
    34.   exit:
    35.   invoke ExitProcess,[msg.wParam]
    36. ;----------------------------------------------------------------------
    37. proc WindowProc hwnd,wmsg,wparam,lparam
    38.   mov [hwnd],rcx
    39.   mov [wmsg],rdx
    40.   mov [wparam],r8
    41.   mov [lparam],r9
    42.  
    43.   cmp [wmsg],WM_CREATE
    44.   je .create
    45.  
    46.  
    47.   cmp [wmsg],WM_TIMER
    48.   je .timer
    49.  
    50.   cmp [wmsg],WM_PAINT
    51.   je .paint
    52.  
    53.   cmp [wmsg],WM_DESTROY
    54.   jne .defwndproc
    55.  
    56.   invoke PostQuitMessage,0
    57.   jmp .exit
    58.  
    59.   .defwndproc:
    60.   invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
    61.   ret
    62.  
    63.   .create:
    64.   mov  [GdiplusSInput.GdiplusVersion],1
    65.   mov  [GdiplusSInput.DebugEventCallback],0
    66.   mov  [GdiplusSInput.SuppressBackgroundThread],0
    67.   mov  [GdiplusSInput.SuppressExternalCodecs],0
    68.  
    69.   invoke GetLocalTime,systime
    70.  
    71.   .timer:
    72.  
    73.   .paint:
    74.  
    75.   .exit:
    76.   ret
    77. endp
    78. ;----------------------------------------------------------------------
    79. section '.data' data readable writeable
    80.  
    81. szTitle db 'CLOCK',0
    82.  
    83. struct GdiplusStartupInput
    84.   GdiplusVersion  dd ?
    85.   DebugEventCallback  dq ?
    86.   SuppressBackgroundThread  dd ?
    87.   SuppressExternalCodecs  dd ?
    88. ends
    89.  
    90. wc WNDCLASSEX
    91. msg MSG
    92. systime SYSTEMTIME
    93. GdiplusSInput GdiplusStartupInput
    94. ;----------------------------------------------------------------------
    95.  
    96. section '.idata' import data readable writeable
    97.  
    98.   library kernel,'KERNEL32.DLL',\
    99.   user,'USER32.DLL',\
    100.   gdiplus,'GDIPLUS.DLL'
    101.  
    102.   import kernel,\
    103.   ExitProcess,'ExitProcess',\
    104.   GetModuleHandle,'GetModuleHandleA',\
    105.   GetLocalTime,'GetLocalTime'
    106.  
    107.   import user,\
    108.   PostQuitMessage,'PostQuitMessage',\
    109.   LoadIcon,'LoadIconA',\
    110.   LoadCursor,'LoadCursorA',\
    111.   RegisterClassEx,'RegisterClassExA',\
    112.   CreateWindowEx,'CreateWindowExA',\
    113.   DefWindowProc,'DefWindowProcA',\
    114.   GetMessage,'GetMessageA',\
    115.   TranslateMessage,'TranslateMessage',\
    116.   DispatchMessage,'DispatchMessageA'
    117.  
     
  17. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    669
    Вот круг:
    Код (ASM):
    1.  
    2. .386
    3. .model flat, stdcall
    4. option casemap :none
    5. include \masm32\include\windows.inc
    6. include \masm32\include\gdiplus.inc
    7. include \masm32\include\user32.inc
    8. include \masm32\include\kernel32.inc
    9. includelib \masm32\lib\gdiplus.lib
    10. includelib \masm32\lib\user32.lib
    11. includelib \masm32\lib\kernel32.lib
    12. DialogProc proto :DWORD,:DWORD,:DWORD,:DWORD
    13. GdiplusStartupInput STRUCT
    14.   GdiplusVersion           dd ?
    15.   DebugEventCallback       dd ?
    16.   SuppressBackgroundThread dd ?
    17.   SuppressExternalCodecs   dd ?
    18. GdiplusStartupInput ENDS
    19. UnitPixel equ 2
    20. SmoothingModeAntiAlias equ 4
    21.    
    22. .data        
    23. DLG_TEMP dd WS_OVERLAPPEDWINDOW XOR WS_THICKFRAME OR DS_CENTER, WS_EX_APPWINDOW
    24. dw 0, 0, 0, 200, 200, 0, 0, 0
    25. hPen dd ?
    26. lToken dd ?
    27. tGpInput GdiplusStartupInput {1, 0, 0, 0}
    28.    
    29. .code
    30.                        
    31. start:
    32. invoke GetModuleHandle, NULL;
    33.     invoke DialogBoxIndirectParam, eax, offset DLG_TEMP, NULL, offset  DialogProc, NULL;
    34.    
    35.     invoke ExitProcess, 0
    36.      
    37. DialogProc  proc hwndDlg :DWORD,
    38.           uMsg :DWORD,
    39.           wParam :DWORD,
    40.           lParam :DWORD
    41.     LOCAL ps:PAINTSTRUCT
    42.     LOCAL hGraphics:DWORD
    43.     xor eax, eax
    44.    
    45.     .if uMsg == WM_INITDIALOG                  
    46.    
    47.     invoke GdiplusStartup, offset lToken, offset tGpInput, NULL
    48.     invoke GdipCreatePen1, 0ff0000ffh, 40400000h, UnitPixel, offset hPen
    49. .elseif uMsg == WM_PAINT
    50. invoke BeginPaint, hwndDlg, ADDR ps
    51. invoke GdipCreateFromHDC, ps.hdc, ADDR hGraphics
    52. invoke GdipSetSmoothingMode, hGraphics, SmoothingModeAntiAlias
    53. invoke GdipGraphicsClear, hGraphics, 0ffffffffh
    54. invoke GdipDrawEllipseI, hGraphics, hPen, 100, 100, 200, 200
    55. invoke GdipDeleteGraphics, hGraphics
    56. invoke EndPaint, hwndDlg, ADDR ps
    57.     .elseif uMsg == WM_CLOSE
    58.    
    59.     invoke GdipDeletePen, hPen
    60.     invoke GdiplusShutdown, lToken
    61.     invoke EndDialog, hwndDlg, 0
    62.    
    63.     .endif
    64.    
    65.     ret
    66.    
    67. DialogProc endp  
    68.    
    69. end start                        
    70.  
     
    Mikl___ нравится это.
  18. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.179
    Orbit,
    а к кругу добавляется секундная стрелка с помощью вызова MoveTo и LineTo
     
  19. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    669
    Можно GdipDrawLineI если продолжать мой пример.
     
    Mikl___ нравится это.
  20. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.179
    Thetrik,
    я бы не перегружал Orbit GDIPlus'ом -- достаточно было WinAPI'шных Ellipse, MoveTo, LineTo + перерисовка каждую секунду, а так он в деталях запутается :)