95be852ae1
git-svn-id: svn://kolibrios.org@5312 a494cfbc-eb01-0410-851d-a64ba20cac60
3428 lines
97 KiB
PHP
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
|
|
; ============================================================================ ; |