File: | Lighting.c |
Warning: | line 168, column 15 The result of the left shift is undefined because the left operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include "Lighting.h" | ||||
2 | #include "Block.h" | ||||
3 | #include "Funcs.h" | ||||
4 | #include "MapRenderer.h" | ||||
5 | #include "Platform.h" | ||||
6 | #include "World.h" | ||||
7 | #include "Logger.h" | ||||
8 | #include "Event.h" | ||||
9 | #include "Game.h" | ||||
10 | |||||
11 | cc_int16* Lighting_Heightmap; | ||||
12 | #define HEIGHT_UNCALCULATED((cc_int16)32767) Int16_MaxValue((cc_int16)32767) | ||||
13 | |||||
14 | #define Lighting_CalcBody(get_block)for (y = maxY; y >= 0; y--, i -= World.OneY) { block = get_block ; if (Blocks.BlocksLight[block]) { offset = (Blocks.LightOffset [block] >> FACE_YMAX) & 1; Lighting_Heightmap[hIndex ] = y - offset; return y - offset; }}\ | ||||
15 | for (y = maxY; y >= 0; y--, i -= World.OneY) {\ | ||||
16 | block = get_block;\ | ||||
17 | \ | ||||
18 | if (Blocks.BlocksLight[block]) {\ | ||||
19 | offset = (Blocks.LightOffset[block] >> FACE_YMAX) & 1;\ | ||||
20 | Lighting_Heightmap[hIndex] = y - offset;\ | ||||
21 | return y - offset;\ | ||||
22 | }\ | ||||
23 | } | ||||
24 | |||||
25 | static int Lighting_CalcHeightAt(int x, int maxY, int z, int hIndex) { | ||||
26 | int i = World_Pack(x, maxY, z)(((maxY) * World.Length + (z)) * World.Width + (x)); | ||||
27 | BlockID block; | ||||
28 | int y, offset; | ||||
29 | |||||
30 | #ifndef EXTENDED_BLOCKS | ||||
31 | Lighting_CalcBody(World.Blocks[i])for (y = maxY; y >= 0; y--, i -= World.OneY) { block = World .Blocks[i]; if (Blocks.BlocksLight[block]) { offset = (Blocks .LightOffset[block] >> FACE_YMAX) & 1; Lighting_Heightmap [hIndex] = y - offset; return y - offset; }}; | ||||
32 | #else | ||||
33 | if (World.IDMask <= 0xFF) { | ||||
34 | Lighting_CalcBody(World.Blocks[i])for (y = maxY; y >= 0; y--, i -= World.OneY) { block = World .Blocks[i]; if (Blocks.BlocksLight[block]) { offset = (Blocks .LightOffset[block] >> FACE_YMAX) & 1; Lighting_Heightmap [hIndex] = y - offset; return y - offset; }}; | ||||
35 | } else { | ||||
36 | Lighting_CalcBody(World.Blocks[i] | (World.Blocks2[i] << 8))for (y = maxY; y >= 0; y--, i -= World.OneY) { block = World .Blocks[i] | (World.Blocks2[i] << 8); if (Blocks.BlocksLight [block]) { offset = (Blocks.LightOffset[block] >> FACE_YMAX ) & 1; Lighting_Heightmap[hIndex] = y - offset; return y - offset; }}; | ||||
37 | } | ||||
38 | #endif | ||||
39 | |||||
40 | Lighting_Heightmap[hIndex] = -10; | ||||
41 | return -10; | ||||
42 | } | ||||
43 | |||||
44 | static int Lighting_GetLightHeight(int x, int z) { | ||||
45 | int hIndex = Lighting_Pack(x, z)((x) + World.Width * (z)); | ||||
46 | int lightH = Lighting_Heightmap[hIndex]; | ||||
47 | return lightH == HEIGHT_UNCALCULATED((cc_int16)32767) ? Lighting_CalcHeightAt(x, World.Height - 1, z, hIndex) : lightH; | ||||
48 | } | ||||
49 | |||||
50 | /* Outside colour is same as sunlight colour, so we reuse when possible */ | ||||
51 | cc_bool Lighting_IsLit(int x, int y, int z) { | ||||
52 | return y > Lighting_GetLightHeight(x, z); | ||||
53 | } | ||||
54 | |||||
55 | PackedCol Lighting_Col(int x, int y, int z) { | ||||
56 | return y > Lighting_GetLightHeight(x, z) ? Env.SunCol : Env.ShadowCol; | ||||
57 | } | ||||
58 | |||||
59 | PackedCol Lighting_Col_XSide(int x, int y, int z) { | ||||
60 | return y > Lighting_GetLightHeight(x, z) ? Env.SunXSide : Env.ShadowXSide; | ||||
61 | } | ||||
62 | |||||
63 | PackedCol Lighting_Col_Sprite_Fast(int x, int y, int z) { | ||||
64 | return y > Lighting_Heightmap[Lighting_Pack(x, z)((x) + World.Width * (z))] ? Env.SunCol : Env.ShadowCol; | ||||
65 | } | ||||
66 | |||||
67 | PackedCol Lighting_Col_YMax_Fast(int x, int y, int z) { | ||||
68 | return y > Lighting_Heightmap[Lighting_Pack(x, z)((x) + World.Width * (z))] ? Env.SunCol : Env.ShadowCol; | ||||
69 | } | ||||
70 | |||||
71 | PackedCol Lighting_Col_YMin_Fast(int x, int y, int z) { | ||||
72 | return y > Lighting_Heightmap[Lighting_Pack(x, z)((x) + World.Width * (z))] ? Env.SunYMin : Env.ShadowYMin; | ||||
73 | } | ||||
74 | |||||
75 | PackedCol Lighting_Col_XSide_Fast(int x, int y, int z) { | ||||
76 | return y > Lighting_Heightmap[Lighting_Pack(x, z)((x) + World.Width * (z))] ? Env.SunXSide : Env.ShadowXSide; | ||||
77 | } | ||||
78 | |||||
79 | PackedCol Lighting_Col_ZSide_Fast(int x, int y, int z) { | ||||
80 | return y > Lighting_Heightmap[Lighting_Pack(x, z)((x) + World.Width * (z))] ? Env.SunZSide : Env.ShadowZSide; | ||||
81 | } | ||||
82 | |||||
83 | void Lighting_Refresh(void) { | ||||
84 | int i; | ||||
85 | for (i = 0; i < World.Width * World.Length; i++) { | ||||
86 | Lighting_Heightmap[i] = HEIGHT_UNCALCULATED((cc_int16)32767); | ||||
87 | } | ||||
88 | } | ||||
89 | |||||
90 | |||||
91 | /*########################################################################################################################* | ||||
92 | *----------------------------------------------------Lighting update------------------------------------------------------* | ||||
93 | *#########################################################################################################################*/ | ||||
94 | static void Lighting_UpdateLighting(int x, int y, int z, BlockID oldBlock, BlockID newBlock, int index, int lightH) { | ||||
95 | cc_bool didBlock = Blocks.BlocksLight[oldBlock]; | ||||
96 | cc_bool nowBlocks = Blocks.BlocksLight[newBlock]; | ||||
97 | int oldOffset = (Blocks.LightOffset[oldBlock] >> FACE_YMAX) & 1; | ||||
98 | int newOffset = (Blocks.LightOffset[newBlock] >> FACE_YMAX) & 1; | ||||
99 | BlockID above; | ||||
100 | |||||
101 | /* Two cases we need to handle here: */ | ||||
102 | if (didBlock == nowBlocks) { | ||||
103 | if (!didBlock) return; /* a) both old and new block do not block light */ | ||||
104 | if (oldOffset == newOffset) return; /* b) both blocks blocked light at the same Y coordinate */ | ||||
105 | } | ||||
106 | |||||
107 | if ((y - newOffset) >= lightH) { | ||||
108 | if (nowBlocks) { | ||||
109 | Lighting_Heightmap[index] = y - newOffset; | ||||
110 | } else { | ||||
111 | /* Part of the column is now visible to light, we don't know how exactly how high it should be though. */ | ||||
112 | /* However, we know that if the old block was above or equal to light height, then the new light height must be <= old block.y */ | ||||
113 | Lighting_CalcHeightAt(x, y, z, index); | ||||
114 | } | ||||
115 | } else if (y == lightH && oldOffset == 0) { | ||||
116 | /* For a solid block on top of an upside down slab, they will both have the same light height. */ | ||||
117 | /* So we need to account for this particular case. */ | ||||
118 | above = y == (World.Height - 1) ? BLOCK_AIR : World_GetBlock(x, y + 1, z); | ||||
119 | if (Blocks.BlocksLight[above]) return; | ||||
120 | |||||
121 | if (nowBlocks) { | ||||
122 | Lighting_Heightmap[index] = y - newOffset; | ||||
123 | } else { | ||||
124 | Lighting_CalcHeightAt(x, y - 1, z, index); | ||||
125 | } | ||||
126 | } | ||||
127 | } | ||||
128 | |||||
129 | static cc_bool Lighting_Needs(BlockID block, BlockID other) { | ||||
130 | return Blocks.Draw[block] != DRAW_OPAQUE || Blocks.Draw[other] != DRAW_GAS; | ||||
131 | } | ||||
132 | |||||
133 | #define Lighting_NeedsNeighourBody(get_block)for (; y >= minY; y--, i -= World.OneY) { other = get_block ; affected = y == nY ? Lighting_Needs(block, other) : Blocks. Draw[other] != DRAW_GAS; if (affected) return 1;}\ | ||||
134 | /* Update if any blocks in the chunk are affected by light change. */ \ | ||||
135 | for (; y >= minY; y--, i -= World.OneY) {\ | ||||
136 | other = get_block;\ | ||||
137 | affected = y == nY ? Lighting_Needs(block, other) : Blocks.Draw[other] != DRAW_GAS;\ | ||||
138 | if (affected) return true1;\ | ||||
139 | } | ||||
140 | |||||
141 | static cc_bool Lighting_NeedsNeighour(BlockID block, int i, int minY, int y, int nY) { | ||||
142 | BlockID other; | ||||
143 | cc_bool affected; | ||||
144 | |||||
145 | #ifndef EXTENDED_BLOCKS | ||||
146 | Lighting_NeedsNeighourBody(World.Blocks[i])for (; y >= minY; y--, i -= World.OneY) { other = World.Blocks [i]; affected = y == nY ? Lighting_Needs(block, other) : Blocks .Draw[other] != DRAW_GAS; if (affected) return 1;}; | ||||
147 | #else | ||||
148 | if (World.IDMask <= 0xFF) { | ||||
149 | Lighting_NeedsNeighourBody(World.Blocks[i])for (; y >= minY; y--, i -= World.OneY) { other = World.Blocks [i]; affected = y == nY ? Lighting_Needs(block, other) : Blocks .Draw[other] != DRAW_GAS; if (affected) return 1;}; | ||||
150 | } else { | ||||
151 | Lighting_NeedsNeighourBody(World.Blocks[i] | (World.Blocks2[i] << 8))for (; y >= minY; y--, i -= World.OneY) { other = World.Blocks [i] | (World.Blocks2[i] << 8); affected = y == nY ? Lighting_Needs (block, other) : Blocks.Draw[other] != DRAW_GAS; if (affected ) return 1;}; | ||||
152 | } | ||||
153 | #endif | ||||
154 | return false0; | ||||
155 | } | ||||
156 | |||||
157 | static void Lighting_ResetNeighbour(int x, int y, int z, BlockID block, int cx, int cy, int cz, int minCy, int maxCy) { | ||||
158 | int minY, maxY; | ||||
159 | |||||
160 | if (minCy
| ||||
161 | minY = cy << CHUNK_SHIFT4; | ||||
162 | |||||
163 | if (Lighting_NeedsNeighour(block, World_Pack(x, y, z)(((y) * World.Length + (z)) * World.Width + (x)), minY, y, y)) { | ||||
164 | MapRenderer_RefreshChunk(cx, cy, cz); | ||||
165 | } | ||||
166 | } else { | ||||
167 | for (cy = maxCy; cy
| ||||
168 | minY = (cy << CHUNK_SHIFT4); | ||||
| |||||
169 | maxY = (cy << CHUNK_SHIFT4) + CHUNK_MAX15; | ||||
170 | if (maxY > World.MaxY) maxY = World.MaxY; | ||||
171 | |||||
172 | if (Lighting_NeedsNeighour(block, World_Pack(x, maxY, z)(((maxY) * World.Length + (z)) * World.Width + (x)), minY, maxY, y)) { | ||||
173 | MapRenderer_RefreshChunk(cx, cy, cz); | ||||
174 | } | ||||
175 | } | ||||
176 | } | ||||
177 | } | ||||
178 | |||||
179 | static void Lighting_ResetColumn(int cx, int cy, int cz, int minCy, int maxCy) { | ||||
180 | if (minCy == maxCy) { | ||||
181 | MapRenderer_RefreshChunk(cx, cy, cz); | ||||
182 | } else { | ||||
183 | for (cy = maxCy; cy >= minCy; cy--) { | ||||
184 | MapRenderer_RefreshChunk(cx, cy, cz); | ||||
185 | } | ||||
186 | } | ||||
187 | } | ||||
188 | |||||
189 | static void Lighting_RefreshAffected(int x, int y, int z, BlockID block, int oldHeight, int newHeight) { | ||||
190 | int cx = x >> CHUNK_SHIFT4, bX = x & CHUNK_MASK15; | ||||
191 | int cy = y >> CHUNK_SHIFT4, bY = y & CHUNK_MASK15; | ||||
192 | int cz = z >> CHUNK_SHIFT4, bZ = z & CHUNK_MASK15; | ||||
193 | |||||
194 | /* NOTE: much faster to only update the chunks that are affected by the change in shadows, rather than the entire column. */ | ||||
195 | int newCy = newHeight < 0 ? 0 : newHeight >> 4; | ||||
196 | int oldCy = oldHeight < 0 ? 0 : oldHeight >> 4; | ||||
197 | int minCy = min(oldCy, newCy)((oldCy) < (newCy) ? (oldCy) : (newCy)), maxCy = max(oldCy, newCy)((oldCy) > (newCy) ? (oldCy) : (newCy)); | ||||
198 | Lighting_ResetColumn(cx, cy, cz, minCy, maxCy); | ||||
199 | |||||
200 | if (bX == 0 && cx > 0) { | ||||
201 | Lighting_ResetNeighbour(x - 1, y, z, block, cx - 1, cy, cz, minCy, maxCy); | ||||
202 | } | ||||
203 | if (bY == 0 && cy > 0 && Lighting_Needs(block, World_GetBlock(x, y - 1, z))) { | ||||
204 | MapRenderer_RefreshChunk(cx, cy - 1, cz); | ||||
205 | } | ||||
206 | if (bZ == 0 && cz > 0) { | ||||
207 | Lighting_ResetNeighbour(x, y, z - 1, block, cx, cy, cz - 1, minCy, maxCy); | ||||
208 | } | ||||
209 | |||||
210 | if (bX == 15 && cx < MapRenderer_ChunksX - 1) { | ||||
211 | Lighting_ResetNeighbour(x + 1, y, z, block, cx + 1, cy, cz, minCy, maxCy); | ||||
212 | } | ||||
213 | if (bY == 15 && cy < MapRenderer_ChunksY - 1 && Lighting_Needs(block, World_GetBlock(x, y + 1, z))) { | ||||
214 | MapRenderer_RefreshChunk(cx, cy + 1, cz); | ||||
215 | } | ||||
216 | if (bZ == 15 && cz < MapRenderer_ChunksZ - 1) { | ||||
217 | Lighting_ResetNeighbour(x, y, z + 1, block, cx, cy, cz + 1, minCy, maxCy); | ||||
218 | } | ||||
219 | } | ||||
220 | |||||
221 | void Lighting_OnBlockChanged(int x, int y, int z, BlockID oldBlock, BlockID newBlock) { | ||||
222 | int hIndex = Lighting_Pack(x, z)((x) + World.Width * (z)); | ||||
223 | int lightH = Lighting_Heightmap[hIndex]; | ||||
224 | int newHeight; | ||||
225 | |||||
226 | /* Since light wasn't checked to begin with, means column never had meshes for any of its chunks built. */ | ||||
227 | /* So we don't need to do anything. */ | ||||
228 | if (lightH == HEIGHT_UNCALCULATED((cc_int16)32767)) return; | ||||
| |||||
229 | |||||
230 | Lighting_UpdateLighting(x, y, z, oldBlock, newBlock, hIndex, lightH); | ||||
231 | newHeight = Lighting_Heightmap[hIndex] + 1; | ||||
232 | Lighting_RefreshAffected(x, y, z, newBlock, lightH + 1, newHeight); | ||||
233 | } | ||||
234 | |||||
235 | |||||
236 | /*########################################################################################################################* | ||||
237 | *---------------------------------------------------Lighting heightmap----------------------------------------------------* | ||||
238 | *#########################################################################################################################*/ | ||||
239 | static int Lighting_InitialHeightmapCoverage(int x1, int z1, int xCount, int zCount, int* skip) { | ||||
240 | int elemsLeft = 0, index = 0, curRunCount = 0; | ||||
241 | int x, z, hIndex, lightH; | ||||
242 | |||||
243 | for (z = 0; z < zCount; z++) { | ||||
244 | hIndex = Lighting_Pack(x1, z1 + z)((x1) + World.Width * (z1 + z)); | ||||
245 | for (x = 0; x < xCount; x++) { | ||||
246 | lightH = Lighting_Heightmap[hIndex++]; | ||||
247 | |||||
248 | skip[index] = 0; | ||||
249 | if (lightH == HEIGHT_UNCALCULATED((cc_int16)32767)) { | ||||
250 | elemsLeft++; | ||||
251 | curRunCount = 0; | ||||
252 | } else { | ||||
253 | skip[index - curRunCount]++; | ||||
254 | curRunCount++; | ||||
255 | } | ||||
256 | index++; | ||||
257 | } | ||||
258 | curRunCount = 0; /* We can only skip an entire X row at most. */ | ||||
259 | } | ||||
260 | return elemsLeft; | ||||
261 | } | ||||
262 | |||||
263 | #define Lighting_CalculateBody(get_block)for (y = World.Height - 1; y >= 0; y--) { if (elemsLeft <= 0) { return 1; } mapIndex = (((y) * World.Length + (z1)) * World .Width + (x1)); hIndex = ((x1) + World.Width * (z1)); for (z = 0; z < zCount; z++) { baseIndex = mapIndex; index = z * xCount ; for (x = 0; x < xCount;) { curRunCount = skip[index]; x += curRunCount; mapIndex += curRunCount; index += curRunCount; if (x < xCount && Blocks.BlocksLight[get_block]) { lightOffset = (Blocks.LightOffset[get_block] >> FACE_YMAX) & 1 ; Lighting_Heightmap[hIndex + x] = (cc_int16)(y - lightOffset ); elemsLeft--; skip[index] = 0; offset = prevRunCount + curRunCount ; newRunCount = skip[index - offset] + 1; oldRunCount = (x - offset + newRunCount) < xCount ? skip[index - offset + newRunCount ] : 0; if (oldRunCount != 0) { skip[index - offset + newRunCount ] = 0; newRunCount += oldRunCount; } skip[index - offset] = newRunCount ; x += oldRunCount; index += oldRunCount; mapIndex += oldRunCount ; prevRunCount = newRunCount; } else { prevRunCount = 0; } x++ ; mapIndex++; index++; } prevRunCount = 0; hIndex += World.Width ; mapIndex = baseIndex + World.Width; }}\ | ||||
264 | for (y = World.Height - 1; y >= 0; y--) {\ | ||||
265 | if (elemsLeft <= 0) { return true1; } \ | ||||
266 | mapIndex = World_Pack(x1, y, z1)(((y) * World.Length + (z1)) * World.Width + (x1));\ | ||||
267 | hIndex = Lighting_Pack(x1, z1)((x1) + World.Width * (z1));\ | ||||
268 | \ | ||||
269 | for (z = 0; z < zCount; z++) {\ | ||||
270 | baseIndex = mapIndex;\ | ||||
271 | index = z * xCount;\ | ||||
272 | for (x = 0; x < xCount;) {\ | ||||
273 | curRunCount = skip[index];\ | ||||
274 | x += curRunCount; mapIndex += curRunCount; index += curRunCount;\ | ||||
275 | \ | ||||
276 | if (x < xCount && Blocks.BlocksLight[get_block]) {\ | ||||
277 | lightOffset = (Blocks.LightOffset[get_block] >> FACE_YMAX) & 1;\ | ||||
278 | Lighting_Heightmap[hIndex + x] = (cc_int16)(y - lightOffset);\ | ||||
279 | elemsLeft--;\ | ||||
280 | skip[index] = 0;\ | ||||
281 | \ | ||||
282 | offset = prevRunCount + curRunCount;\ | ||||
283 | newRunCount = skip[index - offset] + 1;\ | ||||
284 | \ | ||||
285 | /* consider case 1 0 1 0, where we are at last 0 */ \ | ||||
286 | /* we need to make this 3 0 0 0 and advance by 1 */ \ | ||||
287 | oldRunCount = (x - offset + newRunCount) < xCount ? skip[index - offset + newRunCount] : 0; \ | ||||
288 | if (oldRunCount != 0) {\ | ||||
289 | skip[index - offset + newRunCount] = 0; \ | ||||
290 | newRunCount += oldRunCount; \ | ||||
291 | } \ | ||||
292 | skip[index - offset] = newRunCount; \ | ||||
293 | x += oldRunCount; index += oldRunCount; mapIndex += oldRunCount; \ | ||||
294 | prevRunCount = newRunCount; \ | ||||
295 | } else { \ | ||||
296 | prevRunCount = 0; \ | ||||
297 | }\ | ||||
298 | x++; mapIndex++; index++; \ | ||||
299 | }\ | ||||
300 | prevRunCount = 0;\ | ||||
301 | hIndex += World.Width;\ | ||||
302 | mapIndex = baseIndex + World.Width; /* advance one Z */ \ | ||||
303 | }\ | ||||
304 | } | ||||
305 | |||||
306 | static cc_bool Lighting_CalculateHeightmapCoverage(int x1, int z1, int xCount, int zCount, int elemsLeft, int* skip) { | ||||
307 | int prevRunCount = 0, curRunCount, newRunCount, oldRunCount; | ||||
308 | int lightOffset, offset; | ||||
309 | int mapIndex, hIndex, baseIndex, index; | ||||
310 | int x, y, z; | ||||
311 | |||||
312 | #ifndef EXTENDED_BLOCKS | ||||
313 | Lighting_CalculateBody(World.Blocks[mapIndex])for (y = World.Height - 1; y >= 0; y--) { if (elemsLeft <= 0) { return 1; } mapIndex = (((y) * World.Length + (z1)) * World .Width + (x1)); hIndex = ((x1) + World.Width * (z1)); for (z = 0; z < zCount; z++) { baseIndex = mapIndex; index = z * xCount ; for (x = 0; x < xCount;) { curRunCount = skip[index]; x += curRunCount; mapIndex += curRunCount; index += curRunCount; if (x < xCount && Blocks.BlocksLight[World.Blocks[mapIndex ]]) { lightOffset = (Blocks.LightOffset[World.Blocks[mapIndex ]] >> FACE_YMAX) & 1; Lighting_Heightmap[hIndex + x ] = (cc_int16)(y - lightOffset); elemsLeft--; skip[index] = 0 ; offset = prevRunCount + curRunCount; newRunCount = skip[index - offset] + 1; oldRunCount = (x - offset + newRunCount) < xCount ? skip[index - offset + newRunCount] : 0; if (oldRunCount != 0) { skip[index - offset + newRunCount] = 0; newRunCount += oldRunCount; } skip[index - offset] = newRunCount; x += oldRunCount ; index += oldRunCount; mapIndex += oldRunCount; prevRunCount = newRunCount; } else { prevRunCount = 0; } x++; mapIndex++; index++; } prevRunCount = 0; hIndex += World.Width; mapIndex = baseIndex + World.Width; }}; | ||||
314 | #else | ||||
315 | if (World.IDMask <= 0xFF) { | ||||
316 | Lighting_CalculateBody(World.Blocks[mapIndex])for (y = World.Height - 1; y >= 0; y--) { if (elemsLeft <= 0) { return 1; } mapIndex = (((y) * World.Length + (z1)) * World .Width + (x1)); hIndex = ((x1) + World.Width * (z1)); for (z = 0; z < zCount; z++) { baseIndex = mapIndex; index = z * xCount ; for (x = 0; x < xCount;) { curRunCount = skip[index]; x += curRunCount; mapIndex += curRunCount; index += curRunCount; if (x < xCount && Blocks.BlocksLight[World.Blocks[mapIndex ]]) { lightOffset = (Blocks.LightOffset[World.Blocks[mapIndex ]] >> FACE_YMAX) & 1; Lighting_Heightmap[hIndex + x ] = (cc_int16)(y - lightOffset); elemsLeft--; skip[index] = 0 ; offset = prevRunCount + curRunCount; newRunCount = skip[index - offset] + 1; oldRunCount = (x - offset + newRunCount) < xCount ? skip[index - offset + newRunCount] : 0; if (oldRunCount != 0) { skip[index - offset + newRunCount] = 0; newRunCount += oldRunCount; } skip[index - offset] = newRunCount; x += oldRunCount ; index += oldRunCount; mapIndex += oldRunCount; prevRunCount = newRunCount; } else { prevRunCount = 0; } x++; mapIndex++; index++; } prevRunCount = 0; hIndex += World.Width; mapIndex = baseIndex + World.Width; }}; | ||||
317 | } else { | ||||
318 | Lighting_CalculateBody(World.Blocks[mapIndex] | (World.Blocks2[mapIndex] << 8))for (y = World.Height - 1; y >= 0; y--) { if (elemsLeft <= 0) { return 1; } mapIndex = (((y) * World.Length + (z1)) * World .Width + (x1)); hIndex = ((x1) + World.Width * (z1)); for (z = 0; z < zCount; z++) { baseIndex = mapIndex; index = z * xCount ; for (x = 0; x < xCount;) { curRunCount = skip[index]; x += curRunCount; mapIndex += curRunCount; index += curRunCount; if (x < xCount && Blocks.BlocksLight[World.Blocks[mapIndex ] | (World.Blocks2[mapIndex] << 8)]) { lightOffset = (Blocks .LightOffset[World.Blocks[mapIndex] | (World.Blocks2[mapIndex ] << 8)] >> FACE_YMAX) & 1; Lighting_Heightmap [hIndex + x] = (cc_int16)(y - lightOffset); elemsLeft--; skip [index] = 0; offset = prevRunCount + curRunCount; newRunCount = skip[index - offset] + 1; oldRunCount = (x - offset + newRunCount ) < xCount ? skip[index - offset + newRunCount] : 0; if (oldRunCount != 0) { skip[index - offset + newRunCount] = 0; newRunCount += oldRunCount; } skip[index - offset] = newRunCount; x += oldRunCount ; index += oldRunCount; mapIndex += oldRunCount; prevRunCount = newRunCount; } else { prevRunCount = 0; } x++; mapIndex++; index++; } prevRunCount = 0; hIndex += World.Width; mapIndex = baseIndex + World.Width; }}; | ||||
319 | } | ||||
320 | #endif | ||||
321 | return false0; | ||||
322 | } | ||||
323 | |||||
324 | static void Lighting_FinishHeightmapCoverage(int x1, int z1, int xCount, int zCount) { | ||||
325 | int x, z, hIndex, lightH; | ||||
326 | |||||
327 | for (z = 0; z < zCount; z++) { | ||||
328 | hIndex = Lighting_Pack(x1, z1 + z)((x1) + World.Width * (z1 + z)); | ||||
329 | for (x = 0; x < xCount; x++, hIndex++) { | ||||
330 | lightH = Lighting_Heightmap[hIndex]; | ||||
331 | |||||
332 | if (lightH == HEIGHT_UNCALCULATED((cc_int16)32767)) { | ||||
333 | Lighting_Heightmap[hIndex] = -10; | ||||
334 | } | ||||
335 | } | ||||
336 | } | ||||
337 | } | ||||
338 | |||||
339 | void Lighting_LightHint(int startX, int startZ) { | ||||
340 | int x1 = max(startX, 0)((startX) > (0) ? (startX) : (0)), x2 = min(World.Width, startX + EXTCHUNK_SIZE)((World.Width) < (startX + 18) ? (World.Width) : (startX + 18)); | ||||
341 | int z1 = max(startZ, 0)((startZ) > (0) ? (startZ) : (0)), z2 = min(World.Length, startZ + EXTCHUNK_SIZE)((World.Length) < (startZ + 18) ? (World.Length) : (startZ + 18)); | ||||
342 | int xCount = x2 - x1, zCount = z2 - z1; | ||||
343 | int skip[EXTCHUNK_SIZE18 * EXTCHUNK_SIZE18]; | ||||
344 | |||||
345 | int elemsLeft = Lighting_InitialHeightmapCoverage(x1, z1, xCount, zCount, skip); | ||||
346 | if (!Lighting_CalculateHeightmapCoverage(x1, z1, xCount, zCount, elemsLeft, skip)) { | ||||
347 | Lighting_FinishHeightmapCoverage(x1, z1, xCount, zCount); | ||||
348 | } | ||||
349 | } | ||||
350 | |||||
351 | |||||
352 | /*########################################################################################################################* | ||||
353 | *---------------------------------------------------Lighting component----------------------------------------------------* | ||||
354 | *#########################################################################################################################*/ | ||||
355 | static void OnReset(void) { | ||||
356 | Mem_Free(Lighting_Heightmap); | ||||
357 | Lighting_Heightmap = NULL((void*)0); | ||||
358 | } | ||||
359 | |||||
360 | static void OnNewMapLoaded(void) { | ||||
361 | Lighting_Heightmap = (cc_int16*)Mem_Alloc(World.Width * World.Length, 2, "lighting heightmap"); | ||||
362 | Lighting_Refresh(); | ||||
363 | } | ||||
364 | |||||
365 | struct IGameComponent Lighting_Component = { | ||||
366 | NULL((void*)0), /* Init */ | ||||
367 | OnReset, /* Free */ | ||||
368 | OnReset, /* Reset */ | ||||
369 | OnReset, /* OnNewMap */ | ||||
370 | OnNewMapLoaded /* OnNewMapLoaded */ | ||||
371 | }; |