Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 5311 → Rev 5312

/programs/games/Dungeons/AKODE/AKODE.inc
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
; ============================================================================ ;
/programs/games/Dungeons/AKODE/data.inc
0,0 → 1,19
; ================================== Data ==================================== ;
 
align 4
akode_data.Angle0 dd 0
 
akode_data.ImageBufferPtr dd 0
akode_data.TrigonometricTablePtr dd 0
akode_data.BlockWidthTanTablePtr dd 0
 
akode_data.DepthBufferPtr dd 0
 
akode_data.CurrentLevelGridPtr dd 0
akode_data.CurrentLevelObjectsPtr dd 0
akode_data.CurrentLevelAddTexturesPtr dd 0
 
akode_data.ShadingTablePtr dd 0
 
akode_data.LevelLoadCallback dd 0
akode_data.ActionCallback dd 0
/programs/games/Dungeons/AKODE/datadef.inc
0,0 → 1,127
; ============================ Data definitions ============================== ;
 
struct akode.Point
X dd ?
Y dd ?
ends
 
struct akode.Point3D akode.Point
Z dd ?
ends
 
struct akode.Size
Width dd ?
Height dd ?
ends
 
struct akode.Rect
X dd ?
Y dd ?
Width dd ?
Height dd ?
ends
 
struct akode.Camera
Position akode.Point3D
Direction dd ?
FieldOfView dd ?
ends
 
struct akode.ProjectionPlane
MidY dd ?
Size akode.Size
ends
 
struct akode.CombinedTexture ; combine 2 textures
DescPtr1 dd ? ; main texture
DescPtr2 dd ? ; 2nd optional texture
ends
 
AKODE_TEXTURE_TYPE.IMAGE = 0
AKODE_TEXTURE_TYPE.COLOR = 1
 
AKODE_TEXTURE_USAGE.ENVIRONMENT = 0
AKODE_TEXTURE_USAGE.OBJECT = 1
 
AKODE_VIRTUAL_SCALE_MODE.TOPLEFT = 00h
AKODE_VIRTUAL_SCALE_MODE.TOPCENTER = 01h
AKODE_VIRTUAL_SCALE_MODE.TOPRIGHT = 02h
AKODE_VIRTUAL_SCALE_MODE.CENTERLEFT = 10h
AKODE_VIRTUAL_SCALE_MODE.CENTER = 11h
AKODE_VIRTUAL_SCALE_MODE.CENTERRIGHT = 12h
AKODE_VIRTUAL_SCALE_MODE.BOTTOMLEFT = 20h
AKODE_VIRTUAL_SCALE_MODE.BOTTOMCENTER = 21h
AKODE_VIRTUAL_SCALE_MODE.BOTTOMRIGHT = 22h
 
struct akode.TextureDesc
Type dd ? ; AKODE_TEXTURE_TYPE
 
union
ImagePathPtr dd ?
Color dd ?
ends
 
ImageDataPtr dd ?
 
HasMagicPink db ? ; boolean
TileWalls db ? ; boolean
Usage db ? ; AKODE_TEXTURE_USAGE
VirtualScale db ? ; AKODE_VIRTUAL_SCALE_MODE, not supported yet
VirtualSize akode.Size ; (0, 0) for original size, not supported yet
ends
 
struct akode.GridCell
WallTexture1 akode.CombinedTexture ; 4 combined textures for walls
WallTexture2 akode.CombinedTexture
WallTexture3 akode.CombinedTexture
WallTexture4 akode.CombinedTexture
 
FloorTexture akode.CombinedTexture
CeilingTexture akode.CombinedTexture
 
Passable dd ? ; boolean
 
ActionCallback dd ? ; proc callback AKODE_ACTION, cell x, cell y
ends
 
struct akode.Object
TextureDescPtr dd ?
Position akode.Point
Visible dd ? ; boolean
DisableShading dd ? ; boolean
Tag dd ?
 
; for internal use
Distance dd ?
ShadingDistance dd ?
Angle dd ?
ends
 
AKODE_DIRECTION.EAST = 0
AKODE_DIRECTION.NORTH = 1
AKODE_DIRECTION.WEST = 2
AKODE_DIRECTION.SOUTH = 3
 
struct akode.LevelHeader
Size akode.Size
StartPosition akode.Point
StartDirection dd ? ; AKODE_DIRECTION
BackgroundColor dd ? ; FF00FF for no background color
ShadingColor dd ?
ShadingDistance dd ? ; 0 for no shading
 
ObjectCount dd ?
TextureCount dd ? ; number of additional textures
 
InitCallback dd ?
DestroyCallback dd ?
ActionCallback dd ? ; proc callback AKODE_ACTION, cell x, cell y
ends
 
AKODE_LEVEL_LOAD.START = 0
AKODE_LEVEL_LOAD.END = 1
AKODE_LEVEL_LOAD.UNLOADED = 2
 
AKODE_ACTION.CELL_LEAVE = 0
AKODE_ACTION.CELL_ENTER = 1
AKODE_ACTION.CUSTOM = 0100h
/programs/games/Dungeons/AKODE/import.inc
0,0 → 1,19
; ================================= Import =================================== ;
 
library libio, 'libio.obj', \
libimg, 'libimg.obj'
 
import libio, \
file_size, 'file_size', \
file_open, 'file_open', \
file_read, 'file_read', \
file_close, 'file_close'
 
import libimg, \
img_decode, 'img_decode', \
img_convert, 'img_convert', \
img_scale, 'img_scale', \
img_flip, 'img_flip', \
img_rotate, 'img_rotate', \
img_to_rgb, 'img_to_rgb', \
img_destroy, 'img_destroy'
/programs/games/Dungeons/AKODE/udata.inc
0,0 → 1,34
; =========================== Uninitialized data ============================= ;
 
align 4
akode_data.BlockSize akode.Size ; first - width and height of the block base, must be power of 2
; second - height of the block
akode_data.BlockWidthPowerOf2 dd ?
akode_data.Camera akode.Camera
akode_data.ProjectionPlane akode.ProjectionPlane
 
akode_data.CameraToPlaneDistance dd ?
akode_data.WallHeightDividend dd ?
akode_data.FloorDistanceDividend dd ?
akode_data.CeilingDistanceDividend dd ?
 
akode_data.Angle90 dd ?
akode_data.Angle180 dd ?
akode_data.Angle270 dd ?
akode_data.Angle360 dd ?
 
akode_data.ShadingColor dd ?
akode_data.ShadingDistance dd ?
 
akode_data.CurrentLevel akode.LevelHeader
 
akode_data.MovementSpeed dd ?
akode_data.TurningSpeed dd ?
akode_data.MovementDirection dd ?
akode_data.TurningDirection dd ?
akode_data.LastMoveTimestamp dd ?
akode_data.LastTurnTimestamp dd ?
 
akode_data.ImageBufferSize dd ?
 
