;***********************************************************************************************************
; Этот файл содержит текст функций SetupDialog и DW2A
; Разработал Пономарев Михаил ака keYMax
; По всем вопросам мыльте mybox@aib.ru 
;***********************************************************************************************************
SetupDialog proc hDlg:HWND , iMsg:DWORD , wParam:WPARAM , lParam:LPARAM

  .DATA    
   WinModeTable       dw 320,240,640,480,800,600,1024,768   ; Размеры окон для оконного режима
                      dw 1280,1024,1600,1200
   WinModeStrTable    dd OFFSET szMode1 , OFFSET szMode2    ; Указатели на текстовые строки
                      dd OFFSET szMode3 , OFFSET szMode4
                      dd OFFSET szMode5 , OFFSET szMode6
   szMode1            db "320x240",0                        ; Текстовые строки для оконного режима
   szMode2            db "640x480",0   
   szMode3            db "800x600",0
   szMode4            db "1024x768",0
   szMode5            db "1280x1024",0
   szMode6            db "1600x1200",0  			

   ZBufferFormatTable db D3DFMT_D16                         ; Форматы Z буфера
                      db D3DFMT_D16_LOCKABLE   
                      db D3DFMT_D24X8              
                      db D3DFMT_D32    
   ZBufferStrTable    dd OFFSET szZMode1 , OFFSET szZMode2  ; Указатели на текстовые строки
                      dd OFFSET szZMode3 , OFFSET szZMode4 
   szZMode1           db "16 bit",0                         ; Текстовые строки для Z буфера
   szZMode2           db "16 bit lock",0
   szZMode3           db "24 bit",0
   szZMode4           db "32 bit",0
         
   szDoubleBuffer     db "Двойной",0
   szTripleBuffer     db "Тройной",0
               
  .DATA?  				
    pd3d               dd ?                         ; Указатель на Direct3D			    
    d3ddm              D3DDISPLAYMODE < ? >         ; Структура для получения информации о доступных режимах  		 
    d3dpp              D3DPRESENT_PARAMETERS < ? >  ; Структура для создания Direct3DDevice8

    cmbHerz            dd ?                         ; ID ComboBox герц    
    cmbFullScreen      dd ?                         ; ID ComboBox полноэкранных режимов
    cmbWindow          dd ?                         ; ID ComboBox оконных режимов
    cmbBackBuffer      dd ?                         ; ID ComboBox количества BackBuffer
    cmbZBuffer         dd ?                         ; ID ComboBox форматов Z буфера    
            
    FullModeTable      dd 50 dup (?)                ; Для хранения доступных полноэкранных режимов ( делаем с запасом ). На каждый режим по 4 байта
    FullModeBPPTable   db 50 dup (?)                ; Для хранения форматов поверхности. На каждый режим по одному байту
    FullModeHerzTable  db 50 dup (?)                ; Для хранения частоты в Герцах. На каждый режим по одной самой высокой частоте
    FullModeStrBuffer  db 16 dup (?)                ; Буфер для формирования строки заносимой в ComboBox полноэкранных режимов
         
  .CODE
    mov     eax, iMsg
   
    cmp     eax, WM_INITDIALOG                      ; Если мы обрабатываем это сообщение то надо ОБЯЗАТЕЛЬНО вернуть в EAX число 1 
    je     wmInitDialog                             ; Если мы обработаем это сообщение то фокус ввода установится на первый обьект 
                                                    ; прописаный в ресурсах диалога
    cmp     eax, WM_COMMAND
    je     wmCommandDialog 
          
    xor eax, eax
    ret
    
;-----------------------------------------------------------------------------------------------------------------------------------------   
  wmInitDialog:
;--------------
   pushad				         ; Эта команда необходима для корректной работы приложения в Win98
   invoke  CheckRadioButton, hDlg , 20 , 21 , 20 ; Ставим метку на "В окошке" и снимаем с "Полноэкранное"
   
   lea     esi, cmbHerz                          ; Получаем идентификаторы наших ComboBox
   xor     ebx, ebx
   getId:
   push    ebx
   push    esi
   add     ebx, 22
   invoke  GetDlgItem, hDlg , ebx
   pop     esi
   pop     ebx
   mov     [esi+ebx*4],  eax
   inc     ebx
   cmp     ebx, 6
   jne     getId
            
   invoke  Direct3DCreate8, D3D_SDK_VERSION      ; Создаем Direct3D 			
   mov     pd3d, eax                             ; Сохраняем указатель на него
   
   d3d8    GetAdapterDisplayMode, pd3d, D3DADAPTER_DEFAULT, ADDR d3dpp  ; Получаем текущие размеры экрана и формат поверхности
   
   ;---------------------------------------------- Проверка доступных оконных режимов и заполнение списка
   lea     esi, d3dpp.BackBufferWidth
   mov     eax, [esi]			
   add     eax, [esi+4]                          ; Складываем текущие Высоту и Ширину
   mov     ebx, [esi+12]                         ; Заносим на правильное место текущий формат поверхности
   mov     [esi+8], ebx
   xor     ebx, ebx   
   
   getNextMode:                                  ; Цикл сравнения суммы текущих размеров и суммы возможных размеров окна
   push    ebx
   push    eax
   invoke  SendMessage, cmbWindow , CB_ADDSTRING , 0 , [WinModeStrTable + ebx*4] ; Добавляем в ComboBox строку с размерами окна
   pop     eax
   pop     ebx
   movzx   ecx, [WinModeTable+ebx*4]
   movzx   edx, [WinModeTable+ebx*4+2]
   add     ecx, edx   
   inc     ebx
   cmp     eax, ecx
   ja      getNextMode				
   
   ; В итоге в ComboBox занесены строки доступных нам оконных режимов от минимальных до текущих размеров экрана включительно
   
   ;---------------------------------------------------- Проверка доступных полноэкранных режимов и заполнение списка 				   	
   d3d8	GetAdapterModeCount, pd3d, D3DADAPTER_DEFAULT  ; Получаем число всех доступных полноэкранных режимов 
   dec    eax                                            ; Уменьшаем его на 1, т.к. их нумерация начинается с 0

   lea    esi, FullModeTable
   xor    ebx, ebx   
   mov    edx, ebx
   mov    ecx, eax         
   
   getMode:		
   push   ecx
   
   push   esi                                            ; Перед вызовом методов Direct3D всегда приходиться
   push   ebx                                            ; сохранять регистры
   push   edx
   
   d3d8   EnumAdapterModes, pd3d, D3DADAPTER_DEFAULT, ecx, ADDR d3ddm	; Получаем информацию об очередном режиме
   mov    eax, d3ddm.Width1							
   mov    ecx, d3ddm.Height
   mov    edi, eax
   add    edi, ecx
   add    edi, d3ddm.Format                              ; Складываем высоту, ширину и формат поверхности
   
   pop    edx
   pop    ebx
   pop    esi   
   
   cmp    edx, edi                                       ; Если у нас уже присутствует такая сумма то информацию о ней не заносим     
   je     noAdd   
   mov    edx, d3ddm.RefreshRate                         ; Если такой суммы нет то заносим данные в таблицу размеров, 
   mov    BYTE PTR [FullModeHerzTable+ebx], dl           ; Герц и формата поверхности
   mov    edx, d3ddm.Format
   mov    [FullModeBPPTable+ebx], dl 
   push   edx
   push   edi
   pop    edx
   pop    edi
   
   mov    [esi+ebx*4], eax
   mov    [esi+ebx*4+2], ecx
   inc    ebx   
   
   push   ebx       
   push   esi
   push   edx
   
   ;---------------------------------------------- Формирование строки и добавление ее в Combobox
   invoke  DW2A, eax, ADDR FullModeStrBuffer
   mov     BYTE PTR [ebx], 'x'
   inc     ebx
   invoke  DW2A, ecx, ebx
   mov     BYTE PTR [ebx], 'x'
   inc     ebx
   push    16
   pop     ecx
   cmp     edi, D3DFMT_X8R8G8B8
   jne     nextFormat
   push    32
   pop     ecx
   nextFormat:   
   cmp     edi, D3DFMT_A8R8G8B8
   jne     nextFormat2
   push    32
   pop     ecx
   nextFormat2:
   cmp     edi, D3DFMT_R8G8B8
   jne     exitCompare
   push    24
   pop     ecx
   exitCompare:
   invoke  DW2A, ecx , ebx    ; После всех этих манипуляций получается строка такого формата: 1024x768x32
   mov     BYTE PTR [ebx], 0       	
   invoke  SendMessage, cmbFullScreen , CB_ADDSTRING , 0 , ADDR FullModeStrBuffer	
   	   
   pop     edx
   pop     esi
   pop     ebx  	
     
   noAdd:   	
   pop     ecx
   dec     ecx
   test    ecx, ecx
   jne     getMode            ; LOOP применить не удается т.к. между ним и меткой получается больше 128 байт
   
   ; В итоге в ComboBox занесены строки доступных нам полноэкранных режимов с разными форматами поверхности
   ; и самым высоким числом Герц для каждого режима
      
   invoke  SendMessage, cmbBackBuffer , CB_ADDSTRING , 0 , ADDR szDoubleBuffer   ; Добавляем строки в ComboBox BackBuffer
   invoke  SendMessage, cmbBackBuffer , CB_ADDSTRING , 0 , ADDR szTripleBuffer   
   
   lea     esi, cmbHerz       ; Устанавливаем выбранными первые элементы в трех ComboBox
   push    3
   pop     ecx
   setSel:
   push    ecx
   push    esi
   invoke  SendMessage, [esi+ecx*4] , CB_SETCURSEL , 0 , 0
   pop     esi
   pop     ecx
   loop    setSel
   
   invoke  SendMessage, hDlg, WM_COMMAND ,  23 + CBN_SELCHANGE shl 16  , 0 ; Посылаем сообщение чтобы в ComboBox 
                                                                           ; была установлена частота и формат Z буфера
   popad                      ; Эта команда необходима для корректной работы приложения в Win98
   xor    eax, eax
   inc    eax                 ; Возвращаем 1, т.к. мы обработали сообщение WM_INITDIALOG
   ret     
