; 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