akode_data.OptimizedGetImage dd ?
/programs/games/Dungeons/Dungeons.asm
0,0 → 1,974
; 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/>.
 
format binary as 'kex'
 
__DEBUG__ = 1 ; 0 - disable debug output / 1 - enable debug output
__DEBUG_LEVEL__ = DEBUG_FINE ; DEBUG_FINE - all debug messages / DEBUG_INFO - info and errors / DEBUG_ERR - only errors
 
DEBUG_FINE = 0
DEBUG_INFO = 1
DEBUG_ERR = 2
 
include 'macros.inc'
purge mov, add, sub
 
; ================================= Header =================================== ;
MEOS_APP_START
store dword StartupPath at $ - 4
 
; ================================ Includes ================================== ;
include '../../debug-fdo.inc'
include '../../proc32.inc'
include '../../dll.inc'
 
include 'AKODE/AKODE.inc'
include 'datadef.inc'
 
; =============================== Entry point ================================ ;
CODE
DEBUGF DEBUG_INFO, 'Started\n'
 
mcall 68, 11 ; initialize heap
test eax, eax
jz .exit_fail_heap_init
 
stdcall dll.Load, @IMPORT ; load libraries
test eax, eax
jnz .exit_fail_load_libs
 
mcall 40, MAIN_EVENT_MASK ; used events
mcall 66, 1, 1 ; use scancodes
 
stdcall draw_window
 
mcall 9, ThreadInfoBuffer, -1 ; get real window size
mov eax, [ebx + process_information.client_box.width]
inc eax
mov [MainWindowWidth], eax
mov edx, [ebx + process_information.client_box.height]
inc edx
mov [MainWindowHeight], edx
DEBUGF DEBUG_FINE, 'Window width: %u\nWindow height: %u\n', eax, edx
 
mov ecx, eax
shl ecx, 2
imul ecx, edx ; ecx = width * 4 * height
 
sub edx, HUD_PANEL_HEIGHT
mov [WorldViewHeight], edx
 
if FSAA
shl eax, FSAA
shl edx, FSAA
end if
 
stdcall akode.init, eax, edx, FIELD_OF_VIEW, BLOCK_BASE_SIZE, BLOCK_HEIGHT
test eax, eax
jz .exit_fail_akode_init
 
mcall 68, 12 ; alloc ecx bytes for image buffer
test eax, eax
jz .exit_fail_alloc
 
mov [ImageBufferPtr], eax
push eax
 
stdcall set_startup_path
 
stdcall load_hud_images
test eax, eax
jnz @f
DEBUGF DEBUG_ERR, 'Failed to load HUD images\n'
jmp .exit_fail_load_hud
 
@@:
cld
xor eax, eax
mov edi, PressedKeys
mov ecx, 128 * 2
rep stosd
 
mov edi, Inventory
mov ecx, INVENTORY_SIZE * 2
rep stosd
 
stdcall akode.set_callbacks, level_load_callback, action_callback
 
stdcall akode.load_level, levels.level1
 
if FULLSCREEN
stdcall hide_cursor
push eax
end if
 
stdcall main_loop
 
if FULLSCREEN
pop ecx
test ecx, ecx
jz @f
mcall 37, 6 ; delete cursor
@@:
end if
 
.exit_fail_load_hud:
stdcall free_hud_images
 
pop ecx
mcall 68, 13 ; free image buffer
 
jmp .exit
 
.exit_fail_heap_init:
DEBUGF DEBUG_ERR, 'Heap initialization failed\n'
jmp .exit
 
.exit_fail_load_libs:
DEBUGF DEBUG_ERR, 'Failed to load libraries\n'
jmp .exit
 
.exit_fail_akode_init:
DEBUGF DEBUG_ERR, 'AKODE initialization failed\n'
jmp .exit
 
.exit_fail_alloc:
DEBUGF DEBUG_ERR, 'Memory allocation for image buffer failed\n'
;jmp .exit
 
.exit:
stdcall akode.cleanup
DEBUGF DEBUG_INFO, 'Exiting\n'
 
xor eax, eax
dec eax
mcall ; kill this thread
 
; ============================================================================ ;
proc set_startup_path
cld
mov esi, StartupPath
mov ecx, esi
 
@@:
lodsb
test al, al
jnz @b
 
sub esi, 2
std
 
@@:
lodsb
cmp al, '/'
jne @b
 
mov [esi + 1], byte 0
 
mcall 30, 1 ; set current directory
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
; < eax = 0 - fail ;
; ============================================================================ ;
proc load_hud_images
mov ebx, [MainWindowWidth]
mov ecx, [MainWindowHeight]
xor edx, edx
 
stdcall akode.load_and_scale_image, LevelLoadingImageFile, ebx, ecx, edx
test eax, eax
jz .exit
 
mov [LevelLoadingImagePtr], eax
 
stdcall akode.load_and_scale_image, DeathImageFile, ebx, ecx, edx
test eax, eax
jz .exit
 
mov [DeathImagePtr], eax
 
stdcall akode.load_and_scale_image, EndImageFile, ebx, ecx, edx
test eax, eax
jz .exit
 
mov [EndImagePtr], eax
 
stdcall akode.load_and_scale_image, HudPanelImageFile, ebx, HUD_PANEL_HEIGHT, edx
test eax, eax
jz .exit
 
mov [HudPanelImagePtr], eax
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc free_hud_images
xor edx, edx
mov ebx, 13
 
mov ecx, [LevelLoadingImagePtr]
test ecx, ecx
jz @f
mcall 68 ; free
mov [LevelLoadingImagePtr], edx
@@:
mov ecx, [HudPanelImagePtr]
test ecx, ecx
jz @f
mcall 68
mov [HudPanelImagePtr], edx
@@:
mov ecx, [DeathImagePtr]
test ecx, ecx
jz @f
mcall 68
mov [DeathImagePtr], edx
@@:
mov ecx, [EndImagePtr]
test ecx, ecx
jz @f
mcall 68
mov [EndImagePtr], edx
@@:
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
; < eax = cursor handle / 0 - fail ;
; ============================================================================ ;
proc hide_cursor
mcall 68, 12, 32 * 32 * 4
test eax, eax
jz .exit
 
mov edi, eax
xor ebx, ebx
shr ecx, 2
@@: mov [eax], ebx
add eax, 4
loop @b
 
mcall 37, 4, edi, 2 ; load cursor
mov ecx, eax
inc ebx
mcall 37 ; set cursor
 
xchg edi, ecx
 
mcall 68, 13
 
mov eax, edi
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc draw_image uses eax ebx ecx edx esi edi, image_ptr, x, y, width, height
mov ebx, [image_ptr]
mpack ecx, [width], [height]
mpack edx, [x], [y]
mov esi, 32
xor edi, edi
xchg edi, ebp
mcall 65
mov ebp, edi
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc draw_image_to_buffer uses eax ebx ecx edx esi edi, image_ptr, x, y, width, height
cld
mov esi, [image_ptr]
mov edi, [ImageBufferPtr]
mov ebx, [MainWindowWidth]
mov eax, [y]
mul ebx
add eax, [x]
lea edi, [edi + eax * 4]
 
