| 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_TryAlloc(World.Width * World.Length, 2); | ||||
| 362 | if (Lighting_Heightmap) { | ||||
| 363 | Lighting_Refresh(); | ||||
| 364 | } else { | ||||
| 365 | World_OutOfMemory(); | ||||
| 366 | } | ||||
| 367 | } | ||||
| 368 | |||||
| 369 | struct IGameComponent Lighting_Component = { | ||||
| 370 | NULL((void*)0), /* Init */ | ||||
| 371 | OnReset, /* Free */ | ||||
| 372 | OnReset, /* Reset */ | ||||
| 373 | OnReset, /* OnNewMap */ | ||||
| 374 | OnNewMapLoaded /* OnNewMapLoaded */ | ||||
| 375 | }; |