Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. ;    Copyright (C) 2014 Anton_K
  2. ;
  3. ;    This program is free software: you can redistribute it and/or modify
  4. ;    it under the terms of the GNU General Public License as published by
  5. ;    the Free Software Foundation, either version 2 of the License, or
  6. ;    (at your option) any later version.
  7. ;
  8. ;    This program is distributed in the hope that it will be useful,
  9. ;    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;    GNU General Public License for more details.
  12. ;
  13. ;    You should have received a copy of the GNU General Public License
  14. ;    along with this program. If not, see <http://www.gnu.org/licenses/>.
  15.  
  16. include '../../../develop/libraries/libs-dev/libio/libio.inc'
  17. include '../../../develop/libraries/libs-dev/libimg/libimg.inc'
  18.  
  19. include 'datadef.inc'
  20.  
  21. ; ============================================================================ ;
  22. ; < eax = 0 - fail                                                             ;
  23. ; ============================================================================ ;
  24. proc akode.init uses ebx ecx edx, plane_width, plane_height, fov, block_base_size, block_height
  25.         bsr     ecx, [block_base_size]
  26.         xor     eax, eax
  27.         inc     eax
  28.         shl     eax, cl
  29.         mov     [akode_data.BlockWidthPowerOf2], ecx
  30.         mov     [akode_data.BlockSize.Width], eax
  31.  
  32.         mov     eax, [block_height]
  33.         mov     [akode_data.BlockSize.Height], eax
  34.  
  35.         shr     eax, 1
  36.         mov     [akode_data.Camera.Position.Z], eax
  37.  
  38.         xor     eax, eax
  39.         mov     [akode_data.Camera.Position.X], eax
  40.         mov     [akode_data.Camera.Position.Y], eax
  41.         mov     [akode_data.Camera.Direction], eax
  42.         mov     [akode_data.OptimizedGetImage], eax
  43.         dec     eax
  44.         mov     [akode_data.MovementDirection], eax
  45.         mov     [akode_data.TurningDirection], eax
  46.         inc     eax
  47.         stdcall akode.set_shading, eax, eax
  48.         test    eax, eax
  49.         jz      .exit
  50.  
  51.         mov     edx, [plane_width]
  52.  
  53.         mov     ecx, edx
  54.         shl     ecx, 2
  55.         mcall   68, 12                                          ; alloc width * 4 bytes
  56.  
  57.         test    eax, eax
  58.         jz      .exit
  59.  
  60.         mov     [akode_data.DepthBufferPtr], eax
  61.  
  62.         mov     eax, [plane_height]
  63.         mov     ecx, eax
  64.         shl     ecx, 2
  65.         imul    ecx, edx                                        ; ecx = height * 4 * width
  66.  
  67.         mov     [akode_data.ProjectionPlane.Size.Height], eax
  68.         mov     [akode_data.ProjectionPlane.Size.Width], edx
  69.         mov     [akode_data.ImageBufferSize], ecx
  70.  
  71.         mov     ebx, eax
  72.         or      ebx, edx
  73.         test    ebx, 0Fh
  74.         jnz     @f
  75.         inc     [akode_data.OptimizedGetImage]
  76. @@:
  77.  
  78.         shr     eax, 1
  79.         mov     [akode_data.ProjectionPlane.MidY], eax          ; MidY = height / 2
  80.  
  81.         mcall   68, 12                                          ; alloc ecx bytes
  82.  
  83.         test    eax, eax
  84.         jz      .exit
  85.  
  86.         mov     [akode_data.ImageBufferPtr], eax
  87.         DEBUGF  DEBUG_FINE, 'akode_data.ImageBufferPtr: %x\n', eax:8
  88.         DEBUGF  DEBUG_FINE, 'akode_data.OptimizedGetImage: %u\n', [akode_data.OptimizedGetImage]
  89.  
  90.         mov     ecx, [fov]
  91.         mov     ebx, edx
  92.         imul    eax, edx, 360
  93.         xor     edx, edx
  94.         div     ecx                                             ; eax = width * 360 / fov
  95.  
  96.         mov     [akode_data.Camera.FieldOfView], ecx
  97.  
  98.         mov     [akode_data.Angle360], eax
  99.  
  100.         stdcall akode._.calc_tables
  101.  
  102.         test    eax, eax
  103.         jz      .exit
  104.  
  105.         shr     ebx, 1                                          ; ebx = width / 2
  106.         push    ebx
  107.         shl     ebx, 5                                          ; ebx * 32
  108.         mov     eax, [akode_data.TrigonometricTablePtr]
  109.  
  110.         fild    dword [esp]                                     ; width / 2
  111.         fdiv    qword [eax + ebx + 16]                          ; tan (fov / 2)
  112.         fistp   dword [esp]
  113.  
  114.         pop     eax
  115.         mov     [akode_data.CameraToPlaneDistance], eax
  116.         mov     ebx, eax
  117.  
  118.         mul     [block_height]
  119.         mov     [akode_data.WallHeightDividend], eax
  120.  
  121.         mov     eax, [block_height]
  122.         sub     eax, [akode_data.Camera.Position.Z]
  123.         mul     ebx
  124.         mov     [akode_data.CeilingDistanceDividend], eax
  125.  
  126.         imul    ebx, [akode_data.Camera.Position.Z]
  127.         mov     [akode_data.FloorDistanceDividend], ebx
  128.  
  129.         DEBUGF  DEBUG_FINE, 'akode_data.CameraToPlaneDistance: %u\n', [akode_data.CameraToPlaneDistance]
  130.  
  131.         stdcall akode.set_movement_speed, [akode_data.BlockSize.Width], 90
  132.  
  133. .exit:
  134.         ret
  135. endp
  136. ; ============================================================================ ;
  137.  
  138. ; ============================================================================ ;
  139. proc akode.cleanup uses eax ebx ecx edx
  140.         stdcall akode.unload_current_level
  141.  
  142.         xor     edx, edx
  143.         mov     ebx, 13
  144.  
  145.         mov     ecx, [akode_data.ImageBufferPtr]
  146.         test    ecx, ecx
  147.         jz      @f
  148.         mcall   68                                              ; free
  149.         mov     [akode_data.ImageBufferPtr], edx
  150. @@:
  151.         mov     ecx, [akode_data.DepthBufferPtr]
  152.         test    ecx, ecx
  153.         jz      @f
  154.         mcall   68
  155.         mov     [akode_data.DepthBufferPtr], edx
  156. @@:
  157.         mov     ecx, [akode_data.TrigonometricTablePtr]
  158.         test    ecx, ecx
  159.         jz      @f
  160.         mcall   68
  161.         mov     [akode_data.TrigonometricTablePtr], edx
  162. @@:
  163.         mov     ecx, [akode_data.BlockWidthTanTablePtr]
  164.         test    ecx, ecx
  165.         jz      @f
  166.         mcall   68
  167.         mov     [akode_data.BlockWidthTanTablePtr], edx
  168. @@:
  169.         mov     ecx, [akode_data.ShadingTablePtr]
  170.         test    ecx, ecx
  171.         jz      @f
  172.         mcall   68
  173.         mov     [akode_data.ShadingTablePtr], edx
  174. @@:
  175.  
  176.         ret
  177. endp
  178. ; ============================================================================ ;
  179.  
  180. ; ============================================================================ ;
  181. ; > level_load_callback = proc callback AKODE_LEVEL_LOAD, result               ;
  182. ; > action_callback     = proc callback AKODE_ACTION, cell x, cell y, result   ;
  183. ; ============================================================================ ;
  184. proc akode.set_callbacks level_load_callback, action_callback
  185.         m2m     [akode_data.LevelLoadCallback], [level_load_callback]
  186.         m2m     [akode_data.ActionCallback], [action_callback]
  187.         ret
  188. endp
  189. ; ============================================================================ ;
  190.  
  191. ; ============================================================================ ;
  192. ; < eax = 0 - failed to load some textures or create shading table             ;
  193. ; ============================================================================ ;
  194. proc akode.load_level uses ebx ecx edx esi edi, level_ptr
  195.         locals
  196.                 load_texture_results    dd 1
  197.         endl
  198.  
  199.         stdcall akode.unload_current_level
  200.  
  201.         mov     ebx, akode_data.CurrentLevel
  202.  
  203.         cld
  204.         mov     esi, [level_ptr]
  205.         mov     edi, ebx
  206.         mov     ecx, sizeof.akode.LevelHeader
  207.         rep     movsb
  208.  
  209.         mov     [akode_data.CurrentLevelGridPtr], esi
  210.  
  211.         mov     eax, [ebx + akode.LevelHeader.InitCallback]
  212.         test    eax, eax
  213.         jz      @f
  214.         stdcall eax
  215.  
  216. @@:
  217.         mov     edx, [akode_data.LevelLoadCallback]
  218.         test    edx, edx
  219.         jz      @f
  220.         stdcall edx, AKODE_LEVEL_LOAD.START, eax
  221.  
  222. @@:
  223.         mov     ecx, [ebx + akode.LevelHeader.Size.Width]
  224.         imul    ecx, [ebx + akode.LevelHeader.Size.Height]
  225.  
  226. .load_textures_loop:
  227.         mov     edi, [esi]
  228.         add     esi, 4
  229.  
  230.         test    edi, edi
  231.         jz      .skip
  232.  
  233.         push    ecx
  234.  
  235.         mov     ecx, 6 * 2                                      ; 6 combined textures per cell
  236.  
  237. .load_cell_textures_loop:
  238.         mov     eax, [edi]
  239.         add     edi, 4
  240.  
  241.         test    eax, eax
  242.         jz      @f
  243.  
  244.         stdcall akode.load_texture, eax
  245.  
  246.         test    eax, eax
  247.         jnz     @f
  248.         mov     [load_texture_results], eax
  249.  
  250. @@:
  251.         sub     ecx, 1
  252.         jnz     .load_cell_textures_loop
  253.  
  254.         pop     ecx
  255.  
  256. .skip:
  257.         sub     ecx, 1
  258.         jnz     .load_textures_loop
  259.  
  260.         mov     ecx, [ebx + akode.LevelHeader.ObjectCount]
  261.         test    ecx, ecx
  262.         jz      @f
  263.  
  264.         mov     [akode_data.CurrentLevelObjectsPtr], esi
  265.  
  266. .load_object_textures_loop:
  267.         mov     eax, [esi]
  268.         add     esi, sizeof.akode.Object
  269.  
  270.         test    eax, eax
  271.         jz      .skip_object
  272.  
  273.         stdcall akode.load_texture, eax
  274.  
  275.         test    eax, eax
  276.         jnz     .skip_object
  277.         mov     [load_texture_results], eax
  278.  
  279. .skip_object:
  280.         sub     ecx, 1
  281.         jnz     .load_object_textures_loop
  282.  
  283. @@:
  284.         mov     ecx, [ebx + akode.LevelHeader.TextureCount]
  285.         test    ecx, ecx
  286.         jz      @f
  287.  
  288.         mov     [akode_data.CurrentLevelAddTexturesPtr], esi
  289.  
  290. .load_additional_textures_loop:
  291.         mov     eax, [esi]
  292.         add     esi, 4
  293.  
  294.         test    eax, eax
  295.         jz      .skip_additional
  296.  
  297.         stdcall akode.load_texture, eax
  298.  
  299.         test    eax, eax
  300.         jnz     .skip_additional
  301.         mov     [load_texture_results], eax
  302.  
  303. .skip_additional:
  304.         sub     ecx, 1
  305.         jnz     .load_additional_textures_loop
  306.  
  307. @@:
  308.         mov     edi, [akode_data.BlockSize.Width]
  309.         shr     edi, 1
  310.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  311.  
  312.         mov     eax, [ebx + akode.LevelHeader.StartPosition.X]
  313.         shl     eax, cl
  314.         add     eax, edi
  315.         mov     [akode_data.Camera.Position.X], eax
  316.  
  317.         mov     eax, [ebx + akode.LevelHeader.StartPosition.Y]
  318.         shl     eax, cl
  319.         add     eax, edi
  320.         mov     [akode_data.Camera.Position.Y], eax
  321.  
  322.         mov     eax, [ebx + akode.LevelHeader.StartDirection]
  323.         imul    eax, [akode_data.Angle90]
  324.         mov     [akode_data.Camera.Direction], eax
  325.  
  326.         xor     eax, eax
  327.         dec     eax
  328.         mov     [akode_data.MovementDirection], eax
  329.         mov     [akode_data.TurningDirection], eax
  330.  
  331.         stdcall akode.set_shading, [ebx + akode.LevelHeader.ShadingColor], [ebx + akode.LevelHeader.ShadingDistance]
  332.         test    eax, eax
  333.         jz      @f
  334.         mov     eax, [load_texture_results]
  335. @@:
  336.  
  337.         test    edx, edx
  338.         jz      @f
  339.         stdcall edx, AKODE_LEVEL_LOAD.END, eax
  340.  
  341. @@:
  342.         ret
  343. endp
  344. ; ============================================================================ ;
  345.  
  346. ; ============================================================================ ;
  347. proc akode.unload_current_level uses eax ecx edx esi edi
  348.         mov     esi, [akode_data.CurrentLevelGridPtr]
  349.         test    esi, esi
  350.         jz      .exit
  351.  
  352.         mov     ecx, [akode_data.CurrentLevel.Size.Width]
  353.         imul    ecx, [akode_data.CurrentLevel.Size.Height]
  354.  
  355. .unload_textures_loop:
  356.         mov     edi, [esi]
  357.         add     esi, 4
  358.  
  359.         test    edi, edi
  360.         jz      .skip
  361.  
  362.         mov     edx, 6 * 2                                      ; 6 combined textures per cell
  363.  
  364. .unload_cell_textures_loop:
  365.         mov     eax, [edi]
  366.         add     edi, 4
  367.  
  368.         test    eax, eax
  369.         jz      @f
  370.  
  371.         stdcall akode.unload_texture, eax
  372.  
  373. @@:
  374.         sub     edx, 1
  375.         jnz     .unload_cell_textures_loop
  376.  
  377. .skip:
  378.         sub     ecx, 1
  379.         jnz     .unload_textures_loop
  380.  
  381.         mov     [akode_data.CurrentLevelGridPtr], ecx
  382.  
  383.         mov     ecx, [akode_data.CurrentLevel.ObjectCount]
  384.         test    ecx, ecx
  385.         jz      @f
  386.  
  387. .unload_object_textures_loop:
  388.         mov     eax, [esi]
  389.         add     esi, sizeof.akode.Object
  390.  
  391.         test    eax, eax
  392.         jz      .skip_object
  393.  
  394.         stdcall akode.unload_texture, eax
  395.  
  396. .skip_object:
  397.         sub     ecx, 1
  398.         jnz     .unload_object_textures_loop
  399.  
  400. @@:
  401.         mov     [akode_data.CurrentLevelObjectsPtr], ecx
  402.  
  403.         mov     ecx, [akode_data.CurrentLevel.TextureCount]
  404.         test    ecx, ecx
  405.         jz      @f
  406.  
  407. .unload_additional_textures_loop:
  408.         mov     eax, [esi]
  409.         add     esi, 4
  410.  
  411.         test    eax, eax
  412.         jz      .skip_additional
  413.  
  414.         stdcall akode.unload_texture, eax
  415.  
  416. .skip_additional:
  417.         sub     ecx, 1
  418.         jnz     .unload_additional_textures_loop
  419.  
  420. @@:
  421.         mov     [akode_data.CurrentLevelAddTexturesPtr], ecx
  422.  
  423.         mov     eax, [akode_data.CurrentLevel.DestroyCallback]
  424.         test    eax, eax
  425.         jz      @f
  426.         stdcall eax
  427.  
  428. @@:
  429.         mov     edx, [akode_data.LevelLoadCallback]
  430.         test    edx, edx
  431.         jz      @f
  432.         stdcall edx, AKODE_LEVEL_LOAD.UNLOADED, eax
  433.  
  434. @@:
  435.  
  436. .exit:
  437.         ret
  438. endp
  439. ; ============================================================================ ;
  440.  
  441. ; ============================================================================ ;
  442. ; < eax = 0 - fail                                                             ;
  443. ; ============================================================================ ;
  444. proc akode.load_texture uses ebx ecx edx, texture_desc_ptr
  445.         mov     ebx, [texture_desc_ptr]
  446.  
  447.         mov     eax, [ebx + akode.TextureDesc.Type]
  448.         or      eax, [ebx + akode.TextureDesc.ImageDataPtr]
  449.         jnz     .exit
  450.  
  451.         mov     ecx, [akode_data.BlockSize.Width]
  452.         mov     edx, ecx
  453.  
  454.         mov     al, [ebx + akode.TextureDesc.Usage]
  455.         test    al, al
  456.         jz      @f
  457.         mov     edx, [akode_data.BlockSize.Height]
  458.  
  459. @@:
  460.         stdcall akode.load_and_scale_image, [ebx + akode.TextureDesc.ImagePathPtr], ecx, edx, 1
  461.  
  462.         mov     [ebx + akode.TextureDesc.ImageDataPtr], eax
  463.  
  464. .exit:
  465.         ret
  466. endp
  467. ; ============================================================================ ;
  468.  
  469. ; ============================================================================ ;
  470. proc akode.unload_texture uses eax ebx ecx, texture_desc_ptr
  471.         mov     ebx, [texture_desc_ptr]
  472.  
  473.         mov     eax, [ebx + akode.TextureDesc.Type]
  474.         test    eax, eax
  475.         jnz     .exit
  476.  
  477.         mov     ecx, [ebx + akode.TextureDesc.ImageDataPtr]
  478.         test    ecx, ecx
  479.         jz      .exit
  480.  
  481.         push    ebx
  482.         mcall   68, 13
  483.         pop     ebx
  484.  
  485.         xor     eax, eax
  486.         mov     [ebx + akode.TextureDesc.ImageDataPtr], eax
  487.  
  488. .exit:
  489.         ret
  490. endp
  491. ; ============================================================================ ;
  492.  
  493. ; ============================================================================ ;
  494. ; < eax = pointer to image data / 0 - fail                                     ;
  495. ; ============================================================================ ;
  496. proc akode.load_and_scale_image uses ebx ecx edx esi edi, image_path_ptr, width, height, internal_format
  497.         locals
  498.                 decode_options  ImageDecodeOptions      sizeof.ImageDecodeOptions, 0FF00FFh
  499.         endl
  500.  
  501.         stdcall akode.load_file, [image_path_ptr]
  502.         test    eax, eax
  503.         jz      .exit
  504.  
  505.         mov     esi, eax                                        ; esi = file data
  506.  
  507.         lea     eax, [decode_options]
  508.         push    esi
  509.         invoke  img_decode, esi, ebx, eax
  510.         pop     esi
  511.         test    eax, eax
  512.         jz      .exit_and_free_file_fail
  513.  
  514.         mov     edi, eax                                        ; edi = image handle
  515.  
  516.         xor     eax, eax
  517.         push    esi edi
  518.         invoke  img_convert, edi, eax, Image.bpp24, eax, eax
  519.         pop     edi esi
  520.         push    eax
  521.  
  522.         push    esi
  523.         invoke  img_destroy, edi                                ; destroy handle from img_decode
  524.         pop     ecx
  525.         mcall   68, 13
  526.  
  527.         pop     edi                                             ; edi = image handle from img_convert
  528.         test    edi, edi
  529.         jz      .exit_fail
  530.  
  531.         mov     ebx, [width]
  532.         mov     ecx, [height]
  533.  
  534.         cmp     [edi + Image.Width], ebx
  535.         jne     .scale
  536.         cmp     [edi + Image.Height], ecx
  537.         jne     .scale
  538.         jmp     @f
  539.  
  540. .scale:
  541.         xor     eax, eax
  542.         push    edi
  543.         invoke  img_scale, edi, eax, eax, [edi + Image.Width], [edi + Image.Height], eax, LIBIMG_SCALE_STRETCH, LIBIMG_INTER_BILINEAR, ebx, ecx
  544.         pop     edi
  545.         push    eax
  546.  
  547.         invoke  img_destroy, edi                                ; destroy handle from img_convert
  548.  
  549.         pop     edi                                             ; edi = image handle from img_scale
  550.         test    edi, edi
  551.         jz      .exit_fail
  552.  
  553. @@:
  554.         mov     eax, [internal_format]
  555.         test    eax, eax
  556.         jz      @f
  557.  
  558.         invoke  img_flip, edi, FLIP_HORIZONTAL
  559.         invoke  img_rotate, edi, ROTATE_90_CCW
  560.  
  561. @@:
  562.         stdcall akode._.convert_image_to_32bpp, edi
  563.         push    eax
  564.  
  565.         invoke  img_destroy, edi
  566.  
  567.         pop     eax
  568.         jmp     .exit
  569.  
  570. .exit_and_free_file_fail:
  571.         mcall   68, 13, esi
  572. .exit_fail:
  573.         xor     eax, eax
  574. .exit:
  575.         ret
  576. endp
  577. ; ============================================================================ ;
  578.  
  579. ; ============================================================================ ;
  580. ; < eax = pointer to image data / 0 - fail                                     ;
  581. ; ============================================================================ ;
  582. proc akode._.convert_image_to_32bpp uses ebx ecx edx esi edi, image
  583.         mov     edi, [image]
  584.  
  585.         invoke  img_to_rgb, edi
  586.         test    eax, eax
  587.         jz      .exit
  588.  
  589.         mov     esi, eax
  590.  
  591.         mov     ecx, [edi + Image.Width]
  592.         imul    ecx, [edi + Image.Height]
  593.         shl     ecx, 2
  594.  
  595.         mcall   68, 12
  596.         test    eax, eax
  597.         jz      .exit_and_free_fail
  598.  
  599.         push    eax
  600.         mov     edi, eax
  601.         mov     edx, esi
  602.         add     esi, 8
  603.         shr     ecx, 2
  604.  
  605. @@:
  606.         mov     ax, [esi]
  607.         movzx   bx, byte [esi + 2]
  608.  
  609.         mov     [edi], ax
  610.         mov     [edi + 2], bx
  611.  
  612.         add     esi, 3
  613.         add     edi, 4
  614.  
  615.         sub     ecx, 1
  616.         jnz     @b
  617.  
  618.         mcall   68, 13, edx
  619.         pop     eax
  620.         jmp     .exit
  621.  
  622. .exit_and_free_fail:
  623.         mcall   68, 13, esi
  624.         xor     eax, eax
  625. .exit:
  626.         ret
  627. endp
  628. ; ============================================================================ ;
  629.  
  630. ; ============================================================================ ;
  631. ; < eax = pointer to data / 0 - fail                                           ;
  632. ; < ebx = file size                                                            ;
  633. ; ============================================================================ ;
  634. proc akode.load_file uses ecx edx esi edi, file_path_ptr
  635.         invoke  file_size, [file_path_ptr]
  636.         test    eax, eax
  637.         jnz     .exit_fail
  638.  
  639.         mov     edx, ebx                                        ; edx = file size
  640.  
  641.         mcall   68, 12, edx
  642.         test    eax, eax
  643.         jz      .exit
  644.  
  645.         mov     edi, eax                                        ; edi = pointer to data
  646.  
  647.         invoke  file_open, [file_path_ptr], O_READ
  648.         test    eax, eax
  649.         jz      .exit_and_free_fail
  650.  
  651.         mov     esi, eax                                        ; esi = file handle
  652.         mov     ebx, edx
  653.  
  654.         invoke  file_read, esi, edi, edx
  655.         sub     edx, eax
  656.  
  657.         invoke  file_close, esi
  658.  
  659.         test    edx, edx
  660.         jnz     .exit_and_free_fail
  661.  
  662.         mov     eax, edi
  663.         jmp     .exit
  664.  
  665. .exit_and_free_fail:
  666.         mcall   68, 13, edi
  667. .exit_fail:
  668.         xor     eax, eax
  669. .exit:
  670.         ret
  671. endp
  672. ; ============================================================================ ;
  673.  
  674. ; ============================================================================ ;
  675. ; < eax = 0 - fail                                                             ;
  676. ; ============================================================================ ;
  677. proc akode._.calc_tables uses ebx ecx edx esi edi
  678.         mov     eax, [akode_data.Angle360]
  679.         mov     ecx, eax
  680.         mov     edi, eax
  681.  
  682.         shr     eax, 1
  683.         mov     [akode_data.Angle180], eax
  684.         mov     ebx, eax
  685.  
  686.         shr     eax, 1
  687.         mov     [akode_data.Angle90], eax
  688.  
  689.         add     ebx, eax
  690.         mov     [akode_data.Angle270], ebx
  691.  
  692.         DEBUGF  DEBUG_FINE, 'akode_data.ProjectionPlane.Size.Width: %u\n', [akode_data.ProjectionPlane.Size.Width]
  693.         DEBUGF  DEBUG_FINE, 'akode_data.Camera.FieldOfView: %u\n', [akode_data.Camera.FieldOfView]
  694.         DEBUGF  DEBUG_FINE, 'akode_data.Angle[90, 180, 270, 360]: %u, %u, %u, %u\n', [akode_data.Angle90], [akode_data.Angle180], \
  695.                                                                                      [akode_data.Angle270], [akode_data.Angle360]
  696.  
  697.         shl     ecx, 5                                          ; ecx = Angle360 * (8 bytes * 4 columns)
  698.         mcall   68, 20, , [akode_data.TrigonometricTablePtr]    ; realloc ecx bytes
  699.  
  700.         test    eax, eax
  701.         jz      .exit
  702.  
  703.         mov     [akode_data.TrigonometricTablePtr], eax
  704.  
  705.         fninit
  706.         xor     ecx, ecx
  707.         fldpi
  708.         fldpi
  709.         faddp
  710.         fidiv   [akode_data.Angle360]                           ; 2 * pi / Angle360
  711. @@:                                                             ; calculate sin, cos, tan, 1 / cos
  712.         fld     st0
  713.         mov     [eax], ecx
  714.  
  715.         fimul   dword [eax]                                     ; 2 * pi / Angle360 * ecx = ecx in radians
  716.  
  717.         fsincos
  718.         fst     qword [eax + 8]                                 ; cos
  719.  
  720.         fld     st0
  721.         fld1
  722.         fdivrp
  723.         fstp    qword [eax + 24]                                ; 1 / cos
  724.  
  725.         fxch
  726.         fst     qword [eax]                                     ; sin
  727.         fdivrp
  728.         fstp    qword [eax + 16]                                ; tan
  729.  
  730.         add     ecx, 1
  731.         add     eax, 32
  732.         cmp     ecx, edi
  733.         jne     @b
  734.  
  735.         ;mov     ecx, edi
  736.         shl     ecx, 3                                          ; ecx = Angle360 * (4 bytes * 2 columns)
  737.         mcall   68, 20, , [akode_data.BlockWidthTanTablePtr]    ; realloc ecx bytes
  738.  
  739.         test    eax, eax
  740.         jz      .pop_fpu_exit
  741.  
  742.         mov     [akode_data.BlockWidthTanTablePtr], eax
  743.  
  744.         mov     edx, [akode_data.Angle180]
  745.         mov     ebx, [akode_data.Angle90]
  746.         mov     esi, [akode_data.Angle270]
  747.         xor     ecx, ecx
  748. @@:                                                             ; calculate BlockSize.Width * tan and BlockSize.Width / tan
  749.         fld     st0
  750.         mov     [eax], ecx
  751.  
  752.         fimul   dword [eax]                                     ; 2 * pi / Angle360 * ecx = ecx in radians
  753.  
  754.         fptan
  755.         fld     st1
  756.         fimul   [akode_data.BlockSize.Width]
  757.         fistp   dword [eax]                                     ; BlockSize.Width * tan
  758.  
  759.         cmp     ecx, ebx
  760.         jb      .reverse_sign
  761.         cmp     ecx, esi
  762.         ja      .reverse_sign
  763.         jmp     .dont_reverse_sign
  764. .reverse_sign:
  765.         neg     dword [eax]                                     ; reverse sign for angles < 90 and > 270
  766. .dont_reverse_sign:
  767.  
  768.         fdivrp
  769.         fimul   [akode_data.BlockSize.Width]
  770.         fistp   dword [eax + 4]                                 ; BlockSize.Width * 1 / tan
  771.  
  772.         cmp     ecx, edx
  773.         jna     .dont_reverse_sign2
  774.         neg     dword [eax + 4]                                 ; reverse sign for angles > 180
  775. .dont_reverse_sign2:
  776.  
  777.         add     ecx, 1
  778.         add     eax, 8
  779.         cmp     ecx, edi
  780.         jne     @b
  781.  
  782. .pop_fpu_exit:
  783.         fstp    st0
  784.  
  785. .exit:
  786.         ret
  787. endp
  788. ; ============================================================================ ;
  789.  
  790. ; ============================================================================ ;
  791. proc akode.set_field_of_view fov
  792.         ; not supported
  793.  
  794.         ret
  795. endp
  796. ; ============================================================================ ;
  797.  
  798. ; ============================================================================ ;
  799. ; < eax = 0 - fail                                                             ;
  800. ; ============================================================================ ;
  801. proc akode.set_shading uses ebx ecx edx, color, distance
  802.         m2m     [akode_data.ShadingColor], [color]
  803.  
  804.         mov     ecx, [distance]
  805.         mov     [akode_data.ShadingDistance], ecx
  806.  
  807.         inc     ecx
  808.         shl     ecx, 2
  809.  
  810.         mcall   68, 20, , [akode_data.ShadingTablePtr]          ; realloc ecx bytes
  811.         test    eax, eax
  812.         jz      .exit
  813.  
  814.         mov     [akode_data.ShadingTablePtr], eax
  815.  
  816.         fninit
  817.         xor     ecx, ecx
  818.         cmp     [distance], ecx
  819.         jne     @f
  820.         mov     dword [eax], 255
  821.         jmp     .exit
  822.  
  823. @@:
  824.         imul    ebx, ecx, 255
  825.         mov     [eax], ebx
  826.         fild    dword [eax]
  827.         fidiv   [distance]
  828.         fistp   dword [eax]
  829.  
  830.         mov     ebx, 255
  831.         sub     ebx, [eax]
  832.         mov     [eax], ebx
  833.  
  834.         add     ecx, 1
  835.         add     eax, 4
  836.         cmp     [distance], ecx
  837.         jae     @b
  838.  
  839. .exit:
  840.         ret
  841. endp
  842. ; ============================================================================ ;
  843.  
  844. ; ============================================================================ ;
  845. ; > movement_speed      = speed in px per second                               ;
  846. ; > turning_speed       = speed in degrees per second                          ;
  847. ; ============================================================================ ;
  848. proc akode.set_movement_speed uses eax ebx edx, movement_speed, turning_speed
  849.         mov     eax, [turning_speed]
  850.         mul     [akode_data.Angle360]
  851.         mov     ebx, 360
  852.         div     ebx
  853.         mov     [akode_data.TurningSpeed], eax
  854.  
  855.         m2m     [akode_data.MovementSpeed], [movement_speed]
  856.  
  857.         ret
  858. endp
  859. ; ============================================================================ ;
  860.  
  861. ; ============================================================================ ;
  862. ; > movement_direction  = AKODE_DIRECTION.NORTH - forward,                     ;
  863. ;                         AKODE_DIRECTION.SOUTH - backward                     ;
  864. ; ============================================================================ ;
  865. proc akode.start_moving uses eax ebx, movement_direction
  866.         m2m     [akode_data.MovementDirection], [movement_direction]
  867.         mcall   26, 9
  868.         mov     [akode_data.LastMoveTimestamp], eax
  869.         ret
  870. endp
  871. ; ============================================================================ ;
  872.  
  873. ; ============================================================================ ;
  874. proc akode.stop_moving
  875.         mov     [akode_data.MovementDirection], -1
  876.         ret
  877. endp
  878. ; ============================================================================ ;
  879.  
  880. ; ============================================================================ ;
  881. ; > turning_direction   = AKODE_DIRECTION.WEST - left,                         ;
  882. ;                         AKODE_DIRECTION.EAST - right                         ;
  883. ; ============================================================================ ;
  884. proc akode.start_turning uses eax ebx, turning_direction
  885.         m2m     [akode_data.TurningDirection], [turning_direction]
  886.         mcall   26, 9
  887.         mov     [akode_data.LastTurnTimestamp], eax
  888.         ret
  889. endp
  890. ; ============================================================================ ;
  891.  
  892. ; ============================================================================ ;
  893. proc akode.stop_turning
  894.         mov     [akode_data.TurningDirection], -1
  895.         ret
  896. endp
  897. ; ============================================================================ ;
  898.  
  899. ; ============================================================================ ;
  900. proc akode.process uses eax ebx ecx edx esi edi
  901.         stdcall akode._.process_moving
  902.  
  903.         ret
  904. endp
  905. ; ============================================================================ ;
  906.  
  907. ; ============================================================================ ;
  908. proc akode._.process_moving
  909.         locals
  910.                 timestamp               dd ?
  911.                 collision_distance      dd ?
  912.                 current_cell_x          dd ?
  913.                 current_cell_y          dd ?
  914.         endl
  915.  
  916.         mov     esi, [akode_data.MovementDirection]
  917.         mov     edi, [akode_data.TurningDirection]
  918.         mov     eax, esi
  919.         and     eax, edi
  920.         js      .exit
  921.  
  922.         mcall   26, 9                                           ; get timestamp
  923.         mov     [timestamp], eax
  924.  
  925.         test    edi, edi
  926.         js      .not_turning
  927.  
  928.         mov     ebx, eax
  929.         sub     ebx, [akode_data.LastTurnTimestamp]
  930.         cmp     ebx, 4
  931.         jb      .not_turning
  932.  
  933.         mov     [akode_data.LastTurnTimestamp], eax
  934.  
  935.         mov     eax, ebx
  936.         mul     [akode_data.TurningSpeed]
  937.         mov     ecx, 100
  938.         div     ecx                                             ; eax = turn angle
  939.  
  940.         test    eax, eax
  941.         jnz     @f
  942.         inc     eax                                             ; clamp
  943. @@:
  944.  
  945.         cmp     [akode_data.Angle90], eax
  946.         jae     @f
  947.         mov     eax, [akode_data.Angle90]                       ; clamp
  948. @@:
  949.  
  950.         mov     edx, [akode_data.Camera.Direction]
  951.         mov     ecx, [akode_data.Angle360]
  952.  
  953.         test    edi, edi
  954.         jz      .turn_right
  955.  
  956.         ; turn left
  957.         add     edx, eax
  958.         cmp     ecx, edx
  959.         ja      @f
  960.         sub     edx, ecx
  961. @@:
  962.         jmp     @f
  963.  
  964. .turn_right:
  965.         sub     edx, eax
  966.         jns     @f
  967.         add     edx, ecx
  968. @@:
  969.         mov     [akode_data.Camera.Direction], edx
  970.  
  971.         mov     eax, [timestamp]
  972.  
  973. .not_turning:
  974.         test    esi, esi
  975.         js      .exit
  976.  
  977.         mov     ebx, eax
  978.         sub     ebx, [akode_data.LastMoveTimestamp]
  979.         cmp     ebx, 4
  980.         jb      .exit
  981.  
  982.         mov     [akode_data.LastMoveTimestamp], eax
  983.  
  984.         mov     eax, ebx
  985.         mul     [akode_data.MovementSpeed]
  986.         mov     ecx, 100
  987.         div     ecx                                             ; eax = move distance
  988.  
  989.         cmp     eax, 3
  990.         jae     @f
  991.         mov     eax, 3                                          ; clamp
  992. @@:
  993.  
  994.         mov     edx, [akode_data.BlockSize.Width]
  995.         shr     edx, 2
  996.         mov     ebx, edx
  997.         sub     edx, 2
  998.         cmp     edx, eax
  999.         jae     @f
  1000.         mov     eax, edx                                        ; clamp
  1001. @@:
  1002.  
  1003.         mov     [collision_distance], ebx
  1004.  
  1005.         fninit
  1006.  
  1007.         mov     ebx, [akode_data.Camera.Direction]
  1008.         shl     ebx, 5
  1009.         add     ebx, [akode_data.TrigonometricTablePtr]
  1010.  
  1011.         push    eax
  1012.         fild    dword [esp]
  1013.         fld     st0
  1014.         fmul    qword [ebx]
  1015.         fistp   dword [esp]
  1016.         mov     ecx, [esp]                                      ; ecx = distance * sin (Camera.Direction) = y displacement
  1017.  
  1018.         fmul    qword [ebx + 8]
  1019.         fistp   dword [esp]
  1020.         pop     edx                                             ; edx = distance * cos (Camera.Direction) = x displacement
  1021.  
  1022.         cmp     esi, AKODE_DIRECTION.NORTH
  1023.         mov     esi, [akode_data.Camera.Position.X]
  1024.         mov     edi, [akode_data.Camera.Position.Y]
  1025.         mov     eax, esi
  1026.         mov     ebx, edi
  1027.         jne     .move_backward
  1028.  
  1029.         ; move forward
  1030.         add     esi, edx
  1031.         sub     edi, ecx
  1032.         jmp     @f
  1033.  
  1034. .move_backward:
  1035.         sub     esi, edx
  1036.         add     edi, ecx
  1037. @@:
  1038.  
  1039.         ; collision detection
  1040.         locals
  1041.                 top_border              dd 0
  1042.                 left_border             dd 0
  1043.                 right_border            dd 0
  1044.                 bottom_border           dd 0
  1045.                 new_x                   dd ?
  1046.                 new_y                   dd ?
  1047.         endl
  1048.  
  1049.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  1050.         mov     edx, [akode_data.CurrentLevelGridPtr]
  1051.         shr     eax, cl
  1052.         shr     ebx, cl
  1053.         mov     [current_cell_x], eax
  1054.         mov     [current_cell_y], ebx
  1055.  
  1056.         ; top border
  1057.         mov     eax, esi
  1058.         mov     ebx, edi
  1059.         sub     ebx, [collision_distance]
  1060.  
  1061.         shr     eax, cl
  1062.         shr     ebx, cl
  1063.  
  1064.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1065.         add     ebx, eax
  1066.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1067.         test    eax, eax
  1068.         jz      @f
  1069.         mov     ebx, [eax + akode.GridCell.Passable]
  1070.         test    ebx, ebx
  1071.         jnz     @f
  1072.         shr     edi, cl
  1073.         shl     edi, cl
  1074.         add     edi, [collision_distance]
  1075.         mov     [top_border], 1
  1076. @@:
  1077.  
  1078.         ; left border
  1079.         mov     eax, esi
  1080.         mov     ebx, edi
  1081.         sub     eax, [collision_distance]
  1082.  
  1083.         shr     eax, cl
  1084.         shr     ebx, cl
  1085.  
  1086.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1087.         add     ebx, eax
  1088.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1089.         test    eax, eax
  1090.         jz      @f
  1091.         mov     ebx, [eax + akode.GridCell.Passable]
  1092.         test    ebx, ebx
  1093.         jnz     @f
  1094.         shr     esi, cl
  1095.         shl     esi, cl
  1096.         add     esi, [collision_distance]
  1097.         mov     [left_border], 1
  1098. @@:
  1099.  
  1100.         ; right border
  1101.         mov     eax, esi
  1102.         mov     ebx, edi
  1103.         add     eax, [collision_distance]
  1104.  
  1105.         shr     eax, cl
  1106.         shr     ebx, cl
  1107.  
  1108.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1109.         add     ebx, eax
  1110.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1111.         test    eax, eax
  1112.         jz      @f
  1113.         mov     ebx, [eax + akode.GridCell.Passable]
  1114.         test    ebx, ebx
  1115.         jnz     @f
  1116.         shr     esi, cl
  1117.         shl     esi, cl
  1118.         add     esi, [akode_data.BlockSize.Width]
  1119.         sub     esi, [collision_distance]
  1120.         sub     esi, 1
  1121.         mov     [right_border], 1
  1122. @@:
  1123.  
  1124.         ; bottom border
  1125.         mov     eax, esi
  1126.         mov     ebx, edi
  1127.         add     ebx, [collision_distance]
  1128.  
  1129.         shr     eax, cl
  1130.         shr     ebx, cl
  1131.  
  1132.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1133.         add     ebx, eax
  1134.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1135.         test    eax, eax
  1136.         jz      @f
  1137.         mov     ebx, [eax + akode.GridCell.Passable]
  1138.         test    ebx, ebx
  1139.         jnz     @f
  1140.         shr     edi, cl
  1141.         shl     edi, cl
  1142.         add     edi, [akode_data.BlockSize.Width]
  1143.         sub     edi, [collision_distance]
  1144.         sub     edi, 1
  1145.         mov     [bottom_border], 1
  1146. @@:
  1147.  
  1148.         ; top left border
  1149.         mov     eax, [top_border]
  1150.         or      eax, [left_border]
  1151.         jnz     @f
  1152.  
  1153.         mov     eax, esi
  1154.         mov     ebx, edi
  1155.         sub     eax, [collision_distance]
  1156.         sub     ebx, [collision_distance]
  1157.  
  1158.         shr     eax, cl
  1159.         shr     ebx, cl
  1160.  
  1161.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1162.         add     ebx, eax
  1163.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1164.         test    eax, eax
  1165.         jz      @f
  1166.         mov     ebx, [eax + akode.GridCell.Passable]
  1167.         test    ebx, ebx
  1168.         jnz     @f
  1169.         mov     eax, esi
  1170.         mov     ebx, edi
  1171.  
  1172.         shr     eax, cl
  1173.         shl     eax, cl
  1174.         add     eax, [collision_distance]
  1175.         mov     [new_x], eax
  1176.         shr     ebx, cl
  1177.         shl     ebx, cl
  1178.         add     ebx, [collision_distance]
  1179.         mov     [new_y], ebx
  1180.  
  1181.         sub     eax, esi
  1182.         sub     ebx, edi
  1183.         cmp     eax, ebx
  1184.         jb      .l1
  1185.         mov     edi, [new_y]
  1186.         jmp     @f
  1187. .l1:    mov     esi, [new_x]
  1188. @@:
  1189.  
  1190.         ; top right border
  1191.         mov     eax, [top_border]
  1192.         or      eax, [right_border]
  1193.         jnz     @f
  1194.  
  1195.         mov     eax, esi
  1196.         mov     ebx, edi
  1197.         add     eax, [collision_distance]
  1198.         sub     ebx, [collision_distance]
  1199.  
  1200.         shr     eax, cl
  1201.         shr     ebx, cl
  1202.  
  1203.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1204.         add     ebx, eax
  1205.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1206.         test    eax, eax
  1207.         jz      @f
  1208.         mov     ebx, [eax + akode.GridCell.Passable]
  1209.         test    ebx, ebx
  1210.         jnz     @f
  1211.         mov     eax, esi
  1212.         mov     ebx, edi
  1213.  
  1214.         shr     eax, cl
  1215.         shl     eax, cl
  1216.         add     eax, [akode_data.BlockSize.Width]
  1217.         sub     eax, [collision_distance]
  1218.         sub     eax, 1
  1219.         mov     [new_x], eax
  1220.         shr     ebx, cl
  1221.         shl     ebx, cl
  1222.         add     ebx, [collision_distance]
  1223.         mov     [new_y], ebx
  1224.  
  1225.         neg     eax
  1226.         add     eax, esi
  1227.         sub     ebx, edi
  1228.         cmp     eax, ebx
  1229.         jb      .l2
  1230.         mov     edi, [new_y]
  1231.         jmp     @f
  1232. .l2:    mov     esi, [new_x]
  1233. @@:
  1234.  
  1235.         ; bottom left border
  1236.         mov     eax, [bottom_border]
  1237.         or      eax, [left_border]
  1238.         jnz     @f
  1239.  
  1240.         mov     eax, esi
  1241.         mov     ebx, edi
  1242.         sub     eax, [collision_distance]
  1243.         add     ebx, [collision_distance]
  1244.  
  1245.         shr     eax, cl
  1246.         shr     ebx, cl
  1247.  
  1248.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1249.         add     ebx, eax
  1250.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1251.         test    eax, eax
  1252.         jz      @f
  1253.         mov     ebx, [eax + akode.GridCell.Passable]
  1254.         test    ebx, ebx
  1255.         jnz     @f
  1256.         mov     eax, esi
  1257.         mov     ebx, edi
  1258.  
  1259.         shr     eax, cl
  1260.         shl     eax, cl
  1261.         add     eax, [collision_distance]
  1262.         mov     [new_x], eax
  1263.         shr     ebx, cl
  1264.         shl     ebx, cl
  1265.         add     ebx, [akode_data.BlockSize.Width]
  1266.         sub     ebx, [collision_distance]
  1267.         sub     ebx, 1
  1268.         mov     [new_y], ebx
  1269.  
  1270.         sub     eax, esi
  1271.         neg     ebx
  1272.         add     ebx, edi
  1273.         cmp     eax, ebx
  1274.         jb      .l3
  1275.         mov     edi, [new_y]
  1276.         jmp     @f
  1277. .l3:    mov     esi, [new_x]
  1278. @@:
  1279.  
  1280.         ; bottom right border
  1281.         mov     eax, [bottom_border]
  1282.         or      eax, [right_border]
  1283.         jnz     @f
  1284.  
  1285.         mov     eax, esi
  1286.         mov     ebx, edi
  1287.         add     eax, [collision_distance]
  1288.         add     ebx, [collision_distance]
  1289.  
  1290.         shr     eax, cl
  1291.         shr     ebx, cl
  1292.  
  1293.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1294.         add     ebx, eax
  1295.         mov     eax, [edx + ebx * 4]                            ; eax = pointer to akode.GridCell
  1296.         test    eax, eax
  1297.         jz      @f
  1298.         mov     ebx, [eax + akode.GridCell.Passable]
  1299.         test    ebx, ebx
  1300.         jnz     @f
  1301.         mov     eax, esi
  1302.         mov     ebx, edi
  1303.  
  1304.         shr     eax, cl
  1305.         shl     eax, cl
  1306.         add     eax, [akode_data.BlockSize.Width]
  1307.         sub     eax, [collision_distance]
  1308.         sub     eax, 1
  1309.         mov     [new_x], eax
  1310.         shr     ebx, cl
  1311.         shl     ebx, cl
  1312.         add     ebx, [akode_data.BlockSize.Width]
  1313.         sub     ebx, [collision_distance]
  1314.         sub     ebx, 1
  1315.         mov     [new_y], ebx
  1316.  
  1317.         neg     eax
  1318.         add     eax, esi
  1319.         neg     ebx
  1320.         add     ebx, edi
  1321.         cmp     eax, ebx
  1322.         jb      .l4
  1323.         mov     edi, [new_y]
  1324.         jmp     @f
  1325. .l4:    mov     esi, [new_x]
  1326. @@:
  1327.  
  1328.         mov     eax, esi
  1329.         mov     ebx, edi
  1330.         shr     eax, cl
  1331.         shr     ebx, cl
  1332.  
  1333.         cmp     [current_cell_x], eax
  1334.         jne     .new_cell
  1335.         cmp     [current_cell_y], ebx
  1336.         jne     .new_cell
  1337.  
  1338.         mov     [akode_data.Camera.Position.X], esi
  1339.         mov     [akode_data.Camera.Position.Y], edi
  1340.         jmp     .exit
  1341.  
  1342. .new_cell:
  1343.         stdcall akode.action, AKODE_ACTION.CELL_LEAVE
  1344.  
  1345.         mov     [akode_data.Camera.Position.X], esi
  1346.         mov     [akode_data.Camera.Position.Y], edi
  1347.  
  1348.         stdcall akode.action, AKODE_ACTION.CELL_ENTER
  1349.  
  1350. .exit:
  1351.         ret
  1352. endp
  1353. ; ============================================================================ ;
  1354.  
  1355. ; ============================================================================ ;
  1356. ; > action      = AKODE_ACTION                                                 ;
  1357. ; ---------------------------------------------------------------------------- ;
  1358. ; < eax         = action result                                                ;
  1359. ; ============================================================================ ;
  1360. proc akode.action uses ebx ecx edx esi edi, action
  1361.         mov     edi, [action]
  1362.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  1363.         mov     ebx, [akode_data.Camera.Position.X]
  1364.         mov     edx, [akode_data.Camera.Position.Y]
  1365.         shr     ebx, cl
  1366.         shr     edx, cl
  1367.  
  1368.         mov     eax, edx
  1369.         imul    eax, [akode_data.CurrentLevel.Size.Width]
  1370.         add     eax, ebx
  1371.         mov     esi, [akode_data.CurrentLevelGridPtr]
  1372.         mov     esi, [esi + eax * 4]
  1373.         test    esi, esi
  1374.         jz      .default_action
  1375.  
  1376.         mov     eax, [esi + akode.GridCell.ActionCallback]
  1377.         test    eax, eax
  1378.         jz      .default_action
  1379.         stdcall eax, edi, ebx, edx
  1380.         cmp     eax, -1
  1381.         jne     @f
  1382.  
  1383. .default_action:
  1384.         mov     eax, [akode_data.CurrentLevel.ActionCallback]
  1385.         test    eax, eax
  1386.         jz      @f
  1387.         stdcall eax, edi, ebx, edx
  1388.  
  1389. @@:
  1390.         mov     esi, [akode_data.ActionCallback]
  1391.         test    esi, esi
  1392.         jz      @f
  1393.         stdcall esi, edi, ebx, edx, eax
  1394.  
  1395. @@:
  1396.         ret
  1397. endp
  1398. ; ============================================================================ ;
  1399.  
  1400. ; ============================================================================ ;
  1401. proc akode.fill_with_color uses eax ecx edi, color
  1402.         cld
  1403.         mov     eax, [color]
  1404.         mov     edi, [akode_data.ImageBufferPtr]
  1405.         mov     ecx, [akode_data.ImageBufferSize]
  1406.         shr     ecx, 2
  1407.         rep     stosd
  1408.  
  1409.         ret
  1410. endp
  1411. ; ============================================================================ ;
  1412.  
  1413. ; ============================================================================ ;
  1414. ; > eax = color 1                                                              ;
  1415. ; > ebx = color 2                                                              ;
  1416. ; > edx = alpha, 255 -> color 1, 0 -> color 2                                  ;
  1417. ; ---------------------------------------------------------------------------- ;
  1418. ; < eax = result color                                                         ;
  1419. ; ============================================================================ ;
  1420. macro akode._.blend_colors
  1421. {
  1422.         push    ebx ecx edx esi edi
  1423.  
  1424.         mov     ecx, 256
  1425.         sub     ecx, edx
  1426.         add     edx, 1
  1427.  
  1428.         mov     edi, eax
  1429.         and     edi, 0FF00FFh
  1430.         imul    edi, edx
  1431.  
  1432.         mov     esi, ebx
  1433.         and     esi, 0FF00FFh
  1434.         imul    esi, ecx
  1435.  
  1436.         add     edi, esi
  1437.         and     edi, 0FF00FF00h
  1438.  
  1439.         and     eax, 00FF00h
  1440.         imul    eax, edx
  1441.  
  1442.         and     ebx, 00FF00h
  1443.         imul    ebx, ecx
  1444.  
  1445.         add     eax, ebx
  1446.         and     eax, 0FF0000h
  1447.         or      eax, edi
  1448.         shr     eax, 8
  1449.  
  1450.         pop     edi esi edx ecx ebx
  1451. }
  1452. ; ============================================================================ ;
  1453.  
  1454. ; ============================================================================ ;
  1455. ; > eax = color 1                                                              ;
  1456. ; > ebx = color 2                                                              ;
  1457. ; > edx = alpha, 255 -> color 1, 0 -> color 2                                  ;
  1458. ; ---------------------------------------------------------------------------- ;
  1459. ; < eax = result color                                                         ;
  1460. ; ============================================================================ ;
  1461. macro akode._.blend_colors_mmx
  1462. {
  1463.         movd    mm0, eax
  1464.         movd    mm1, ebx
  1465.         pxor    mm2, mm2
  1466.         punpcklbw mm0, mm2
  1467.         punpcklbw mm1, mm2
  1468.  
  1469.         mov     eax, 256
  1470.         sub     eax, edx
  1471.         movd    mm2, eax
  1472.         pshufw  mm3, mm2, 0
  1473.  
  1474.         mov     eax, edx
  1475.         add     eax, 1
  1476.         movd    mm4, eax
  1477.         pshufw  mm2, mm4, 0
  1478.  
  1479.         pmullw  mm1, mm3
  1480.         pmullw  mm0, mm2
  1481.         paddw   mm0, mm1
  1482.         psrlw   mm0, 8
  1483.         packuswb mm0, mm0
  1484.         movd    eax, mm0
  1485.  
  1486.         ;emms
  1487. }
  1488. ; ============================================================================ ;
  1489.  
  1490. ; ============================================================================ ;
  1491. ; < eax = pointer to image / 0 - fail                                          ;
  1492. ; ============================================================================ ;
  1493. proc akode.render uses ebx ecx edx esi edi
  1494.         mov     eax, [akode_data.CurrentLevelGridPtr]
  1495.         test    eax, eax
  1496.         jz      .exit
  1497.  
  1498.         mov     eax, [akode_data.CurrentLevel.BackgroundColor]
  1499.         cmp     eax, 0FF00FFh
  1500.         je      @f
  1501.         stdcall akode.fill_with_color, eax
  1502.  
  1503. @@:
  1504.         mov     eax, [akode_data.ProjectionPlane.Size.Width]
  1505.         mov     ebx, eax
  1506.         sub     ebx, 1
  1507.         shr     eax, 1
  1508.         add     eax, [akode_data.Camera.Direction]
  1509.         mov     edx, [akode_data.Angle360]
  1510.         cmp     edx, eax
  1511.         ja      @f
  1512.         sub     eax, edx
  1513.  
  1514. @@:
  1515.         push    eax                                             ; start_angle for akode._.draw_objects
  1516.         stdcall akode._.render_slices, 0, ebx, eax
  1517.         stdcall akode._.draw_objects
  1518.  
  1519.         mov     eax, [akode_data.ImageBufferPtr]
  1520.  
  1521. .exit:
  1522.         ret
  1523. endp
  1524. ; ============================================================================ ;
  1525.  
  1526. ; ============================================================================ ;
  1527. macro akode._.draw_textured_wall_slice
  1528. {
  1529.         label   .int_part       dword at x
  1530.         label   .fract_part     dword at y
  1531.         label   .e              dword at x_delta
  1532.         label   .target_height  dword at wall_slice_height
  1533.  
  1534.         mov     eax, [esi + akode.TextureDesc.ImageDataPtr]
  1535.         mov     [texture_desc_ptr1], eax
  1536.  
  1537.         mov     esi, [texture_desc_ptr2]
  1538.         test    esi, esi
  1539.         jz      .draw_one_texture
  1540.  
  1541.         mov     eax, [esi + akode.TextureDesc.Type]
  1542.         test    eax, eax
  1543.         jnz     .draw_one_texture
  1544.  
  1545.         movzx   eax, [esi + akode.TextureDesc.HasMagicPink]
  1546.         test    eax, eax
  1547.         jnz     @f
  1548.         mov     eax, [esi + akode.TextureDesc.ImageDataPtr]
  1549.         mov     [texture_desc_ptr1], eax
  1550.         jmp     .draw_one_texture
  1551.  
  1552. @@:
  1553.         ; draw 2 textures
  1554.  
  1555.         push    edx
  1556.  
  1557.         mov     esi, [esi + akode.TextureDesc.ImageDataPtr]
  1558.         mov     edx, [texture_x_coordinate]
  1559.         mov     eax, [akode_data.BlockSize.Width]
  1560.         imul    edx, eax
  1561.         shl     edx, 2
  1562.         add     esi, edx
  1563.         add     [texture_desc_ptr1], edx
  1564.  
  1565.         xor     edx, edx
  1566.         div     [.target_height]
  1567.         shl     eax, 2
  1568.         mov     [.int_part], eax
  1569.         mov     [.fract_part], edx
  1570.  
  1571.         pop     edx
  1572.  
  1573.         xor     eax, eax
  1574.         mov     [.e], eax
  1575.  
  1576.         mov     eax, [wall_slice_y]
  1577.         test    eax, eax
  1578.         js      .clipping2
  1579.  
  1580. .draw_double_textured_wall_slice_loop:
  1581.         mov     eax, [esi]
  1582.         cmp     eax, 0FF00FFh
  1583.         jne     @f
  1584.         mov     eax, [texture_desc_ptr1]
  1585.         mov     eax, [eax]
  1586.  
  1587. @@:
  1588.  
  1589. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1590.         akode._.blend_colors_mmx
  1591. end if
  1592.  
  1593.         mov     [edi], eax
  1594.  
  1595.         add     edi, 4
  1596.         mov     eax, [.int_part]
  1597.         add     esi, eax
  1598.         add     [texture_desc_ptr1], eax
  1599.         mov     eax, [.e]
  1600.         add     eax, [.fract_part]
  1601.         mov     [.e], eax
  1602.  
  1603.         sub     eax, [.target_height]
  1604.         jl      @f
  1605.         mov     [.e], eax
  1606.         add     esi, 4
  1607.         add     [texture_desc_ptr1], 4
  1608.  
  1609. @@:
  1610.         sub     ecx, 1
  1611.         jnz     .draw_double_textured_wall_slice_loop
  1612.  
  1613. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1614.         emms
  1615. end if
  1616.  
  1617.         jmp     .draw_floor_slice
  1618.  
  1619. .clipping2:
  1620.         sub     ecx, [wall_slice_y]
  1621.  
  1622. .draw_double_textured_wall_slice_loop2:
  1623.         mov     eax, [wall_slice_y]
  1624.         test    eax, eax
  1625.         js      .skip_pixel
  1626.  
  1627.         mov     eax, [esi]
  1628.         cmp     eax, 0FF00FFh
  1629.         jne     @f
  1630.         mov     eax, [texture_desc_ptr1]
  1631.         mov     eax, [eax]
  1632.  
  1633. @@:
  1634.  
  1635. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1636.         akode._.blend_colors_mmx
  1637. end if
  1638.  
  1639.         mov     [edi], eax
  1640.         add     edi, 4
  1641. .skip_pixel:
  1642.         add     [wall_slice_y], 1
  1643.         mov     eax, [.int_part]
  1644.         add     esi, eax
  1645.         add     [texture_desc_ptr1], eax
  1646.         mov     eax, [.e]
  1647.         add     eax, [.fract_part]
  1648.         mov     [.e], eax
  1649.  
  1650.         sub     eax, [.target_height]
  1651.         jl      @f
  1652.         mov     [.e], eax
  1653.         add     esi, 4
  1654.         add     [texture_desc_ptr1], 4
  1655.  
  1656. @@:
  1657.         sub     ecx, 1
  1658.         jnz     .draw_double_textured_wall_slice_loop2
  1659.  
  1660. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1661.         emms
  1662. end if
  1663.  
  1664.         jmp     .draw_floor_slice
  1665.  
  1666. .draw_one_texture:
  1667.         push    edx
  1668.  
  1669.         mov     esi, [texture_desc_ptr1]
  1670.         mov     edx, [texture_x_coordinate]
  1671.         mov     eax, [akode_data.BlockSize.Width]
  1672.         imul    edx, eax
  1673.         lea     esi, [esi + edx * 4]
  1674.  
  1675.         xor     edx, edx
  1676.         div     [.target_height]
  1677.         shl     eax, 2
  1678.         mov     [.int_part], eax
  1679.         mov     [.fract_part], edx
  1680.  
  1681.         pop     edx
  1682.  
  1683.         xor     eax, eax
  1684.         mov     [.e], eax
  1685.  
  1686.         mov     eax, [wall_slice_y]
  1687.         test    eax, eax
  1688.         js      .clipping
  1689.  
  1690. .draw_textured_wall_slice_loop:
  1691.         mov     eax, [esi]
  1692.  
  1693. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1694.         akode._.blend_colors_mmx
  1695. end if
  1696.  
  1697.         mov     [edi], eax
  1698.  
  1699.         add     edi, 4
  1700.         add     esi, [.int_part]
  1701.         mov     eax, [.e]
  1702.         add     eax, [.fract_part]
  1703.         mov     [.e], eax
  1704.  
  1705.         sub     eax, [.target_height]
  1706.         jl      @f
  1707.         mov     [.e], eax
  1708.         add     esi, 4
  1709.  
  1710. @@:
  1711.         sub     ecx, 1
  1712.         jnz     .draw_textured_wall_slice_loop
  1713.  
  1714. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1715.         emms
  1716. end if
  1717.  
  1718.         jmp     .draw_floor_slice
  1719.  
  1720. .clipping:
  1721.         sub     ecx, [wall_slice_y]
  1722.  
  1723. .draw_textured_wall_slice_loop2:
  1724.         mov     eax, [wall_slice_y]
  1725.         test    eax, eax
  1726.         js      @f
  1727.         mov     eax, [esi]
  1728.  
  1729. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1730.         akode._.blend_colors_mmx
  1731. end if
  1732.  
  1733.         mov     [edi], eax
  1734.         add     edi, 4
  1735. @@:
  1736.         add     [wall_slice_y], 1
  1737.         add     esi, [.int_part]
  1738.         mov     eax, [.e]
  1739.         add     eax, [.fract_part]
  1740.         mov     [.e], eax
  1741.  
  1742.         sub     eax, [.target_height]
  1743.         jl      @f
  1744.         mov     [.e], eax
  1745.         add     esi, 4
  1746.  
  1747. @@:
  1748.         sub     ecx, 1
  1749.         jnz     .draw_textured_wall_slice_loop2
  1750.  
  1751. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  1752.         emms
  1753. end if
  1754. }
  1755.  
  1756. ;void ScaleLine(PIXEL *Target, PIXEL *Source, int SrcWidth, int TgtWidth)
  1757. ;{
  1758. ;  int NumPixels = TgtWidth;
  1759. ;  int IntPart = SrcWidth / TgtWidth;
  1760. ;  int FractPart = SrcWidth % TgtWidth;
  1761. ;  int E = 0;
  1762. ;
  1763. ;  while (NumPixels-- > 0) {
  1764. ;    *Target++ = *Source;
  1765. ;    Source += IntPart;
  1766. ;    E += FractPart;
  1767. ;    if (E >= TgtWidth) {
  1768. ;      E -= TgtWidth;
  1769. ;      Source++;
  1770. ;    } /* if */
  1771. ;  } /* while */
  1772. ;}
  1773.  
  1774. proc akode._.render_slices first_slice, last_slice, start_angle
  1775.         locals
  1776.                 distance_to_floor               dd ?
  1777.                 distance_to_wall                dd ?
  1778.                 horizontal_distance_to_wall     dq ?
  1779.                 vertical_distance_to_wall       dq ?
  1780.  
  1781.                 texture_x_coordinate            dd ?
  1782.                 texture_y_coordinate            dd ?
  1783.  
  1784.                 wall_slice_height               dd ?
  1785.                 wall_slice_y                    dd ?
  1786.                 wall_slice_top                  dd ?
  1787.                 wall_slice_bottom               dd ?
  1788.                 wall_slice_top_ptr              dd ?
  1789.  
  1790.                 horizontal_texture_desc_ptr1    dd ?
  1791.                 horizontal_texture_desc_ptr2    dd ?
  1792.  
  1793.                 vertical_texture_desc_ptr1      dd ?
  1794.                 vertical_texture_desc_ptr2      dd ?
  1795.  
  1796.                 texture_desc_ptr1               dd ?
  1797.                 texture_desc_ptr2               dd ?
  1798.  
  1799.                 x                               dd ?
  1800.                 y                               dd ?
  1801.                 x_delta                         dd ?
  1802.                 y_delta                         dd ?
  1803.  
  1804.                 wall_side                       dd ?
  1805.         endl
  1806.  
  1807.         fninit
  1808.  
  1809. .slice_loop:
  1810.         ;DEBUGF  DEBUG_FINE, 'first_slice: %u, last_slice: %u, start_angle: %u\n', [first_slice], [last_slice], [start_angle]
  1811.  
  1812. ; ------------------------------- render walls ------------------------------- ;
  1813.  
  1814.         ; horizontal intersections
  1815.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  1816.         mov     eax, [akode_data.Camera.Position.Y]
  1817.         mov     edi, eax
  1818.         shr     eax, cl
  1819.         shl     eax, cl
  1820.         mov     edx, [akode_data.BlockSize.Width]
  1821.  
  1822.         mov     ebx, [start_angle]
  1823.         test    ebx, ebx
  1824.         jz      .ray_is_horizontal
  1825.         cmp     [akode_data.Angle180], ebx
  1826.         je      .ray_is_horizontal
  1827.         jb      .ray_is_facing_down
  1828.  
  1829.         ; ray is facing up
  1830.  
  1831.         sub     eax, 1
  1832.         neg     edx
  1833.         mov     [wall_side], AKODE_DIRECTION.SOUTH
  1834.         jmp     @f
  1835.  
  1836.         ; ray is facing down
  1837.  
  1838. .ray_is_facing_down:
  1839.         add     eax, edx                                        ; edx = BlockSize.Width
  1840.         mov     [wall_side], AKODE_DIRECTION.NORTH
  1841.  
  1842. @@:
  1843.         mov     [y], eax
  1844.         mov     [y_delta], edx
  1845.  
  1846.         sub     edi, eax                                        ; edi = Camera.Position.Y - y
  1847.         push    edi
  1848.         mov     esi, ebx
  1849.         shl     esi, 5                                          ; esi = angle * 32
  1850.         add     esi, [akode_data.TrigonometricTablePtr]
  1851.  
  1852.         fild    dword [esp]
  1853.         fdiv    qword [esi + 16]
  1854.         fistp   dword [esp]
  1855.         pop     edi                                             ; edi = (Camera.Position.Y - y) / tan (angle)
  1856.  
  1857.         add     edi, [akode_data.Camera.Position.X]
  1858.         mov     [x], edi
  1859.  
  1860.         mov     esi, [akode_data.BlockWidthTanTablePtr]
  1861.         mov     eax, [esi + ebx * 8 + 4]                        ; eax = BlockSize.Width / tan (angle)
  1862.         mov     [x_delta], eax
  1863.         ;DEBUGF  DEBUG_FINE, 'x_delta: %d\n', eax
  1864.  
  1865. .horizontal_intersections_loop:
  1866.         mov     eax, [x]
  1867.         mov     ebx, [y]
  1868.  
  1869.         sar     eax, cl
  1870.         js      .ray_is_horizontal
  1871.         cmp     [akode_data.CurrentLevel.Size.Width], eax
  1872.         jna     .ray_is_horizontal
  1873.  
  1874.         sar     ebx, cl
  1875.         js      .ray_is_horizontal
  1876.         cmp     [akode_data.CurrentLevel.Size.Height], ebx
  1877.         jna     .ray_is_horizontal
  1878.  
  1879.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  1880.         add     ebx, eax
  1881.         mov     esi, [akode_data.CurrentLevelGridPtr]
  1882.         mov     esi, [esi + ebx * 4]                            ; esi = pointer to akode.GridCell
  1883.  
  1884.         test    esi, esi
  1885.         jz      .next_horizontal_intersection
  1886.  
  1887.         mov     eax, [wall_side]
  1888.         lea     edi, [esi + eax * 8]
  1889.  
  1890.         mov     ebx, [edi]                                      ; first texture desc ptr
  1891.         test    ebx, ebx
  1892.         jz      .next_horizontal_intersection
  1893.  
  1894.         mov     edx, [edi + 4]                                  ; second texture desc ptr
  1895.  
  1896.         mov     [horizontal_texture_desc_ptr1], ebx
  1897.         mov     [horizontal_texture_desc_ptr2], edx
  1898.  
  1899.         mov     edx, -1
  1900.         shl     edx, cl
  1901.         not     edx
  1902.  
  1903.         mov     esi, [x]
  1904.         and     esi, edx
  1905.         cmp     eax, AKODE_DIRECTION.NORTH
  1906.         jne     @f
  1907.         mov     eax, [akode_data.BlockSize.Width]
  1908.         add     esi, 1
  1909.         xchg    eax, esi
  1910.         sub     esi, eax
  1911. @@:
  1912.         mov     [texture_x_coordinate], esi
  1913.  
  1914.         mov     ebx, [start_angle]
  1915.         mov     esi, [akode_data.TrigonometricTablePtr]
  1916.  
  1917.         mov     eax, [akode_data.Camera.Position.Y]
  1918.         sub     eax, [y]
  1919.  
  1920.         mov     edx, ebx
  1921.         shl     edx, 5
  1922.  
  1923.         push    eax
  1924.         fild    dword [esp]
  1925.         add     esp, 4
  1926.         fdiv    qword [esi + edx]                               ; st0 = (Camera.Position.Y - y) / sin (angle)
  1927.  
  1928.         ; correct fisheye
  1929.         mov     eax, [akode_data.Camera.Direction]
  1930.         sub     eax, ebx
  1931.         jns     @f
  1932.         neg     eax
  1933.  
  1934. @@:
  1935.         shl     eax, 5
  1936.         fmul    qword [esi + eax + 8]                           ; st0 * cos (Camera.Direction - angle)
  1937.         fstp    [horizontal_distance_to_wall]
  1938.  
  1939.         jmp     .vertical_intersections
  1940.  
  1941. .next_horizontal_intersection:
  1942.         mov     eax, [x_delta]
  1943.         mov     ebx, [y_delta]
  1944.         add     [x], eax
  1945.         add     [y], ebx
  1946.         jmp     .horizontal_intersections_loop
  1947.  
  1948. .ray_is_horizontal:
  1949.         ; horizontal_distance_to_wall = max double
  1950.         mov     dword [horizontal_distance_to_wall], 0FFFFFFFFh
  1951.         mov     dword [horizontal_distance_to_wall + 4], 7FEFFFFFh
  1952.  
  1953.         ; vertical intersections
  1954. .vertical_intersections:
  1955.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  1956.         mov     eax, [akode_data.Camera.Position.X]
  1957.         mov     edi, eax
  1958.         shr     eax, cl
  1959.         shl     eax, cl
  1960.         mov     edx, [akode_data.BlockSize.Width]
  1961.  
  1962.         mov     ebx, [start_angle]
  1963.         cmp     [akode_data.Angle90], ebx
  1964.         je      .ray_is_vertical
  1965.         ja      .ray_is_facing_right
  1966.         cmp     [akode_data.Angle270], ebx
  1967.         je      .ray_is_vertical
  1968.         jb      .ray_is_facing_right
  1969.  
  1970.         ; ray is facing left
  1971.  
  1972.         sub     eax, 1
  1973.         neg     edx
  1974.         mov     [wall_side], AKODE_DIRECTION.EAST
  1975.         jmp     @f
  1976.  
  1977.         ; ray is facing right
  1978.  
  1979. .ray_is_facing_right:
  1980.         add     eax, edx                                        ; edx = BlockSize.Width
  1981.         mov     [wall_side], AKODE_DIRECTION.WEST
  1982.  
  1983. @@:
  1984.         mov     [x], eax
  1985.         mov     [x_delta], edx
  1986.  
  1987.         sub     edi, eax                                        ; edi = Camera.Position.X - x
  1988.         push    edi
  1989.         mov     esi, ebx
  1990.         shl     esi, 5                                          ; esi = angle * 32
  1991.         add     esi, [akode_data.TrigonometricTablePtr]
  1992.  
  1993.         fild    dword [esp]
  1994.         fmul    qword [esi + 16]
  1995.         fistp   dword [esp]
  1996.         pop     edi                                             ; edi = (Camera.Position.X - x) * tan (angle)
  1997.  
  1998.         add     edi, [akode_data.Camera.Position.Y]
  1999.         mov     [y], edi
  2000.  
  2001.         mov     esi, [akode_data.BlockWidthTanTablePtr]
  2002.         mov     eax, [esi + ebx * 8]                            ; eax = BlockSize.Width * tan (angle)
  2003.         mov     [y_delta], eax
  2004.         ;DEBUGF  DEBUG_FINE, 'y_delta: %d\n', eax
  2005.  
  2006. .vertical_intersections_loop:
  2007.         mov     eax, [x]
  2008.         mov     ebx, [y]
  2009.  
  2010.         sar     eax, cl
  2011.         js      .ray_is_vertical
  2012.         cmp     [akode_data.CurrentLevel.Size.Width], eax
  2013.         jna     .ray_is_vertical
  2014.  
  2015.         sar     ebx, cl
  2016.         js      .ray_is_vertical
  2017.         cmp     [akode_data.CurrentLevel.Size.Height], ebx
  2018.         jna     .ray_is_vertical
  2019.  
  2020.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  2021.         add     ebx, eax
  2022.         mov     esi, [akode_data.CurrentLevelGridPtr]
  2023.         mov     esi, [esi + ebx * 4]                            ; esi = pointer to akode.GridCell
  2024.  
  2025.         test    esi, esi
  2026.         jz      .next_vertical_intersection
  2027.  
  2028.         mov     eax, [wall_side]
  2029.         lea     edi, [esi + eax * 8]
  2030.  
  2031.         mov     ebx, [edi]                                      ; first texture desc ptr
  2032.         test    ebx, ebx
  2033.         jz      .next_vertical_intersection
  2034.  
  2035.         mov     edx, [edi + 4]                                  ; second texture desc ptr
  2036.  
  2037.         mov     [vertical_texture_desc_ptr1], ebx
  2038.         mov     [vertical_texture_desc_ptr2], edx
  2039.  
  2040.         mov     edx, -1
  2041.         shl     edx, cl
  2042.         not     edx
  2043.  
  2044.         mov     esi, [y]
  2045.         and     esi, edx
  2046.         test    eax, eax                                        ; cmp eax, AKODE_DIRECTION.EAST
  2047.         jnz     @f
  2048.         mov     eax, [akode_data.BlockSize.Width]
  2049.         add     esi, 1
  2050.         xchg    eax, esi
  2051.         sub     esi, eax
  2052. @@:
  2053.         mov     [texture_y_coordinate], esi
  2054.  
  2055.         mov     ebx, [start_angle]
  2056.         mov     esi, [akode_data.TrigonometricTablePtr]
  2057.  
  2058.         mov     eax, [x]
  2059.         sub     eax, [akode_data.Camera.Position.X]
  2060.  
  2061.         mov     edx, ebx
  2062.         shl     edx, 5
  2063.  
  2064.         push    eax
  2065.         fild    dword [esp]
  2066.         add     esp, 4
  2067.         fmul    qword [esi + edx + 24]                          ; st0 = (x - Camera.Position.X) / cos (angle)
  2068.  
  2069.         ; correct fisheye
  2070.         mov     eax, [akode_data.Camera.Direction]
  2071.         sub     eax, ebx
  2072.         jns     @f
  2073.         neg     eax
  2074.  
  2075. @@:
  2076.         shl     eax, 5
  2077.         fmul    qword [esi + eax + 8]                           ; st0 * cos (Camera.Direction - angle)
  2078.         fstp    [vertical_distance_to_wall]
  2079.  
  2080.         jmp     .draw_wall_slice
  2081.  
  2082. .next_vertical_intersection:
  2083.         mov     eax, [x_delta]
  2084.         mov     ebx, [y_delta]
  2085.         add     [x], eax
  2086.         add     [y], ebx
  2087.         jmp     .vertical_intersections_loop
  2088.  
  2089. .ray_is_vertical:
  2090.         ; vertical_distance_to_wall = max double
  2091.         mov     dword [vertical_distance_to_wall], 0FFFFFFFFh
  2092.         mov     dword [vertical_distance_to_wall + 4], 7FEFFFFFh
  2093.  
  2094.  
  2095. ; ----------------------------- draw wall slice ------------------------------ ;
  2096.  
  2097. .draw_wall_slice:
  2098.         fld     [horizontal_distance_to_wall]
  2099.         fld     [vertical_distance_to_wall]
  2100.         fcomi   st1
  2101.         fcmovnb st1
  2102.         fist    [distance_to_wall]
  2103.         fidivr  [akode_data.WallHeightDividend]
  2104.         fistp   [wall_slice_height]
  2105.         fstp    st0
  2106.  
  2107.         mov     ebx, [akode_data.DepthBufferPtr]
  2108.         mov     ecx, [first_slice]
  2109.         lea     ebx, [ebx + ecx * 4]
  2110.         mov     eax, [distance_to_wall]
  2111.         mov     [ebx], eax
  2112.  
  2113.         jnb     .horizontal_textures
  2114.         mov     eax, [vertical_texture_desc_ptr1]
  2115.         mov     ebx, [vertical_texture_desc_ptr2]
  2116.  
  2117.         mov     ecx, [texture_y_coordinate]
  2118.         mov     [texture_x_coordinate], ecx
  2119.         jmp     @f
  2120.  
  2121. .horizontal_textures:
  2122.         mov     eax, [horizontal_texture_desc_ptr1]
  2123.         mov     ebx, [horizontal_texture_desc_ptr2]
  2124.  
  2125. @@:
  2126.         mov     ecx, [wall_slice_height]
  2127.         test    ecx, ecx
  2128.         jz      .skip_draw_wall_slice
  2129.  
  2130.         mov     [texture_desc_ptr1], eax
  2131.         mov     [texture_desc_ptr2], ebx
  2132.  
  2133.         mov     edx, [akode_data.ProjectionPlane.MidY]
  2134.         mov     eax, ecx
  2135.         shr     eax, 1
  2136.         sub     edx, eax
  2137.         mov     [wall_slice_y], edx
  2138.         jns     @f
  2139.         xor     edx, edx
  2140.  
  2141. @@:
  2142.         mov     ebx, [akode_data.ProjectionPlane.Size.Height]
  2143.         mov     eax, ecx
  2144.         add     eax, edx
  2145.         cmp     ebx, eax
  2146.         jae     @f
  2147.         mov     ecx, ebx
  2148.         sub     ecx, edx
  2149.  
  2150. @@:
  2151.         mov     eax, edx
  2152.         sub     eax, 1
  2153.         mov     [wall_slice_top], eax
  2154.         mov     eax, edx
  2155.         add     eax, ecx
  2156.         mov     [wall_slice_bottom], eax
  2157.  
  2158.         mov     eax, [akode_data.ProjectionPlane.Size.Height]
  2159.         imul    eax, [first_slice]
  2160.         add     eax, edx
  2161.         mov     edi, [akode_data.ImageBufferPtr]
  2162.         lea     edi, [edi + eax * 4]
  2163.         mov     eax, edi
  2164.         sub     eax, 4
  2165.         mov     [wall_slice_top_ptr], eax
  2166.  
  2167. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2168.         mov     esi, [akode_data.ShadingTablePtr]
  2169.         mov     ebx, [akode_data.ShadingDistance]
  2170.         mov     eax, [distance_to_wall]
  2171.         cmp     ebx, eax
  2172.         jae     @f
  2173.         mov     eax, ebx
  2174. @@:
  2175.         mov     edx, [esi + eax * 4]
  2176.         mov     ebx, [akode_data.ShadingColor]
  2177. end if
  2178.  
  2179.         mov     esi, [texture_desc_ptr1]
  2180.         mov     eax, [esi + akode.TextureDesc.Type]
  2181.         test    eax, eax
  2182.         jz      .texture_type_image
  2183.  
  2184.         ; texture type is color
  2185.  
  2186.         add     esi, akode.TextureDesc.Color
  2187.  
  2188. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2189. .draw_color_wall_slice_loop:
  2190.         mov     eax, [esi]
  2191.  
  2192.         akode._.blend_colors_mmx
  2193.  
  2194.         mov     [edi], eax
  2195.         add     edi, 4
  2196.  
  2197.         sub     ecx, 1
  2198.         jnz     .draw_color_wall_slice_loop
  2199.  
  2200.         emms
  2201. else
  2202.         mov     eax, [esi]
  2203.  
  2204. .draw_color_wall_slice_loop:
  2205.         mov     [edi], eax
  2206.         add     edi, 4
  2207.  
  2208.         sub     ecx, 1
  2209.         jnz     .draw_color_wall_slice_loop
  2210. end if
  2211.  
  2212.         jmp     .draw_floor_slice
  2213.  
  2214. .texture_type_image:
  2215.         akode._.draw_textured_wall_slice
  2216.         jmp     .draw_floor_slice
  2217.  
  2218. .skip_draw_wall_slice:
  2219.         mov     eax, [akode_data.ProjectionPlane.MidY]
  2220.         mov     [wall_slice_top], eax
  2221.         add     eax, 1
  2222.         mov     [wall_slice_bottom], eax
  2223.  
  2224.         mov     eax, [akode_data.ProjectionPlane.Size.Height]
  2225.         imul    eax, [first_slice]
  2226.         add     eax, [wall_slice_bottom]
  2227.         mov     edi, [akode_data.ImageBufferPtr]
  2228.         lea     edi, [edi + eax * 4]
  2229.         mov     eax, edi
  2230.         sub     eax, 4
  2231.         mov     [wall_slice_top_ptr], eax
  2232.  
  2233. ; ----------------------------- draw floor slice ----------------------------- ;
  2234.  
  2235. .draw_floor_slice:
  2236.         mov     esi, [akode_data.TrigonometricTablePtr]
  2237.         mov     ebx, [start_angle]
  2238.         mov     eax, ebx
  2239.         shl     eax, 5
  2240.         fld     qword [esi + eax]                               ; sin (angle)
  2241.         fld     qword [esi + eax + 8]                           ; cos (angle)
  2242.  
  2243.         mov     eax, [akode_data.Camera.Direction]
  2244.         sub     eax, ebx
  2245.         jns     @f
  2246.         neg     eax
  2247.  
  2248. @@:
  2249.         shl     eax, 5
  2250.         fld     qword [esi + eax + 24]                          ; 1 / cos (Camera.Direction - angle)
  2251.  
  2252.         mov     ecx, [wall_slice_bottom]
  2253.         cmp     [akode_data.ProjectionPlane.Size.Height], ecx
  2254.         jbe     .skip_draw_floor_slice
  2255.  
  2256.         add     ecx, 1
  2257.         fild    [akode_data.FloorDistanceDividend]
  2258.         fmul    st0, st1                                        ; st0 = FloorDistanceDividend / cos (Camera.Direction - angle)
  2259.  
  2260. .draw_floor_slice_loop:
  2261.         mov     eax, ecx
  2262.         sub     eax, [akode_data.ProjectionPlane.MidY]
  2263.         push    eax
  2264.  
  2265.         fld     st0
  2266.         fidiv   dword [esp]
  2267.         fist    [distance_to_floor]                             ; FloorDistanceDividend / cos (Camera.Direction - angle) / (ecx - ProjectionPlane.MidY)
  2268.  
  2269.         fld     st0
  2270.         fmul    st0, st4                                        ; distance * cos (angle)
  2271.         fistp   dword [esp]
  2272.         mov     ebx, [esp]                                      ; ebx = x delta
  2273.  
  2274.         fmul    st0, st4                                        ; distance * sin (angle)
  2275.         fistp   dword [esp]
  2276.         pop     edx                                             ; edx = y delta
  2277.  
  2278.         mov     eax, [akode_data.Camera.Position.X]
  2279.         add     eax, ebx
  2280.         mov     ebx, [akode_data.Camera.Position.Y]
  2281.         sub     ebx, edx
  2282.  
  2283.         push    ecx
  2284.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  2285.  
  2286.         mov     edx, -1
  2287.         shl     edx, cl
  2288.         not     edx
  2289.  
  2290.         mov     esi, eax
  2291.         and     esi, edx
  2292.         mov     [texture_x_coordinate], esi
  2293.  
  2294.         mov     esi, ebx
  2295.         and     esi, edx
  2296.         mov     [texture_y_coordinate], esi
  2297.  
  2298.         sar     eax, cl
  2299.         js      .next_floor_intersection
  2300.         cmp     [akode_data.CurrentLevel.Size.Width], eax
  2301.         jna     .next_floor_intersection
  2302.  
  2303.         sar     ebx, cl
  2304.         js      .next_floor_intersection
  2305.         cmp     [akode_data.CurrentLevel.Size.Height], ebx
  2306.         jna     .next_floor_intersection
  2307.  
  2308.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  2309.         add     ebx, eax
  2310.         mov     eax, [akode_data.CurrentLevelGridPtr]
  2311.         mov     eax, [eax + ebx * 4]                            ; eax = pointer to akode.GridCell
  2312.  
  2313.         test    eax, eax
  2314.         jz      .next_floor_intersection
  2315.  
  2316.         mov     esi, [eax + akode.GridCell.FloorTexture]
  2317.         test    esi, esi
  2318.         jz      .next_floor_intersection
  2319.  
  2320. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2321.         mov     edx, [akode_data.ShadingTablePtr]
  2322.         mov     ebx, [akode_data.ShadingDistance]
  2323.         mov     ecx, [distance_to_floor]
  2324.         cmp     ebx, ecx
  2325.         jae     @f
  2326.         mov     ecx, ebx
  2327. @@:
  2328.         mov     edx, [edx + ecx * 4]
  2329.         mov     ebx, [akode_data.ShadingColor]
  2330. end if
  2331.  
  2332.         mov     eax, [esi + akode.TextureDesc.Type]
  2333.         test    eax, eax
  2334.         jz      .texture_type_image2
  2335.  
  2336.         ; texture type is color
  2337.         mov     eax, [esi + akode.TextureDesc.Color]
  2338.  
  2339. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2340.         akode._.blend_colors
  2341. end if
  2342.  
  2343.         mov     [edi], eax
  2344.  
  2345.         jmp     .next_floor_intersection
  2346.  
  2347. .texture_type_image2:
  2348.         mov     eax, [texture_x_coordinate]
  2349.         imul    eax, [akode_data.BlockSize.Width]
  2350.         add     eax, [texture_y_coordinate]
  2351.         mov     esi, [esi + akode.TextureDesc.ImageDataPtr]
  2352.         mov     eax, [esi + eax * 4]
  2353.  
  2354. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2355.         akode._.blend_colors
  2356. end if
  2357.  
  2358.         mov     [edi], eax
  2359.  
  2360. .next_floor_intersection:
  2361.         pop     ecx
  2362.  
  2363.         add     edi, 4
  2364.         add     ecx, 1
  2365.         cmp     [akode_data.ProjectionPlane.Size.Height], ecx
  2366.         jae     .draw_floor_slice_loop
  2367.  
  2368.         fstp    st0
  2369.  
  2370. .skip_draw_floor_slice:
  2371.  
  2372. ; ---------------------------- draw ceiling slice ---------------------------- ;
  2373.  
  2374.         mov     ecx, [wall_slice_top]
  2375.         test    ecx, ecx
  2376.         js      .skip_draw_ceiling_slice
  2377.  
  2378.         sub     ecx, 1
  2379.         fild    [akode_data.CeilingDistanceDividend]
  2380.         fmul    st0, st1                                        ; st0 = CeilingDistanceDividend / cos (Camera.Direction - angle)
  2381.         mov     edi, [wall_slice_top_ptr]
  2382.  
  2383. .draw_ceiling_slice_loop:
  2384.         mov     eax, [akode_data.ProjectionPlane.MidY]
  2385.         sub     eax, ecx
  2386.         push    eax
  2387.  
  2388.         fld     st0
  2389.         fidiv   dword [esp]
  2390.         fist    [distance_to_floor]                             ; CeilingDistanceDividend / cos (Camera.Direction - angle) / (ProjectionPlane.MidY - ecx)
  2391.  
  2392.         fld     st0
  2393.         fmul    st0, st4                                        ; distance * cos (angle)
  2394.         fistp   dword [esp]
  2395.         mov     ebx, [esp]                                      ; ebx = x delta
  2396.  
  2397.         fmul    st0, st4                                        ; distance * sin (angle)
  2398.         fistp   dword [esp]
  2399.         pop     edx                                             ; edx = y delta
  2400.  
  2401.         mov     eax, [akode_data.Camera.Position.X]
  2402.         add     eax, ebx
  2403.         mov     ebx, [akode_data.Camera.Position.Y]
  2404.         sub     ebx, edx
  2405.  
  2406.         push    ecx
  2407.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  2408.  
  2409.         mov     edx, -1
  2410.         shl     edx, cl
  2411.         not     edx
  2412.  
  2413.         mov     esi, eax
  2414.         and     esi, edx
  2415.         mov     [texture_x_coordinate], esi
  2416.  
  2417.         mov     esi, ebx
  2418.         and     esi, edx
  2419.         mov     [texture_y_coordinate], esi
  2420.  
  2421.         sar     eax, cl
  2422.         js      .next_ceiling_intersection
  2423.         cmp     [akode_data.CurrentLevel.Size.Width], eax
  2424.         jna     .next_ceiling_intersection
  2425.  
  2426.         sar     ebx, cl
  2427.         js      .next_ceiling_intersection
  2428.         cmp     [akode_data.CurrentLevel.Size.Height], ebx
  2429.         jna     .next_ceiling_intersection
  2430.  
  2431.         imul    ebx, [akode_data.CurrentLevel.Size.Width]
  2432.         add     ebx, eax
  2433.         mov     eax, [akode_data.CurrentLevelGridPtr]
  2434.         mov     eax, [eax + ebx * 4]                            ; eax = pointer to akode.GridCell
  2435.  
  2436.         test    eax, eax
  2437.         jz      .next_ceiling_intersection
  2438.  
  2439.         mov     esi, [eax + akode.GridCell.CeilingTexture]
  2440.         test    esi, esi
  2441.         jz      .next_ceiling_intersection
  2442.  
  2443. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2444.         mov     edx, [akode_data.ShadingTablePtr]
  2445.         mov     ebx, [akode_data.ShadingDistance]
  2446.         mov     ecx, [distance_to_floor]
  2447.         cmp     ebx, ecx
  2448.         jae     @f
  2449.         mov     ecx, ebx
  2450. @@:
  2451.         mov     edx, [edx + ecx * 4]
  2452.         mov     ebx, [akode_data.ShadingColor]
  2453. end if
  2454.  
  2455.         mov     eax, [esi + akode.TextureDesc.Type]
  2456.         test    eax, eax
  2457.         jz      .texture_type_image3
  2458.  
  2459.         ; texture type is color
  2460.         mov     eax, [esi + akode.TextureDesc.Color]
  2461.  
  2462. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2463.         akode._.blend_colors
  2464. end if
  2465.  
  2466.         mov     [edi], eax
  2467.  
  2468.         jmp     .next_ceiling_intersection
  2469.  
  2470. .texture_type_image3:
  2471.         mov     eax, [texture_x_coordinate]
  2472.         imul    eax, [akode_data.BlockSize.Width]
  2473.         add     eax, [texture_y_coordinate]
  2474.         mov     esi, [esi + akode.TextureDesc.ImageDataPtr]
  2475.         mov     eax, [esi + eax * 4]
  2476.  
  2477. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2478.         akode._.blend_colors
  2479. end if
  2480.  
  2481.         mov     [edi], eax
  2482.  
  2483. .next_ceiling_intersection:
  2484.         pop     ecx
  2485.  
  2486.         sub     edi, 4
  2487.         sub     ecx, 1
  2488.         cmp     ecx, -1
  2489.         jge     .draw_ceiling_slice_loop
  2490.  
  2491.         fstp    st0
  2492.  
  2493. .skip_draw_ceiling_slice:
  2494.  
  2495.         fstp    st0
  2496.         fstp    st0
  2497.         fstp    st0
  2498.  
  2499.         sub     [start_angle], 1
  2500.         jns     @f
  2501.         mov     edx, [akode_data.Angle360]
  2502.         sub     edx, 1
  2503.         mov     [start_angle], edx
  2504.  
  2505. @@:
  2506.         mov     eax, [first_slice]
  2507.         add     eax, 1
  2508.         mov     [first_slice], eax
  2509.         cmp     [last_slice], eax
  2510.         jae     .slice_loop
  2511.  
  2512.         ret
  2513. endp
  2514. ; ============================================================================ ;
  2515.  
  2516. ; ============================================================================ ;
  2517. macro akode._.draw_object_slice
  2518. {
  2519. ;        mov     eax, [akode_data.BlockSize.Height]
  2520. ;        xor     edx, edx
  2521. ;        div     [object_screen_height]
  2522. ;        shl     eax, 2
  2523. ;        mov     [slice.int_part], eax
  2524. ;        mov     [slice.fract_part], edx
  2525.  
  2526.         xor     eax, eax
  2527.         mov     [slice.e], eax
  2528.         mov     ecx, [slice.pixel_count]
  2529.  
  2530. .draw_object_slice:
  2531.         mov     eax, [slice.y]
  2532.         test    eax, eax
  2533.         js      .skip_pixel
  2534.  
  2535.         mov     eax, [esi]
  2536.         cmp     eax, 0FF00FFh
  2537.         je      @f
  2538.         mov     [edi], eax
  2539. @@:     add     edi, 4
  2540.  
  2541. .skip_pixel:
  2542.         add     [slice.y], 1
  2543.         add     esi, [slice.int_part]
  2544.         mov     eax, [slice.e]
  2545.         add     eax, [slice.fract_part]
  2546.         mov     [slice.e], eax
  2547.  
  2548.         sub     eax, [object_screen_height]
  2549.         jl      @f
  2550.         mov     [slice.e], eax
  2551.         add     esi, 4
  2552.  
  2553. @@:
  2554.         sub     ecx, 1
  2555.         jnz     .draw_object_slice
  2556. }
  2557.  
  2558. macro akode._.draw_object_slice_with_shading
  2559. {
  2560.         xor     eax, eax
  2561.         mov     [slice.e], eax
  2562.         mov     ecx, [slice.pixel_count]
  2563.  
  2564. .draw_object_slice2:
  2565.         mov     eax, [slice.y]
  2566.         test    eax, eax
  2567.         js      .skip_pixel2
  2568.  
  2569.         mov     eax, [esi]
  2570.         cmp     eax, 0FF00FFh
  2571.         je      @f
  2572.         akode._.blend_colors_mmx
  2573.         mov     [edi], eax
  2574. @@:     add     edi, 4
  2575.  
  2576. .skip_pixel2:
  2577.         add     [slice.y], 1
  2578.         add     esi, [slice.int_part]
  2579.         mov     eax, [slice.e]
  2580.         add     eax, [slice.fract_part]
  2581.         mov     [slice.e], eax
  2582.  
  2583.         sub     eax, [object_screen_height]
  2584.         jl      @f
  2585.         mov     [slice.e], eax
  2586.         add     esi, 4
  2587.  
  2588. @@:
  2589.         sub     ecx, 1
  2590.         jnz     .draw_object_slice2
  2591. }
  2592.  
  2593. macro akode._.draw_object
  2594. {
  2595.         locals
  2596.                 slice.int_part          dd ?
  2597.                 slice.fract_part        dd ?
  2598.                 slice.e                 dd ?
  2599.                 slice.y                 dd ?
  2600.                 slice.pixel_count       dd ?
  2601.  
  2602.                 int_part                dd ?
  2603.                 fract_part              dd ?
  2604.                 e                       dd ?
  2605.                 slice_count             dd ?
  2606.                 object_distance         dd ?
  2607.         endl
  2608.  
  2609.         mov     eax, [object_screen_height]
  2610.         mov     ebx, [object_screen_width]
  2611.  
  2612.         cmp     eax, 10
  2613.         jb      .draw_object_exit
  2614.         cmp     ebx, 10
  2615.         jb      .draw_object_exit
  2616.  
  2617.         mov     ecx, [object_screen_x]
  2618.         mov     edx, [object_screen_y]
  2619.  
  2620.         cmp     ecx, [akode_data.ProjectionPlane.Size.Width]
  2621.         jge     .draw_object_exit
  2622.         cmp     edx, [akode_data.ProjectionPlane.Size.Height]
  2623.         jge     .draw_object_exit
  2624.  
  2625.         add     ecx, ebx
  2626.         add     edx, eax
  2627.  
  2628.         xor     edi, edi
  2629.  
  2630.         cmp     ecx, edi
  2631.         jle     .draw_object_exit
  2632.         cmp     edx, edi
  2633.         jle     .draw_object_exit
  2634.  
  2635.         sub     ecx, [akode_data.ProjectionPlane.Size.Width]
  2636.         jbe     @f
  2637.         sub     ebx, ecx
  2638. @@:
  2639.         mov     [slice_count], ebx
  2640.  
  2641.         sub     edx, [akode_data.ProjectionPlane.Size.Height]
  2642.         jbe     @f
  2643.         sub     eax, edx
  2644. @@:
  2645.         mov     [slice.pixel_count], eax
  2646.  
  2647.         mov     eax, [akode_data.BlockSize.Height]
  2648.         xor     edx, edx
  2649.         div     [object_screen_height]
  2650.         shl     eax, 2
  2651.         mov     [slice.int_part], eax
  2652.         mov     [slice.fract_part], edx
  2653.  
  2654.         mov     eax, [akode_data.BlockSize.Width]
  2655.         xor     edx, edx
  2656.         div     [object_screen_width]
  2657.         mov     [fract_part], edx
  2658.         mul     [akode_data.BlockSize.Height]
  2659.         shl     eax, 2
  2660.         mov     [int_part], eax
  2661.  
  2662.         xor     eax, eax
  2663.         mov     [e], eax
  2664.  
  2665.         mov     eax, [object_screen_x]
  2666.         cmp     eax, edi
  2667.         jge     @f
  2668.         xor     eax, eax
  2669.  
  2670. @@:
  2671.         mov     edi, [akode_data.ImageBufferPtr]
  2672.         mul     [akode_data.ProjectionPlane.Size.Height]
  2673.         lea     edi, [edi + eax * 4]
  2674.  
  2675.         mov     eax, [esi + akode.Object.Distance]
  2676.         mov     [object_distance], eax
  2677.         mov     ecx, [esi + akode.Object.ShadingDistance]
  2678.  
  2679.         mov     eax, [esi + akode.Object.DisableShading]
  2680.         mov     esi, [esi + akode.Object.TextureDescPtr]
  2681.         mov     esi, [esi + akode.TextureDesc.ImageDataPtr]
  2682.  
  2683. if ~(defined DISABLE_SHADING & DISABLE_SHADING)
  2684.         test    eax, eax
  2685.         jnz     .draw_object_without_shading
  2686.  
  2687.         ; draw object with shading
  2688.         mov     edx, [akode_data.ShadingTablePtr]
  2689.         mov     ebx, [akode_data.ShadingDistance]
  2690.         cmp     ebx, ecx
  2691.         jae     @f
  2692.         mov     ecx, ebx
  2693. @@:
  2694.         mov     edx, [edx + ecx * 4]
  2695.         mov     ebx, [akode_data.ShadingColor]
  2696.  
  2697. .draw_object_slices_loop2:
  2698.         mov     eax, [object_screen_x]
  2699.         test    eax, eax
  2700.         js      .skip_slice2
  2701.  
  2702.         mov     ecx, [akode_data.DepthBufferPtr]
  2703.         mov     eax, [ecx + eax * 4]
  2704.         cmp     [object_distance], eax
  2705.         jae     .slice_hidden_by_wall2
  2706.  
  2707.         push    esi
  2708.         push    edi
  2709.  
  2710.         mov     eax, [object_screen_y]
  2711.         mov     [slice.y], eax
  2712.  
  2713.         test    eax, eax
  2714.         jns     @f
  2715.         xor     eax, eax
  2716. @@:     lea     edi, [edi + eax * 4]
  2717.  
  2718.         akode._.draw_object_slice_with_shading
  2719.  
  2720.         pop     edi
  2721.         pop     esi
  2722.  
  2723. .slice_hidden_by_wall2:
  2724.         mov     eax, [akode_data.ProjectionPlane.Size.Height]
  2725.         lea     edi, [edi + eax * 4]
  2726.  
  2727. .skip_slice2:
  2728.         add     [object_screen_x], 1
  2729.         add     esi, [int_part]
  2730.         mov     eax, [e]
  2731.         add     eax, [fract_part]
  2732.         mov     [e], eax
  2733.  
  2734.         sub     eax, [object_screen_width]
  2735.         jl      @f
  2736.         mov     [e], eax
  2737.         mov     eax, [akode_data.BlockSize.Height]
  2738.         lea     esi, [esi + eax * 4]
  2739.  
  2740. @@:
  2741.         sub     [slice_count], 1
  2742.         jnz     .draw_object_slices_loop2
  2743.  
  2744.         emms
  2745.  
  2746.         jmp     .draw_object_exit
  2747. end if
  2748.  
  2749. .draw_object_without_shading:
  2750.  
  2751. .draw_object_slices_loop:
  2752.         mov     eax, [object_screen_x]
  2753.         test    eax, eax
  2754.         js      .skip_slice
  2755.  
  2756.         mov     ecx, [akode_data.DepthBufferPtr]
  2757.         mov     eax, [ecx + eax * 4]
  2758.         cmp     [object_distance], eax
  2759.         jae     .slice_hidden_by_wall
  2760.  
  2761.         push    esi
  2762.         push    edi
  2763.  
  2764.         mov     eax, [object_screen_y]
  2765.         mov     [slice.y], eax
  2766.  
  2767.         test    eax, eax
  2768.         jns     @f
  2769.         xor     eax, eax
  2770. @@:     lea     edi, [edi + eax * 4]
  2771.  
  2772.         akode._.draw_object_slice
  2773.  
  2774.         pop     edi
  2775.         pop     esi
  2776.  
  2777. .slice_hidden_by_wall:
  2778.         mov     eax, [akode_data.ProjectionPlane.Size.Height]
  2779.         lea     edi, [edi + eax * 4]
  2780.  
  2781. .skip_slice:
  2782.         add     [object_screen_x], 1
  2783.         add     esi, [int_part]
  2784.         mov     eax, [e]
  2785.         add     eax, [fract_part]
  2786.         mov     [e], eax
  2787.  
  2788.         sub     eax, [object_screen_width]
  2789.         jl      @f
  2790.         mov     [e], eax
  2791.         mov     eax, [akode_data.BlockSize.Height]
  2792.         lea     esi, [esi + eax * 4]
  2793.  
  2794. @@:
  2795.         sub     [slice_count], 1
  2796.         jnz     .draw_object_slices_loop
  2797.  
  2798.         .draw_object_exit:
  2799. }
  2800.  
  2801. proc akode._.draw_objects start_angle
  2802.         locals
  2803.                 camera_cell_x           dd ?
  2804.                 camera_cell_y           dd ?
  2805.  
  2806.                 quadrants               dd ?
  2807.                 x_quadrants             dd ?
  2808.                 y_quadrants             dd ?
  2809.  
  2810.                 object_count            dd ?
  2811.  
  2812.                 object_screen_x_delta   dd ?
  2813.                 object_screen_x         dd ?
  2814.                 object_screen_y         dd ?
  2815.                 object_screen_width     dd ?
  2816.                 object_screen_height    dd ?
  2817.         endl
  2818.  
  2819.         mov     eax, [akode_data.CurrentLevel.ObjectCount]
  2820.         test    eax, eax
  2821.         jz      .exit
  2822.  
  2823.         fninit
  2824.  
  2825.         mov     eax, [start_angle]
  2826.  
  2827.         cmp     [akode_data.Angle0], eax
  2828.         jne     @f
  2829.         mov     ebx, 1001b
  2830.         jmp     .first_quadrant_found
  2831.  
  2832. @@:     cmp     [akode_data.Angle90], eax
  2833.         jne     @f
  2834.         mov     ebx, 0011b
  2835.         jmp     .first_quadrant_found
  2836.  
  2837. @@:     jb      @f
  2838.         mov     ebx, 0001b
  2839.         jmp     .first_quadrant_found
  2840.  
  2841. @@:     cmp     [akode_data.Angle180], eax
  2842.         jne     @f
  2843.         mov     ebx, 0110b
  2844.         jmp     .first_quadrant_found
  2845.  
  2846. @@:     jb      @f
  2847.         mov     ebx, 0010b
  2848.         jmp     .first_quadrant_found
  2849.  
  2850. @@:     cmp     [akode_data.Angle270], eax
  2851.         jne     @f
  2852.         mov     ebx, 1100b
  2853.         jmp     .first_quadrant_found
  2854.  
  2855. @@:     jb      @f
  2856.         mov     ebx, 0100b
  2857.         jmp     .first_quadrant_found
  2858.  
  2859. @@:     mov     ebx, 1000b
  2860.  
  2861. .first_quadrant_found:
  2862.         sub     eax, [akode_data.ProjectionPlane.Size.Width]
  2863.         add     eax, 1
  2864.         jns     @f
  2865.         add     eax, [akode_data.Angle360]
  2866.  
  2867. @@:
  2868.         cmp     [akode_data.Angle0], eax
  2869.         jne     @f
  2870.         mov     edx, 1001b
  2871.         jmp     .second_quadrant_found
  2872.  
  2873. @@:     cmp     [akode_data.Angle90], eax
  2874.         jne     @f
  2875.         mov     edx, 0011b
  2876.         jmp     .second_quadrant_found
  2877.  
  2878. @@:     jb      @f
  2879.         mov     edx, 0001b
  2880.         jmp     .second_quadrant_found
  2881.  
  2882. @@:     cmp     [akode_data.Angle180], eax
  2883.         jne     @f
  2884.         mov     edx, 0110b
  2885.         jmp     .second_quadrant_found
  2886.  
  2887. @@:     jb      @f
  2888.         mov     edx, 0010b
  2889.         jmp     .second_quadrant_found
  2890.  
  2891. @@:     cmp     [akode_data.Angle270], eax
  2892.         jne     @f
  2893.         mov     edx, 1100b
  2894.         jmp     .second_quadrant_found
  2895.  
  2896. @@:     jb      @f
  2897.         mov     edx, 0100b
  2898.         jmp     .second_quadrant_found
  2899.  
  2900. @@:     mov     edx, 1000b
  2901.  
  2902. .second_quadrant_found:
  2903.         mov     eax, ebx
  2904.         and     eax, edx
  2905.         jnz     @f
  2906.         mov     eax, ebx
  2907.         or      eax, edx
  2908.  
  2909. @@:
  2910.         mov     [quadrants], eax
  2911.  
  2912.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  2913.  
  2914.         mov     eax, [akode_data.Camera.Position.X]
  2915.         shr     eax, cl
  2916.         mov     [camera_cell_x], eax
  2917.  
  2918.         mov     eax, [akode_data.Camera.Position.Y]
  2919.         shr     eax, cl
  2920.         mov     [camera_cell_y], eax
  2921.  
  2922.         mov     esi, [akode_data.CurrentLevelObjectsPtr]
  2923.         xor     eax, eax
  2924.         mov     [object_count], eax
  2925.         mov     ecx, [akode_data.CurrentLevel.ObjectCount]
  2926.  
  2927. .calc_distance_to_objects_loop:
  2928.         mov     eax, [esi + akode.Object.Visible]
  2929.         test    eax, eax
  2930.         jz      .next_object
  2931.  
  2932.         mov     ebx, [esi + akode.Object.Position.X]
  2933.         mov     edx, [esi + akode.Object.Position.Y]
  2934.  
  2935.         cmp     ebx, [camera_cell_x]
  2936.         jne     @f
  2937.         mov     [x_quadrants], 1111b
  2938.         jmp     .x_quadrants_found
  2939.  
  2940. @@:     jb      @f
  2941.         mov     [x_quadrants], 1001b
  2942.         jmp     .x_quadrants_found
  2943.  
  2944. @@:     mov     [x_quadrants], 0110b
  2945.  
  2946. .x_quadrants_found:
  2947.         cmp     edx, [camera_cell_y]
  2948.         jne     @f
  2949.         mov     [y_quadrants], 1111b
  2950.         jmp     .y_quadrants_found
  2951.  
  2952. @@:     jb      @f
  2953.         mov     [y_quadrants], 1100b
  2954.         jmp     .y_quadrants_found
  2955.  
  2956. @@:     mov     [y_quadrants], 0011b
  2957.  
  2958. .y_quadrants_found:
  2959.         mov     eax, [x_quadrants]
  2960.         and     eax, [y_quadrants]
  2961.         cmp     eax, 0Fh
  2962.         je      .next_object
  2963.  
  2964.         test    eax, [quadrants]
  2965.         jz      .next_object
  2966.  
  2967.         push    ecx
  2968.         mov     ecx, [akode_data.BlockWidthPowerOf2]
  2969.         shl     ebx, cl
  2970.         shl     edx, cl
  2971.         pop     ecx
  2972.         mov     eax, [akode_data.BlockSize.Width]
  2973.         shr     eax, 1
  2974.         add     ebx, eax
  2975.         add     edx, eax
  2976.  
  2977.         sub     ebx, [akode_data.Camera.Position.X]
  2978.         neg     edx
  2979.         add     edx, [akode_data.Camera.Position.Y]
  2980.  
  2981.         push    ebx
  2982.         push    edx
  2983.         fild    dword [esp]
  2984.         fild    dword [esp + 4]
  2985.         fpatan
  2986.         add     esp, 8
  2987.  
  2988.         imul    ebx, ebx
  2989.         imul    edx, edx
  2990.         add     ebx, edx
  2991.  
  2992.         push    ebx
  2993.         fild    dword [esp]
  2994.         fsqrt
  2995.         add     esp, 4
  2996.         fistp   [esi + akode.Object.Distance]
  2997.  
  2998.         mov     eax, [esi + akode.Object.Distance]
  2999.         mov     [esi + akode.Object.ShadingDistance], eax
  3000.  
  3001.         fldpi
  3002.         fldpi
  3003.         faddp
  3004.         fidivr  [akode_data.Angle360]                           ; Angle360 / 2 * pi
  3005.         fmulp
  3006.         fistp   [esi + akode.Object.Angle]
  3007.  
  3008.         mov     eax, [esi + akode.Object.Angle]
  3009.         test    eax, eax
  3010.         jns     @f
  3011.         add     eax, [akode_data.Angle360]
  3012.         mov     [esi + akode.Object.Angle], eax
  3013.  
  3014. @@:
  3015.         push    esi
  3016.         add     [object_count], 1
  3017.  
  3018. .next_object:
  3019.         add     esi, sizeof.akode.Object
  3020.         sub     ecx, 1
  3021.         jnz     .calc_distance_to_objects_loop
  3022.  
  3023.         mov     eax, [object_count]
  3024.         test    eax, eax
  3025.         jz      .exit
  3026.  
  3027.         mov     ebx, esp
  3028.         stdcall akode._.sort_objects, ebx, eax
  3029.  
  3030.         mov     ecx, [object_count]
  3031.  
  3032. .draw_objects_loop:
  3033.         pop     esi
  3034.  
  3035.         mov     eax, [esi + akode.Object.Angle]
  3036.         sub     eax, [akode_data.Camera.Direction]
  3037.         mov     ebx, eax
  3038.         jns     @f
  3039.         add     eax, [akode_data.Angle360]
  3040.         neg     ebx
  3041.  
  3042. @@:
  3043.         cmp     [akode_data.Angle90], eax
  3044.         je      .draw_next_object
  3045.         cmp     [akode_data.Angle270], eax
  3046.         je      .draw_next_object
  3047.  
  3048.         mov     edi, [akode_data.TrigonometricTablePtr]
  3049.  
  3050.         shl     eax, 5
  3051.         fld     qword [edi + eax + 16]
  3052.         fimul   [akode_data.CameraToPlaneDistance]
  3053.         fistp   [object_screen_x_delta]
  3054.  
  3055.         shl     ebx, 5
  3056.         fld     qword [edi + ebx + 8]
  3057.         fabs
  3058.         fimul   [esi + akode.Object.Distance]
  3059.         fist    [esi + akode.Object.Distance]
  3060.         fidivr  [akode_data.WallHeightDividend]
  3061.         fistp   [object_screen_height]
  3062.         ;fimul   [akode_data.BlockSize.Width]
  3063.         ;fidiv   [akode_data.BlockSize.Height]
  3064.         ;fistp   [object_screen_width]
  3065.  
  3066.         mov     ebx, [akode_data.ProjectionPlane.MidY]
  3067.         mov     eax, [object_screen_height]
  3068.         mov     edx, eax
  3069.         shr     edx, 1
  3070.         sub     ebx, edx
  3071.         mov     [object_screen_y], ebx
  3072.  
  3073.         mul     [akode_data.BlockSize.Width]
  3074.         div     [akode_data.BlockSize.Height]
  3075.         mov     [object_screen_width], eax
  3076.  
  3077.         mov     ebx, [akode_data.ProjectionPlane.Size.Width]
  3078.         shr     ebx, 1
  3079.         sub     ebx, [object_screen_x_delta]
  3080.         shr     eax, 1
  3081.         sub     ebx, eax
  3082.         mov     [object_screen_x], ebx
  3083.  
  3084.         push    ecx
  3085.         akode._.draw_object
  3086.         pop     ecx
  3087.  
  3088. .draw_next_object:
  3089.         sub     ecx, 1
  3090.         jnz     .draw_objects_loop
  3091.  
  3092. .exit:
  3093.         ret
  3094. endp
  3095. ; ============================================================================ ;
  3096.  
  3097. ; ============================================================================ ;
  3098. proc akode._.sort_objects objects_ptr, object_count
  3099.         mov     edx, [object_count]
  3100.         mov     ecx, 1
  3101.  
  3102.         cmp     edx, ecx
  3103.         jbe     .exit
  3104.  
  3105.         mov     esi, [objects_ptr]
  3106.  
  3107. .sort_loop:
  3108.         mov     ebx, ecx
  3109.         mov     edi, [esi + ebx * 4]
  3110.  
  3111. @@:
  3112.         test    ebx, ebx
  3113.         jz      .insert
  3114.  
  3115.         mov     eax, [esi + ebx * 4 - 4]
  3116.         mov     eax, [eax + akode.Object.Distance]
  3117.         cmp     [edi + akode.Object.Distance], eax
  3118.         jna     .insert
  3119.  
  3120.         mov     eax, [esi + ebx * 4 - 4]
  3121.         mov     [esi + ebx * 4], eax
  3122.         sub     ebx, 1
  3123.         jmp     @b
  3124.  
  3125. .insert:
  3126.         mov     [esi + ebx * 4], edi
  3127.  
  3128.         add     ecx, 1
  3129.         cmp     edx, ecx
  3130.         jne     .sort_loop
  3131.  
  3132. .exit:
  3133.         ret
  3134. endp
  3135.  
  3136. ;void insertionsort()
  3137. ;    {
  3138. ;        int i, j, t;
  3139. ;        for (i=1; i<n; i++)
  3140. ;        {
  3141. ;            j=i;
  3142. ;            t=a[j];
  3143. ;            while (j>0 && a[j-1]>t)
  3144. ;            {
  3145. ;                a[j]=a[j-1];
  3146. ;                j--;
  3147. ;            }
  3148. ;            a[j]=t;
  3149. ;        }
  3150. ;    }
  3151. ; ============================================================================ ;
  3152.  
  3153. ; ============================================================================ ;
  3154. ; > ebx = width of image (in px)                                               ;
  3155. ; > edx = height of image (in px)                                              ;
  3156. ; > esi = pointer to source block                                              ;
  3157. ; > edi = pointer to destination block                                         ;
  3158. ; ============================================================================ ;
  3159. macro akode._.transpose16x16
  3160. {
  3161.         local   .loop1, .loop2
  3162.  
  3163.         push    ebx
  3164.         push    edx
  3165.  
  3166.         mov     ebx, 15
  3167.  
  3168. .loop1:
  3169.         mov     ecx, 15
  3170.  
  3171. .loop2:
  3172.         mov     eax, ecx
  3173.         imul    eax, [esp]
  3174.         add     eax, ebx
  3175.         mov     eax, [esi + eax * 4]
  3176.  
  3177.         mov     edx, ebx
  3178.         imul    edx, [esp + 4]
  3179.         add     edx, ecx
  3180.         mov     [edi + edx * 4], eax
  3181.  
  3182.         sub     ecx, 1
  3183.         jns     .loop2
  3184.  
  3185.         sub     ebx, 1
  3186.         jns     .loop1
  3187.  
  3188.         pop     edx
  3189.         pop     ebx
  3190. }
  3191.  
  3192. ; ============================================================================ ;
  3193. ; > ebx = width of image / 2 (in px)                                           ;
  3194. ; > edx = height of image (in px)                                              ;
  3195. ; > esi = pointer to source block                                              ;
  3196. ; > edi = pointer to destination block                                         ;
  3197. ; ============================================================================ ;
  3198. macro akode._.transpose16x16to8x8
  3199. {
  3200.         local   .loop1, .loop2
  3201.  
  3202.         push    ebx
  3203.  
  3204.         mov     ebx, 7
  3205.  
  3206. .loop1:
  3207.         mov     ecx, 7
  3208.  
  3209. .loop2:
  3210.         mov     eax, ecx
  3211.         imul    eax, edx
  3212.         add     eax, ebx
  3213.         lea     eax, [esi + eax * 8]
  3214.  
  3215.         movq    mm0, [eax]
  3216.         pavgb   mm0, [eax + edx * 4]
  3217.         movq    mm1, mm0
  3218.         psrlq   mm0, 32
  3219.         pavgb   mm1, mm0
  3220.  
  3221.         mov     eax, ebx
  3222.         imul    eax, [esp]
  3223.         add     eax, ecx
  3224.         movd    [edi + eax * 4], mm1
  3225.  
  3226.         sub     ecx, 1
  3227.         jns     .loop2
  3228.  
  3229.         sub     ebx, 1
  3230.         jns     .loop1
  3231.  
  3232.         pop     ebx
  3233. }
  3234.  
  3235. ; ============================================================================ ;
  3236. proc akode.get_image uses eax ebx ecx edx esi edi, buffer_ptr, downscale_factor_pow2
  3237.         mov     esi, [akode_data.ImageBufferPtr]
  3238.         mov     edi, [buffer_ptr]
  3239.         mov     ebx, [akode_data.ProjectionPlane.Size.Width]
  3240.         mov     edx, [akode_data.ProjectionPlane.Size.Height]
  3241.         mov     eax, [downscale_factor_pow2]
  3242.  
  3243.         mov     ecx, [akode_data.OptimizedGetImage]
  3244.         ;xor     ecx, ecx
  3245.         test    ecx, ecx
  3246.         jz      .no_optimization
  3247.  
  3248. ; optimized
  3249.         test    edi, 0Fh
  3250.         jz      @f
  3251.         DEBUGF  DEBUG_INFO, 'akode.get_image: buffer_ptr is not aligned by 16\n'
  3252. @@:
  3253.  
  3254.         test    eax, eax
  3255.         jnz     .downscale2_optimized
  3256.  
  3257. ; no downscale optimized
  3258.         xor     eax, eax
  3259.  
  3260. .loop1:
  3261.         xor     ecx, ecx
  3262.  
  3263. .loop2:
  3264. ;        mov     esi, ecx
  3265. ;        imul    esi, edx
  3266. ;        add     esi, eax
  3267. ;        shl     esi, 2
  3268. ;        add     esi, [akode_data.ImageBufferPtr]
  3269. ;
  3270. ;        mov     edi, eax
  3271. ;        imul    edi, ebx
  3272. ;        add     edi, ecx
  3273. ;        shl     edi, 2
  3274. ;        add     edi, [buffer_ptr]
  3275.  
  3276.         mov     esi, ecx
  3277.         mov     edi, eax
  3278.  
  3279.         imul    esi, edx
  3280.         imul    edi, ebx
  3281.  
  3282.         add     esi, eax
  3283.         add     edi, ecx
  3284.  
  3285.         shl     esi, 2
  3286.         shl     edi, 2
  3287.  
  3288.         add     esi, [akode_data.ImageBufferPtr]
  3289.         add     edi, [buffer_ptr]
  3290.  
  3291.         push    eax
  3292.         push    ecx
  3293.  
  3294.         akode._.transpose16x16
  3295.  
  3296.         pop     ecx
  3297.         pop     eax
  3298.  
  3299.         add     ecx, 16
  3300.         cmp     ecx, ebx
  3301.         jne     .loop2
  3302.  
  3303.         add     eax, 16
  3304.         cmp     eax, edx
  3305.         jne     .loop1
  3306.  
  3307.         jmp     .exit
  3308.  
  3309. .downscale2_optimized:
  3310.         shr     ebx, 1
  3311.  
  3312.         xor     eax, eax
  3313.  
  3314. .loop3:
  3315.         xor     ecx, ecx
  3316.  
  3317. .loop4:
  3318. ;        mov     esi, ecx
  3319. ;        imul    esi, edx
  3320. ;        add     esi, eax
  3321. ;        shl     esi, 2
  3322. ;        add     esi, [akode_data.ImageBufferPtr]
  3323. ;
  3324. ;        mov     edi, eax
  3325. ;        imul    edi, ebx
  3326. ;        add     edi, ecx
  3327. ;        shl     edi, 1
  3328. ;        add     edi, [buffer_ptr]
  3329.  
  3330.         mov     esi, ecx
  3331.         mov     edi, eax
  3332.  
  3333.         imul    esi, edx
  3334.         imul    edi, ebx
  3335.  
  3336.         add     esi, eax
  3337.         add     edi, ecx
  3338.  
  3339.         shl     esi, 2
  3340.         shl     edi, 1
  3341.  
  3342.         add     esi, [akode_data.ImageBufferPtr]
  3343.         add     edi, [buffer_ptr]
  3344.  
  3345.         push    eax
  3346.         push    ecx
  3347.  
  3348.         akode._.transpose16x16to8x8
  3349.  
  3350.         pop     ecx
  3351.         pop     eax
  3352.  
  3353.         add     ecx, 16
  3354.         cmp     [akode_data.ProjectionPlane.Size.Width], ecx
  3355.         jne     .loop4
  3356.  
  3357.         add     eax, 16
  3358.         cmp     eax, edx
  3359.         jne     .loop3
  3360.  
  3361.         emms
  3362.  
  3363.         jmp     .exit
  3364.  
  3365. .no_optimization:
  3366.         test    eax, eax
  3367.         jnz     .downscale2_no_optimization
  3368.  
  3369. ; no downscale
  3370.         mov     ecx, ebx
  3371.         shl     ebx, 2
  3372. @@:
  3373.         mov     eax, [esi]
  3374.         mov     [edi], eax
  3375.         add     esi, 4
  3376.         add     edi, ebx
  3377.  
  3378.         sub     edx, 1
  3379.         jnz     @b
  3380.  
  3381.         mov     edx, [akode_data.ProjectionPlane.Size.Height]
  3382.         mov     edi, [buffer_ptr]
  3383.         add     edi, 4
  3384.         mov     [buffer_ptr], edi
  3385.  
  3386.         sub     ecx, 1
  3387.         jnz     @b
  3388.  
  3389.         jmp     .exit
  3390.  
  3391. .downscale2_no_optimization:
  3392.         mov     eax, edx
  3393.         shr     edx, 1
  3394.         shl     eax, 2
  3395.  
  3396.         shr     ebx, 1
  3397.         mov     ecx, ebx
  3398.         shl     ecx, 2
  3399. @@:
  3400.         movq    mm0, [esi]
  3401.         pavgb   mm0, [esi + eax]
  3402.         movq    mm1, mm0
  3403.         psrlq   mm0, 32
  3404.         pavgb   mm1, mm0
  3405.         movd    [edi], mm1
  3406.  
  3407.         add     esi, 8
  3408.         add     edi, ecx
  3409.  
  3410.         sub     edx, 1
  3411.         jnz     @b
  3412.  
  3413.         mov     edx, [akode_data.ProjectionPlane.Size.Height]
  3414.         shr     edx, 1
  3415.         add     esi, eax
  3416.         mov     edi, [buffer_ptr]
  3417.         add     edi, 4
  3418.         mov     [buffer_ptr], edi
  3419.  
  3420.         sub     ebx, 1
  3421.         jnz     @b
  3422.  
  3423.         emms
  3424.  
  3425. .exit:
  3426.         ret
  3427. endp
  3428. ; ============================================================================ ;