sub ebx, [width]
shl ebx, 2
mov edx, [height]
 
@@:
mov ecx, [width]
rep movsd
add edi, ebx
 
sub edx, 1
jnz @b
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc draw_image_with_transparency_to_buffer uses eax ebx ecx edx esi edi, image_ptr, x, y, width, height
mov esi, [image_ptr]
mov edi, [ImageBufferPtr]
mov ebx, [MainWindowWidth]
mov eax, [y]
mul ebx
add eax, [x]
lea edi, [edi + eax * 4]
 
sub ebx, [width]
shl ebx, 2
mov edx, [height]
 
.y_draw_loop:
mov ecx, [width]
 
.x_draw_loop:
mov eax, [esi]
cmp eax, 0FF00FFh
je @f
mov [edi], eax
@@:
add esi, 4
add edi, 4
 
sub ecx, 1
jnz .x_draw_loop
 
add edi, ebx
 
sub edx, 1
jnz .y_draw_loop
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc draw_window
mcall 12, 1 ; start drawing
 
if FULLSCREEN
mov ebx, 0FFFFh
mov ecx, 0FFFFh
else
mcall 48, 4 ; eax - skin height
 
mpack ebx, MAIN_WINDOW_X, MAIN_WINDOW_WIDTH + 9
mpack ecx, MAIN_WINDOW_Y, MAIN_WINDOW_HEIGHT + 4
add ecx, eax
end if
mov edx, MAIN_WINDOW_STYLE
mov esi, MAIN_WINDOW_STYLE2
mov edi, MAIN_WINDOW_TITLE
xor eax, eax
mcall ; draw window
 
mcall 12, 2 ; end drawing
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc draw_world
mov ebx, [ImageBufferPtr]
;test ebx, ebx
;jz @f
 
stdcall akode.render
stdcall akode.get_image, ebx, FSAA
 
mpack ecx, [MainWindowWidth], [WorldViewHeight]
xor edx, edx
mov esi, 32
xor edi, edi
xchg edi, ebp
mcall 65
mov ebp, edi
 
;@@:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc draw_hud
mov eax, [HudPanelNeedsRedraw]
test eax, eax
jz .exit
 
xor eax, eax
mov [HudPanelNeedsRedraw], eax
 
stdcall draw_image_to_buffer, [HudPanelImagePtr], eax, [WorldViewHeight], [MainWindowWidth], HUD_PANEL_HEIGHT
 
mov esi, Inventory + 4
mov ebx, INVENTORY_Y
add ebx, [WorldViewHeight]
mov edx, 2
 
.y_inventory_loop:
mov eax, INVENTORY_X
mov ecx, INVENTORY_SIZE / 2
 
.x_inventory_loop:
mov edi, [esi]
add esi, 8
test edi, edi
jz @f
stdcall draw_image_with_transparency_to_buffer, edi, eax, ebx, OBJECT_IMAGE_WIDTH, OBJECT_IMAGE_HEIGHT
 
@@:
add eax, OBJECT_IMAGE_WIDTH + INVENTORY_PADDING_X
 
sub ecx, 1
jnz .x_inventory_loop
 
add ebx, OBJECT_IMAGE_HEIGHT + INVENTORY_PADDING_Y
 
sub edx, 1
jnz .y_inventory_loop
 
mpack ecx, [MainWindowWidth], HUD_PANEL_HEIGHT
mov edx, [WorldViewHeight]
mov ebx, [ImageBufferPtr]
mov eax, [MainWindowWidth]
imul eax, edx
lea ebx, [ebx + eax * 4]
mov esi, 32
xor edi, edi
xchg edi, ebp
mcall 65
mov ebp, edi
 
jmp draw_game_message
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc draw_game_message
mov esi, [GameMessage]
test esi, esi
jz .exit
 
mpack ebx, GAME_MESSAGE_X, GAME_MESSAGE_Y
add ebx, [WorldViewHeight]
mov ecx, GAME_MESSAGE_COLOR or (80h shl 24)
 
.draw_strings_loop:
mov edx, esi
 
@@:
mov al, [esi]
add esi, 1
 
test al, al
jz .draw_last_string
cmp al, 0Ah
jne @b
 
mov [esi - 1], byte 0
 
mcall 4
 
mov [esi - 1], byte 0Ah
add ebx, 10
jmp .draw_strings_loop
 
.draw_last_string:
mcall 4
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc main_loop
locals
frame_count dd 0
last_timestamp dd 0
endl
 
.main_loop:
mcall 26, 9 ; get timestamp
mov ebx, eax
sub ebx, [last_timestamp]
cmp ebx, 100
jb @f
 
mov [last_timestamp], eax
imul eax, [frame_count], 100
xor edx, edx
mov [frame_count], edx
div ebx ; eax - fps
 
DEBUGF DEBUG_FINE, 'FPS: %u\n', eax
 
@@:
mcall 11 ; check events
 
test eax, eax
jz .idle
 
dec eax
jz .redraw
 
dec eax
jz .key
 
dec eax
jz .button
 
sub eax, 3
jz .mouse
 
jmp .idle
 
.redraw:
stdcall draw_window
mov [HudPanelNeedsRedraw], 1
 
.idle:
mov eax, [GameStatus]
test eax, eax
jnz @f
 
stdcall akode.process
 
mov eax, [GameStatus]
test eax, eax
jnz @f
 
stdcall draw_hud
stdcall draw_world
 
add [frame_count], 1
jmp .main_loop
 
@@: cmp eax, GAME_STATUS.LEVEL_LOAD_FAILED
jne @f
jmp .exit
 
@@: cmp eax, GAME_STATUS.DEAD
jne @f
stdcall draw_image, [DeathImagePtr], 0, 0, [MainWindowWidth], [MainWindowHeight]
jmp .main_loop
 
@@: cmp eax, GAME_STATUS.END
jne @f
stdcall draw_image, [EndImagePtr], 0, 0, [MainWindowWidth], [MainWindowHeight]
@@:
jmp .main_loop
 
.key:
stdcall get_key
test eax, eax
jz .idle
 
cmp eax, 001h ; Esc
je .exit
 
cmp eax, 039h ; Space
je .space_pressed
cmp eax, 002h ; 1
jb @f
cmp eax, 00Bh ; 0
ja @f
 
; 0..9 pressed
sub eax, 002h
mov eax, dword [Inventory + eax * 8]
test eax, eax
jz @f
shl eax, 16
push eax
 
stdcall check_key, 02Ah ; left Shift
test eax, eax
jnz .shift_pressed
 
stdcall check_key, 036h ; right Shift
test eax, eax
jnz .shift_pressed
 
pop eax
or eax, ACTION.USE_OBJECT
stdcall akode.action, eax
jmp @f
 