;------------------------------------------------------------------------------------------------------------------------------------------  
  wmCommandDialog:
;------------------------------------------    
   movzx  eax, WORD PTR wParam  ; Здесь нам нужно получить HIWORD и LOWORD из wParam
   mov    ecx, wParam           ; HIWORD - код уведомления от элемента диалога
                                ; LOWORD - ID элемента диалога
   xor    ebx, ebx
						
   cmp    eax, 10               ; Получаем если нажали кнопку Запуск
   je     cmCloseDialog
   
   cmp    eax, 11               ; Получаем если нажали кнопку Закрыть
   je     cmCloseProgram
  
   cmp    eax, 20               ; Получаем если нажали RadioButton "В окошке"
   je     cmRadioWin
   
   cmp    eax, 21               ; Получаем если нажали RadioButton "Полноэкранное"
   je     cmRadioFull
   
   cmp    ecx, 23 + CBN_SELCHANGE shl 16 ; Получаем если выбрали элемент в ComboBox Полноэкранных режимов
   je     cmHerzZBuffer				
         
   xor    eax, eax
   ret   
                    
      cmRadioFull:  ; Выключаем одни ComboBox и включаем другие
     ;------------
      inc     ebx
   
      cmRadioWin:
     ;------------       
      invoke  EnableWindow, cmbFullScreen , ebx		
      invoke  EnableWindow, cmbHerz , ebx
      
      xor     ebx, 1
      invoke  EnableWindow, cmbWindow , ebx  
      xor     eax, eax
      ret       
           
      cmHerzZBuffer: ; Очищаем список и заносим Частоту режима выбранного в ComboBox "Полноэкранное" 
     ;--------------      
      invoke  SendMessage, cmbHerz , CB_RESETCONTENT , 0 , 0           	
      invoke  SendMessage, cmbFullScreen , CB_GETCURSEL , 0 , 0
      movzx   ebx, BYTE PTR [FullModeHerzTable+eax]      
      push    eax
      invoke  DW2A, ebx , ADDR FullModeStrBuffer
      invoke  SendMessage, cmbHerz , CB_ADDSTRING , 0 , ADDR FullModeStrBuffer
      invoke  SendMessage, cmbHerz , CB_SETCURSEL , 0 , 0
      
      invoke  SendMessage, cmbZBuffer , CB_RESETCONTENT , 0 , 0
      pop     eax
      movzx   ebx, BYTE PTR [FullModeBPPTable+eax]
      lea     esi, ZBufferFormatTable
      lea     edi, ZBufferStrTable
      xor     ecx, ecx
      checkZFormat:
      push    ebx      
      push    edi
      push    esi
      push    ecx
      movzx   edx, BYTE PTR [esi+ecx]
      push    edx
      d3d8    CheckDepthStencilMatch, pd3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, ebx, ebx, edx
      pop     edx
      pop     ecx
      test    eax, eax
      jne     noAddStr
      push    ecx
      push    edx
      invoke  SendMessage, cmbZBuffer , CB_ADDSTRING , 0 , [edi+ecx*4]    
      pop     edx
      push    edx
      invoke  SendMessage, cmbZBuffer , CB_SETITEMDATA , eax , edx
      pop     edx
      pop     ecx
      noAddStr:
      pop     esi
      pop     edi
      pop     ebx      
      inc     ecx
      cmp     ecx, 4
      jne     checkZFormat
      invoke  SendMessage, cmbZBuffer , CB_SETCURSEL , 0 , 0
            
      xor     eax, eax
      ret 
           
      cmCloseDialog: ; Заносим окончательные параметры в структуру D3DPRESENT_PARAMETERS
     ;--------------
      invoke  RegisterClassEx, addr cbSize                       ; Регистрируем класс окна                                      
      
      invoke  SendMessage, cmbBackBuffer , CB_GETCURSEL , 0 , 0
      inc     eax
      inc     eax
      mov     DWORD PTR [d3dpp.BackBufferCount], eax             ; Заносим число BackBuffer       
      mov     d3dpp.SwapEffect, D3DSWAPEFFECT_FLIP               ; Эффект обмена поверхностей
      mov     d3dpp.EnableAutoDepthStencil, TRUE                 ; Включаем Z буфер
      invoke  SendMessage, cmbZBuffer , CB_GETCURSEL , 0 , 0     
      invoke  SendMessage, cmbZBuffer , CB_GETITEMDATA , eax , 0
      mov     d3dpp.AutoDepthStencilFormat, eax                  ; Заносим формат Z буфера
            
      invoke  IsDlgButtonChecked, hDlg , 20                      ; Проверяем какая RadioButton выбрана
      test    eax, eax                                           ; и исходя из этого заполняем структуру
      je      EnableFull                   
      invoke  SendMessage, cmbWindow , CB_GETCURSEL , 0 , 0
      lea     esi, WinModeTable
      shl     eax, 2
      add     esi, eax		
      xor     ecx, ecx
      mov     edx, ecx
      push    [esi]   		
      pop     cx                                                 ; Берем размеры для выбранного режима
      pop     dx 		 
      mov     ebx, d3dpp.BackBufferWidth                         ; Здесь у нас пока лежат текущие размеры экрана
      mov     eax, d3dpp.BackBufferHeight
      sub     eax, edx                                           ; Вычисляем координаты x и y чтобы окно было по центру
      shr     eax, 1
      sub     ebx, ecx
      shr     ebx, 1
      mov     d3dpp.BackBufferWidth, ecx                         ; Заносим выбранные размеры
      mov     d3dpp.BackBufferHeight, edx		
      mov     d3dpp.Windowed, 1                                  ; Устанавливаем флаг что работаем в окошке 
      mov     esi, WS_SYSMENU                                    ; Стиль нашего окошка
      jmp     Create                                             ; Ну и собственно создаем окно
      EnableFull:
      invoke  SendMessage, cmbFullScreen , CB_GETCURSEL , 0 , 0
      movzx   ebx, BYTE PTR [FullModeHerzTable+eax]
      mov     d3dpp.FullScreen_RefreshRateInHz, ebx
      movzx   ebx, BYTE PTR [FullModeBPPTable+eax]
      mov     d3dpp.BackBufferFormat, ebx 
      mov     d3dpp.FullScreen_PresentationInterval, D3DPRESENT_INTERVAL_IMMEDIATE      
      lea     esi, FullModeTable
      shl     eax, 2
      add     esi, eax
      push    [esi] 		
      xor     ecx, ecx
      mov     edx, ecx
      mov     eax, ecx
      mov     ebx, ecx
      mov     d3dpp.Windowed, ecx
      pop     cx
      pop     dx
      mov     d3dpp.BackBufferWidth, ecx
      mov     d3dpp.BackBufferHeight, edx
      mov     esi, WS_POPUP
      Create:	; Перед созданием окна у нас уже полность заполнена структура D3DPRESENT_PARAMETERS
      invoke  CreateWindowEx, WS_EX_TOPMOST , ADDR szClassName , ADDR szAppName ,  \
              esi , ebx ,  eax , ecx , edx , NULL , NULL , hInstance , NULL      
      mov     hwnd , eax    							
      invoke  EndDialog, hDlg , 0     		
      xor     eax, eax
      ret
   		
      cmCloseProgram: 		
     ;---------------
      d3d8    Release, pd3d                       ; Освобождаем Direct3D8            
      invoke  EndDialog, hDlg , 0                 ; Если запуск не потребовался то закрываем диалог   
      invoke  ExitProcess, 0                      ; и завершаем выполнение программы
      xor     eax, eax
      ret
      
