Bug Summary

File:Lighting.c
Warning:line 168, column 15
The result of the left shift is undefined because the left operand is negative

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple amd64-unknown-openbsd6.8 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name Lighting.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mthread-model posix -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/10.0.1 -I /usr/X11R6/include -I /usr/local/include -fdebug-compilation-dir /home/ben/Projects/ClassiCube/src -ferror-limit 19 -fmessage-length 0 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -fobjc-runtime=gnustep -fdiagnostics-show-option -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/ClassiCube/src/scan/2021-01-09-173753-31878-1 -x c Lighting.c
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
11cc_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; }}
\
15for (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
25static 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
44static 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 */
51cc_bool Lighting_IsLit(int x, int y, int z) {
52 return y > Lighting_GetLightHeight(x, z);
53}
54
55PackedCol Lighting_Col(int x, int y, int z) {
56 return y > Lighting_GetLightHeight(x, z) ? Env.SunCol : Env.ShadowCol;
57}
58
59PackedCol Lighting_Col_XSide(int x, int y, int z) {
60 return y > Lighting_GetLightHeight(x, z) ? Env.SunXSide : Env.ShadowXSide;
61}
62
63PackedCol 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
67PackedCol 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
71PackedCol 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
75PackedCol 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
79PackedCol 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
83void 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*#########################################################################################################################*/
94static 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
129static 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. */ \
135for (; 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
141static 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
157static 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
14.1
'minCy' is not equal to 'maxCy'
== maxCy) {
15
Taking false branch
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
15.1
'cy' is >= 'minCy'
21.1
'cy' is >= 'minCy'
>= minCy; cy--) {
16
Loop condition is true. Entering loop body
21
The value -1 is assigned to 'cy'
22
Loop condition is true. Entering loop body
168 minY = (cy << CHUNK_SHIFT4);
23
The result of the left shift is undefined because the left operand is negative
169 maxY = (cy << CHUNK_SHIFT4) + CHUNK_MAX15;
170 if (maxY > World.MaxY) maxY = World.MaxY;
17
Assuming 'maxY' is <= field 'MaxY'
18
Taking false branch
171
172 if (Lighting_NeedsNeighour(block, World_Pack(x, maxY, z)(((maxY) * World.Length + (z)) * World.Width + (x)), minY, maxY, y)) {
19
Assuming the condition is false
20
Taking false branch
173 MapRenderer_RefreshChunk(cx, cy, cz);
174 }
175 }
176 }
177}
178
179static 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
189static 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;
4
Assuming 'newHeight' is < 0
5
'?' condition is true
196 int oldCy = oldHeight < 0 ? 0 : oldHeight >> 4;
6
Assuming 'oldHeight' is >= 0
7
'?' condition is false
197 int minCy = min(oldCy, newCy)((oldCy) < (newCy) ? (oldCy) : (newCy)), maxCy = max(oldCy, newCy)((oldCy) > (newCy) ? (oldCy) : (newCy));
8
Assuming 'oldCy' is < 'newCy'
9
'?' condition is true
10
'?' condition is false
198 Lighting_ResetColumn(cx, cy, cz, minCy, maxCy);
199
200 if (bX == 0 && cx > 0) {
11
Assuming 'bX' is equal to 0
12
Assuming 'cx' is > 0
13
Taking true branch
201 Lighting_ResetNeighbour(x - 1, y, z, block, cx - 1, cy, cz, minCy, maxCy);
14
Calling 'Lighting_ResetNeighbour'
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
221void 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;
1
Assuming 'lightH' is not equal to HEIGHT_UNCALCULATED
2
Taking false branch
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);
3
Calling 'Lighting_RefreshAffected'
233}
234
235
236/*########################################################################################################################*
237*---------------------------------------------------Lighting heightmap----------------------------------------------------*
238*#########################################################################################################################*/
239static 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; }}
\
264for (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
306static 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
324static 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
339void 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*#########################################################################################################################*/
355static void OnReset(void) {
356 Mem_Free(Lighting_Heightmap);
357 Lighting_Heightmap = NULL((void*)0);
358}
359
360static void OnNewMapLoaded(void) {
361 Lighting_Heightmap = (cc_int16*)Mem_TryAlloc(World.Width * World.Length, 2);
362 if (Lighting_Heightmap) {
363 Lighting_Refresh();
364 } else {
365 World_OutOfMemory();
366 }
367}
368
369struct IGameComponent Lighting_Component = {
370 NULL((void*)0), /* Init */
371 OnReset, /* Free */
372 OnReset, /* Reset */
373 OnReset, /* OnNewMap */
374 OnNewMapLoaded /* OnNewMapLoaded */
375};