.shift_pressed:
pop eax
or eax, ACTION.LOOK_AT_OBJECT
stdcall akode.action, eax
jmp @f
 
.space_pressed:
stdcall check_key, 02Ah ; left Shift
test eax, eax
jnz .shift_pressed2
 
stdcall check_key, 036h ; right Shift
test eax, eax
jnz .shift_pressed2
 
stdcall akode.action, ACTION.DO_SOMETHING
jmp @f
 
.shift_pressed2:
stdcall akode.action, ACTION.LOOK_AROUND
 
@@:
xor esi, esi
dec esi
 
stdcall check_key, 0E048h ; ^
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.NORTH
jmp .set_moving_direction
 
@@: stdcall check_key, 0E050h ; v
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.SOUTH
jmp .set_moving_direction
 
@@: stdcall check_key, 011h ; W
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.NORTH
jmp .set_moving_direction
 
@@: stdcall check_key, 01Fh ; S
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.SOUTH
;jmp .set_moving_direction
 
@@:
 
.set_moving_direction:
test esi, esi
js @f
stdcall akode.start_moving, esi
jmp .turn
 
@@:
stdcall akode.stop_moving
 
.turn:
xor esi, esi
dec esi
 
stdcall check_key, 0E04Bh ; <-
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.WEST
jmp .set_turning_direction
 
@@: stdcall check_key, 0E04Dh ; ->
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.EAST
jmp .set_turning_direction
 
@@: stdcall check_key, 01Eh ; A
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.WEST
jmp .set_turning_direction
 
@@: stdcall check_key, 020h ; D
test eax, eax
jz @f
mov esi, AKODE_DIRECTION.EAST
;jmp .set_turning_direction
 
@@:
 
.set_turning_direction:
test esi, esi
js @f
stdcall akode.start_turning, esi
jmp .key
 
@@:
stdcall akode.stop_turning
jmp .key
 
.mouse:
 
jmp .idle
 
.button:
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
; < eax = key scancode / 0 - no keys ;
; ============================================================================ ;
proc get_key
mcall 2 ; get key scancode
 
test al, al
jz @f
xor eax, eax
jmp .exit
 
@@:
shr eax, 8
 
cmp eax, 0E1h
jne @f
mcall 2
mcall 2
xor eax, eax
jmp .exit
 
@@:
xor ebx, ebx
mov ecx, eax
 
cmp eax, 0E0h
jne @f
mcall 2
shr eax, 8
mov ecx, eax
or eax, 0E000h
mov ebx, 128
 
@@:
test ecx, 80h
jnz .key_up
 
; key down
add ebx, ecx
lea ebx, [PressedKeys + ebx * 4]
 
mov edx, [ebx]
test edx, edx
jz @f
 
xor eax, eax
jmp .exit
 
@@:
inc edx
mov [ebx], edx
jmp .exit
 
.key_up:
and ecx, 7Fh
add ebx, ecx
xor edx, edx
mov [PressedKeys + ebx * 4], edx
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
; < eax = 1 - key pressed / 0 - not pressed ;
; ============================================================================ ;
proc check_key scancode
mov eax, [scancode]
mov ecx, eax
shr eax, 8
and ecx, 7Fh
xor ebx, ebx
 
cmp eax, 0E0h
jne @f
mov ebx, 128
 
@@:
add ebx, ecx
mov eax, [PressedKeys + ebx * 4]
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc level_load_callback uses eax ebx ecx, load_action, action_result
mov eax, [load_action]
mov ebx, [action_result]
xor ecx, ecx
 
cmp eax, AKODE_LEVEL_LOAD.START
jne @f
stdcall draw_image, [LevelLoadingImagePtr], ecx, ecx, [MainWindowWidth], [MainWindowHeight]
 
cmp ebx, -1
je .level_load_failed
 
mov [GameMessage], ebx
inc ecx
mov [HudPanelNeedsRedraw], ecx
jmp .exit
 
@@: cmp eax, AKODE_LEVEL_LOAD.END
jne @f
DEBUGF DEBUG_INFO, 'Level load result: %u\n', ebx
 
test ebx, ebx
jnz .exit
 
.level_load_failed:
DEBUGF DEBUG_ERR, 'Failed to load level\n'
mov [GameStatus], GAME_STATUS.LEVEL_LOAD_FAILED
;jmp .exit
 
@@:
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc action_callback action, cell_x, cell_y, action_result
m2m [GameMessage], [action_result]
mov [HudPanelNeedsRedraw], 1
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc add_object_to_inventory uses eax ecx edi, object_id, object_image_ptr
mov edi, Inventory
mov ecx, INVENTORY_SIZE
 
.inventory_loop:
mov eax, [edi]
test eax, eax
jnz @f
 
mov eax, [object_id]
mov [edi], eax
mov eax, [object_image_ptr]
mov [edi + 4], eax
mov [HudPanelNeedsRedraw], ecx
jmp .exit
 
@@:
add edi, 8
 
sub ecx, 1
jnz .inventory_loop
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc remove_object_from_inventory uses eax ecx esi, object_id
mov eax, [object_id]
mov esi, Inventory
mov ecx, INVENTORY_SIZE
 
.inventory_loop:
cmp [esi], eax
jne @f
 
xor eax, eax
mov [esi], eax
mov [esi + 4], eax
mov [HudPanelNeedsRedraw], ecx
jmp .exit
 
@@:
add esi, 8
 
sub ecx, 1
jnz .inventory_loop
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
; < eax = pointer to image data / 0 - fail ;
; ============================================================================ ;
proc load_object_image image_path_ptr
stdcall akode.load_and_scale_image, [image_path_ptr], OBJECT_IMAGE_WIDTH, OBJECT_IMAGE_HEIGHT, 0
 
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc free_object_image uses eax ebx ecx, image_ptr
mov ecx, [image_ptr]
test ecx, ecx
jz .exit
 
mcall 68, 13
 
.exit:
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc player_death
mov [GameStatus], GAME_STATUS.DEAD
ret
endp
; ============================================================================ ;
 
; ============================================================================ ;
proc game_over
mov [GameStatus], GAME_STATUS.END
ret
endp
; ============================================================================ ;
 
; ============================ Initialized data ============================== ;
DATA
include 'data.inc'
 
; for debug-fdo
include_debug_strings
 
align 4
@IMPORT:
include 'import.inc'
 
; =========================== Uninitialized data ============================= ;
UDATA
include 'udata.inc'
 
; ================================= The End ================================== ;
MEOS_APP_END
/programs/games/Dungeons/Resources/Levels/1.inc
0,0 → 1,447
 
levels.level1 akode.LevelHeader <level1.Width, level1.Height>, <8, 1>, AKODE_DIRECTION.SOUTH, 0FF00FFh, 000000h, BLOCK_BASE_SIZE * 5, 6, 1, level1.init, 0, level1.action
 
level1:
 
.Width = 24
.Height = 25
 
