================================================================
  Menger_12 [x64 MASM] ANIM - Доработка: Авто-вращение
  Дата: 20.10.2026
================================================================

ЗАДАЧА:
---------
Добавить в меню галочку, при включении которой кубик Менгера
начинает красиво вращаться в 3D автоматически.

---------
В главном меню появился новый пункт "Animation" -> "Auto Rotate  Ctrl+R"
При включении рядом ставится галочка [✓], объект начинает плавно
вращаться вокруг осей Y и X одновременно (эффект турнтейбла).
При выключении - возвращается ручное управление мышью.

================================================================
СПИСОК ИЗМЕНЕННЫХ ФАЙЛОВ:
================================================================
1. CONST.ASM
2. VAR.ASM
3. SZ.ASM
4. APP/03_Menu.asm
5. APP/10_111_Command.asm
6. STRUCT.ASM
7. APP/04_Accel.asm
8. EXTERN.ASM
9. APP/00_WinMain.asm
10. Menger.ASM
11. [НОВЫЙ] OGL/53_Animate.asm

================================================================
ЧТО И ГДЕ ИЗМЕНЕНО:
================================================================

1) CONST.ASM - Константы меню
------------------------------
Добавлено:
  IDM_ANIM_TOGGLE equ 200h

Это ID команды для нового пункта меню. 200h = 512, не конфликтует
с IDM_FILE_SAVE=103h, IDM_FILE_EXIT=109h, IDM_HELP_ABOUT=901h.

2) VAR.ASM - Глобальные переменные
----------------------------------
а) Добавлен хендл нового меню:
  ghMenuAnim dq 0

б) Добавлены флаги и переменные анимации после isRefreshed:

  isAnimEnabled db 0          ; 0=выкл, 1=вкл анимация
  align 4
  f32AnimSpeed  real4 0.6      ; скорость по Y, радиан/сек (~34°/сек)
  f32AnimSpeed2 real4 0.25     ; скорость по X, радиан/сек (~14°/сек)
  f32AnimDeltaAngle  real4 0.0 ; временный дельта-угол Y за кадр
  f32AnimDeltaAngle2 real4 0.0 ; временный дельта-угол X за кадр
  f32AnimSinY real4 0.0
  f32AnimCosY real4 0.0
  f32AnimSinX real4 0.0
  f32AnimCosX real4 0.0
  f32_60 real4 60.0            ; для fallback если QPC не готов

Скорости подобраны чтобы вращение выглядело красиво и не слишком
быстро. Можно поменять 0.6 на 1.0 чтобы крутилось быстрее.

3) SZ.ASM - Строки меню
-------------------------
Добавлено:
  szMenuAnim db "&Animation",0
  szMenuAnimToggle db "&Auto Rotate",9,"Ctrl+R",0

9 - это TAB для выравнивания хоткея в меню. Ctrl+R отображается
справа от пункта.

4) APP/03_Menu.asm - Создание меню
----------------------------------
Было: Main Menu -> File (Save, Exit) -> Help (About)
Стало: Main Menu -> File -> Animation -> Help

Добавлен блок:

;Animation
call CreatePopupMenu
test rax,rax
je CreateMainWnd_Error
mov ghMenuAnim,rax

mov rcx,ghMenu
mov rdx,10h ;MF_POPUP
mov r8,ghMenuAnim
lea r9,szMenuAnim
call AppendMenuA

mov rcx,ghMenuAnim
xor rdx,rdx ;MF_STRING
mov r8,IDM_ANIM_TOGGLE
lea r9,szMenuAnimToggle
call AppendMenuA

Логика галочки делается не здесь, а в обработке WM_COMMAND через
CheckMenuItem.

5) APP/10_111_Command.asm - Обработка клика по меню
---------------------------------------------------
Добавлен обработчик IDM_ANIM_TOGGLE:

@@:
cmp r8w,IDM_ANIM_TOGGLE
jne @f
cmp isAnimEnabled,0
jne anim_off
anim_on:
  mov isAnimEnabled,1
  mov rcx,ghMenuAnim
  mov rdx,IDM_ANIM_TOGGLE
  mov r8,8 ;MF_CHECKED = 8
  call CheckMenuItem
  mov isRefreshed,0 ; попросить перерисовку
  jmp WndProc_Return0
