0,0 → 1,3428 |
; 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 |
; ============================================================================ ; |