W equ level1.Wall
w equ level1.OtherWall
_ equ level1.PassableArea
0 equ level1.NotPassableArea
% equ level1.WallWithCrazyWoodDoor
I equ level1.IronDoor
L equ level1.WallWithLever1
q equ level1.WallWithLever2
v equ level1.WallWithLever3
e equ level1.WallWithLever4
c equ level1.ColumnArea
o equ level1.OgreArea
P equ level1.PortalArea
 
.Grid:
dd W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W
dd W,_,_,W,W,_,_,W,_,W,_,W,_,_,_,_,W,W,W,W,W,W,W,W
dd W,_,_,W,W,_,_,W,_,W,_,W,_,_,_,_,_,_,_,_,_,_,_,W
dd W,_,_,_,_,_,_,W,_,W,_,W,_,_,_,_,_,_,_,_,_,_,_,W
dd W,W,W,_,_,W,W,W,_,W,L,W,_,_,_,W,W,W,_,_,_,W,W,W
dd W,_,_,_,_,_,_,W,_,_,_,W,_,_,_,W,0,W,_,_,_,W,0,W
dd W,_,W,_,W,_,_,W,_,W,W,W,W,W,_,W,c,_,_,_,_,_,c,W
dd W,_,W,_,W,_,_,W,_,W,W,W,W,W,_,W,_,_,_,c,_,_,_,W
dd W,W,W,_,W,W,W,W,%,W,W,W,W,W,_,W,_,_,W,0,W,_,_,W
dd W,_,W,_,W,_,_,_,_,_,_,_,W,W,_,W,_,_,W,W,W,_,_,W
dd W,_,W,W,W,_,_,_,_,_,_,_,I,_,_,W,_,_,_,_,_,_,_,W
dd W,_,_,_,W,_,_,_,_,_,_,_,W,W,W,W,W,W,W,W,W,%,W,W
dd W,_,_,_,W,W,W,W,q,v,e,W,W,_,_,_,_,_,_,_,_,_,_,W
dd W,_,_,_,_,_,_,_,_,_,_,_,W,_,W,W,W,W,W,W,W,W,W,W
dd W,_,_,_,W,_,_,_,_,_,_,_,W,o,W,_,_,_,_,_,_,_,_,W
dd W,_,_,_,W,W,W,W,W,W,W,W,W,0,W,W,W,W,_,_,_,_,_,W
dd W,_,_,_,W,_,_,_,_,_,_,W,_,_,_,_,_,W,w,w,w,w,w,w
dd W,_,_,_,_,_,_,_,_,_,_,W,_,_,_,_,_,_,_,_,_,_,_,w
dd W,_,_,_,_,_,_,_,_,_,_,W,W,W,W,W,_,w,w,_,w,w,_,w
dd W,_,_,_,_,_,_,_,_,_,_,_,_,_,_,w,_,w,_,_,_,w,_,w
dd W,_,_,_,_,_,_,_,_,_,_,_,_,_,_,w,_,_,_,P,_,_,_,w
dd W,_,_,_,_,_,_,_,_,_,_,_,_,_,_,w,_,w,_,_,_,w,_,w
dd W,_,_,_,_,_,_,_,_,_,_,_,_,_,_,w,_,w,w,_,w,w,_,w
dd W,_,_,_,_,_,_,_,_,_,_,_,_,_,_,w,_,_,_,_,_,_,_,w
dd W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,w,w,w,w,w,w,w,w,w
 
restore W, w, _, 0, %, I, L, q, v, e, c, o, P
 
.Chest akode.Object textures.Chest, <13, 2>, 1, 0
.Column1 akode.Object textures.Column1, <16, 5>, 1, 0
.Column2 akode.Object textures.Column2, <19, 8>, 1, 0
.Column3 akode.Object textures.Column3, <22, 5>, 1, 0
.Ogre akode.Object textures.Ogre, <13, 15>, 1, 0
.Portal akode.Object textures.Portal, <19, 20>, 1, 1
 
.Column4TextureDescPtr dd textures.Column4
 
.Wall akode.GridCell <textures.GreenStone1, 0>, \
<textures.GreenStone1, 0>, \
<textures.GreenStone1, 0>, \
<textures.GreenStone1, 0>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.OtherWall akode.GridCell <textures.GreenStone2, 0>, \
<textures.GreenStone2, 0>, \
<textures.GreenStone2, 0>, \
<textures.GreenStone2, 0>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.WallWithCrazyWoodDoor akode.GridCell <textures.GreenStone1, textures.CrazyWoodDoor>, \
<textures.GreenStone1, textures.CrazyWoodDoor>, \
<textures.GreenStone1, textures.CrazyWoodDoor>, \
<textures.GreenStone1, textures.CrazyWoodDoor>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.IronDoor akode.GridCell <textures.IronDoor, 0>, \
<textures.IronDoor, 0>, \
<textures.IronDoor, 0>, \
<textures.IronDoor, 0>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.WallWithLever1 akode.GridCell <textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverDown>, \
<textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverUp>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.WallWithLever2 akode.GridCell <textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverUp>, \
<textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverDown>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.WallWithLever3 akode.GridCell <textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverUp>, \
<textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverDown>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.WallWithLever4 akode.GridCell <textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverUp>, \
<textures.GreenStone1, 0>, \
<textures.GreenStone1, textures.RedLeverDown>, \
<0, 0>, \
<0, 0>, \
0, 0
 
.PassableArea akode.GridCell <0, 0>, \
<0, 0>, \
<0, 0>, \
<0, 0>, \
<textures.YellowStone1, 0>, \
<textures.YellowStone1, 0>, \
1, 0
 
.NotPassableArea akode.GridCell <0, 0>, \
<0, 0>, \
<0, 0>, \
<0, 0>, \
<textures.YellowStone1, 0>, \
<textures.YellowStone1, 0>, \
0, 0
 
.ColumnArea akode.GridCell <0, 0>, \
<0, 0>, \
<0, 0>, \
<0, 0>, \
<textures.YellowStone1, 0>, \
<textures.YellowStone1, 0>, \
1, level1.columns
 
.OgreArea akode.GridCell <0, 0>, \
<0, 0>, \
<0, 0>, \
<0, 0>, \
<textures.YellowStone1, 0>, \
<textures.YellowStone1, 0>, \
1, level1.ogre
 
.PortalArea akode.GridCell <0, 0>, \
<0, 0>, \
<0, 0>, \
<0, 0>, \
<textures.PortalFloor, 0>, \
<textures.YellowStone1, 0>, \
1, level1.portal
 
.CoinImagePtr dd 0
.Sun1ImagePtr dd 0
.Sun2ImagePtr dd 0
.Sun3ImagePtr dd 0
 
proc level1.init
stdcall load_object_image, .coin_file_path
mov [level1.CoinImagePtr], eax
stdcall load_object_image, .sun1_file_path
mov [level1.Sun1ImagePtr], eax
stdcall load_object_image, .sun2_file_path
mov [level1.Sun2ImagePtr], eax
stdcall load_object_image, .sun3_file_path
mov [level1.Sun3ImagePtr], eax
 
