kolibrios/programs/games/Dungeons/AKODE/AKODE.inc
Anton_K 95be852ae1 New game
git-svn-id: svn://kolibrios.org@5312 a494cfbc-eb01-0410-851d-a64ba20cac60
2014-12-31 02:12:08 +00:00

3428 lines
97 KiB
PHP

; 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 <http://www.gnu.org/licenses/>.
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; i<n; i++)
; {
; j=i;
; t=a[j];
; while (j>0 && 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
; ============================================================================ ;