SetupDialog endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DW2A proc dwValue:DWORD, lpBuffer:DWORD ; Возвращает: в EAX - длина строки, в EBX - адрес завершающего нуля
                                        ; Является немного переделанной версией функции dw2a из библиотеки masm32
   push    edx
   push    ecx
   push    esi
   push    edi
    		
   mov     eax, dwValue
   mov     edi, lpBuffer

   test    eax,eax
   jnz     sign
    
  zero:
   mov     word ptr [edi],30h
   ret    
  sign:
   jns     pos
   mov     byte ptr [edi],'-'
   neg     eax
   inc     edi
  pos:      
   mov     ecx,429496730
   mov     esi, edi

  nextDigit:
   mov     ebx,eax
   mul     ecx
   mov     eax,edx
   lea     edx,[edx*4+edx]
   add     edx,edx
   sub     ebx,edx
   add     bl,48
   mov     [edi],bl
   inc     edi
   cmp     eax, 0
   ja      nextDigit
   mov     byte ptr [edi], 0     
   push    edi
    
  nextMove:
   dec     edi
   mov     al, [esi]
   mov     ah, [edi]
   mov     [edi], al
   mov     [esi], ah
   inc     esi
   cmp     esi, edi
   jb      nextMove
    
   pop     eax
   mov     ebx, eax
   sub     eax, lpBuffer

   pop     edi
   pop     esi    
   pop     ecx
   pop     edx
    
   ret
DW2A endp