mov eax, .message
ret
 
.coin_file_path db 'Resources/Textures/Objects/Coin.png', 0
.sun1_file_path db 'Resources/Textures/Objects/Sun1.png', 0
.sun2_file_path db 'Resources/Textures/Objects/Sun2.png', 0
.sun3_file_path db 'Resources/Textures/Objects/Sun3.png', 0
 
.message langstr0 ru, < \
'‚ë - ¨áª â¥«ì ᮪஢¨é. ’ ª ­ ¦¨¢¥ ¯à¨¢¥«  ¢ á ¢ ', 10, \
'«¥á­ãî ¯¥é¥àã, £¤¥, ¯® à á᪠§ ¬ ᥫï­, ¯ àã á⮫¥â¨© ', 10, \
'­ § ¤, ®¤¨­ ¯à ¢¨â¥«ì, á¯àïâ « á¢®î ª §­ã. ‚ ¯¥é¥à¥ ¢ë ', 10, \
'­ è«¨... ¤¢¥àì. “ᨫ¨¥ - ¤¢¥àì ®âªàëâ ! ‚ë ¢®è«¨ ¢­ãâàì', 10, \
'¨ ¤¢¥àì á £à®å®â®¬ § å«®¯­ã« áì. ‚®§¬®¦­®, íâ® ¢ è è ­á', 10, \
'­ ©â¨ ­¥á¬¥â­ë¥ ¡®£ âá⢠ ¨«¨ ¯®£¨¡­ãâì... ' >
 
endp
 
proc level1.action uses ebx ecx edx, action, cell_x, cell_y
mov eax, [action]
mov ebx, [cell_x]
mov ecx, [cell_y]
 
mov edx, ecx
imul edx, level1.Width
add edx, ebx
lea edx, [level1.Grid + edx * 4]
 
cmp ax, ACTION.DO_SOMETHING
jne .check_next_action
 
cmp edx, level1.Grid + (7 * level1.Width + 8) * 4
jne @f
cmp dword [level1.Grid + (8 * level1.Width + 8) * 4], level1.WallWithCrazyWoodDoor
jne .exit_no_message
 
mov eax, .message_door1_closed
jmp .exit
.message_door1_closed langstr0 ru, < \
'‡ ¯¥àâ®. “ ¤¢¥à¨ ­¥â ­¨ àã窨, ­¨ § ¬®ç­®© ᪢ ¦¨­ë. ', 10, \
'‚¥à®ïâ­®, £¤¥-â® ¤®«¦¥­ ¡ëâì áªàëâë© ¬¥å ­¨§¬... ' >
 
@@: cmp edx, level1.Grid + (10 * level1.Width + 21) * 4
jne @f
cmp dword [level1.Grid + (11 * level1.Width + 21) * 4], level1.WallWithCrazyWoodDoor
jne .exit_no_message
 
mov eax, .message_door3_closed
jmp .exit
.message_door3_closed langstr0 ru, < \
'’ ªãî ¤¢¥àì ¢ë 㦥 ¢¨¤¥«¨, ¨ ¢ ¯à®è«ë© à § ®­  â ª ', 10, \
'¯à®áâ® ­¥ ®âªàë« áì. ' >
 
@@: cmp edx, level1.Grid + (5 * level1.Width + 10) * 4
jne @f
cmp dword [level1.Grid + (8 * level1.Width + 8) * 4], level1.WallWithCrazyWoodDoor
jne .exit_no_message
 
mov [level1.WallWithLever1.WallTexture4.DescPtr2], textures.RedLeverDown
mov dword [level1.Grid + (8 * level1.Width + 8) * 4], level1.PassableArea
 
mov eax, .message_door1_opens
jmp .exit
.message_door1_opens langstr0 ru, < \
'‚ë á«ëè¨â¥ §¢ãª «¥¡ñ¤ª¨ ¨ áªà¥¦¥â è¥áâ¥àñ­®ª. ' >
 
@@: cmp edx, level1.Grid + (11 * level1.Width + 8) * 4
jne @f
mov eax, [level1.WallWithLever2.WallTexture2.DescPtr2]
mov ebx, [level1.WallWithLever2.WallTexture4.DescPtr2]
mov [level1.WallWithLever2.WallTexture2.DescPtr2], ebx
mov [level1.WallWithLever2.WallTexture4.DescPtr2], eax
jmp .3levers
 
@@: cmp edx, level1.Grid + (11 * level1.Width + 9) * 4
jne @f
mov eax, [level1.WallWithLever3.WallTexture2.DescPtr2]
mov ebx, [level1.WallWithLever3.WallTexture4.DescPtr2]
mov [level1.WallWithLever3.WallTexture2.DescPtr2], ebx
mov [level1.WallWithLever3.WallTexture4.DescPtr2], eax
jmp .3levers
 
@@: cmp edx, level1.Grid + (11 * level1.Width + 10) * 4
jne @f
mov eax, [level1.WallWithLever4.WallTexture2.DescPtr2]
mov ebx, [level1.WallWithLever4.WallTexture4.DescPtr2]
mov [level1.WallWithLever4.WallTexture2.DescPtr2], ebx
mov [level1.WallWithLever4.WallTexture4.DescPtr2], eax
jmp .3levers
 
@@: cmp edx, level1.Grid + (10 * level1.Width + 11) * 4
jne @f
cmp dword [level1.Grid + (10 * level1.Width + 12) * 4], level1.IronDoor
jne .exit_no_message
mov eax, .message_door2_closed
jmp .exit
 
@@: jmp .exit_no_message
 
.check_next_action:
cmp ax, AKODE_ACTION.CELL_ENTER
jne .exit_no_message
 
cmp edx, level1.Grid + (2 * level1.Width + 13) * 4
jne @f
cmp [level1.Chest.Visible], 1
jne .exit_no_message
 
stdcall add_object_to_inventory, 4, [level1.CoinImagePtr]
stdcall add_object_to_inventory, 1, [level1.Sun1ImagePtr]
stdcall add_object_to_inventory, 2, [level1.Sun2ImagePtr]
stdcall add_object_to_inventory, 3, [level1.Sun3ImagePtr]
 
mov [level1.Chest.Visible], 0
mov eax, .message_chest
jmp .exit
.message_chest langstr0 ru, < \
'‚ë ­ è«¨ áã­¤ãª á ¡ à å«®¬: 1 §®«®â®© ¬®­¥âª®© ¨ ', 10, \
'3-¬ï ¬®­¥â ¬¨ á ¨§®¡à ¦¥­¨¥¬ ᮫­æ  ¢ à §­ëå ä § å. ' >
 
@@: cmp edx, level1.Grid + (14 * level1.Width + 13) * 4
jne @f
cmp [level1.Ogre.Visible], 1
jne .exit_no_message
mov eax, .message_ogre
jmp .exit
 
