; Static world-space lightmap: built once, sampled without walking the light list. .code AddCityLight3D PROC uses ebx esi edi x:DWORD,y:DWORD,rx:DWORD,ry:DWORD,power:DWORD local gx:DWORD,gy:DWORD,minX:DWORD,maxX:DWORD,maxY:DWORD,dy2:DWORD mov eax, x sub eax, rx jns @F xor eax, eax @@: mov minX, eax mov eax, x add eax, rx cmp eax, CITY_LIGHT_W-1 jle @F mov eax, CITY_LIGHT_W-1 @@: mov maxX, eax mov eax, y sub eax, ry jns @F xor eax, eax @@: mov gy, eax mov eax, y add eax, ry cmp eax, CITY_LIGHT_H-1 jle @F mov eax, CITY_LIGHT_H-1 @@: mov maxY, eax city_light_row: mov eax, gy sub eax, y imul eax, 256 cdq idiv ry imul eax, eax mov dy2, eax mov eax, minX mov gx, eax city_light_cell: mov eax, gx sub eax, x imul eax, 256 cdq idiv rx imul eax, eax add eax, dy2 cmp eax, 65536 jae city_light_next neg eax add eax, 65536 mov ecx, eax mul ecx shrd eax, edx, 16 imul eax, power shr eax, 16 mov ebx, gy shl ebx, 9 add ebx, gx add eax, cityLightMap3D[ebx*4] cmp eax, 320 jbe @F mov eax, 320 @@: mov cityLightMap3D[ebx*4], eax city_light_next: inc gx mov eax, gx cmp eax, maxX jle city_light_cell inc gy mov eax, gy cmp eax, maxY jle city_light_row ret AddCityLight3D ENDP BuildCityLighting3D PROC uses ebx esi edi lea edi, cityLightMap3D xor eax, eax mov ecx, CITY_LIGHT_W*CITY_LIGHT_H rep stosd lea esi, cityObjects3D mov ebx, CITY_PROP_COUNT city_light_lamp: cmp [esi].CityProp3D.asset, OFFSET cityPropsPack3D jne city_light_lamp_next cmp [esi].CityProp3D.frame, 3 jne city_light_lamp_next mov eax, [esi].CityProp3D.posX sar eax, 13 mov edx, [esi].CityProp3D.posY sar edx, 13 invoke AddCityLight3D, eax, edx, 25, 25, 240 city_light_lamp_next: add esi, SIZEOF CityProp3D dec ebx jnz city_light_lamp ; Only genuinely lit windows/storefronts cast a narrower spill across the curb. mov esi, 3 city_light_windows: movzx eax, cityMap3D[11*32+esi] cmp eax, 65 je city_light_near_window cmp eax, 62 jne city_light_far_window city_light_near_window: lea eax, [esi*8+4] invoke AddCityLight3D, eax, 12*8+2, 7, 16, 96 city_light_far_window: movzx eax, cityMap3D[17*32+esi] cmp eax, 65 jne city_light_next_window lea eax, [esi*8+4] invoke AddCityLight3D, eax, 17*8-2, 7, 16, 96 city_light_next_window: inc esi cmp esi, 29 jb city_light_windows ; The casino door is at y=8; this does not illuminate an imaginary closed facade. invoke AddCityLight3D, 22*8+4, 8*8+2, 14, 22, 150 mov cityLightReady3D, 1 ret BuildCityLighting3D ENDP SampleCityLight3D PROC x:DWORD,y:DWORD xor eax, eax cmp cityLighting3D, 0 je city_light_sample_done cmp cityLightReady3D, 0 je city_light_sample_done mov ecx, x sar ecx, 13 cmp ecx, CITY_LIGHT_W jae city_light_sample_zero mov edx, y sar edx, 13 cmp edx, CITY_LIGHT_H jae city_light_sample_zero shl edx, 9 add edx, ecx mov eax, cityLightMap3D[edx*4] ret city_light_sample_zero: xor eax, eax city_light_sample_done: ret SampleCityLight3D ENDP ShadeCityGround3D PROC uses ebx esi edi rgb:DWORD,x:DWORD,y:DWORD,ambient:DWORD invoke SampleCityLight3D, x, y mov esi, eax ; Tint the material itself, retaining paving detail instead of painting a flat glow. mov eax, rgb shr eax, 16 and eax, 255 mov ecx, ambient add ecx, esi imul eax, ecx shr eax, 8 cmp eax, 255 jbe @F mov eax, 255 @@: shl eax, 16 mov edi, eax mov eax, rgb shr eax, 8 and eax, 255 mov ecx, esi imul ecx, 3 shr ecx, 2 add ecx, ambient imul eax, ecx shr eax, 8 cmp eax, 255 jbe @F mov eax, 255 @@: shl eax, 8 or edi, eax mov eax, rgb and eax, 255 mov ecx, esi shr ecx, 2 add ecx, ambient imul eax, ecx shr eax, 8 cmp eax, 255 jbe @F mov eax, 255 @@: or eax, edi ret ShadeCityGround3D ENDP ; Bright warm panes and lantern glass emit light; dark windows/brick do not. IsCityEmissive3D PROC uses ebx rgb:DWORD,material:DWORD cmp cityLighting3D, 0 je city_not_emissive mov eax, material cmp eax, 58 je city_emissive_color cmp eax, 62 je city_emissive_color cmp eax, 65 je city_emissive_color cmp eax, 70 jne city_not_emissive city_emissive_color: mov eax, rgb shr eax, 16 and eax, 255 cmp eax, 180 jb city_not_emissive mov edx, rgb shr edx, 8 and edx, 255 cmp edx, 96 jb city_not_emissive sub eax, edx cmp eax, 32 jl city_not_emissive mov ebx, rgb and ebx, 255 sub edx, ebx cmp edx, 24 jl city_not_emissive mov eax, 1 ret city_not_emissive: xor eax, eax ret IsCityEmissive3D ENDP