anim_off:
  mov isAnimEnabled,0
  mov rcx,ghMenuAnim
  mov rdx,IDM_ANIM_TOGGLE
  xor r8,r8 ;MF_UNCHECKED = 0
  call CheckMenuItem
  jmp WndProc_Return0

CheckMenuItem - WinAPI функция, ставит/снимает галочку.
isRefreshed=0 заставляет главный цикл в WinMain выйти из сна
и вызвать DrawScene.

6) STRUCT.ASM - Таблица акселераторов
--------------------------------------
Было 2 строки:
  Ctrl+W -> Exit
  F1 -> About
Стало 3 строки:
  Ctrl+W -> Exit
  Ctrl+R -> Auto Rotate  (НОВОЕ)
  F1 -> About

Изменение в коде :
db 9 ;FVIRTKEY|FCONTROL
db 0
dw 52h ; 'R'
dw IDM_ANIM_TOGGLE

7) APP/04_Accel.asm - Создание акселераторов
--------------------------------------------
Было:
  mov rdx,2
Стало:
  mov rdx,3 ; количество ACCEL структур

8) EXTERN.ASM - Прототипы
--------------------------
Добавлено:
  AnimateObject PROTO
  CheckMenuItem PROTO уже был.

9) APP/00_WinMain.asm - Главный цикл.
------------------------------------
Было:
  include 06_CheckKeys.asm
  ;WinMain_Active:
  cmp isRefreshed,0

Стало:
  include 06_CheckKeys.asm
  call AnimateObject
  ;WinMain_Active:

Теперь каждый кадр, даже без нажатия клавиш, вызывается AnimateObject.
Если анимация включена - он повернет матрицу и поставит isRefreshed=0,
и цикл сразу пойдет в DrawScene вместо Wait16ms.

10) Menger.ASM - Подключен новый файл.
------------------------------------------
Добавлено:
  include ogl\53_Animate.asm
После:
  include ogl\52_MulMat4Mat4.asm

11) OGL/53_Animate.asm - [НОВЫЙ ФАЙЛ] Логика вращения
----------------------------------------------------
Это главный файл доработки. Алгоритм:

AnimateObject proc
  if isAnimEnabled==0 -> выход

  1. Вычислить dt (delta time):
     dt = qpcDelta / qpcFreq  (секунды с прошлого кадра)
     Ограничить dt <= 1 сек чтобы не было скачка при лаге.
     angleY = dt * f32AnimSpeed
     Если QPC еще не готов - fallback angle = speed/60

  2. Сохранить позицию объекта (translation столбец матрицы):
     vecObjPos = mtxObjectVolatile[12,13,14]
     Обнулить translation в матрице, чтобы вращать вокруг центра,
     а не по орбите.

  3. Вычислить sin/cos для angleY через x87 FPU:
     fld angle
     fsincos
     fstp cos
     fstp sin

  4. Построить матрицу Ry (column-major):
     col0: cos, 0, -sin, 0
     col1: 0,   1,   0,  0
     col2: sin, 0,  cos, 0
     col3: 0,   0,   0,  1

  5. Скопировать текущую матрицу объекта в mtxBuffer (16 float)
     и вызвать MulMat4Mat4(Ry, Buffer, mtxObjectVolatile)
     Это R_world * M_object - вращение в мировых координатах.

  6. Повторить шаги 1-5 для оси X:
     angleX = dt * f32AnimSpeed2
     Матрица Rx:
     col0: 1, 0,    0,   0
     col1: 0, cos, sin, 0
     col2: 0,-sin, cos, 0
     col3: 0, 0,    0,  1
     Снова MulMat4Mat4(Rx, ...)

  7. Восстановить позицию объекта:
     mtxObjectVolatile[12,13,14] = vecObjPos

  8. isRefreshed=0 -> попросить перерисовку в следующем цикле

  ret
endp

Почему MulMat4Mat4, а не прямая модификация?
	Уже есть готовая, быстрая SSE процедура умножения 4x4.
	Используем ее чтобы не дублировать код и сохранить точность.

================================================================