.message_ogre langstr0 ru, < \
'- ‘⮩! Šã¤  íâ® âë? „ «ìè¥ å®¤  ­¥â. ' >
 
@@:
 
.exit_no_message:
xor eax, eax
 
.exit:
ret
 
.3levers:
mov eax, [level1.WallWithLever2.WallTexture2.DescPtr2]
mov ebx, [level1.WallWithLever3.WallTexture2.DescPtr2]
mov ecx, [level1.WallWithLever4.WallTexture2.DescPtr2]
 
cmp eax, textures.RedLeverDown
jne @f
cmp ebx, textures.RedLeverUp
jne @f
cmp ecx, textures.RedLeverDown
jne @f
mov dword [level1.Grid + (10 * level1.Width + 12) * 4], level1.PassableArea
mov eax, .message_door2_opens
jmp .exit
 
@@:
mov eax, .message_3levers
jmp .exit
 
.message_3levers langstr0 ru, < \
'‚ë ¯¥à¥áâ ¢¨«¨ íâ®â àëç £ ¢ ¤à㣮¥ ¯®«®¦¥­¨¥. ' >
.message_door2_closed langstr0 ru, < \
'•®âì ¢ë ¨ ¯®«­ë ᨫ, ­® ᤢ¨­ãâì íâã ¤¢¥àì å®âì ­  ', 10, \
'¬¨««¨¬¥âà ã ¢ á ­¥ ¯®«ã稫®áì. ' >
.message_door2_opens langstr0 ru, < \
'„® ¢ á ¤®­ñááï ¬¥â ««¨ç¥áª¨© áªà¥¦¥â. ' >
endp
 
proc level1.columns uses ebx ecx, action, cell_x, cell_y
mov eax, [action]
cmp ax, ACTION.USE_OBJECT
jne .exit_no_message
 
shr eax, 16
mov ebx, eax
 
mov eax, [cell_x]
 
cmp eax, 16
jne @f
cmp ebx, 1
jne .exit_no_message
stdcall remove_object_from_inventory, 1
mov eax, [level1.Column4TextureDescPtr]
mov [level1.Column1.TextureDescPtr], eax
mov [level1.Column1.DisableShading], 1
mov eax, .message_activated
jmp .exit
 
@@: cmp eax, 19
jne @f
cmp ebx, 2
jne .exit_no_message
stdcall remove_object_from_inventory, 2
mov eax, [level1.Column4TextureDescPtr]
mov [level1.Column2.TextureDescPtr], eax
mov [level1.Column2.DisableShading], 1
mov eax, .message_activated
jmp .exit
 
@@: cmp eax, 22
jne @f
cmp ebx, 3
jne .exit_no_message
stdcall remove_object_from_inventory, 3
mov eax, [level1.Column4TextureDescPtr]
mov [level1.Column3.TextureDescPtr], eax
mov [level1.Column3.DisableShading], 1
mov eax, .message_activated
jmp .exit
 
@@:
.exit_no_message:
xor eax, eax
ret
 
.exit:
mov ecx, [level1.Column1.DisableShading]
and ecx, [level1.Column2.DisableShading]
and ecx, [level1.Column3.DisableShading]
jecxz @f
mov dword [level1.Grid + (11 * level1.Width + 21) * 4], level1.PassableArea
@@:
ret
 
.message_activated langstr0 ru, < \
'Š®«®­­  ­ ç «  ᢥâ¨âìáï áâà ­­ë¬ ᢥ⮬,   ­ ¤¯¨áì ', 10, \
'¨á祧« .' >
endp
 
proc level1.ogre action, cell_x, cell_y
mov eax, [action]
 
cmp ax, ACTION.DO_SOMETHING
jne @f
stdcall player_death
xor eax, eax
jmp .exit
 
@@: cmp ax, ACTION.USE_OBJECT
jne .exit_default
shr eax, 16
cmp eax, 4
jne .exit_default
 
mov dword [level1.Grid + (15 * level1.Width + 13) * 4], level1.PassableArea
mov [level1.Ogre.Visible], 0
stdcall remove_object_from_inventory, 4
mov eax, .message_ogre
jmp .exit
 
.exit_default:
xor eax, eax
dec eax
.exit:
ret
 
.message_ogre langstr0 ru, < \
'- Ž©! Œ®­¥âª ! € ­ã ¢¥à­¨áì!!! ' >
endp
 
