EBLAN_ENGINE/include/engine_lighting_core.inc
Игорь Федосеев aa64510def feat: stabilize fixed-tick simulation
Decouple gameplay from presentation and preserve signed movement fractions. Separate cinematic camera ownership with safe body handoff and transactional current-room restarts.

Resample input latches on focus regain, discard modal timing debt, and attach cinematic lighting to the view to match editor preview.

Verify editor 137/137 and ASM 288/288, cinematic traces, RGB bake and IPC framebuffer parity without changing project assets.
2026-10-31 22:31:20 +03:00

835 lines
17 KiB
PHP

; Versioned authored lighting, RGB shading and exact occlusion traversal.
.code
InitLightingSystem PROTO
BakeMapLighting PROTO
UpdateDynamicLights PROTO
AddLightSource PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
SpawnExplosionLight PROTO :DWORD,:DWORD
SpawnMuzzleFlashLight PROTO :DWORD,:DWORD
CastLightRay PROTO :DWORD,:DWORD,:DWORD,:DWORD
ComputeWallLightLevel PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
ComputeSpriteLight PROTO :DWORD,:DWORD,:DWORD
SamplePointLighting PROTO :DWORD,:DWORD,:DWORD,:DWORD
LightCellFree PROTO :DWORD,:DWORD
RefreshLightGrid PROTO
ValidateLightingData PROC uses ebx ecx edx esi, settings:DWORD,sources:DWORD,count:DWORD
mov esi,settings
cmp DWORD PTR [esi],2
ja vl_invalid
cmp DWORD PTR [esi+4],255
ja vl_invalid
cmp DWORD PTR [esi+8],1
ja vl_invalid
cmp DWORD PTR [esi+12],32
jb vl_invalid
cmp DWORD PTR [esi+12],2048
ja vl_invalid
cmp DWORD PTR [esi+16],255
ja vl_invalid
cmp DWORD PTR [esi+20],1
jb vl_invalid
cmp DWORD PTR [esi+20],96
ja vl_invalid
cmp DWORD PTR [esi+24],1
jne vl_invalid
cmp DWORD PTR [esi+28],0
jne vl_invalid
cmp count,13
ja vl_invalid
mov ecx,count
mov esi,sources
vl_source:
test ecx,ecx
jz vl_valid
cmp [esi].LightSource.x,2048
jae vl_invalid
cmp [esi].LightSource.y,2048
jae vl_invalid
cmp [esi].LightSource.radius,1
jb vl_invalid
cmp [esi].LightSource.radius,2048
ja vl_invalid
cmp [esi].LightSource.intensity,255
ja vl_invalid
cmp [esi].LightSource.curIntensity,255
ja vl_invalid
cmp [esi].LightSource.lightType,1
jbe vl_type_ok
cmp [esi].LightSource.lightType,4
jne vl_invalid
vl_type_ok:
mov eax,[esi].LightSource.flags
and eax,0FFFFFFF8h
jnz vl_invalid
test [esi].LightSource.color,0FF000000h
jnz vl_invalid
add esi,40
dec ecx
jmp vl_source
vl_valid:
mov eax,1
ret
vl_invalid:
xor eax,eax
ret
ValidateLightingData ENDP
InitLightingSystem PROC uses eax ecx edi
mov lightingMode,0
mov ambientLightLevel,40
mov isFlashlightOn,1
mov flashlightRadius,384
mov flashlightIntensity,240
mov flashlightConeAngle,45
mov authoredLightCount,0
mov lightingTick,0
mov edi,OFFSET lightSources
mov ecx,MAX_LIGHTS*10
xor eax,eax
rep stosd
mov edi,OFFSET lightGridRGB
mov ecx,MAP_SIZE
mov eax,00282828h
rep stosd
call RefreshLightGrid
ret
InitLightingSystem ENDP
CommitLightingData PROC uses eax ecx esi edi,settings:DWORD,sources:DWORD,count:DWORD,rgb:DWORD
call InitLightingSystem
mov esi,settings
lodsd
mov lightingMode,eax
lodsd
mov ambientLightLevel,eax
lodsd
mov isFlashlightOn,eax
lodsd
mov flashlightRadius,eax
lodsd
mov flashlightIntensity,eax
lodsd
mov flashlightConeAngle,eax
mov esi,sources
mov edi,OFFSET lightSources+40
mov ecx,count
mov authoredLightCount,ecx
imul ecx,10
rep movsd
mov esi,rgb
mov edi,OFFSET lightGridRGB
mov ecx,MAP_SIZE
rep movsd
call RefreshLightGrid
ret
CommitLightingData ENDP
LightCellFree PROC uses edx,x:DWORD,y:DWORD
cmp x,32
jae lcf_no
cmp y,32
jae lcf_no
mov eax,y
shl eax,5
add eax,x
movzx eax,BYTE PTR [gameMap+eax]
cmp eax,0
je lcf_yes
cmp eax,6
je lcf_yes
cmp eax,10
je lcf_yes
lcf_no:
xor eax,eax
ret
lcf_yes:
mov eax,1
ret
LightCellFree ENDP
; Supercover traversal: test both sides when crossing an exact grid corner.
CastLightRay PROC uses ebx ecx edx esi edi,x1:DWORD,y1:DWORD,x2:DWORD,y2:DWORD
LOCAL cellX:DWORD,cellY:DWORD,ex:DWORD,ey:DWORD,deltaX:DWORD,deltaY:DWORD,sx:DWORD,sy:DWORD,nx:DWORD,ny:DWORD,axv:DWORD
mov eax,x1
or eax,y1
or eax,x2
or eax,y2
test eax,0FFFFF800h
jnz lr_blocked
mov eax,x1
shr eax,6
mov cellX,eax
mov eax,y1
shr eax,6
mov cellY,eax
mov eax,x2
shr eax,6
mov ex,eax
mov eax,y2
shr eax,6
mov ey,eax
mov sx,1
mov eax,x2
sub eax,x1
jns lr_dx
neg eax
mov sx,-1
lr_dx:
mov deltaX,eax
mov sy,1
mov eax,y2
sub eax,y1
jns lr_dy
neg eax
mov sy,-1
lr_dy:
mov deltaY,eax
mov eax,cellX
shl eax,6
cmp sx,1
jne lr_nx_neg
add eax,64
sub eax,x1
jmp lr_nx
lr_nx_neg:
neg eax
add eax,x1
lr_nx:
mov nx,eax
mov eax,cellY
shl eax,6
cmp sy,1
jne lr_ny_neg
add eax,64
sub eax,y1
jmp lr_ny
lr_ny_neg:
neg eax
add eax,y1
lr_ny:
mov ny,eax
mov edi,65
lr_step:
mov eax,cellX
cmp eax,ex
jne lr_cross
mov eax,cellY
cmp eax,ey
je lr_end
lr_cross:
mov eax,3FFFFFFFh
cmp deltaX,0
je lr_a
mov eax,nx
imul eax,deltaY
lr_a:
mov axv,eax
mov eax,3FFFFFFFh
cmp deltaY,0
je lr_b
mov eax,ny
imul eax,deltaX
lr_b:
cmp axv,eax
jb lr_x
ja lr_y
mov eax,cellX
add eax,sx
invoke LightCellFree,eax,cellY
test eax,eax
jz lr_blocked
mov eax,cellY
add eax,sy
invoke LightCellFree,cellX,eax
test eax,eax
jz lr_blocked
mov eax,sx
add cellX,eax
add nx,64
lr_y:
mov eax,sy
add cellY,eax
add ny,64
jmp lr_test
lr_x:
mov eax,sx
add cellX,eax
add nx,64
lr_test:
invoke LightCellFree,cellX,cellY
test eax,eax
jz lr_blocked
dec edi
jnz lr_step
lr_blocked:
xor eax,eax
ret
lr_end:
invoke LightCellFree,cellX,cellY
ret
CastLightRay ENDP
LightDistance PROC uses ebx edx,deltaX:DWORD,deltaY:DWORD
mov eax,deltaX
cdq
xor eax,edx
sub eax,edx
mov ebx,eax
mov eax,deltaY
cdq
xor eax,edx
sub eax,edx
cmp eax,ebx
jae ld_max
xchg eax,ebx
ld_max:
lea ebx,[ebx+ebx*2]
shr ebx,3
add eax,ebx
ret
LightDistance ENDP
AddLightColor PROC uses eax ebx ecx edx,color:DWORD,amount:DWORD
mov ebx,255
mov eax,color
and eax,255
imul eax,amount
xor edx,edx
div ebx
add lightAccumB,eax
mov eax,color
shr eax,8
and eax,255
imul eax,amount
xor edx,edx
div ebx
add lightAccumG,eax
mov eax,color
shr eax,16
and eax,255
imul eax,amount
xor edx,edx
div ebx
add lightAccumR,eax
ret
AddLightColor ENDP
PointLightAmount PROC uses ebx ecx edx esi,source:DWORD,x:DWORD,y:DWORD
LOCAL distance:DWORD
mov esi,source
mov eax,x
sub eax,[esi].LightSource.x
mov ecx,y
sub ecx,[esi].LightSource.y
invoke LightDistance,eax,ecx
mov distance,eax
cmp eax,[esi].LightSource.radius
jae pla_zero
test [esi].LightSource.flags,LIGHT_FLAG_SHADOWS
jz pla_visible
invoke CastLightRay,[esi].LightSource.x,[esi].LightSource.y,x,y
test eax,eax
jz pla_zero
pla_visible:
mov eax,[esi].LightSource.radius
sub eax,distance
imul eax,[esi].LightSource.curIntensity
xor edx,edx
div [esi].LightSource.radius
ret
pla_zero:
xor eax,eax
ret
PointLightAmount ENDP
RefreshLightGrid PROC uses eax ebx ecx edx esi edi
mov esi,OFFSET lightGridRGB
mov edi,OFFSET lightGrid
mov ecx,MAP_SIZE
rlg_loop:
lodsd
mov edx,eax
and eax,255
mov ebx,edx
shr ebx,8
and ebx,255
add eax,ebx
shr edx,16
and edx,255
add eax,edx
xor edx,edx
mov ebx,3
div ebx
stosb
loop rlg_loop
ret
RefreshLightGrid ENDP
PackBakedRGB PROC uses ebx edx
mov eax,lightAccumR
cmp eax,255
jbe @F
mov eax,255
@@:
shl eax,16
mov ebx,eax
mov eax,lightAccumG
cmp eax,255
jbe @F
mov eax,255
@@:
shl eax,8
or ebx,eax
mov eax,lightAccumB
cmp eax,255
jbe @F
mov eax,255
@@:
or eax,ebx
ret
PackBakedRGB ENDP
AccumulateBakedCell PROC uses eax ebx ecx edx,x:DWORD,y:DWORD,weight:DWORD
invoke LightCellFree,x,y
test eax,eax
jz abc_done
mov eax,y
shl eax,5
add eax,x
mov edx,[lightGridRGB+eax*4]
mov eax,edx
and eax,255
imul eax,weight
add lightAccumB,eax
mov eax,edx
shr eax,8
and eax,255
imul eax,weight
add lightAccumG,eax
shr edx,16
imul edx,weight
add lightAccumR,edx
mov eax,weight
add lightWeight,eax
abc_done:
ret
AccumulateBakedCell ENDP
BakeMapLighting PROC uses ebx ecx edx esi edi
LOCAL index:DWORD,x:DWORD,y:DWORD
mov index,0
bl_cell:
mov eax,index
and eax,31
mov x,eax
mov eax,index
shr eax,5
mov y,eax
mov eax,ambientLightLevel
mov lightAccumR,eax
mov lightAccumG,eax
mov lightAccumB,eax
invoke LightCellFree,x,y
test eax,eax
jz bl_store
mov eax,x
shl eax,6
add eax,32
mov x,eax
mov eax,y
shl eax,6
add eax,32
mov y,eax
mov esi,OFFSET lightSources+40
mov edi,13
bl_source:
test [esi].LightSource.flags,LIGHT_FLAG_ACTIVE
jz bl_next_source
cmp [esi].LightSource.lightType,LIGHT_TYPE_STATIC
jne bl_next_source
mov eax,[esi].LightSource.intensity
push [esi].LightSource.curIntensity
mov [esi].LightSource.curIntensity,eax
invoke PointLightAmount,esi,x,y
pop [esi].LightSource.curIntensity
invoke AddLightColor,[esi].LightSource.color,eax
bl_next_source:
add esi,40
dec edi
jnz bl_source
bl_store:
call PackBakedRGB
mov ebx,index
mov [lightGridRGB+ebx*4],eax
inc index
cmp index,MAP_SIZE
jb bl_cell
; Smooth out of place, without averaging through wall cells.
mov index,0
bl_smooth:
mov ebx,index
mov eax,[lightGridRGB+ebx*4]
mov [lightSmoothRGB+ebx*4],eax
mov eax,ebx
and eax,31
mov x,eax
shr ebx,5
mov y,ebx
invoke LightCellFree,x,y
test eax,eax
jz bl_next_smooth
mov lightAccumR,0
mov lightAccumG,0
mov lightAccumB,0
mov lightWeight,0
invoke AccumulateBakedCell,x,y,2
mov eax,x
dec eax
invoke AccumulateBakedCell,eax,y,1
mov eax,x
inc eax
invoke AccumulateBakedCell,eax,y,1
mov eax,y
dec eax
invoke AccumulateBakedCell,x,eax,1
mov eax,y
inc eax
invoke AccumulateBakedCell,x,eax,1
mov eax,lightAccumR
xor edx,edx
div lightWeight
mov lightAccumR,eax
mov eax,lightAccumG
xor edx,edx
div lightWeight
mov lightAccumG,eax
mov eax,lightAccumB
xor edx,edx
div lightWeight
mov lightAccumB,eax
call PackBakedRGB
mov ebx,index
mov [lightSmoothRGB+ebx*4],eax
bl_next_smooth:
inc index
cmp index,MAP_SIZE
jb bl_smooth
mov esi,OFFSET lightSmoothRGB
mov edi,OFFSET lightGridRGB
mov ecx,MAP_SIZE
rep movsd
call RefreshLightGrid
ret
BakeMapLighting ENDP
UpdateDynamicLights PROC uses eax ebx ecx edx esi
inc lightingTick
mov esi,OFFSET lightSources+40
mov ecx,1
udl_next:
test [esi].LightSource.flags,LIGHT_FLAG_ACTIVE
jz udl_skip
cmp [esi].LightSource.lightType,LIGHT_TYPE_BURST
je udl_burst
mov eax,[esi].LightSource.intensity
cmp [esi].LightSource.lightType,LIGHT_TYPE_STATIC
je udl_store
cmp [esi].LightSource.lightType,LIGHT_TYPE_PULSE
jne udl_flicker
mov edx,lightingTick
shl edx,2
add edx,ecx
and edx,511
mov ebx,[tableSin+edx*4]
sar ebx,1
add ebx,98304
imul eax,ebx
sar eax,17
udl_flicker:
test [esi].LightSource.flags,LIGHT_FLAG_FLICKER
jz udl_store
mov edx,lightingTick
shr edx,2
imul edx,1103515245
imul ebx,ecx,12345
add edx,ebx
shr edx,16
and edx,15
sub edx,7
add eax,edx
cmp eax,0
jge @F
xor eax,eax
@@:
cmp eax,255
jle udl_store
mov eax,255
jmp udl_store
udl_burst:
mov eax,[esi].LightSource.curIntensity
sub eax,[esi].LightSource.decaySpeed
jg udl_store
xor eax,eax
mov [esi].LightSource.flags,0
udl_store:
mov [esi].LightSource.curIntensity,eax
udl_skip:
add esi,40
inc ecx
cmp ecx,16
jb udl_next
ret
UpdateDynamicLights ENDP
SamplePointLighting PROC uses ebx ecx edx esi edi,x:DWORD,y:DWORD,distance:DWORD,side:DWORD
LOCAL forward:DWORD,lateral:DWORD,beam:DWORD,atten:DWORD,fog:DWORD
LOCAL originX:DWORD,originY:DWORD,originAngle:DWORD
; Camera-attached flashlight. Cinematics never move the gameplay body, but
; use the same lighting origin as the editor's camera-only preview packet.
mov eax,playerX
mov originX,eax
mov eax,playerY
mov originY,eax
mov eax,playerAngle
mov originAngle,eax
cmp isCutsceneActive,0
je spl_origin_ready
mov eax,csCameraX
mov originX,eax
mov eax,csCameraY
mov originY,eax
mov eax,csCameraAngle
mov originAngle,eax
spl_origin_ready:
mov eax,256
mov lightRed,eax
mov lightGreen,eax
mov lightBlue,eax
cmp lightingMode,0
je spl_done
mov eax,x
sar eax,6
and eax,31
mov edx,y
sar edx,6
and edx,31
shl edx,5
add eax,edx
mov eax,[lightGridRGB+eax*4]
mov edx,eax
and eax,255
mov lightAccumB,eax
mov eax,edx
shr eax,8
and eax,255
mov lightAccumG,eax
shr edx,16
mov lightAccumR,edx
cmp lightingMode,2
jne spl_fog
mov esi,OFFSET lightSources+40
mov edi,15
spl_source:
test [esi].LightSource.flags,LIGHT_FLAG_ACTIVE
jz spl_next
cmp [esi].LightSource.lightType,LIGHT_TYPE_STATIC
je spl_next
cmp [esi].LightSource.radius,0
jle spl_next
invoke PointLightAmount,esi,x,y
invoke AddLightColor,[esi].LightSource.color,eax
spl_next:
add esi,40
dec edi
jnz spl_source
cmp isFlashlightOn,0
je spl_fog
mov eax,x
sub eax,originX
mov ebx,y
sub ebx,originY
invoke LightDistance,eax,ebx
cmp eax,flashlightRadius
jae spl_fog
mov edx,flashlightRadius
sub edx,eax
mov eax,edx
imul eax,flashlightIntensity
xor edx,edx
div flashlightRadius
mov atten,eax
mov ecx,originAngle
and ecx,511
mov eax,x
sub eax,originX
imul [tableCos+ecx*4]
shrd eax,edx,16
mov forward,eax
mov eax,y
sub eax,originY
imul [tableSin+ecx*4]
shrd eax,edx,16
add forward,eax
cmp forward,0
jle spl_fog
mov eax,y
sub eax,originY
imul [tableCos+ecx*4]
shrd eax,edx,16
mov lateral,eax
mov eax,x
sub eax,originX
imul [tableSin+ecx*4]
shrd eax,edx,16
sub lateral,eax
mov ecx,flashlightConeAngle
mov eax,forward
imul [tableSin+ecx*4]
idiv DWORD PTR [tableCos+ecx*4]
mov beam,eax
test eax,eax
jle spl_fog
mov eax,lateral
cdq
xor eax,edx
sub eax,edx
cmp eax,beam
jae spl_fog
mov ebx,beam
sub ebx,eax
mov eax,ebx
imul eax,atten
xor edx,edx
div beam
mov atten,eax
invoke CastLightRay,originX,originY,x,y
test eax,eax
jz spl_fog
invoke AddLightColor,00FFFFFFh,atten
spl_fog:
mov fog,256
mov eax,distance
cmp eax,280
jle spl_side
cmp eax,720
jb spl_partial
mov fog,32
jmp spl_side
spl_partial:
sub eax,280
imul eax,224
xor edx,edx
mov ebx,440
div ebx
sub fog,eax
spl_side:
cmp side,1
jne spl_coeff
mov eax,fog
imul eax,192
shr eax,8
mov fog,eax
spl_coeff:
mov eax,lightAccumR
cmp eax,256
jbe @F
mov eax,256
@@:
imul eax,fog
shr eax,8
mov lightRed,eax
mov eax,lightAccumG
cmp eax,256
jbe @F
mov eax,256
@@:
imul eax,fog
shr eax,8
mov lightGreen,eax
mov eax,lightAccumB
cmp eax,256
jbe @F
mov eax,256
@@:
imul eax,fog
shr eax,8
mov lightBlue,eax
spl_done:
mov eax,lightRed
cmp eax,lightGreen
jae @F
mov eax,lightGreen
@@:
cmp eax,lightBlue
jae @F
mov eax,lightBlue
@@:
ret
SamplePointLighting ENDP
ComputeWallLightLevel PROC uses ebx ecx edx,screenX:DWORD,mapX:DWORD,mapY:DWORD,sideHit:DWORD,stepX:DWORD,stepY:DWORD,rawDist:DWORD,perpWallDist:DWORD,rayAngle:DWORD,rayDirX:DWORD,rayDirY:DWORD
LOCAL x:DWORD,y:DWORD
mov eax,rawDist
imul rayDirX
shrd eax,edx,24
add eax,viewX
mov x,eax
mov eax,rawDist
imul rayDirY
shrd eax,edx,24
add eax,viewY
mov y,eax
cmp sideHit,0
jne cwl_y
mov eax,mapX
shl eax,6
cmp stepX,0
jg @F
add eax,64
@@:
sub eax,stepX
mov x,eax
jmp cwl_ready
cwl_y:
mov eax,mapY
shl eax,6
cmp stepY,0
jg @F
add eax,64
@@:
sub eax,stepY
mov y,eax
cwl_ready:
invoke SamplePointLighting,x,y,perpWallDist,sideHit
ret
ComputeWallLightLevel ENDP
ComputeSpriteLight PROC sprX:DWORD,sprY:DWORD,sprDist:DWORD
invoke SamplePointLighting,sprX,sprY,sprDist,0
ret
ComputeSpriteLight ENDP
ShadeLightPixel PROC uses eax ebx
mov eax,edx
and eax,255
imul eax,lightBlue
shr eax,8
mov ebx,eax
mov eax,edx
shr eax,8
and eax,255
imul eax,lightGreen
shr eax,8
shl eax,8
or ebx,eax
mov eax,edx
shr eax,16
and eax,255
imul eax,lightRed
shr eax,8
shl eax,16
or eax,ebx
mov edx,eax
ret
ShadeLightPixel ENDP