; Copyright (C) 2014 Anton_K ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . include '../../../develop/libraries/libs-dev/libio/libio.inc' include '../../../develop/libraries/libs-dev/libimg/libimg.inc' include 'datadef.inc' ; ============================================================================ ; ; < eax = 0 - fail ; ; ============================================================================ ; proc akode.init uses ebx ecx edx, plane_width, plane_height, fov, block_base_size, block_height bsr ecx, [block_base_size] xor eax, eax inc eax shl eax, cl mov [akode_data.BlockWidthPowerOf2], ecx mov [akode_data.BlockSize.Width], eax mov eax, [block_height] mov [akode_data.BlockSize.Height], eax shr eax, 1 mov [akode_data.Camera.Position.Z], eax xor eax, eax mov [akode_data.Camera.Position.X], eax mov [akode_data.Camera.Position.Y], eax mov [akode_data.Camera.Direction], eax mov [akode_data.OptimizedGetImage], eax dec eax mov [akode_data.MovementDirection], eax mov [akode_data.TurningDirection], eax inc eax stdcall akode.set_shading, eax, eax test eax, eax jz .exit mov edx, [plane_width] mov ecx, edx shl ecx, 2 mcall 68, 12 ; alloc width * 4 bytes test eax, eax jz .exit mov [akode_data.DepthBufferPtr], eax mov eax, [plane_height] mov ecx, eax shl ecx, 2 imul ecx, edx ; ecx = height * 4 * width mov [akode_data.ProjectionPlane.Size.Height], eax mov [akode_data.ProjectionPlane.Size.Width], edx mov [akode_data.ImageBufferSize], ecx mov ebx, eax or ebx, edx test ebx, 0Fh jnz @f inc [akode_data.OptimizedGetImage] @@: shr eax, 1 mov [akode_data.ProjectionPlane.MidY], eax ; MidY = height / 2 mcall 68, 12 ; alloc ecx bytes test eax, eax jz .exit mov [akode_data.ImageBufferPtr], eax DEBUGF DEBUG_FINE, 'akode_data.ImageBufferPtr: %x\n', eax:8 DEBUGF DEBUG_FINE, 'akode_data.OptimizedGetImage: %u\n', [akode_data.OptimizedGetImage] mov ecx, [fov] mov ebx, edx imul eax, edx, 360 xor edx, edx div ecx ; eax = width * 360 / fov mov [akode_data.Camera.FieldOfView], ecx mov [akode_data.Angle360], eax stdcall akode._.calc_tables test eax, eax jz .exit shr ebx, 1 ; ebx = width / 2 push ebx shl ebx, 5 ; ebx * 32 mov eax, [akode_data.TrigonometricTablePtr] fild dword [esp] ; width / 2 fdiv qword [eax + ebx + 16] ; tan (fov / 2) fistp dword [esp] pop eax mov [akode_data.CameraToPlaneDistance], eax mov ebx, eax mul [block_height] mov [akode_data.WallHeightDividend], eax mov eax, [block_height] sub eax, [akode_data.Camera.Position.Z] mul ebx mov [akode_data.CeilingDistanceDividend], eax imul ebx, [akode_data.Camera.Position.Z] mov [akode_data.FloorDistanceDividend], ebx DEBUGF DEBUG_FINE, 'akode_data.CameraToPlaneDistance: %u\n', [akode_data.CameraToPlaneDistance] stdcall akode.set_movement_speed, [akode_data.BlockSize.Width], 90 .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.cleanup uses eax ebx ecx edx stdcall akode.unload_current_level xor edx, edx mov ebx, 13 mov ecx, [akode_data.ImageBufferPtr] test ecx, ecx jz @f mcall 68 ; free mov [akode_data.ImageBufferPtr], edx @@: mov ecx, [akode_data.DepthBufferPtr] test ecx, ecx jz @f mcall 68 mov [akode_data.DepthBufferPtr], edx @@: mov ecx, [akode_data.TrigonometricTablePtr] test ecx, ecx jz @f mcall 68 mov [akode_data.TrigonometricTablePtr], edx @@: mov ecx, [akode_data.BlockWidthTanTablePtr] test ecx, ecx jz @f mcall 68 mov [akode_data.BlockWidthTanTablePtr], edx @@: mov ecx, [akode_data.ShadingTablePtr] test ecx, ecx jz @f mcall 68 mov [akode_data.ShadingTablePtr], edx @@: ret endp ; ============================================================================ ; ; ============================================================================ ; ; > level_load_callback = proc callback AKODE_LEVEL_LOAD, result ; ; > action_callback = proc callback AKODE_ACTION, cell x, cell y, result ; ; ============================================================================ ; proc akode.set_callbacks level_load_callback, action_callback m2m [akode_data.LevelLoadCallback], [level_load_callback] m2m [akode_data.ActionCallback], [action_callback] ret endp ; ============================================================================ ; ; ============================================================================ ; ; < eax = 0 - failed to load some textures or create shading table ; ; ============================================================================ ; proc akode.load_level uses ebx ecx edx esi edi, level_ptr locals load_texture_results dd 1 endl stdcall akode.unload_current_level mov ebx, akode_data.CurrentLevel cld mov esi, [level_ptr] mov edi, ebx mov ecx, sizeof.akode.LevelHeader rep movsb mov [akode_data.CurrentLevelGridPtr], esi mov eax, [ebx + akode.LevelHeader.InitCallback] test eax, eax jz @f stdcall eax @@: mov edx, [akode_data.LevelLoadCallback] test edx, edx jz @f stdcall edx, AKODE_LEVEL_LOAD.START, eax @@: mov ecx, [ebx + akode.LevelHeader.Size.Width] imul ecx, [ebx + akode.LevelHeader.Size.Height] .load_textures_loop: mov edi, [esi] add esi, 4 test edi, edi jz .skip push ecx mov ecx, 6 * 2 ; 6 combined textures per cell .load_cell_textures_loop: mov eax, [edi] add edi, 4 test eax, eax jz @f stdcall akode.load_texture, eax test eax, eax jnz @f mov [load_texture_results], eax @@: sub ecx, 1 jnz .load_cell_textures_loop pop ecx .skip: sub ecx, 1 jnz .load_textures_loop mov ecx, [ebx + akode.LevelHeader.ObjectCount] test ecx, ecx jz @f mov [akode_data.CurrentLevelObjectsPtr], esi .load_object_textures_loop: mov eax, [esi] add esi, sizeof.akode.Object test eax, eax jz .skip_object stdcall akode.load_texture, eax test eax, eax jnz .skip_object mov [load_texture_results], eax .skip_object: sub ecx, 1 jnz .load_object_textures_loop @@: mov ecx, [ebx + akode.LevelHeader.TextureCount] test ecx, ecx jz @f mov [akode_data.CurrentLevelAddTexturesPtr], esi .load_additional_textures_loop: mov eax, [esi] add esi, 4 test eax, eax jz .skip_additional stdcall akode.load_texture, eax test eax, eax jnz .skip_additional mov [load_texture_results], eax .skip_additional: sub ecx, 1 jnz .load_additional_textures_loop @@: mov edi, [akode_data.BlockSize.Width] shr edi, 1 mov ecx, [akode_data.BlockWidthPowerOf2] mov eax, [ebx + akode.LevelHeader.StartPosition.X] shl eax, cl add eax, edi mov [akode_data.Camera.Position.X], eax mov eax, [ebx + akode.LevelHeader.StartPosition.Y] shl eax, cl add eax, edi mov [akode_data.Camera.Position.Y], eax mov eax, [ebx + akode.LevelHeader.StartDirection] imul eax, [akode_data.Angle90] mov [akode_data.Camera.Direction], eax xor eax, eax dec eax mov [akode_data.MovementDirection], eax mov [akode_data.TurningDirection], eax stdcall akode.set_shading, [ebx + akode.LevelHeader.ShadingColor], [ebx + akode.LevelHeader.ShadingDistance] test eax, eax jz @f mov eax, [load_texture_results] @@: test edx, edx jz @f stdcall edx, AKODE_LEVEL_LOAD.END, eax @@: ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.unload_current_level uses eax ecx edx esi edi mov esi, [akode_data.CurrentLevelGridPtr] test esi, esi jz .exit mov ecx, [akode_data.CurrentLevel.Size.Width] imul ecx, [akode_data.CurrentLevel.Size.Height] .unload_textures_loop: mov edi, [esi] add esi, 4 test edi, edi jz .skip mov edx, 6 * 2 ; 6 combined textures per cell .unload_cell_textures_loop: mov eax, [edi] add edi, 4 test eax, eax jz @f stdcall akode.unload_texture, eax @@: sub edx, 1 jnz .unload_cell_textures_loop .skip: sub ecx, 1 jnz .unload_textures_loop mov [akode_data.CurrentLevelGridPtr], ecx mov ecx, [akode_data.CurrentLevel.ObjectCount] test ecx, ecx jz @f .unload_object_textures_loop: mov eax, [esi] add esi, sizeof.akode.Object test eax, eax jz .skip_object stdcall akode.unload_texture, eax .skip_object: sub ecx, 1 jnz .unload_object_textures_loop @@: mov [akode_data.CurrentLevelObjectsPtr], ecx mov ecx, [akode_data.CurrentLevel.TextureCount] test ecx, ecx jz @f .unload_additional_textures_loop: mov eax, [esi] add esi, 4 test eax, eax jz .skip_additional stdcall akode.unload_texture, eax .skip_additional: sub ecx, 1 jnz .unload_additional_textures_loop @@: mov [akode_data.CurrentLevelAddTexturesPtr], ecx mov eax, [akode_data.CurrentLevel.DestroyCallback] test eax, eax jz @f stdcall eax @@: mov edx, [akode_data.LevelLoadCallback] test edx, edx jz @f stdcall edx, AKODE_LEVEL_LOAD.UNLOADED, eax @@: .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; ; < eax = 0 - fail ; ; ============================================================================ ; proc akode.load_texture uses ebx ecx edx, texture_desc_ptr mov ebx, [texture_desc_ptr] mov eax, [ebx + akode.TextureDesc.Type] or eax, [ebx + akode.TextureDesc.ImageDataPtr] jnz .exit mov ecx, [akode_data.BlockSize.Width] mov edx, ecx mov al, [ebx + akode.TextureDesc.Usage] test al, al jz @f mov edx, [akode_data.BlockSize.Height] @@: stdcall akode.load_and_scale_image, [ebx + akode.TextureDesc.ImagePathPtr], ecx, edx, 1 mov [ebx + akode.TextureDesc.ImageDataPtr], eax .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.unload_texture uses eax ebx ecx, texture_desc_ptr mov ebx, [texture_desc_ptr] mov eax, [ebx + akode.TextureDesc.Type] test eax, eax jnz .exit mov ecx, [ebx + akode.TextureDesc.ImageDataPtr] test ecx, ecx jz .exit push ebx mcall 68, 13 pop ebx xor eax, eax mov [ebx + akode.TextureDesc.ImageDataPtr], eax .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; ; < eax = pointer to image data / 0 - fail ; ; ============================================================================ ; proc akode.load_and_scale_image uses ebx ecx edx esi edi, image_path_ptr, width, height, internal_format locals decode_options ImageDecodeOptions sizeof.ImageDecodeOptions, 0FF00FFh endl stdcall akode.load_file, [image_path_ptr] test eax, eax jz .exit mov esi, eax ; esi = file data lea eax, [decode_options] push esi invoke img_decode, esi, ebx, eax pop esi test eax, eax jz .exit_and_free_file_fail mov edi, eax ; edi = image handle xor eax, eax push esi edi invoke img_convert, edi, eax, Image.bpp24, eax, eax pop edi esi push eax push esi invoke img_destroy, edi ; destroy handle from img_decode pop ecx mcall 68, 13 pop edi ; edi = image handle from img_convert test edi, edi jz .exit_fail mov ebx, [width] mov ecx, [height] cmp [edi + Image.Width], ebx jne .scale cmp [edi + Image.Height], ecx jne .scale jmp @f .scale: xor eax, eax push edi invoke img_scale, edi, eax, eax, [edi + Image.Width], [edi + Image.Height], eax, LIBIMG_SCALE_STRETCH, LIBIMG_INTER_BILINEAR, ebx, ecx pop edi push eax invoke img_destroy, edi ; destroy handle from img_convert pop edi ; edi = image handle from img_scale test edi, edi jz .exit_fail @@: mov eax, [internal_format] test eax, eax jz @f invoke img_flip, edi, FLIP_HORIZONTAL invoke img_rotate, edi, ROTATE_90_CCW @@: stdcall akode._.convert_image_to_32bpp, edi push eax invoke img_destroy, edi pop eax jmp .exit .exit_and_free_file_fail: mcall 68, 13, esi .exit_fail: xor eax, eax .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; ; < eax = pointer to image data / 0 - fail ; ; ============================================================================ ; proc akode._.convert_image_to_32bpp uses ebx ecx edx esi edi, image mov edi, [image] invoke img_to_rgb, edi test eax, eax jz .exit mov esi, eax mov ecx, [edi + Image.Width] imul ecx, [edi + Image.Height] shl ecx, 2 mcall 68, 12 test eax, eax jz .exit_and_free_fail push eax mov edi, eax mov edx, esi add esi, 8 shr ecx, 2 @@: mov ax, [esi] movzx bx, byte [esi + 2] mov [edi], ax mov [edi + 2], bx add esi, 3 add edi, 4 sub ecx, 1 jnz @b mcall 68, 13, edx pop eax jmp .exit .exit_and_free_fail: mcall 68, 13, esi xor eax, eax .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; ; < eax = pointer to data / 0 - fail ; ; < ebx = file size ; ; ============================================================================ ; proc akode.load_file uses ecx edx esi edi, file_path_ptr invoke file_size, [file_path_ptr] test eax, eax jnz .exit_fail mov edx, ebx ; edx = file size mcall 68, 12, edx test eax, eax jz .exit mov edi, eax ; edi = pointer to data invoke file_open, [file_path_ptr], O_READ test eax, eax jz .exit_and_free_fail mov esi, eax ; esi = file handle mov ebx, edx invoke file_read, esi, edi, edx sub edx, eax invoke file_close, esi test edx, edx jnz .exit_and_free_fail mov eax, edi jmp .exit .exit_and_free_fail: mcall 68, 13, edi .exit_fail: xor eax, eax .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; ; < eax = 0 - fail ; ; ============================================================================ ; proc akode._.calc_tables uses ebx ecx edx esi edi mov eax, [akode_data.Angle360] mov ecx, eax mov edi, eax shr eax, 1 mov [akode_data.Angle180], eax mov ebx, eax shr eax, 1 mov [akode_data.Angle90], eax add ebx, eax mov [akode_data.Angle270], ebx DEBUGF DEBUG_FINE, 'akode_data.ProjectionPlane.Size.Width: %u\n', [akode_data.ProjectionPlane.Size.Width] DEBUGF DEBUG_FINE, 'akode_data.Camera.FieldOfView: %u\n', [akode_data.Camera.FieldOfView] DEBUGF DEBUG_FINE, 'akode_data.Angle[90, 180, 270, 360]: %u, %u, %u, %u\n', [akode_data.Angle90], [akode_data.Angle180], \ [akode_data.Angle270], [akode_data.Angle360] shl ecx, 5 ; ecx = Angle360 * (8 bytes * 4 columns) mcall 68, 20, , [akode_data.TrigonometricTablePtr] ; realloc ecx bytes test eax, eax jz .exit mov [akode_data.TrigonometricTablePtr], eax fninit xor ecx, ecx fldpi fldpi faddp fidiv [akode_data.Angle360] ; 2 * pi / Angle360 @@: ; calculate sin, cos, tan, 1 / cos fld st0 mov [eax], ecx fimul dword [eax] ; 2 * pi / Angle360 * ecx = ecx in radians fsincos fst qword [eax + 8] ; cos fld st0 fld1 fdivrp fstp qword [eax + 24] ; 1 / cos fxch fst qword [eax] ; sin fdivrp fstp qword [eax + 16] ; tan add ecx, 1 add eax, 32 cmp ecx, edi jne @b ;mov ecx, edi shl ecx, 3 ; ecx = Angle360 * (4 bytes * 2 columns) mcall 68, 20, , [akode_data.BlockWidthTanTablePtr] ; realloc ecx bytes test eax, eax jz .pop_fpu_exit mov [akode_data.BlockWidthTanTablePtr], eax mov edx, [akode_data.Angle180] mov ebx, [akode_data.Angle90] mov esi, [akode_data.Angle270] xor ecx, ecx @@: ; calculate BlockSize.Width * tan and BlockSize.Width / tan fld st0 mov [eax], ecx fimul dword [eax] ; 2 * pi / Angle360 * ecx = ecx in radians fptan fld st1 fimul [akode_data.BlockSize.Width] fistp dword [eax] ; BlockSize.Width * tan cmp ecx, ebx jb .reverse_sign cmp ecx, esi ja .reverse_sign jmp .dont_reverse_sign .reverse_sign: neg dword [eax] ; reverse sign for angles < 90 and > 270 .dont_reverse_sign: fdivrp fimul [akode_data.BlockSize.Width] fistp dword [eax + 4] ; BlockSize.Width * 1 / tan cmp ecx, edx jna .dont_reverse_sign2 neg dword [eax + 4] ; reverse sign for angles > 180 .dont_reverse_sign2: add ecx, 1 add eax, 8 cmp ecx, edi jne @b .pop_fpu_exit: fstp st0 .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.set_field_of_view fov ; not supported ret endp ; ============================================================================ ; ; ============================================================================ ; ; < eax = 0 - fail ; ; ============================================================================ ; proc akode.set_shading uses ebx ecx edx, color, distance m2m [akode_data.ShadingColor], [color] mov ecx, [distance] mov [akode_data.ShadingDistance], ecx inc ecx shl ecx, 2 mcall 68, 20, , [akode_data.ShadingTablePtr] ; realloc ecx bytes test eax, eax jz .exit mov [akode_data.ShadingTablePtr], eax fninit xor ecx, ecx cmp [distance], ecx jne @f mov dword [eax], 255 jmp .exit @@: imul ebx, ecx, 255 mov [eax], ebx fild dword [eax] fidiv [distance] fistp dword [eax] mov ebx, 255 sub ebx, [eax] mov [eax], ebx add ecx, 1 add eax, 4 cmp [distance], ecx jae @b .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; ; > movement_speed = speed in px per second ; ; > turning_speed = speed in degrees per second ; ; ============================================================================ ; proc akode.set_movement_speed uses eax ebx edx, movement_speed, turning_speed mov eax, [turning_speed] mul [akode_data.Angle360] mov ebx, 360 div ebx mov [akode_data.TurningSpeed], eax m2m [akode_data.MovementSpeed], [movement_speed] ret endp ; ============================================================================ ; ; ============================================================================ ; ; > movement_direction = AKODE_DIRECTION.NORTH - forward, ; ; AKODE_DIRECTION.SOUTH - backward ; ; ============================================================================ ; proc akode.start_moving uses eax ebx, movement_direction m2m [akode_data.MovementDirection], [movement_direction] mcall 26, 9 mov [akode_data.LastMoveTimestamp], eax ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.stop_moving mov [akode_data.MovementDirection], -1 ret endp ; ============================================================================ ; ; ============================================================================ ; ; > turning_direction = AKODE_DIRECTION.WEST - left, ; ; AKODE_DIRECTION.EAST - right ; ; ============================================================================ ; proc akode.start_turning uses eax ebx, turning_direction m2m [akode_data.TurningDirection], [turning_direction] mcall 26, 9 mov [akode_data.LastTurnTimestamp], eax ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.stop_turning mov [akode_data.TurningDirection], -1 ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.process uses eax ebx ecx edx esi edi stdcall akode._.process_moving ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode._.process_moving locals timestamp dd ? collision_distance dd ? current_cell_x dd ? current_cell_y dd ? endl mov esi, [akode_data.MovementDirection] mov edi, [akode_data.TurningDirection] mov eax, esi and eax, edi js .exit mcall 26, 9 ; get timestamp mov [timestamp], eax test edi, edi js .not_turning mov ebx, eax sub ebx, [akode_data.LastTurnTimestamp] cmp ebx, 4 jb .not_turning mov [akode_data.LastTurnTimestamp], eax mov eax, ebx mul [akode_data.TurningSpeed] mov ecx, 100 div ecx ; eax = turn angle test eax, eax jnz @f inc eax ; clamp @@: cmp [akode_data.Angle90], eax jae @f mov eax, [akode_data.Angle90] ; clamp @@: mov edx, [akode_data.Camera.Direction] mov ecx, [akode_data.Angle360] test edi, edi jz .turn_right ; turn left add edx, eax cmp ecx, edx ja @f sub edx, ecx @@: jmp @f .turn_right: sub edx, eax jns @f add edx, ecx @@: mov [akode_data.Camera.Direction], edx mov eax, [timestamp] .not_turning: test esi, esi js .exit mov ebx, eax sub ebx, [akode_data.LastMoveTimestamp] cmp ebx, 4 jb .exit mov [akode_data.LastMoveTimestamp], eax mov eax, ebx mul [akode_data.MovementSpeed] mov ecx, 100 div ecx ; eax = move distance cmp eax, 3 jae @f mov eax, 3 ; clamp @@: mov edx, [akode_data.BlockSize.Width] shr edx, 2 mov ebx, edx sub edx, 2 cmp edx, eax jae @f mov eax, edx ; clamp @@: mov [collision_distance], ebx fninit mov ebx, [akode_data.Camera.Direction] shl ebx, 5 add ebx, [akode_data.TrigonometricTablePtr] push eax fild dword [esp] fld st0 fmul qword [ebx] fistp dword [esp] mov ecx, [esp] ; ecx = distance * sin (Camera.Direction) = y displacement fmul qword [ebx + 8] fistp dword [esp] pop edx ; edx = distance * cos (Camera.Direction) = x displacement cmp esi, AKODE_DIRECTION.NORTH mov esi, [akode_data.Camera.Position.X] mov edi, [akode_data.Camera.Position.Y] mov eax, esi mov ebx, edi jne .move_backward ; move forward add esi, edx sub edi, ecx jmp @f .move_backward: sub esi, edx add edi, ecx @@: ; collision detection locals top_border dd 0 left_border dd 0 right_border dd 0 bottom_border dd 0 new_x dd ? new_y dd ? endl mov ecx, [akode_data.BlockWidthPowerOf2] mov edx, [akode_data.CurrentLevelGridPtr] shr eax, cl shr ebx, cl mov [current_cell_x], eax mov [current_cell_y], ebx ; top border mov eax, esi mov ebx, edi sub ebx, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f shr edi, cl shl edi, cl add edi, [collision_distance] mov [top_border], 1 @@: ; left border mov eax, esi mov ebx, edi sub eax, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f shr esi, cl shl esi, cl add esi, [collision_distance] mov [left_border], 1 @@: ; right border mov eax, esi mov ebx, edi add eax, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f shr esi, cl shl esi, cl add esi, [akode_data.BlockSize.Width] sub esi, [collision_distance] sub esi, 1 mov [right_border], 1 @@: ; bottom border mov eax, esi mov ebx, edi add ebx, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f shr edi, cl shl edi, cl add edi, [akode_data.BlockSize.Width] sub edi, [collision_distance] sub edi, 1 mov [bottom_border], 1 @@: ; top left border mov eax, [top_border] or eax, [left_border] jnz @f mov eax, esi mov ebx, edi sub eax, [collision_distance] sub ebx, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f mov eax, esi mov ebx, edi shr eax, cl shl eax, cl add eax, [collision_distance] mov [new_x], eax shr ebx, cl shl ebx, cl add ebx, [collision_distance] mov [new_y], ebx sub eax, esi sub ebx, edi cmp eax, ebx jb .l1 mov edi, [new_y] jmp @f .l1: mov esi, [new_x] @@: ; top right border mov eax, [top_border] or eax, [right_border] jnz @f mov eax, esi mov ebx, edi add eax, [collision_distance] sub ebx, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f mov eax, esi mov ebx, edi shr eax, cl shl eax, cl add eax, [akode_data.BlockSize.Width] sub eax, [collision_distance] sub eax, 1 mov [new_x], eax shr ebx, cl shl ebx, cl add ebx, [collision_distance] mov [new_y], ebx neg eax add eax, esi sub ebx, edi cmp eax, ebx jb .l2 mov edi, [new_y] jmp @f .l2: mov esi, [new_x] @@: ; bottom left border mov eax, [bottom_border] or eax, [left_border] jnz @f mov eax, esi mov ebx, edi sub eax, [collision_distance] add ebx, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f mov eax, esi mov ebx, edi shr eax, cl shl eax, cl add eax, [collision_distance] mov [new_x], eax shr ebx, cl shl ebx, cl add ebx, [akode_data.BlockSize.Width] sub ebx, [collision_distance] sub ebx, 1 mov [new_y], ebx sub eax, esi neg ebx add ebx, edi cmp eax, ebx jb .l3 mov edi, [new_y] jmp @f .l3: mov esi, [new_x] @@: ; bottom right border mov eax, [bottom_border] or eax, [right_border] jnz @f mov eax, esi mov ebx, edi add eax, [collision_distance] add ebx, [collision_distance] shr eax, cl shr ebx, cl imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [edx + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz @f mov ebx, [eax + akode.GridCell.Passable] test ebx, ebx jnz @f mov eax, esi mov ebx, edi shr eax, cl shl eax, cl add eax, [akode_data.BlockSize.Width] sub eax, [collision_distance] sub eax, 1 mov [new_x], eax shr ebx, cl shl ebx, cl add ebx, [akode_data.BlockSize.Width] sub ebx, [collision_distance] sub ebx, 1 mov [new_y], ebx neg eax add eax, esi neg ebx add ebx, edi cmp eax, ebx jb .l4 mov edi, [new_y] jmp @f .l4: mov esi, [new_x] @@: mov eax, esi mov ebx, edi shr eax, cl shr ebx, cl cmp [current_cell_x], eax jne .new_cell cmp [current_cell_y], ebx jne .new_cell mov [akode_data.Camera.Position.X], esi mov [akode_data.Camera.Position.Y], edi jmp .exit .new_cell: stdcall akode.action, AKODE_ACTION.CELL_LEAVE mov [akode_data.Camera.Position.X], esi mov [akode_data.Camera.Position.Y], edi stdcall akode.action, AKODE_ACTION.CELL_ENTER .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; ; > action = AKODE_ACTION ; ; ---------------------------------------------------------------------------- ; ; < eax = action result ; ; ============================================================================ ; proc akode.action uses ebx ecx edx esi edi, action mov edi, [action] mov ecx, [akode_data.BlockWidthPowerOf2] mov ebx, [akode_data.Camera.Position.X] mov edx, [akode_data.Camera.Position.Y] shr ebx, cl shr edx, cl mov eax, edx imul eax, [akode_data.CurrentLevel.Size.Width] add eax, ebx mov esi, [akode_data.CurrentLevelGridPtr] mov esi, [esi + eax * 4] test esi, esi jz .default_action mov eax, [esi + akode.GridCell.ActionCallback] test eax, eax jz .default_action stdcall eax, edi, ebx, edx cmp eax, -1 jne @f .default_action: mov eax, [akode_data.CurrentLevel.ActionCallback] test eax, eax jz @f stdcall eax, edi, ebx, edx @@: mov esi, [akode_data.ActionCallback] test esi, esi jz @f stdcall esi, edi, ebx, edx, eax @@: ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode.fill_with_color uses eax ecx edi, color cld mov eax, [color] mov edi, [akode_data.ImageBufferPtr] mov ecx, [akode_data.ImageBufferSize] shr ecx, 2 rep stosd ret endp ; ============================================================================ ; ; ============================================================================ ; ; > eax = color 1 ; ; > ebx = color 2 ; ; > edx = alpha, 255 -> color 1, 0 -> color 2 ; ; ---------------------------------------------------------------------------- ; ; < eax = result color ; ; ============================================================================ ; macro akode._.blend_colors { push ebx ecx edx esi edi mov ecx, 256 sub ecx, edx add edx, 1 mov edi, eax and edi, 0FF00FFh imul edi, edx mov esi, ebx and esi, 0FF00FFh imul esi, ecx add edi, esi and edi, 0FF00FF00h and eax, 00FF00h imul eax, edx and ebx, 00FF00h imul ebx, ecx add eax, ebx and eax, 0FF0000h or eax, edi shr eax, 8 pop edi esi edx ecx ebx } ; ============================================================================ ; ; ============================================================================ ; ; > eax = color 1 ; ; > ebx = color 2 ; ; > edx = alpha, 255 -> color 1, 0 -> color 2 ; ; ---------------------------------------------------------------------------- ; ; < eax = result color ; ; ============================================================================ ; macro akode._.blend_colors_mmx { movd mm0, eax movd mm1, ebx pxor mm2, mm2 punpcklbw mm0, mm2 punpcklbw mm1, mm2 mov eax, 256 sub eax, edx movd mm2, eax pshufw mm3, mm2, 0 mov eax, edx add eax, 1 movd mm4, eax pshufw mm2, mm4, 0 pmullw mm1, mm3 pmullw mm0, mm2 paddw mm0, mm1 psrlw mm0, 8 packuswb mm0, mm0 movd eax, mm0 ;emms } ; ============================================================================ ; ; ============================================================================ ; ; < eax = pointer to image / 0 - fail ; ; ============================================================================ ; proc akode.render uses ebx ecx edx esi edi mov eax, [akode_data.CurrentLevelGridPtr] test eax, eax jz .exit mov eax, [akode_data.CurrentLevel.BackgroundColor] cmp eax, 0FF00FFh je @f stdcall akode.fill_with_color, eax @@: mov eax, [akode_data.ProjectionPlane.Size.Width] mov ebx, eax sub ebx, 1 shr eax, 1 add eax, [akode_data.Camera.Direction] mov edx, [akode_data.Angle360] cmp edx, eax ja @f sub eax, edx @@: push eax ; start_angle for akode._.draw_objects stdcall akode._.render_slices, 0, ebx, eax stdcall akode._.draw_objects mov eax, [akode_data.ImageBufferPtr] .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; macro akode._.draw_textured_wall_slice { label .int_part dword at x label .fract_part dword at y label .e dword at x_delta label .target_height dword at wall_slice_height mov eax, [esi + akode.TextureDesc.ImageDataPtr] mov [texture_desc_ptr1], eax mov esi, [texture_desc_ptr2] test esi, esi jz .draw_one_texture mov eax, [esi + akode.TextureDesc.Type] test eax, eax jnz .draw_one_texture movzx eax, [esi + akode.TextureDesc.HasMagicPink] test eax, eax jnz @f mov eax, [esi + akode.TextureDesc.ImageDataPtr] mov [texture_desc_ptr1], eax jmp .draw_one_texture @@: ; draw 2 textures push edx mov esi, [esi + akode.TextureDesc.ImageDataPtr] mov edx, [texture_x_coordinate] mov eax, [akode_data.BlockSize.Width] imul edx, eax shl edx, 2 add esi, edx add [texture_desc_ptr1], edx xor edx, edx div [.target_height] shl eax, 2 mov [.int_part], eax mov [.fract_part], edx pop edx xor eax, eax mov [.e], eax mov eax, [wall_slice_y] test eax, eax js .clipping2 .draw_double_textured_wall_slice_loop: mov eax, [esi] cmp eax, 0FF00FFh jne @f mov eax, [texture_desc_ptr1] mov eax, [eax] @@: if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors_mmx end if mov [edi], eax add edi, 4 mov eax, [.int_part] add esi, eax add [texture_desc_ptr1], eax mov eax, [.e] add eax, [.fract_part] mov [.e], eax sub eax, [.target_height] jl @f mov [.e], eax add esi, 4 add [texture_desc_ptr1], 4 @@: sub ecx, 1 jnz .draw_double_textured_wall_slice_loop if ~(defined DISABLE_SHADING & DISABLE_SHADING) emms end if jmp .draw_floor_slice .clipping2: sub ecx, [wall_slice_y] .draw_double_textured_wall_slice_loop2: mov eax, [wall_slice_y] test eax, eax js .skip_pixel mov eax, [esi] cmp eax, 0FF00FFh jne @f mov eax, [texture_desc_ptr1] mov eax, [eax] @@: if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors_mmx end if mov [edi], eax add edi, 4 .skip_pixel: add [wall_slice_y], 1 mov eax, [.int_part] add esi, eax add [texture_desc_ptr1], eax mov eax, [.e] add eax, [.fract_part] mov [.e], eax sub eax, [.target_height] jl @f mov [.e], eax add esi, 4 add [texture_desc_ptr1], 4 @@: sub ecx, 1 jnz .draw_double_textured_wall_slice_loop2 if ~(defined DISABLE_SHADING & DISABLE_SHADING) emms end if jmp .draw_floor_slice .draw_one_texture: push edx mov esi, [texture_desc_ptr1] mov edx, [texture_x_coordinate] mov eax, [akode_data.BlockSize.Width] imul edx, eax lea esi, [esi + edx * 4] xor edx, edx div [.target_height] shl eax, 2 mov [.int_part], eax mov [.fract_part], edx pop edx xor eax, eax mov [.e], eax mov eax, [wall_slice_y] test eax, eax js .clipping .draw_textured_wall_slice_loop: mov eax, [esi] if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors_mmx end if mov [edi], eax add edi, 4 add esi, [.int_part] mov eax, [.e] add eax, [.fract_part] mov [.e], eax sub eax, [.target_height] jl @f mov [.e], eax add esi, 4 @@: sub ecx, 1 jnz .draw_textured_wall_slice_loop if ~(defined DISABLE_SHADING & DISABLE_SHADING) emms end if jmp .draw_floor_slice .clipping: sub ecx, [wall_slice_y] .draw_textured_wall_slice_loop2: mov eax, [wall_slice_y] test eax, eax js @f mov eax, [esi] if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors_mmx end if mov [edi], eax add edi, 4 @@: add [wall_slice_y], 1 add esi, [.int_part] mov eax, [.e] add eax, [.fract_part] mov [.e], eax sub eax, [.target_height] jl @f mov [.e], eax add esi, 4 @@: sub ecx, 1 jnz .draw_textured_wall_slice_loop2 if ~(defined DISABLE_SHADING & DISABLE_SHADING) emms end if } ;void ScaleLine(PIXEL *Target, PIXEL *Source, int SrcWidth, int TgtWidth) ;{ ; int NumPixels = TgtWidth; ; int IntPart = SrcWidth / TgtWidth; ; int FractPart = SrcWidth % TgtWidth; ; int E = 0; ; ; while (NumPixels-- > 0) { ; *Target++ = *Source; ; Source += IntPart; ; E += FractPart; ; if (E >= TgtWidth) { ; E -= TgtWidth; ; Source++; ; } /* if */ ; } /* while */ ;} proc akode._.render_slices first_slice, last_slice, start_angle locals distance_to_floor dd ? distance_to_wall dd ? horizontal_distance_to_wall dq ? vertical_distance_to_wall dq ? texture_x_coordinate dd ? texture_y_coordinate dd ? wall_slice_height dd ? wall_slice_y dd ? wall_slice_top dd ? wall_slice_bottom dd ? wall_slice_top_ptr dd ? horizontal_texture_desc_ptr1 dd ? horizontal_texture_desc_ptr2 dd ? vertical_texture_desc_ptr1 dd ? vertical_texture_desc_ptr2 dd ? texture_desc_ptr1 dd ? texture_desc_ptr2 dd ? x dd ? y dd ? x_delta dd ? y_delta dd ? wall_side dd ? endl fninit .slice_loop: ;DEBUGF DEBUG_FINE, 'first_slice: %u, last_slice: %u, start_angle: %u\n', [first_slice], [last_slice], [start_angle] ; ------------------------------- render walls ------------------------------- ; ; horizontal intersections mov ecx, [akode_data.BlockWidthPowerOf2] mov eax, [akode_data.Camera.Position.Y] mov edi, eax shr eax, cl shl eax, cl mov edx, [akode_data.BlockSize.Width] mov ebx, [start_angle] test ebx, ebx jz .ray_is_horizontal cmp [akode_data.Angle180], ebx je .ray_is_horizontal jb .ray_is_facing_down ; ray is facing up sub eax, 1 neg edx mov [wall_side], AKODE_DIRECTION.SOUTH jmp @f ; ray is facing down .ray_is_facing_down: add eax, edx ; edx = BlockSize.Width mov [wall_side], AKODE_DIRECTION.NORTH @@: mov [y], eax mov [y_delta], edx sub edi, eax ; edi = Camera.Position.Y - y push edi mov esi, ebx shl esi, 5 ; esi = angle * 32 add esi, [akode_data.TrigonometricTablePtr] fild dword [esp] fdiv qword [esi + 16] fistp dword [esp] pop edi ; edi = (Camera.Position.Y - y) / tan (angle) add edi, [akode_data.Camera.Position.X] mov [x], edi mov esi, [akode_data.BlockWidthTanTablePtr] mov eax, [esi + ebx * 8 + 4] ; eax = BlockSize.Width / tan (angle) mov [x_delta], eax ;DEBUGF DEBUG_FINE, 'x_delta: %d\n', eax .horizontal_intersections_loop: mov eax, [x] mov ebx, [y] sar eax, cl js .ray_is_horizontal cmp [akode_data.CurrentLevel.Size.Width], eax jna .ray_is_horizontal sar ebx, cl js .ray_is_horizontal cmp [akode_data.CurrentLevel.Size.Height], ebx jna .ray_is_horizontal imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov esi, [akode_data.CurrentLevelGridPtr] mov esi, [esi + ebx * 4] ; esi = pointer to akode.GridCell test esi, esi jz .next_horizontal_intersection mov eax, [wall_side] lea edi, [esi + eax * 8] mov ebx, [edi] ; first texture desc ptr test ebx, ebx jz .next_horizontal_intersection mov edx, [edi + 4] ; second texture desc ptr mov [horizontal_texture_desc_ptr1], ebx mov [horizontal_texture_desc_ptr2], edx mov edx, -1 shl edx, cl not edx mov esi, [x] and esi, edx cmp eax, AKODE_DIRECTION.NORTH jne @f mov eax, [akode_data.BlockSize.Width] add esi, 1 xchg eax, esi sub esi, eax @@: mov [texture_x_coordinate], esi mov ebx, [start_angle] mov esi, [akode_data.TrigonometricTablePtr] mov eax, [akode_data.Camera.Position.Y] sub eax, [y] mov edx, ebx shl edx, 5 push eax fild dword [esp] add esp, 4 fdiv qword [esi + edx] ; st0 = (Camera.Position.Y - y) / sin (angle) ; correct fisheye mov eax, [akode_data.Camera.Direction] sub eax, ebx jns @f neg eax @@: shl eax, 5 fmul qword [esi + eax + 8] ; st0 * cos (Camera.Direction - angle) fstp [horizontal_distance_to_wall] jmp .vertical_intersections .next_horizontal_intersection: mov eax, [x_delta] mov ebx, [y_delta] add [x], eax add [y], ebx jmp .horizontal_intersections_loop .ray_is_horizontal: ; horizontal_distance_to_wall = max double mov dword [horizontal_distance_to_wall], 0FFFFFFFFh mov dword [horizontal_distance_to_wall + 4], 7FEFFFFFh ; vertical intersections .vertical_intersections: mov ecx, [akode_data.BlockWidthPowerOf2] mov eax, [akode_data.Camera.Position.X] mov edi, eax shr eax, cl shl eax, cl mov edx, [akode_data.BlockSize.Width] mov ebx, [start_angle] cmp [akode_data.Angle90], ebx je .ray_is_vertical ja .ray_is_facing_right cmp [akode_data.Angle270], ebx je .ray_is_vertical jb .ray_is_facing_right ; ray is facing left sub eax, 1 neg edx mov [wall_side], AKODE_DIRECTION.EAST jmp @f ; ray is facing right .ray_is_facing_right: add eax, edx ; edx = BlockSize.Width mov [wall_side], AKODE_DIRECTION.WEST @@: mov [x], eax mov [x_delta], edx sub edi, eax ; edi = Camera.Position.X - x push edi mov esi, ebx shl esi, 5 ; esi = angle * 32 add esi, [akode_data.TrigonometricTablePtr] fild dword [esp] fmul qword [esi + 16] fistp dword [esp] pop edi ; edi = (Camera.Position.X - x) * tan (angle) add edi, [akode_data.Camera.Position.Y] mov [y], edi mov esi, [akode_data.BlockWidthTanTablePtr] mov eax, [esi + ebx * 8] ; eax = BlockSize.Width * tan (angle) mov [y_delta], eax ;DEBUGF DEBUG_FINE, 'y_delta: %d\n', eax .vertical_intersections_loop: mov eax, [x] mov ebx, [y] sar eax, cl js .ray_is_vertical cmp [akode_data.CurrentLevel.Size.Width], eax jna .ray_is_vertical sar ebx, cl js .ray_is_vertical cmp [akode_data.CurrentLevel.Size.Height], ebx jna .ray_is_vertical imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov esi, [akode_data.CurrentLevelGridPtr] mov esi, [esi + ebx * 4] ; esi = pointer to akode.GridCell test esi, esi jz .next_vertical_intersection mov eax, [wall_side] lea edi, [esi + eax * 8] mov ebx, [edi] ; first texture desc ptr test ebx, ebx jz .next_vertical_intersection mov edx, [edi + 4] ; second texture desc ptr mov [vertical_texture_desc_ptr1], ebx mov [vertical_texture_desc_ptr2], edx mov edx, -1 shl edx, cl not edx mov esi, [y] and esi, edx test eax, eax ; cmp eax, AKODE_DIRECTION.EAST jnz @f mov eax, [akode_data.BlockSize.Width] add esi, 1 xchg eax, esi sub esi, eax @@: mov [texture_y_coordinate], esi mov ebx, [start_angle] mov esi, [akode_data.TrigonometricTablePtr] mov eax, [x] sub eax, [akode_data.Camera.Position.X] mov edx, ebx shl edx, 5 push eax fild dword [esp] add esp, 4 fmul qword [esi + edx + 24] ; st0 = (x - Camera.Position.X) / cos (angle) ; correct fisheye mov eax, [akode_data.Camera.Direction] sub eax, ebx jns @f neg eax @@: shl eax, 5 fmul qword [esi + eax + 8] ; st0 * cos (Camera.Direction - angle) fstp [vertical_distance_to_wall] jmp .draw_wall_slice .next_vertical_intersection: mov eax, [x_delta] mov ebx, [y_delta] add [x], eax add [y], ebx jmp .vertical_intersections_loop .ray_is_vertical: ; vertical_distance_to_wall = max double mov dword [vertical_distance_to_wall], 0FFFFFFFFh mov dword [vertical_distance_to_wall + 4], 7FEFFFFFh ; ----------------------------- draw wall slice ------------------------------ ; .draw_wall_slice: fld [horizontal_distance_to_wall] fld [vertical_distance_to_wall] fcomi st1 fcmovnb st1 fist [distance_to_wall] fidivr [akode_data.WallHeightDividend] fistp [wall_slice_height] fstp st0 mov ebx, [akode_data.DepthBufferPtr] mov ecx, [first_slice] lea ebx, [ebx + ecx * 4] mov eax, [distance_to_wall] mov [ebx], eax jnb .horizontal_textures mov eax, [vertical_texture_desc_ptr1] mov ebx, [vertical_texture_desc_ptr2] mov ecx, [texture_y_coordinate] mov [texture_x_coordinate], ecx jmp @f .horizontal_textures: mov eax, [horizontal_texture_desc_ptr1] mov ebx, [horizontal_texture_desc_ptr2] @@: mov ecx, [wall_slice_height] test ecx, ecx jz .skip_draw_wall_slice mov [texture_desc_ptr1], eax mov [texture_desc_ptr2], ebx mov edx, [akode_data.ProjectionPlane.MidY] mov eax, ecx shr eax, 1 sub edx, eax mov [wall_slice_y], edx jns @f xor edx, edx @@: mov ebx, [akode_data.ProjectionPlane.Size.Height] mov eax, ecx add eax, edx cmp ebx, eax jae @f mov ecx, ebx sub ecx, edx @@: mov eax, edx sub eax, 1 mov [wall_slice_top], eax mov eax, edx add eax, ecx mov [wall_slice_bottom], eax mov eax, [akode_data.ProjectionPlane.Size.Height] imul eax, [first_slice] add eax, edx mov edi, [akode_data.ImageBufferPtr] lea edi, [edi + eax * 4] mov eax, edi sub eax, 4 mov [wall_slice_top_ptr], eax if ~(defined DISABLE_SHADING & DISABLE_SHADING) mov esi, [akode_data.ShadingTablePtr] mov ebx, [akode_data.ShadingDistance] mov eax, [distance_to_wall] cmp ebx, eax jae @f mov eax, ebx @@: mov edx, [esi + eax * 4] mov ebx, [akode_data.ShadingColor] end if mov esi, [texture_desc_ptr1] mov eax, [esi + akode.TextureDesc.Type] test eax, eax jz .texture_type_image ; texture type is color add esi, akode.TextureDesc.Color if ~(defined DISABLE_SHADING & DISABLE_SHADING) .draw_color_wall_slice_loop: mov eax, [esi] akode._.blend_colors_mmx mov [edi], eax add edi, 4 sub ecx, 1 jnz .draw_color_wall_slice_loop emms else mov eax, [esi] .draw_color_wall_slice_loop: mov [edi], eax add edi, 4 sub ecx, 1 jnz .draw_color_wall_slice_loop end if jmp .draw_floor_slice .texture_type_image: akode._.draw_textured_wall_slice jmp .draw_floor_slice .skip_draw_wall_slice: mov eax, [akode_data.ProjectionPlane.MidY] mov [wall_slice_top], eax add eax, 1 mov [wall_slice_bottom], eax mov eax, [akode_data.ProjectionPlane.Size.Height] imul eax, [first_slice] add eax, [wall_slice_bottom] mov edi, [akode_data.ImageBufferPtr] lea edi, [edi + eax * 4] mov eax, edi sub eax, 4 mov [wall_slice_top_ptr], eax ; ----------------------------- draw floor slice ----------------------------- ; .draw_floor_slice: mov esi, [akode_data.TrigonometricTablePtr] mov ebx, [start_angle] mov eax, ebx shl eax, 5 fld qword [esi + eax] ; sin (angle) fld qword [esi + eax + 8] ; cos (angle) mov eax, [akode_data.Camera.Direction] sub eax, ebx jns @f neg eax @@: shl eax, 5 fld qword [esi + eax + 24] ; 1 / cos (Camera.Direction - angle) mov ecx, [wall_slice_bottom] cmp [akode_data.ProjectionPlane.Size.Height], ecx jbe .skip_draw_floor_slice add ecx, 1 fild [akode_data.FloorDistanceDividend] fmul st0, st1 ; st0 = FloorDistanceDividend / cos (Camera.Direction - angle) .draw_floor_slice_loop: mov eax, ecx sub eax, [akode_data.ProjectionPlane.MidY] push eax fld st0 fidiv dword [esp] fist [distance_to_floor] ; FloorDistanceDividend / cos (Camera.Direction - angle) / (ecx - ProjectionPlane.MidY) fld st0 fmul st0, st4 ; distance * cos (angle) fistp dword [esp] mov ebx, [esp] ; ebx = x delta fmul st0, st4 ; distance * sin (angle) fistp dword [esp] pop edx ; edx = y delta mov eax, [akode_data.Camera.Position.X] add eax, ebx mov ebx, [akode_data.Camera.Position.Y] sub ebx, edx push ecx mov ecx, [akode_data.BlockWidthPowerOf2] mov edx, -1 shl edx, cl not edx mov esi, eax and esi, edx mov [texture_x_coordinate], esi mov esi, ebx and esi, edx mov [texture_y_coordinate], esi sar eax, cl js .next_floor_intersection cmp [akode_data.CurrentLevel.Size.Width], eax jna .next_floor_intersection sar ebx, cl js .next_floor_intersection cmp [akode_data.CurrentLevel.Size.Height], ebx jna .next_floor_intersection imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [akode_data.CurrentLevelGridPtr] mov eax, [eax + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz .next_floor_intersection mov esi, [eax + akode.GridCell.FloorTexture] test esi, esi jz .next_floor_intersection if ~(defined DISABLE_SHADING & DISABLE_SHADING) mov edx, [akode_data.ShadingTablePtr] mov ebx, [akode_data.ShadingDistance] mov ecx, [distance_to_floor] cmp ebx, ecx jae @f mov ecx, ebx @@: mov edx, [edx + ecx * 4] mov ebx, [akode_data.ShadingColor] end if mov eax, [esi + akode.TextureDesc.Type] test eax, eax jz .texture_type_image2 ; texture type is color mov eax, [esi + akode.TextureDesc.Color] if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors end if mov [edi], eax jmp .next_floor_intersection .texture_type_image2: mov eax, [texture_x_coordinate] imul eax, [akode_data.BlockSize.Width] add eax, [texture_y_coordinate] mov esi, [esi + akode.TextureDesc.ImageDataPtr] mov eax, [esi + eax * 4] if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors end if mov [edi], eax .next_floor_intersection: pop ecx add edi, 4 add ecx, 1 cmp [akode_data.ProjectionPlane.Size.Height], ecx jae .draw_floor_slice_loop fstp st0 .skip_draw_floor_slice: ; ---------------------------- draw ceiling slice ---------------------------- ; mov ecx, [wall_slice_top] test ecx, ecx js .skip_draw_ceiling_slice sub ecx, 1 fild [akode_data.CeilingDistanceDividend] fmul st0, st1 ; st0 = CeilingDistanceDividend / cos (Camera.Direction - angle) mov edi, [wall_slice_top_ptr] .draw_ceiling_slice_loop: mov eax, [akode_data.ProjectionPlane.MidY] sub eax, ecx push eax fld st0 fidiv dword [esp] fist [distance_to_floor] ; CeilingDistanceDividend / cos (Camera.Direction - angle) / (ProjectionPlane.MidY - ecx) fld st0 fmul st0, st4 ; distance * cos (angle) fistp dword [esp] mov ebx, [esp] ; ebx = x delta fmul st0, st4 ; distance * sin (angle) fistp dword [esp] pop edx ; edx = y delta mov eax, [akode_data.Camera.Position.X] add eax, ebx mov ebx, [akode_data.Camera.Position.Y] sub ebx, edx push ecx mov ecx, [akode_data.BlockWidthPowerOf2] mov edx, -1 shl edx, cl not edx mov esi, eax and esi, edx mov [texture_x_coordinate], esi mov esi, ebx and esi, edx mov [texture_y_coordinate], esi sar eax, cl js .next_ceiling_intersection cmp [akode_data.CurrentLevel.Size.Width], eax jna .next_ceiling_intersection sar ebx, cl js .next_ceiling_intersection cmp [akode_data.CurrentLevel.Size.Height], ebx jna .next_ceiling_intersection imul ebx, [akode_data.CurrentLevel.Size.Width] add ebx, eax mov eax, [akode_data.CurrentLevelGridPtr] mov eax, [eax + ebx * 4] ; eax = pointer to akode.GridCell test eax, eax jz .next_ceiling_intersection mov esi, [eax + akode.GridCell.CeilingTexture] test esi, esi jz .next_ceiling_intersection if ~(defined DISABLE_SHADING & DISABLE_SHADING) mov edx, [akode_data.ShadingTablePtr] mov ebx, [akode_data.ShadingDistance] mov ecx, [distance_to_floor] cmp ebx, ecx jae @f mov ecx, ebx @@: mov edx, [edx + ecx * 4] mov ebx, [akode_data.ShadingColor] end if mov eax, [esi + akode.TextureDesc.Type] test eax, eax jz .texture_type_image3 ; texture type is color mov eax, [esi + akode.TextureDesc.Color] if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors end if mov [edi], eax jmp .next_ceiling_intersection .texture_type_image3: mov eax, [texture_x_coordinate] imul eax, [akode_data.BlockSize.Width] add eax, [texture_y_coordinate] mov esi, [esi + akode.TextureDesc.ImageDataPtr] mov eax, [esi + eax * 4] if ~(defined DISABLE_SHADING & DISABLE_SHADING) akode._.blend_colors end if mov [edi], eax .next_ceiling_intersection: pop ecx sub edi, 4 sub ecx, 1 cmp ecx, -1 jge .draw_ceiling_slice_loop fstp st0 .skip_draw_ceiling_slice: fstp st0 fstp st0 fstp st0 sub [start_angle], 1 jns @f mov edx, [akode_data.Angle360] sub edx, 1 mov [start_angle], edx @@: mov eax, [first_slice] add eax, 1 mov [first_slice], eax cmp [last_slice], eax jae .slice_loop ret endp ; ============================================================================ ; ; ============================================================================ ; macro akode._.draw_object_slice { ; mov eax, [akode_data.BlockSize.Height] ; xor edx, edx ; div [object_screen_height] ; shl eax, 2 ; mov [slice.int_part], eax ; mov [slice.fract_part], edx xor eax, eax mov [slice.e], eax mov ecx, [slice.pixel_count] .draw_object_slice: mov eax, [slice.y] test eax, eax js .skip_pixel mov eax, [esi] cmp eax, 0FF00FFh je @f mov [edi], eax @@: add edi, 4 .skip_pixel: add [slice.y], 1 add esi, [slice.int_part] mov eax, [slice.e] add eax, [slice.fract_part] mov [slice.e], eax sub eax, [object_screen_height] jl @f mov [slice.e], eax add esi, 4 @@: sub ecx, 1 jnz .draw_object_slice } macro akode._.draw_object_slice_with_shading { xor eax, eax mov [slice.e], eax mov ecx, [slice.pixel_count] .draw_object_slice2: mov eax, [slice.y] test eax, eax js .skip_pixel2 mov eax, [esi] cmp eax, 0FF00FFh je @f akode._.blend_colors_mmx mov [edi], eax @@: add edi, 4 .skip_pixel2: add [slice.y], 1 add esi, [slice.int_part] mov eax, [slice.e] add eax, [slice.fract_part] mov [slice.e], eax sub eax, [object_screen_height] jl @f mov [slice.e], eax add esi, 4 @@: sub ecx, 1 jnz .draw_object_slice2 } macro akode._.draw_object { locals slice.int_part dd ? slice.fract_part dd ? slice.e dd ? slice.y dd ? slice.pixel_count dd ? int_part dd ? fract_part dd ? e dd ? slice_count dd ? object_distance dd ? endl mov eax, [object_screen_height] mov ebx, [object_screen_width] cmp eax, 10 jb .draw_object_exit cmp ebx, 10 jb .draw_object_exit mov ecx, [object_screen_x] mov edx, [object_screen_y] cmp ecx, [akode_data.ProjectionPlane.Size.Width] jge .draw_object_exit cmp edx, [akode_data.ProjectionPlane.Size.Height] jge .draw_object_exit add ecx, ebx add edx, eax xor edi, edi cmp ecx, edi jle .draw_object_exit cmp edx, edi jle .draw_object_exit sub ecx, [akode_data.ProjectionPlane.Size.Width] jbe @f sub ebx, ecx @@: mov [slice_count], ebx sub edx, [akode_data.ProjectionPlane.Size.Height] jbe @f sub eax, edx @@: mov [slice.pixel_count], eax mov eax, [akode_data.BlockSize.Height] xor edx, edx div [object_screen_height] shl eax, 2 mov [slice.int_part], eax mov [slice.fract_part], edx mov eax, [akode_data.BlockSize.Width] xor edx, edx div [object_screen_width] mov [fract_part], edx mul [akode_data.BlockSize.Height] shl eax, 2 mov [int_part], eax xor eax, eax mov [e], eax mov eax, [object_screen_x] cmp eax, edi jge @f xor eax, eax @@: mov edi, [akode_data.ImageBufferPtr] mul [akode_data.ProjectionPlane.Size.Height] lea edi, [edi + eax * 4] mov eax, [esi + akode.Object.Distance] mov [object_distance], eax mov ecx, [esi + akode.Object.ShadingDistance] mov eax, [esi + akode.Object.DisableShading] mov esi, [esi + akode.Object.TextureDescPtr] mov esi, [esi + akode.TextureDesc.ImageDataPtr] if ~(defined DISABLE_SHADING & DISABLE_SHADING) test eax, eax jnz .draw_object_without_shading ; draw object with shading mov edx, [akode_data.ShadingTablePtr] mov ebx, [akode_data.ShadingDistance] cmp ebx, ecx jae @f mov ecx, ebx @@: mov edx, [edx + ecx * 4] mov ebx, [akode_data.ShadingColor] .draw_object_slices_loop2: mov eax, [object_screen_x] test eax, eax js .skip_slice2 mov ecx, [akode_data.DepthBufferPtr] mov eax, [ecx + eax * 4] cmp [object_distance], eax jae .slice_hidden_by_wall2 push esi push edi mov eax, [object_screen_y] mov [slice.y], eax test eax, eax jns @f xor eax, eax @@: lea edi, [edi + eax * 4] akode._.draw_object_slice_with_shading pop edi pop esi .slice_hidden_by_wall2: mov eax, [akode_data.ProjectionPlane.Size.Height] lea edi, [edi + eax * 4] .skip_slice2: add [object_screen_x], 1 add esi, [int_part] mov eax, [e] add eax, [fract_part] mov [e], eax sub eax, [object_screen_width] jl @f mov [e], eax mov eax, [akode_data.BlockSize.Height] lea esi, [esi + eax * 4] @@: sub [slice_count], 1 jnz .draw_object_slices_loop2 emms jmp .draw_object_exit end if .draw_object_without_shading: .draw_object_slices_loop: mov eax, [object_screen_x] test eax, eax js .skip_slice mov ecx, [akode_data.DepthBufferPtr] mov eax, [ecx + eax * 4] cmp [object_distance], eax jae .slice_hidden_by_wall push esi push edi mov eax, [object_screen_y] mov [slice.y], eax test eax, eax jns @f xor eax, eax @@: lea edi, [edi + eax * 4] akode._.draw_object_slice pop edi pop esi .slice_hidden_by_wall: mov eax, [akode_data.ProjectionPlane.Size.Height] lea edi, [edi + eax * 4] .skip_slice: add [object_screen_x], 1 add esi, [int_part] mov eax, [e] add eax, [fract_part] mov [e], eax sub eax, [object_screen_width] jl @f mov [e], eax mov eax, [akode_data.BlockSize.Height] lea esi, [esi + eax * 4] @@: sub [slice_count], 1 jnz .draw_object_slices_loop .draw_object_exit: } proc akode._.draw_objects start_angle locals camera_cell_x dd ? camera_cell_y dd ? quadrants dd ? x_quadrants dd ? y_quadrants dd ? object_count dd ? object_screen_x_delta dd ? object_screen_x dd ? object_screen_y dd ? object_screen_width dd ? object_screen_height dd ? endl mov eax, [akode_data.CurrentLevel.ObjectCount] test eax, eax jz .exit fninit mov eax, [start_angle] cmp [akode_data.Angle0], eax jne @f mov ebx, 1001b jmp .first_quadrant_found @@: cmp [akode_data.Angle90], eax jne @f mov ebx, 0011b jmp .first_quadrant_found @@: jb @f mov ebx, 0001b jmp .first_quadrant_found @@: cmp [akode_data.Angle180], eax jne @f mov ebx, 0110b jmp .first_quadrant_found @@: jb @f mov ebx, 0010b jmp .first_quadrant_found @@: cmp [akode_data.Angle270], eax jne @f mov ebx, 1100b jmp .first_quadrant_found @@: jb @f mov ebx, 0100b jmp .first_quadrant_found @@: mov ebx, 1000b .first_quadrant_found: sub eax, [akode_data.ProjectionPlane.Size.Width] add eax, 1 jns @f add eax, [akode_data.Angle360] @@: cmp [akode_data.Angle0], eax jne @f mov edx, 1001b jmp .second_quadrant_found @@: cmp [akode_data.Angle90], eax jne @f mov edx, 0011b jmp .second_quadrant_found @@: jb @f mov edx, 0001b jmp .second_quadrant_found @@: cmp [akode_data.Angle180], eax jne @f mov edx, 0110b jmp .second_quadrant_found @@: jb @f mov edx, 0010b jmp .second_quadrant_found @@: cmp [akode_data.Angle270], eax jne @f mov edx, 1100b jmp .second_quadrant_found @@: jb @f mov edx, 0100b jmp .second_quadrant_found @@: mov edx, 1000b .second_quadrant_found: mov eax, ebx and eax, edx jnz @f mov eax, ebx or eax, edx @@: mov [quadrants], eax mov ecx, [akode_data.BlockWidthPowerOf2] mov eax, [akode_data.Camera.Position.X] shr eax, cl mov [camera_cell_x], eax mov eax, [akode_data.Camera.Position.Y] shr eax, cl mov [camera_cell_y], eax mov esi, [akode_data.CurrentLevelObjectsPtr] xor eax, eax mov [object_count], eax mov ecx, [akode_data.CurrentLevel.ObjectCount] .calc_distance_to_objects_loop: mov eax, [esi + akode.Object.Visible] test eax, eax jz .next_object mov ebx, [esi + akode.Object.Position.X] mov edx, [esi + akode.Object.Position.Y] cmp ebx, [camera_cell_x] jne @f mov [x_quadrants], 1111b jmp .x_quadrants_found @@: jb @f mov [x_quadrants], 1001b jmp .x_quadrants_found @@: mov [x_quadrants], 0110b .x_quadrants_found: cmp edx, [camera_cell_y] jne @f mov [y_quadrants], 1111b jmp .y_quadrants_found @@: jb @f mov [y_quadrants], 1100b jmp .y_quadrants_found @@: mov [y_quadrants], 0011b .y_quadrants_found: mov eax, [x_quadrants] and eax, [y_quadrants] cmp eax, 0Fh je .next_object test eax, [quadrants] jz .next_object push ecx mov ecx, [akode_data.BlockWidthPowerOf2] shl ebx, cl shl edx, cl pop ecx mov eax, [akode_data.BlockSize.Width] shr eax, 1 add ebx, eax add edx, eax sub ebx, [akode_data.Camera.Position.X] neg edx add edx, [akode_data.Camera.Position.Y] push ebx push edx fild dword [esp] fild dword [esp + 4] fpatan add esp, 8 imul ebx, ebx imul edx, edx add ebx, edx push ebx fild dword [esp] fsqrt add esp, 4 fistp [esi + akode.Object.Distance] mov eax, [esi + akode.Object.Distance] mov [esi + akode.Object.ShadingDistance], eax fldpi fldpi faddp fidivr [akode_data.Angle360] ; Angle360 / 2 * pi fmulp fistp [esi + akode.Object.Angle] mov eax, [esi + akode.Object.Angle] test eax, eax jns @f add eax, [akode_data.Angle360] mov [esi + akode.Object.Angle], eax @@: push esi add [object_count], 1 .next_object: add esi, sizeof.akode.Object sub ecx, 1 jnz .calc_distance_to_objects_loop mov eax, [object_count] test eax, eax jz .exit mov ebx, esp stdcall akode._.sort_objects, ebx, eax mov ecx, [object_count] .draw_objects_loop: pop esi mov eax, [esi + akode.Object.Angle] sub eax, [akode_data.Camera.Direction] mov ebx, eax jns @f add eax, [akode_data.Angle360] neg ebx @@: cmp [akode_data.Angle90], eax je .draw_next_object cmp [akode_data.Angle270], eax je .draw_next_object mov edi, [akode_data.TrigonometricTablePtr] shl eax, 5 fld qword [edi + eax + 16] fimul [akode_data.CameraToPlaneDistance] fistp [object_screen_x_delta] shl ebx, 5 fld qword [edi + ebx + 8] fabs fimul [esi + akode.Object.Distance] fist [esi + akode.Object.Distance] fidivr [akode_data.WallHeightDividend] fistp [object_screen_height] ;fimul [akode_data.BlockSize.Width] ;fidiv [akode_data.BlockSize.Height] ;fistp [object_screen_width] mov ebx, [akode_data.ProjectionPlane.MidY] mov eax, [object_screen_height] mov edx, eax shr edx, 1 sub ebx, edx mov [object_screen_y], ebx mul [akode_data.BlockSize.Width] div [akode_data.BlockSize.Height] mov [object_screen_width], eax mov ebx, [akode_data.ProjectionPlane.Size.Width] shr ebx, 1 sub ebx, [object_screen_x_delta] shr eax, 1 sub ebx, eax mov [object_screen_x], ebx push ecx akode._.draw_object pop ecx .draw_next_object: sub ecx, 1 jnz .draw_objects_loop .exit: ret endp ; ============================================================================ ; ; ============================================================================ ; proc akode._.sort_objects objects_ptr, object_count mov edx, [object_count] mov ecx, 1 cmp edx, ecx jbe .exit mov esi, [objects_ptr] .sort_loop: mov ebx, ecx mov edi, [esi + ebx * 4] @@: test ebx, ebx jz .insert mov eax, [esi + ebx * 4 - 4] mov eax, [eax + akode.Object.Distance] cmp [edi + akode.Object.Distance], eax jna .insert mov eax, [esi + ebx * 4 - 4] mov [esi + ebx * 4], eax sub ebx, 1 jmp @b .insert: mov [esi + ebx * 4], edi add ecx, 1 cmp edx, ecx jne .sort_loop .exit: ret endp ;void insertionsort() ; { ; int i, j, t; ; for (i=1; i0 && a[j-1]>t) ; { ; a[j]=a[j-1]; ; j--; ; } ; a[j]=t; ; } ; } ; ============================================================================ ; ; ============================================================================ ; ; > ebx = width of image (in px) ; ; > edx = height of image (in px) ; ; > esi = pointer to source block ; ; > edi = pointer to destination block ; ; ============================================================================ ; macro akode._.transpose16x16 { local .loop1, .loop2 push ebx push edx mov ebx, 15 .loop1: mov ecx, 15 .loop2: mov eax, ecx imul eax, [esp] add eax, ebx mov eax, [esi + eax * 4] mov edx, ebx imul edx, [esp + 4] add edx, ecx mov [edi + edx * 4], eax sub ecx, 1 jns .loop2 sub ebx, 1 jns .loop1 pop edx pop ebx } ; ============================================================================ ; ; > ebx = width of image / 2 (in px) ; ; > edx = height of image (in px) ; ; > esi = pointer to source block ; ; > edi = pointer to destination block ; ; ============================================================================ ; macro akode._.transpose16x16to8x8 { local .loop1, .loop2 push ebx mov ebx, 7 .loop1: mov ecx, 7 .loop2: mov eax, ecx imul eax, edx add eax, ebx lea eax, [esi + eax * 8] movq mm0, [eax] pavgb mm0, [eax + edx * 4] movq mm1, mm0 psrlq mm0, 32 pavgb mm1, mm0 mov eax, ebx imul eax, [esp] add eax, ecx movd [edi + eax * 4], mm1 sub ecx, 1 jns .loop2 sub ebx, 1 jns .loop1 pop ebx } ; ============================================================================ ; proc akode.get_image uses eax ebx ecx edx esi edi, buffer_ptr, downscale_factor_pow2 mov esi, [akode_data.ImageBufferPtr] mov edi, [buffer_ptr] mov ebx, [akode_data.ProjectionPlane.Size.Width] mov edx, [akode_data.ProjectionPlane.Size.Height] mov eax, [downscale_factor_pow2] mov ecx, [akode_data.OptimizedGetImage] ;xor ecx, ecx test ecx, ecx jz .no_optimization ; optimized test edi, 0Fh jz @f DEBUGF DEBUG_INFO, 'akode.get_image: buffer_ptr is not aligned by 16\n' @@: test eax, eax jnz .downscale2_optimized ; no downscale optimized xor eax, eax .loop1: xor ecx, ecx .loop2: ; mov esi, ecx ; imul esi, edx ; add esi, eax ; shl esi, 2 ; add esi, [akode_data.ImageBufferPtr] ; ; mov edi, eax ; imul edi, ebx ; add edi, ecx ; shl edi, 2 ; add edi, [buffer_ptr] mov esi, ecx mov edi, eax imul esi, edx imul edi, ebx add esi, eax add edi, ecx shl esi, 2 shl edi, 2 add esi, [akode_data.ImageBufferPtr] add edi, [buffer_ptr] push eax push ecx akode._.transpose16x16 pop ecx pop eax add ecx, 16 cmp ecx, ebx jne .loop2 add eax, 16 cmp eax, edx jne .loop1 jmp .exit .downscale2_optimized: shr ebx, 1 xor eax, eax .loop3: xor ecx, ecx .loop4: ; mov esi, ecx ; imul esi, edx ; add esi, eax ; shl esi, 2 ; add esi, [akode_data.ImageBufferPtr] ; ; mov edi, eax ; imul edi, ebx ; add edi, ecx ; shl edi, 1 ; add edi, [buffer_ptr] mov esi, ecx mov edi, eax imul esi, edx imul edi, ebx add esi, eax add edi, ecx shl esi, 2 shl edi, 1 add esi, [akode_data.ImageBufferPtr] add edi, [buffer_ptr] push eax push ecx akode._.transpose16x16to8x8 pop ecx pop eax add ecx, 16 cmp [akode_data.ProjectionPlane.Size.Width], ecx jne .loop4 add eax, 16 cmp eax, edx jne .loop3 emms jmp .exit .no_optimization: test eax, eax jnz .downscale2_no_optimization ; no downscale mov ecx, ebx shl ebx, 2 @@: mov eax, [esi] mov [edi], eax add esi, 4 add edi, ebx sub edx, 1 jnz @b mov edx, [akode_data.ProjectionPlane.Size.Height] mov edi, [buffer_ptr] add edi, 4 mov [buffer_ptr], edi sub ecx, 1 jnz @b jmp .exit .downscale2_no_optimization: mov eax, edx shr edx, 1 shl eax, 2 shr ebx, 1 mov ecx, ebx shl ecx, 2 @@: movq mm0, [esi] pavgb mm0, [esi + eax] movq mm1, mm0 psrlq mm0, 32 pavgb mm1, mm0 movd [edi], mm1 add esi, 8 add edi, ecx sub edx, 1 jnz @b mov edx, [akode_data.ProjectionPlane.Size.Height] shr edx, 1 add esi, eax mov edi, [buffer_ptr] add edi, 4 mov [buffer_ptr], edi sub ebx, 1 jnz @b emms .exit: ret endp ; ============================================================================ ;