proc level1.portal action, cell_x, cell_y
mov eax, [action]
cmp ax, AKODE_ACTION.CELL_ENTER
jne @f
stdcall game_over
@@:
xor eax, eax
ret
endp
/programs/games/Dungeons/Resources/Levels/levels.inc
0,0 → 1,2
align 4
include '1.inc'
/programs/games/Dungeons/Resources/Textures/Environment/CrazyWoodDoor.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Environment/GreenStone1.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Environment/GreenStone2.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Environment/IronDoor.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Environment/Portal.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Environment/RedLeverDown.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Environment/RedLeverUp.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Environment/YellowStone1.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/HUD/Death.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/HUD/End.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/HUD/LevelLoading.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/HUD/Panel.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Licenses.txt
0,0 → 1,10
Textures/HUD/* - Anton_K, CC BY-SA 4.0
 
Textures/Environment/*.png - CC0 1.0 (Public Domain)
Textures/Environment/IronDoor.jpg - CC0 1.0 (Public Domain)
Textures/Environment/*Stone*.jpg - p0ss, GNU GPL 2.0, http://opengameart.org/content/117-stone-wall-tilable-textures-in-8-themes
Textures/Environment/Portal.jpg - Clint Bellanger, CC BY 3.0, http://opengameart.org/content/teleporter-circle
 
Textures/Objects/*.png - CC0 1.0 (Public Domain)
Textures/Objects/Chest.png - Daniel Cook, modified by Anton_K, CC BY 3.0, http://opengameart.org/content/planetcute-chest-closedpng
Textures/Objects/Portal.png - Clint Bellanger, modified by Robert C., modified by Anton_K, CC BY 3.0, http://opengameart.org/content/teleporter-circle
/programs/games/Dungeons/Resources/Textures/Objects/Chest.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Coin.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Column1.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Column2.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Column3.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Column4.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Ogre.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Portal.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Sun1.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Sun2.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/Objects/Sun3.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/games/Dungeons/Resources/Textures/textures.inc
0,0 → 1,69
;struct akode.TextureDesc
; Type dd ? ; AKODE_TEXTURE_TYPE
;
; union
; ImagePathPtr dd ?
; Color dd ?
; ends
;
; ImageDataPtr dd ?
;
; HasMagicPink db ? ; boolean
; TileWalls db ? ; boolean
; Usage db ? ; AKODE_TEXTURE_USAGE
; VirtualScale db ? ; AKODE_VIRTUAL_SCALE_MODE, not supported yet
; VirtualSize akode.Size ; (0, 0) for original size, not supported yet
;ends
 
align 4
textures:
 
.GreenStone1 akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.GreenStone1, 0, 0, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
.GreenStone2 akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.GreenStone2, 0, 0, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
 
.YellowStone1 akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.YellowStone1, 0, 0, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
 
.CrazyWoodDoor akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.CrazyWoodDoor, 0, 1, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
.IronDoor akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.IronDoor, 0, 0, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
 
.RedLeverUp akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.RedLeverUp, 0, 1, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
.RedLeverDown akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.RedLeverDown, 0, 1, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
 
.PortalFloor akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.PortalFloor, 0, 0, 0, AKODE_TEXTURE_USAGE.ENVIRONMENT
 
.Chest akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.Chest, 0, 1, 0, AKODE_TEXTURE_USAGE.OBJECT
 
.Column1 akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.Column1, 0, 1, 0, AKODE_TEXTURE_USAGE.OBJECT
.Column2 akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.Column2, 0, 1, 0, AKODE_TEXTURE_USAGE.OBJECT
.Column3 akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.Column3, 0, 1, 0, AKODE_TEXTURE_USAGE.OBJECT
.Column4 akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.Column4, 0, 1, 0, AKODE_TEXTURE_USAGE.OBJECT
 
.Ogre akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.Ogre, 0, 1, 0, AKODE_TEXTURE_USAGE.OBJECT
 
.Portal akode.TextureDesc AKODE_TEXTURE_TYPE.IMAGE, texture_files.Portal, 0, 1, 0, AKODE_TEXTURE_USAGE.OBJECT
 
texture_files:
 
.GreenStone1 db 'Resources/Textures/Environment/GreenStone1.jpg', 0
.GreenStone2 db 'Resources/Textures/Environment/GreenStone2.jpg', 0
 
.YellowStone1 db 'Resources/Textures/Environment/YellowStone1.jpg', 0
 
.CrazyWoodDoor db 'Resources/Textures/Environment/CrazyWoodDoor.png', 0
.IronDoor db 'Resources/Textures/Environment/IronDoor.jpg', 0
 
.RedLeverUp db 'Resources/Textures/Environment/RedLeverUp.png', 0
.RedLeverDown db 'Resources/Textures/Environment/RedLeverDown.png', 0
 
.PortalFloor db 'Resources/Textures/Environment/Portal.jpg', 0
 
.Chest db 'Resources/Textures/Objects/Chest.png', 0
 
.Column1 db 'Resources/Textures/Objects/Column1.png', 0
.Column2 db 'Resources/Textures/Objects/Column2.png', 0
.Column3 db 'Resources/Textures/Objects/Column3.png', 0
.Column4 db 'Resources/Textures/Objects/Column4.png', 0
 
.Ogre db 'Resources/Textures/Objects/Ogre.png', 0
 
.Portal db 'Resources/Textures/Objects/Portal.png', 0
/programs/games/Dungeons/data.inc
0,0 → 1,91
include 'lang.inc'
 
struc langstr [lng, data]
{
if lang eq lng
sz ., data
end if
}
 
struc langstr0 [lng, data]
{
if lang eq lng
sz0 ., data
end if
}
 
include 'AKODE/data.inc'
include 'Resources/Textures/textures.inc'
include 'Resources/Levels/levels.inc'
 
FULLSCREEN = 0
FSAA = 0
DISABLE_SHADING = 0
 
FIELD_OF_VIEW = 60
BLOCK_BASE_SIZE = 512
BLOCK_HEIGHT = 512
 
INVENTORY_SIZE = 10
 
HUD_PANEL_HEIGHT = 120
 
INVENTORY_X = 570
INVENTORY_Y = 15
INVENTORY_PADDING_X = 10
INVENTORY_PADDING_Y = 10
OBJECT_IMAGE_WIDTH = 40
OBJECT_IMAGE_HEIGHT = 40
 
GAME_MESSAGE_X = 150 + 15
GAME_MESSAGE_Y = 15 + 15
GAME_MESSAGE_COLOR = 000000h
 
if FULLSCREEN
;MAIN_WINDOW_X = 0
;MAIN_WINDOW_Y = 0
;MAIN_WINDOW_WIDTH = 0FFFFh
;MAIN_WINDOW_HEIGHT = 0FFFFh
MAIN_WINDOW_STYLE = (01000001b) shl 24
MAIN_WINDOW_STYLE2 = 1 shl 24
else
MAIN_WINDOW_X = 150
MAIN_WINDOW_Y = 150
MAIN_WINDOW_WIDTH = 960
MAIN_WINDOW_HEIGHT = 720
MAIN_WINDOW_STYLE = (01110100b) shl 24
MAIN_WINDOW_STYLE2 = 0
end if
 
MAIN_EVENT_MASK = EVM_REDRAW or EVM_KEY or EVM_BUTTON or EVM_MOUSE or EVM_MOUSE_FILTER
 
MAIN_WINDOW_TITLE langstr0 \
en, 'Dungeons of Augastes 0.1', \
ru, '®¤§¥¬¥«ìï €ã£ áâ¥á  0.1'
 
LevelLoadingImageFile db 'Resources/Textures/HUD/LevelLoading.png', 0
HudPanelImageFile db 'Resources/Textures/HUD/Panel.png', 0
DeathImageFile db 'Resources/Textures/HUD/Death.png', 0
EndImageFile db 'Resources/Textures/HUD/End.png', 0
 
align 4
LevelLoadingImagePtr dd 0
HudPanelImagePtr dd 0
DeathImagePtr dd 0
EndImagePtr dd 0
 
ImageBufferPtr dd 0
 
HudPanelNeedsRedraw dd 0
 
GameMessage dd 0
GameStatus dd 0
 
GAME_STATUS.LEVEL_LOAD_FAILED = 1
GAME_STATUS.DEAD = 2
GAME_STATUS.END = 3
 
ACTION.DO_SOMETHING = AKODE_ACTION.CUSTOM + 1
ACTION.LOOK_AROUND = AKODE_ACTION.CUSTOM + 2
ACTION.USE_OBJECT = AKODE_ACTION.CUSTOM + 3
ACTION.LOOK_AT_OBJECT = AKODE_ACTION.CUSTOM + 4
/programs/games/Dungeons/datadef.inc
--- games/Dungeons/import.inc (nonexistent)
+++ games/Dungeons/import.inc (revision 5312)
@@ -0,0 +1 @@
+include 'AKODE/import.inc'
\ No newline at end of file
/programs/games/Dungeons/lang.inc
0,0 → 1,0
lang fix ru
/programs/games/Dungeons/udata.inc
0,0 → 1,14
include 'AKODE/udata.inc'
 
align 4
StartupPath rb 1024
 
ThreadInfoBuffer process_information
 
MainWindowWidth dd ?
MainWindowHeight dd ?
 
WorldViewHeight dd ?
 
PressedKeys rd 128 * 2
Inventory rq INVENTORY_SIZE