KAZIK/src_graphics/rooftop_details.inc
Artvasil09 41ba8f46ed feat: add rooftop city and optimize native terrace rendering
Add rooftop elevator, lounge, volumetric city, river and animated traffic. Prune invisible mesh faces, clip CPU surfaces, streamline compositing and add automatic/F8 roof quality profiles with renderer diagnostics.

Include dartboard/reticle improvements, tracked fortune orb numerals and fate-session visuals, native regression tests, compatible jukebox IDs and updated shipping executables.
2026-10-26 23:20:35 +03:00

1496 lines
33 KiB
PHP

; Native ray/ellipsoid intersection supplies rounded cushions and copper domes.
DrawRoofEllipsoid3D PROC uses ebx esi edi centreX:DWORD,centreY:DWORD,centreZ:DWORD,radiusX:DWORD,radiusY:DWORD,radiusZ:DWORD,material:DWORD
local leftPx:DWORD,rightPx:DWORD,topPx:DWORD,bottomPx:DWORD,column:DWORD,row:DWORD
local centrePx:DWORD,centreDepth:DWORD,pixelDepth:DWORD,temp:DWORD,texU:DWORD,texV:DWORD
local texture:DWORD,texWidth:DWORD,texHeight:DWORD,shade:DWORD,color:DWORD
local ox:REAL4,oy:REAL4,oz:REAL4,rayX:REAL4,rayY:REAL4,rayZ:REAL4
local quadraticC:REAL4,quadraticA:REAL4,quadraticB:REAL4,discriminant:REAL4,hitTime:REAL4
invoke ResolveCitySurface3D,material
test eax,eax
jz roof_round_done
mov texture,eax
mov texWidth,ecx
mov texHeight,edx
invoke ProjectCityPoint3D,centreX,centreY
cmp edx,FP_1/8
jle roof_round_done
mov centrePx,eax
mov centreDepth,edx
mov eax,radiusX
add eax,radiusY
imul eax,SCREEN_H
cdq
idiv centreDepth
mov ecx,centrePx
sub ecx,eax
mov leftPx,ecx
add eax,centrePx
mov rightPx,eax
mov eax,viewEye3D
sub eax,centreZ
sub eax,radiusZ
imul eax,SCREEN_H
cdq
idiv centreDepth
add eax,viewHorizon3D
sub eax,4
mov topPx,eax
mov eax,viewEye3D
sub eax,centreZ
add eax,radiusZ
imul eax,SCREEN_H
cdq
idiv centreDepth
add eax,viewHorizon3D
add eax,4
mov bottomPx,eax
cmp leftPx,0
jge @F
mov leftPx,0
@@:
cmp rightPx,SCREEN_W-1
jle @F
mov rightPx,SCREEN_W-1
@@:
cmp topPx,0
jge @F
mov topPx,0
@@:
cmp bottomPx,SCREEN_H-1
jle @F
mov bottomPx,SCREEN_H-1
@@:
mov eax,leftPx
cmp eax,rightPx
jge roof_round_done
mov eax,topPx
cmp eax,bottomPx
jge roof_round_done
mov eax,playerX
sub eax,centreX
mov temp,eax
fild temp
fidiv radiusX
fstp ox
mov eax,playerY
sub eax,centreY
mov temp,eax
fild temp
fidiv radiusY
fstp oy
mov eax,viewEye3D
sub eax,centreZ
mov temp,eax
fild temp
fidiv radiusZ
fstp oz
fld ox
fmul st,st
fld oy
fmul st,st
faddp st(1),st
fld oz
fmul st,st
faddp st(1),st
fld1
fsubp st(1),st
fstp quadraticC
mov eax,topPx
mov row,eax
roof_round_row:
mov eax,viewHorizon3D
sub eax,row
mov temp,eax
fild temp
fmul roofFloatFP3D
fdiv roofFloat4803D
fidiv radiusZ
fstp rayZ
mov eax,row
imul eax,SCREEN_W*4
mov ebx,leftPx
lea edi,[eax+ebx*4]
mov column,ebx
roof_round_pixel:
mov ebx,column
fild cityRayX3D[ebx*4]
fidiv radiusX
fstp rayX
fild cityRayY3D[ebx*4]
fidiv radiusY
fstp rayY
fld rayX
fmul st,st
fld rayY
fmul st,st
faddp st(1),st
fld rayZ
fmul st,st
faddp st(1),st
fstp quadraticA
fld rayX
fmul ox
fld rayY
fmul oy
faddp st(1),st
fld rayZ
fmul oz
faddp st(1),st
fstp quadraticB
fld quadraticB
fmul st,st
fld quadraticA
fmul quadraticC
fsubp st(1),st
fst discriminant
ftst
fnstsw ax
sahf
fstp st(0)
jb roof_round_next
fld discriminant
fsqrt
fadd quadraticB
fchs
fdiv quadraticA
fst hitTime
fmul roofFloatFP3D
fistp pixelDepth
mov eax,pixelDepth
cmp eax,4096
jle roof_round_next
cmp eax,cityDepthBuffer3D[edi]
jae roof_round_next
fld hitTime
fmul rayX
fadd ox
fld1
faddp st(1),st
fmul roofFloatHalfTex3D
fistp texU
fld hitTime
fmul rayZ
fadd oz
fchs
fld1
faddp st(1),st
fmul roofFloatHalfTex3D
fistp texV
fld hitTime
fmul rayZ
fadd oz
fmul roofFloatShade3D
fadd roofFloatAmbient3D
fistp shade
mov eax,texV
and eax,255
mov ecx,texHeight
imul eax,ecx
shr eax,8
imul eax,texWidth
mov edx,texU
and edx,255
imul edx,texWidth
shr edx,8
add eax,edx
mov esi,texture
mov eax,[esi+eax*4]
mov color,eax
movzx eax,al
imul eax,shade
shr eax,8
mov ebx,eax
mov eax,color
shr eax,8
and eax,255
imul eax,shade
and eax,0FF00h
or ebx,eax
mov eax,color
shr eax,16
and eax,255
imul eax,shade
and eax,0FF00h
shl eax,8
or eax,ebx
cmp roofCityPass3D,0
je roof_round_color_ready
invoke ShadeRoofCityPixel3D,eax,pixelDepth,256,material
mov ecx,edi
shr ecx,2
mov edx,roofPixelGlow3D
mov roofGlowMask3D[ecx],dl
roof_round_color_ready:
mov screenBuffer[edi],eax
cmp hallLevel3D,HALL_ROOF
jne @F
mov ecx,edi
shr ecx,2
mov edx,roofCityPass3D
mov roofCityMask3D[ecx],dl
@@:
mov eax,pixelDepth
mov cityDepthBuffer3D[edi],eax
roof_round_next:
add edi,4
inc column
mov eax,column
cmp eax,rightPx
jbe roof_round_pixel
inc row
mov eax,row
cmp eax,bottomPx
jbe roof_round_row
roof_round_done:
ret
DrawRoofEllipsoid3D ENDP
; Closed furniture parts use material surfaces, never pictures of whole chairs.
DrawRoofSolid3D PROC uses ebx esi x0:DWORD,x1:DWORD,y0:DWORD,y1:DWORD,z0:DWORD,z1:DWORD,mat:DWORD
mov eax,x0
cmp playerX,eax
jge @F
invoke DrawCityVertical3D,0,x0,y0,y1,z0,z1,mat
@@:
mov eax,x1
cmp playerX,eax
jle @F
invoke DrawCityVertical3D,0,x1,y0,y1,z0,z1,mat
@@:
mov eax,y0
cmp playerY,eax
jge @F
invoke DrawCityVertical3D,1,y0,x0,x1,z0,z1,mat
@@:
mov eax,y1
cmp playerY,eax
jle @F
invoke DrawCityVertical3D,1,y1,x0,x1,z0,z1,mat
@@:
mov eax,z1
cmp viewEye3D,eax
jle @F
invoke DrawCityHorizontal3D,x0,x1,y0,y1,z1,mat
@@:
ret
DrawRoofSolid3D ENDP
DrawRoofPadding3D PROC uses ebx esi edi centreX:DWORD,centreY:DWORD,centreZ:DWORD,rx:DWORD,ry:DWORD,rz:DWORD,mat:DWORD
local x0:DWORD,x1:DWORD,y0:DWORD,y1:DWORD,z0:DWORD,z1:DWORD
local insetX0:DWORD,insetX1:DWORD,insetY0:DWORD,insetY1:DWORD,loZ:DWORD,hiZ:DWORD
mov eax,centreX
sub eax,rx
mov x0,eax
add eax,FP_1*35/1000
mov insetX0,eax
mov eax,centreX
add eax,rx
mov x1,eax
sub eax,FP_1*35/1000
mov insetX1,eax
mov eax,centreY
sub eax,ry
mov y0,eax
add eax,FP_1*35/1000
mov insetY0,eax
mov eax,centreY
add eax,ry
mov y1,eax
sub eax,FP_1*35/1000
mov insetY1,eax
mov eax,centreZ
sub eax,rz
mov z0,eax
add eax,FP_1*35/1000
mov loZ,eax
mov eax,centreZ
add eax,rz
mov z1,eax
sub eax,FP_1*35/1000
mov hiZ,eax
invoke DrawRoofSolid3D,insetX0,insetX1,insetY0,insetY1,z0,z1,mat
invoke DrawRoofSolid3D,x0,x1,insetY0,insetY1,loZ,hiZ,mat
invoke DrawRoofSolid3D,insetX0,insetX1,y0,y1,loZ,hiZ,mat
ret
DrawRoofPadding3D ENDP
DrawRoofUpholstery3D PROC uses ebx esi edi centreX:DWORD,frontY:DWORD,kind:DWORD
local x0:DWORD,x1:DWORD,y1:DWORD,halfWidth:DWORD,count:DWORD,seatZ:DWORD,backZ:DWORD
local xa:DWORD,xb:DWORD,ya:DWORD,yb:DWORD,za:DWORD,zb:DWORD
mov halfWidth,FP_1*120/100
mov count,3
mov seatZ,FP_1*45/100
mov backZ,FP_1*92/100
mov ecx,FP_1*90/100
cmp kind,0
je @F
mov halfWidth,FP_1*46/100
mov count,1
mov ecx,FP_1*86/100
cmp kind,2
jb @F
mov halfWidth,FP_1*27/100
mov seatZ,FP_1*78/100
mov backZ,FP_1*108/100
mov ecx,FP_1*48/100
@@:
mov eax,centreX
sub eax,halfWidth
mov x0,eax
mov eax,centreX
add eax,halfWidth
mov x1,eax
mov eax,frontY
add eax,ecx
mov y1,eax
; Four metal feet, solid armrests, a seat base and separate upholstered pads.
xor esi,esi
roof_furniture_foot:
mov eax,x0
add eax,FP_1*8/100
test esi,1
jz @F
mov eax,x1
sub eax,FP_1*12/100
@@:
mov xa,eax
add eax,FP_1*4/100
mov xb,eax
mov eax,frontY
add eax,FP_1*8/100
test esi,2
jz @F
mov eax,y1
sub eax,FP_1*12/100
@@:
mov ya,eax
add eax,FP_1*4/100
mov yb,eax
mov eax,seatZ
sub eax,FP_1*12/100
invoke DrawRoofSolid3D,xa,xb,ya,yb,0,eax,ROOF_METAL
inc esi
cmp esi,4
jb roof_furniture_foot
mov eax,seatZ
sub eax,FP_1*14/100
mov za,eax
add eax,FP_1*5/100
invoke DrawRoofSolid3D,x0,x1,frontY,y1,za,eax,ROOF_TEAL
mov eax,y1
sub eax,FP_1*14/100
mov ya,eax
invoke DrawRoofSolid3D,x0,x1,ya,y1,seatZ,backZ,ROOF_TEAL
mov eax,x0
add eax,FP_1*12/100
mov xa,eax
mov eax,x1
sub eax,FP_1*12/100
mov xb,eax
; Soft rectangular cushion edges are inset in three shallow bands.
xor esi,esi
roof_furniture_pad:
mov eax,xb
sub eax,xa
xor edx,edx
div count
mov edi,eax
imul eax,esi
add eax,xa
add eax,FP_1/100
mov ebx,eax
add ebx,edi
sub ebx,FP_1*2/100
mov ecx,frontY
add ecx,FP_1*5/100
mov edx,y1
sub edx,FP_1*16/100
mov za,eax
mov zb,ebx
mov ya,ecx
mov yb,edx
mov eax,seatZ
sub eax,FP_1*9/100
mov eax,za
add eax,zb
sar eax,1
mov ebx,zb
sub ebx,za
sar ebx,1
mov ecx,ya
add ecx,yb
sar ecx,1
mov edx,yb
sub edx,ya
sar edx,1
mov edi,seatZ
sub edi,FP_1*4/100
invoke DrawRoofPadding3D,eax,ecx,edi,ebx,edx,FP_1*8/100,ROOF_IVORY
mov eax,za
add eax,FP_1*2/100
mov ebx,zb
sub ebx,FP_1*2/100
mov ecx,ya
add ecx,FP_1*2/100
mov edx,yb
sub edx,FP_1*2/100
mov ya,ecx
mov yb,edx
mov ecx,seatZ
add ecx,FP_1*2/100
; Back cushions are real thin volumes, not alpha views pasted on each side.
mov eax,y1
sub eax,FP_1*22/100
mov ya,eax
add eax,FP_1*9/100
mov yb,eax
mov eax,seatZ
add eax,FP_1*2/100
mov ecx,backZ
sub ecx,FP_1*3/100
add eax,ecx
sar eax,1
mov edi,eax
mov eax,za
add eax,zb
sar eax,1
mov ebx,zb
sub ebx,za
sar ebx,1
mov ecx,ya
add ecx,yb
sar ecx,1
invoke DrawRoofPadding3D,eax,ecx,edi,ebx,FP_1*9/100,FP_1*23/100,ROOF_IVORY
inc esi
cmp esi,count
jb roof_furniture_pad
cmp kind,2
jae roof_furniture_done
mov eax,seatZ
add eax,FP_1*17/100
mov zb,eax
mov eax,x0
add eax,FP_1*11/100
invoke DrawRoofSolid3D,x0,eax,frontY,y1,seatZ,zb,ROOF_TEAL
mov eax,x1
sub eax,FP_1*11/100
invoke DrawRoofSolid3D,eax,x1,frontY,y1,seatZ,zb,ROOF_TEAL
roof_furniture_done:
ret
DrawRoofUpholstery3D ENDP
DrawRoofPlanter3D PROC uses ebx esi x0:DWORD,x1:DWORD,y0:DWORD,y1:DWORD
local xa:DWORD,xb:DWORD,ya:DWORD,yb:DWORD
invoke DrawRoofSolid3D,x0,x1,y0,y1,0,FP_1*42/100,ROOF_STONE
mov eax,x0
add eax,FP_1*4/100
mov xa,eax
mov eax,x1
sub eax,FP_1*4/100
mov xb,eax
mov eax,y0
add eax,FP_1*4/100
mov ya,eax
mov eax,y1
sub eax,FP_1*4/100
mov yb,eax
invoke DrawCityHorizontal3D,xa,xb,ya,yb,FP_1*425/1000,ROOF_EARTH
; Several separated foliage tufts give the bed depth from either end.
mov esi,xa
roof_planter_tuft:
mov ebx,esi
add ebx,FP_1*34/100
cmp ebx,xb
jae roof_planter_done
mov eax,ya
add eax,FP_1*10/100
invoke DrawCityVertical3D,1,eax,esi,ebx,FP_1*43/100,FP_1*85/100,ROOF_FOLIAGE
mov eax,yb
sub eax,FP_1*10/100
invoke DrawCityVertical3D,1,eax,esi,ebx,FP_1*43/100,FP_1*78/100,ROOF_FOLIAGE
mov eax,esi
add eax,FP_1*17/100
invoke DrawCityVertical3D,0,eax,ya,yb,FP_1*43/100,FP_1*85/100,ROOF_FOLIAGE
add esi,FP_1*38/100
jmp roof_planter_tuft
roof_planter_done:
ret
DrawRoofPlanter3D ENDP
UpdateRoofGuests3D PROC uses ebx esi edi milliseconds:DWORD
local px:DWORD,py:DWORD,stepSize:DWORD,savedSeat:DWORD,savedLean:DWORD
mov eax,milliseconds
add roofGuestClock3D,eax
imul eax,38
mov stepSize,eax
mov eax,roofSeat3D
mov savedSeat,eax
mov eax,roofLean3D
mov savedLean,eax
mov roofSeat3D,0
mov roofLean3D,0
xor esi,esi
roof_person_update:
mov roofGuestMoving3D[esi*4],0
mov eax,milliseconds
cmp roofGuestWait3D[esi*4],eax
jbe roof_person_step
sub roofGuestWait3D[esi*4],eax
jmp roof_person_next
roof_person_step:
mov roofGuestWait3D[esi*4],0
mov eax,roofGuestX3D[esi*4]
mov px,eax
mov eax,roofGuestY3D[esi*4]
mov py,eax
mov eax,roofGuestDir3D[esi*4]
mov ebx,stepSize
cmp eax,0
jne @F
add px,ebx
jmp roof_person_check
@@:
cmp eax,1
jne @F
sub px,ebx
jmp roof_person_check
@@:
cmp eax,2
jne @F
add py,ebx
jmp roof_person_check
@@:
sub py,ebx
roof_person_check:
invoke RoofCanWalk3D,px,py
test eax,eax
jz roof_person_turn
mov eax,px
sub eax,playerX
cdq
xor eax,edx
sub eax,edx
mov ebx,eax
mov eax,py
sub eax,playerY
cdq
xor eax,edx
sub eax,edx
add eax,ebx
cmp eax,FP_1*7/10
jb roof_person_turn
mov eax,px
mov roofGuestX3D[esi*4],eax
mov eax,py
mov roofGuestY3D[esi*4],eax
mov roofGuestMoving3D[esi*4],1
mov eax,stepSize
add roofGuestDistance3D[esi*4],eax
add roofGuestStep3D[esi*4],eax
cmp roofGuestStep3D[esi*4],FP_1*18/10
jb roof_person_next
roof_person_turn:
mov roofGuestStep3D[esi*4],0
mov roofGuestWait3D[esi*4],1700
inc roofGuestDir3D[esi*4]
and roofGuestDir3D[esi*4],3
roof_person_next:
inc esi
cmp esi,ROOF_GUEST_COUNT
jb roof_person_update
mov eax,savedSeat
mov roofSeat3D,eax
mov eax,savedLean
mov roofLean3D,eax
ret
UpdateRoofGuests3D ENDP
CheckRoofRail3D PROC
mov roofLeanSide3D,-1
cmp playerY,FP_1*191/10
jb @F
cmp playerAngle,64
jb @F
cmp playerAngle,192
ja @F
mov roofLeanSide3D,0
@@:
cmp playerX,FP_1*272/10
jb @F
mov eax,playerAngle
add eax,64
and eax,511
cmp eax,128
ja @F
mov roofLeanSide3D,1
@@:
cmp playerX,FP_1*128/10
ja @F
cmp playerAngle,192
jb @F
cmp playerAngle,320
ja @F
; The western drinks counter is not a handrail approach.
cmp playerY,11*FP_1
jb roof_check_west_rail
cmp playerY,17*FP_1
jbe @F
roof_check_west_rail:
mov roofLeanSide3D,2
@@:
cmp roofLeanSide3D,-1
je @F
mov interactTargetId,INTERACT_ROOF_RAIL
mov interactPromptPtr,OFFSET roofLeanPrompt3D
@@:
ret
CheckRoofRail3D ENDP
StartRoofLean3D PROC
mov eax,playerX
mov roofReturnX3D,eax
mov eax,playerY
mov roofReturnY3D,eax
mov eax,playerAngle
mov roofReturnAngle3D,eax
mov roofLeanAngle3D,128
mov eax,playerX
mov edx,FP_1*1975/100
cmp roofLeanSide3D,0
je roof_start_lean_check
mov eax,FP_1*2775/100
mov edx,playerY
mov roofLeanAngle3D,0
cmp roofLeanSide3D,1
je roof_start_lean_check
mov eax,FP_1*1225/100
mov roofLeanAngle3D,256
roof_start_lean_check:
push eax
push edx
invoke RoofCanWalk3D,eax,edx
mov ecx,eax
pop edx
pop eax
test ecx,ecx
jz roof_start_lean_done
mov playerX,eax
mov playerY,edx
mov eax,roofLeanAngle3D
mov playerAngle,eax
mov roofLean3D,1
mov roofLeanTime3D,0
call UpdateCamera3D
roof_start_lean_done:
ret
StartRoofLean3D ENDP
UpdateRoofLook3D PROC
cmp roofLean3D,0
je roof_look_done
mov eax,playerAngle
sub eax,roofLeanAngle3D
add eax,256
and eax,511
sub eax,256
cmp eax,104
jle @F
mov eax,104
@@:
cmp eax,-104
jge @F
mov eax,-104
@@:
add eax,roofLeanAngle3D
and eax,511
mov playerAngle,eax
call UpdateCamera3D
roof_look_done:
ret
UpdateRoofLook3D ENDP
RenderRoofLean3D PROC uses ebx esi
local anchorX:DWORD,anchorY:DWORD,depth:DWORD,left:DWORD,widthPx:DWORD,heightPx:DWORD
cmp roofLean3D,0
je roof_hands_done
cmp engineMode,MODE_WALK
jne roof_hands_done
mov eax,roofLeanTime3D
imul eax,31
xor edx,edx
mov ecx,1100
div ecx
mov esi,eax
; Project the fixed rail contact instead of rotating the hands with the head.
mov ebx,roofLeanAngle3D
and ebx,511
mov eax,tableCos[ebx*4]
mov ecx,FP_1*115/100
imul ecx
shrd eax,edx,16
add eax,playerX
mov anchorX,eax
mov eax,tableSin[ebx*4]
imul ecx
shrd eax,edx,16
add eax,playerY
mov anchorY,eax
invoke ProjectCityPoint3D,anchorX,anchorY
cmp edx,FP_1/5
jle roof_hands_done
mov depth,edx
mov left,eax
mov roofHandsContactX3D,eax
mov eax,640*FP_1*115/100
cdq
idiv depth
mov widthPx,eax
mov roofHandsWidth3D,eax
shr eax,1
sub left,eax
mov eax,widthPx
shr eax,1
mov heightPx,eax
mov eax,viewEye3D
sub eax,ROOF_RAIL_HEIGHT
imul eax,480
cdq
idiv depth
add eax,viewHorizon3D
mov ebx,eax
mov eax,widthPx
imul eax,166
xor edx,edx
mov ecx,640
div ecx
sub ebx,eax
invoke DrawRoofHandsPlane3D,esi,left,widthPx
roof_hands_done:
ret
RenderRoofLean3D ENDP
; Keep the forearms in the first-person view; shear their contact line onto the rail.
DrawRoofHandsPlane3D PROC uses ebx esi edi frame:DWORD,left:DWORD,scaleW:DWORD
local source:DWORD,col:DWORD,normalX:DWORD,normalY:DWORD,denom:DWORD
local depth:DWORD,srcX:DWORD,srcY:DWORD,stepY:DWORD,row:DWORD,lastRow:DWORD
local extension:DWORD,shiftDown:DWORD
cmp roofHandsArt3D.pixels,0
je roof_hands_plane_done
mov eax,frame
cmp eax,roofHandsArt3D.frames
jae roof_hands_plane_done
imul eax,640*320*4
add eax,roofHandsArt3D.pixels
mov source,eax
mov eax,roofLeanAngle3D
and eax,511
mov ecx,tableCos[eax*4]
mov normalX,ecx
mov ecx,tableSin[eax*4]
mov normalY,ecx
mov eax,FP_1*640
cdq
idiv scaleW
mov stepY,eax
mov col,0
roof_hands_plane_column:
cmp col,640
jge roof_hands_plane_done
mov esi,col
mov eax,cityRayX3D[esi*4]
imul normalX
shrd eax,edx,16
mov ebx,eax
mov eax,cityRayY3D[esi*4]
imul normalY
shrd eax,edx,16
add eax,ebx
cmp eax,FP_1/12
jle roof_hands_plane_next
mov denom,eax
mov eax,FP_1*115/100
mov ecx,FP_1
imul ecx
idiv denom
cmp eax,16*FP_1
jge roof_hands_plane_next
mov depth,eax
mov eax,col
sub eax,left
imul eax,640
cdq
idiv scaleW
mov extension,0
mov shiftDown,0
cmp eax,8
jge roof_hands_check_right_edge
mov eax,scaleW
xor edx,edx
mov ecx,80
div ecx
add eax,left
sub eax,col
mov shiftDown,eax
mov extension,1
mov eax,8
jmp roof_hands_source_column
roof_hands_check_right_edge:
cmp eax,632
jl roof_hands_source_column
mov eax,scaleW
imul eax,632
xor edx,edx
mov ecx,640
div ecx
add eax,left
mov ecx,col
sub ecx,eax
mov shiftDown,ecx
mov extension,1
mov eax,631
roof_hands_source_column:
mov srcX,eax
mov eax,viewEye3D
sub eax,ROOF_RAIL_HEIGHT
imul eax,480
cdq
idiv depth
add eax,viewHorizon3D
mov ebx,eax
mov eax,scaleW
imul eax,166
xor edx,edx
mov ecx,640
div ecx
sub ebx,eax
mov eax,shiftDown
add ebx,eax
mov denom,ebx
mov eax,ebx
test eax,eax
jns @F
xor eax,eax
@@:
cmp eax,480
jge roof_hands_plane_next
mov row,eax
mov eax,scaleW
shr eax,1
add eax,denom
cmp eax,480
jle @F
mov eax,480
@@:
mov lastRow,eax
cmp extension,0
je @F
mov lastRow,480
@@:
mov eax,row
sub eax,denom
imul eax,stepY
mov srcY,eax
mov eax,row
imul eax,640*4
mov edi,col
lea edi,[eax+edi*4]
mov ebx,srcX
shl ebx,2
add ebx,source
roof_hands_plane_pixel:
mov eax,row
cmp eax,lastRow
jge roof_hands_plane_next
mov edx,srcY
sar edx,16
cmp extension,0
je @F
cmp edx,314
jl @F
mov edx,313
@@:
cmp edx,320
jae roof_hands_plane_advance
imul edx,640*4
mov eax,[ebx+edx]
cmp eax,80000000h
jb roof_hands_plane_advance
and eax,00FFFFFFh
mov screenBuffer[edi],eax
mov eax,edi
shr eax,2
mov roofCityMask3D[eax],0
roof_hands_plane_advance:
mov eax,stepY
add srcY,eax
add edi,640*4
inc row
jmp roof_hands_plane_pixel
roof_hands_plane_next:
inc col
cmp col,640
jb roof_hands_plane_column
roof_hands_plane_done:
ret
DrawRoofHandsPlane3D ENDP
ShadeRoofNight3D PROC uses ebx esi edi
cmp roofNight3D,0
je roof_night_done
; Sky is already night artwork. Only shade actual depth-tested world pixels.
xor edi,edi
roof_night_pixel:
mov eax,edi
shr eax,2
cmp roofCityMask3D[eax],0
jne roof_night_next
cmp cityDepthBuffer3D[edi],ROOF_FAR_DEPTH
jae roof_night_next
mov eax,screenBuffer[edi]
mov edx,eax
and edx,000000FFh
cmp edx,90
ja @F
mov edx,eax
shr edx,16
cmp edx,110
ja roof_night_next
@@:
and eax,00FCFCFCh
shr eax,2
add eax,00070D1Dh
mov screenBuffer[edi],eax
roof_night_next:
add edi,4
cmp edi,SCREEN_SIZE*4
jb roof_night_pixel
roof_night_done:
ret
ShadeRoofNight3D ENDP
PrepareRoofFloorDepth3D PROC uses ebx esi edi
local row:DWORD,depth:DWORD,px:DWORD,py:DWORD,deltaX:DWORD,deltaY:DWORD
mov eax,viewHorizon3D
inc eax
mov row,eax
roof_floor_depth_row:
mov ecx,row
sub ecx,viewHorizon3D
mov eax,viewEye3D
imul eax,SCREEN_H
cdq
idiv ecx
mov depth,eax
imul cityRayX3D[0]
shrd eax,edx,16
add eax,playerX
mov px,eax
mov eax,depth
imul cityRayY3D[0]
shrd eax,edx,16
add eax,playerY
mov py,eax
mov eax,depth
imul playerPlaneX
shrd eax,edx,16
shl eax,1
cdq
mov ecx,SCREEN_W
idiv ecx
mov deltaX,eax
mov eax,depth
imul playerPlaneY
shrd eax,edx,16
shl eax,1
cdq
idiv ecx
mov deltaY,eax
mov eax,row
imul eax,SCREEN_W*4
mov edi,eax
xor ebx,ebx
roof_floor_depth_pixel:
cmp px,FP_1*109/10
jl roof_floor_depth_next
cmp px,FP_1*291/10
jge roof_floor_depth_next
cmp py,FP_1*9/10
jl roof_floor_depth_next
cmp py,FP_1*211/10
jge roof_floor_depth_next
mov eax,depth
mov cityDepthBuffer3D[edi],eax
mov eax,edi
shr eax,2
mov roofCityMask3D[eax],0
cmp roofHDReady3D,1
jne roof_floor_depth_next
cmp engineMode,MODE_WALK
jne roof_floor_depth_next
mov roofCityMask3D[eax],3
roof_floor_depth_next:
mov eax,deltaX
add px,eax
mov eax,deltaY
add py,eax
add edi,4
inc ebx
cmp ebx,SCREEN_W
jb roof_floor_depth_pixel
inc row
cmp row,SCREEN_H
jb roof_floor_depth_row
ret
PrepareRoofFloorDepth3D ENDP
RenderRoofDistrict3D PROC uses ebx esi edi
local x0:DWORD,x1:DWORD,y0:DWORD,y1:DWORD,z:DWORD,mat:DWORD,roofZ:DWORD
local screenX:DWORD,centreDepth:DWORD,middle:DWORD,ridgeZ:DWORD
xor esi,esi
roof_district_building:
imul edi,esi,28
mov eax,roofDistrict3D[edi]
mov x0,eax
mov eax,roofDistrict3D[edi+4]
mov x1,eax
add eax,x0
sar eax,1
mov ebx,roofDistrict3D[edi+8]
mov y0,ebx
mov ecx,roofDistrict3D[edi+12]
mov y1,ecx
add ebx,ecx
sar ebx,1
invoke ProjectCityPoint3D,eax,ebx
cmp edx,-12*FP_1
jle roof_district_next
mov centreDepth,edx
mov screenX,eax
cmp edx,12*FP_1
jle roof_district_visible
mov eax,x1
sub eax,x0
add eax,y1
sub eax,y0
imul eax,SCREEN_H
cdq
idiv centreDepth
mov edx,screenX
add edx,eax
cmp edx,0
jl roof_district_next
neg eax
add eax,screenX
cmp eax,SCREEN_W
jg roof_district_next
roof_district_visible:
mov eax,roofDistrict3D[edi+16]
mov z,eax
mov eax,roofDistrict3D[edi+20]
mov mat,eax
invoke DrawCityBoxSides3D,x0,x1,y0,y1,ROOF_CITY_STREET_Z,z,mat
mov eax,z
add eax,FP_1/6
mov roofZ,eax
invoke DrawRoofSolid3D,x0,x1,y0,y1,z,eax,ROOF_PLASTER
cmp mat,ROOF_MODERN_FACADE
jae roof_city_flat_roof
cmp centreDepth,100*FP_1
jle @F
roof_city_flat_roof:
mov eax,roofZ
add eax,FP_1/20
invoke DrawCityHorizontal3D,x0,x1,y0,y1,eax,ROOF_CITY_ROOF
jmp roof_district_next
@@:
; Stepped low mansards, dormers and chimneys give the skyline real parallax.
mov ebx,x0
add ebx,FP_1*6/10
mov ecx,x1
sub ecx,FP_1*6/10
mov edx,y0
add edx,FP_1*6/10
mov eax,y1
sub eax,FP_1*6/10
mov x0,ebx
mov x1,ecx
mov y0,edx
mov y1,eax
mov eax,roofZ
add eax,FP_1*24/10
mov ridgeZ,eax
mov eax,x1
sub eax,x0
mov edx,y1
sub edx,y0
cmp eax,edx
ja roof_mansard_ridge_x
mov eax,x0
add eax,x1
sar eax,1
mov middle,eax
invoke DrawRoofSlope3D,0,x0,middle,y0,y1,roofZ,FP_1*24/10,ROOF_CITY_ROOF
invoke DrawRoofSlope3D,0,middle,x1,y0,y1,ridgeZ,-FP_1*24/10,ROOF_CITY_ROOF
jmp roof_mansard_chimney
roof_mansard_ridge_x:
mov eax,y0
add eax,y1
sar eax,1
mov middle,eax
invoke DrawRoofSlope3D,1,x0,x1,y0,middle,roofZ,FP_1*24/10,ROOF_CITY_ROOF
invoke DrawRoofSlope3D,1,x0,x1,middle,y1,ridgeZ,-FP_1*24/10,ROOF_CITY_ROOF
roof_mansard_chimney:
mov eax,ridgeZ
mov roofZ,eax
mov eax,x0
add eax,FP_1/2
mov ebx,y0
add ebx,FP_1/2
mov ecx,z
add ecx,FP_1*24/10
invoke DrawRoofSolid3D,x0,eax,y0,ebx,roofZ,ecx,ROOF_STONE
roof_district_next:
inc esi
cmp esi,ROOF_BUILDING_COUNT
jb roof_district_building
ret
RenderRoofDistrict3D ENDP
RenderRoofCityGround3D PROC uses ebx esi edi
local row:DWORD,depth:DWORD,px:DWORD,py:DWORD,deltaX:DWORD,deltaY:DWORD
local road:DWORD,stone:DWORD,water:DWORD,tex:DWORD,ix:DWORD,iy:DWORD
local sampleDepth:DWORD,planeHeight:DWORD,waterHeight:DWORD
mov eax,viewEye3D
sub eax,ROOF_CITY_STREET_Z
mov planeHeight,eax
add eax,2*FP_1
mov waterHeight,eax
invoke ResolveRoofSurface3D,ROOF_CITY_ROAD
mov road,eax
invoke ResolveRoofSurface3D,ROOF_CITY_WATER
mov water,eax
invoke ResolveRoofSurface3D,ROOF_STONE
mov stone,eax
cmp road,0
jne @F
mov road,0FFFFFFFFh
@@:
cmp water,0
jne @F
mov water,0FFFFFFFDh
@@:
cmp stone,0
jne @F
mov stone,0FFFFFFFEh
@@:
mov roofGroundRoadPixels3D,0
mov roofGroundWaterPixels3D,0
mov eax,viewHorizon3D
inc eax
mov row,eax
roof_city_ground_row:
mov ecx,row
sub ecx,viewHorizon3D
mov eax,viewEye3D
sub eax,ROOF_CITY_STREET_Z
imul eax,SCREEN_H
cdq
idiv ecx
cmp eax,ROOF_FAR_DEPTH
jae roof_city_ground_next_row
mov depth,eax
imul cityRayX3D[0]
shrd eax,edx,16
add eax,playerX
mov px,eax
mov eax,depth
imul cityRayY3D[0]
shrd eax,edx,16
add eax,playerY
mov py,eax
mov eax,depth
imul playerPlaneX
shrd eax,edx,16
shl eax,1
cdq
mov ecx,SCREEN_W
idiv ecx
mov deltaX,eax
mov eax,depth
imul playerPlaneY
shrd eax,edx,16
shl eax,1
cdq
idiv ecx
mov deltaY,eax
mov eax,row
imul eax,SCREEN_W*4
mov edi,eax
xor ebx,ebx
roof_city_ground_pixel:
mov eax,depth
mov sampleDepth,eax
cmp px,-600*FP_1
jl roof_city_ground_advance
cmp px,600*FP_1
jg roof_city_ground_advance
cmp py,-600*FP_1
jl roof_city_ground_advance
cmp py,600*FP_1
jg roof_city_ground_advance
mov eax,depth
cmp eax,cityDepthBuffer3D[edi]
jae roof_city_ground_advance
mov eax,px
sar eax,16
sub eax,20
cdq
mov ecx,36
idiv ecx
test edx,edx
jns @F
add edx,36
@@:
mov ix,edx
mov eax,py
sar eax,16
sub eax,11
cdq
idiv ecx
test edx,edx
jns @F
add edx,36
@@:
mov iy,edx
mov eax,road
mov tex,eax
; Narrow stone pavements border the connected eight-metre carriageways.
cmp ix,13
jb roof_city_ground_y_street
cmp ix,23
ja roof_city_ground_y_street
cmp ix,14
jb roof_city_ground_pavement
cmp ix,22
ja roof_city_ground_pavement
jmp roof_city_ground_canal
roof_city_ground_y_street:
cmp iy,13
jb roof_city_ground_pavement
cmp iy,23
ja roof_city_ground_pavement
cmp iy,14
jb roof_city_ground_pavement
cmp iy,22
jbe roof_city_ground_canal
roof_city_ground_pavement:
mov eax,stone
mov tex,eax
roof_city_ground_canal:
cmp py,29*FP_1
jl roof_city_ground_sample
cmp py,76*FP_1
jg roof_city_ground_sample
cmp py,60*FP_1
jge roof_city_old_channel
cmp px,70*FP_1
jl roof_city_ground_sample
jmp roof_city_new_bridges
roof_city_old_channel:
mov eax,px
add eax,34*FP_1
add eax,3*FP_1
cmp eax,6*FP_1
jbe roof_city_ground_sample
mov eax,px
sub eax,38*FP_1-3*FP_1
cmp eax,6*FP_1
jbe roof_city_ground_sample
roof_city_new_bridges:
mov eax,px
sub eax,110*FP_1-3*FP_1
cmp eax,6*FP_1
jbe roof_city_ground_sample
mov eax,px
sub eax,254*FP_1-3*FP_1
cmp eax,6*FP_1
jbe roof_city_ground_sample
mov eax,px
sub eax,398*FP_1-3*FP_1
cmp eax,6*FP_1
jbe roof_city_ground_sample
roof_city_ground_water:
mov eax,water
mov tex,eax
mov eax,depth
imul waterHeight
idiv planeHeight
mov sampleDepth,eax
roof_city_ground_sample:
mov eax,py
sar eax,9
and eax,511
shl eax,9
mov edx,px
sar edx,9
and edx,511
add eax,edx
mov esi,tex
cmp esi,stone
jne @F
shr eax,2
and eax,65535
@@:
cmp esi,0FFFFFFFDh
jb roof_city_ground_texel
mov eax,00343B42h
cmp esi,0FFFFFFFFh
je roof_city_ground_texel_ready
mov eax,0063686Ah
cmp esi,0FFFFFFFEh
je roof_city_ground_texel_ready
mov eax,00183848h
jmp roof_city_ground_texel_ready
roof_city_ground_texel:
mov eax,[esi+eax*4]
roof_city_ground_texel_ready:
and eax,00FFFFFFh
cmp esi,road
jne @F
inc roofGroundRoadPixels3D
@@:
cmp esi,water
jne roof_city_ground_lighting
inc roofGroundWaterPixels3D
cmp roofNight3D,0
je @F
mov eax,006E6E6Eh
jmp roof_city_ground_lighting
@@:
mov edx,px
sar edx,11
add edx,animationClock3D
shr edx,4
and edx,31
cmp edx,3
ja roof_city_ground_lighting
add eax,0020160Ch
roof_city_ground_lighting:
invoke SampleRoofGroundLight3D,eax,px,py
invoke ShadeRoofCityPixel3D,eax,sampleDepth,225,ROOF_CITY_ROAD
mov screenBuffer[edi],eax
mov eax,edi
shr eax,2
mov roofCityMask3D[eax],1
mov eax,sampleDepth
mov cityDepthBuffer3D[edi],eax
roof_city_ground_advance:
mov eax,deltaX
add px,eax
mov eax,deltaY
add py,eax
add edi,4
inc ebx
cmp ebx,SCREEN_W
jb roof_city_ground_pixel
roof_city_ground_next_row:
inc row
cmp row,SCREEN_H
jb roof_city_ground_row
; Continuous stone quays and three traversing bridge decks.
invoke DrawCityBoxSides3D,-190*FP_1,230*FP_1,59*FP_1,60*FP_1,ROOF_CITY_STREET_Z-2*FP_1,ROOF_CITY_STREET_Z,ROOF_STONE
invoke DrawCityBoxSides3D,-190*FP_1,230*FP_1,76*FP_1,77*FP_1,ROOF_CITY_STREET_Z-2*FP_1,ROOF_CITY_STREET_Z,ROOF_STONE
mov esi,-34*FP_1
mov ebx,3
roof_city_bridge:
mov eax,esi
sub eax,3*FP_1
mov edx,esi
add edx,3*FP_1
invoke DrawCityHorizontal3D,eax,edx,59*FP_1,77*FP_1,ROOF_CITY_STREET_Z,ROOF_CITY_ROAD
add esi,72*FP_1
dec ebx
jnz roof_city_bridge
roof_city_ground_done:
ret
RenderRoofCityGround3D ENDP
RenderRoofLandmarks3D PROC uses ebx esi edi
mov roofLandmarkLight3D,1
lea esi,roofLandmarkParts3D
mov ebx,ROOF_LANDMARK_PARTS
roof_landmark_piece:
cmp DWORD PTR [esi],0
jne roof_landmark_round
invoke DrawRoofSolid3D,[esi+4],[esi+8],[esi+12],[esi+16],[esi+20],[esi+24],[esi+28]
jmp roof_landmark_next
roof_landmark_round:
cmp DWORD PTR [esi],2
jne @F
invoke DrawRoofPyramid3D,[esi+4],[esi+8],[esi+12],[esi+16],[esi+20],[esi+24],[esi+28]
jmp roof_landmark_next
@@:
invoke DrawRoofEllipsoid3D,[esi+4],[esi+8],[esi+12],[esi+16],[esi+20],[esi+24],[esi+28]
roof_landmark_next:
add esi,32
dec ebx
jnz roof_landmark_piece
mov roofLandmarkLight3D,0
ret
RenderRoofLandmarks3D ENDP
RenderRoofCityParks3D PROC uses ebx esi edi
local px:DWORD,py:DWORD,x0:DWORD,x1:DWORD,y0:DWORD,y1:DWORD,treeX:DWORD,treeY:DWORD
xor esi,esi
roof_city_park:
mov eax,roofCityParks3D[esi*8]
mov px,eax
sub eax,12*FP_1
mov x0,eax
add eax,24*FP_1
mov x1,eax
mov eax,roofCityParks3D[esi*8+4]
mov py,eax
sub eax,12*FP_1
mov y0,eax
add eax,24*FP_1
mov y1,eax
invoke DrawCityHorizontal3D,x0,x1,y0,y1,ROOF_CITY_STREET_Z+FP_1/20,ROOF_CITY_LAWN
mov eax,px
sub eax,FP_1
mov edx,px
add edx,FP_1
invoke DrawCityHorizontal3D,eax,edx,y0,y1,ROOF_CITY_STREET_Z+FP_1/10,ROOF_STONE
xor ebx,ebx
roof_city_park_tree:
mov eax,px
sub eax,8*FP_1
test ebx,1
jz @F
add eax,16*FP_1
@@:
mov treeX,eax
mov eax,ebx
shr eax,1
imul eax,8*FP_1
add eax,py
sub eax,8*FP_1
mov treeY,eax
mov eax,treeX
sub eax,FP_1/8
mov edx,treeX
add edx,FP_1/8
mov ecx,treeY
sub ecx,FP_1/8
mov edi,treeY
add edi,FP_1/8
invoke DrawRoofSolid3D,eax,edx,ecx,edi,ROOF_CITY_STREET_Z,ROOF_CITY_STREET_Z+3*FP_1,ROOF_STONE
invoke DrawRoofEllipsoid3D,treeX,treeY,ROOF_CITY_STREET_Z+4*FP_1,FP_1*18/10,FP_1*18/10,FP_1*22/10,ROOF_CITY_LAWN
inc ebx
cmp ebx,6
jb roof_city_park_tree
inc esi
cmp esi,ROOF_PARK_COUNT
jb roof_city_park
ret
RenderRoofCityParks3D ENDP