diff options
author | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
---|---|---|
committer | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
commit | abef6da56913f1c55528103e60a50451a39628b1 (patch) | |
tree | b3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Builder.c |
initial commit
Diffstat (limited to 'src/Builder.c')
-rw-r--r-- | src/Builder.c | 1662 |
1 files changed, 1662 insertions, 0 deletions
diff --git a/src/Builder.c b/src/Builder.c new file mode 100644 index 0000000..654a2b7 --- /dev/null +++ b/src/Builder.c @@ -0,0 +1,1662 @@ +#include "Builder.h" +#include "Constants.h" +#include "World.h" +#include "Funcs.h" +#include "Lighting.h" +#include "Platform.h" +#include "MapRenderer.h" +#include "Graphics.h" +#include "Drawer.h" +#include "ExtMath.h" +#include "Block.h" +#include "PackedCol.h" +#include "TexturePack.h" +#include "Game.h" +#include "Options.h" + +int Builder_SidesLevel, Builder_EdgeLevel; +/* Packs an index into the 16x16x16 count array. Coordinates range from 0 to 15. */ +#define Builder_PackCount(xx, yy, zz) ((((yy) << 8) | ((zz) << 4) | (xx)) * FACE_COUNT) +/* Packs an index into the 18x18x18 chunk array. Coordinates range from -1 to 16. */ +#define Builder_PackChunk(xx, yy, zz) (((yy) + 1) * EXTCHUNK_SIZE_2 + ((zz) + 1) * EXTCHUNK_SIZE + ((xx) + 1)) + +static BlockID* Builder_Chunk; +static cc_uint8* Builder_Counts; +static int* Builder_BitFlags; +static int Builder_X, Builder_Y, Builder_Z; +static BlockID Builder_Block; +static int Builder_ChunkIndex; +static cc_bool Builder_FullBright; +static int Builder_ChunkEndX, Builder_ChunkEndZ; +static int Builder_Offsets[FACE_COUNT] = { -1,1, -EXTCHUNK_SIZE,EXTCHUNK_SIZE, -EXTCHUNK_SIZE_2,EXTCHUNK_SIZE_2 }; + +static int (*Builder_StretchXLiquid)(int countIndex, int x, int y, int z, int chunkIndex, BlockID block); +static int (*Builder_StretchX)(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face); +static int (*Builder_StretchZ)(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face); +static void (*Builder_RenderBlock)(int countsIndex, int x, int y, int z); +static void (*Builder_PrePrepareChunk)(void); +static void (*Builder_PostPrepareChunk)(void); + +/* Contains state for vertices for a portion of a chunk mesh (vertices that are in a 1D atlas) */ +struct Builder1DPart { + /* Union to save on memory, since chunk building is divided into counting then building phases */ + union FaceData { + struct VertexTextured* vertices[FACE_COUNT]; + int count[FACE_COUNT]; + } faces; + int sCount, sOffset; +}; + +/* Part builder data, for both normal and translucent parts. +The first ATLAS1D_MAX_ATLASES parts are for normal parts, remainder are for translucent parts. */ +static struct Builder1DPart Builder_Parts[ATLAS1D_MAX_ATLASES * 2]; +static struct VertexTextured* Builder_Vertices; + +static int Builder1DPart_VerticesCount(struct Builder1DPart* part) { + int i, count = part->sCount; + for (i = 0; i < FACE_COUNT; i++) { count += part->faces.count[i]; } + return count; +} + +static int Builder1DPart_CalcOffsets(struct Builder1DPart* part, int offset) { + int i, counts[FACE_COUNT]; + part->sOffset = offset; + + /* Have to copy first due to count and vertices fields being a union */ + for (i = 0; i < FACE_COUNT; i++) + { + counts[i] = part->faces.count[i]; + } + + offset += part->sCount; + for (i = 0; i < FACE_COUNT; i++) + { + part->faces.vertices[i] = &Builder_Vertices[offset]; + offset += counts[i]; + } + return offset; +} + +static int Builder_TotalVerticesCount(void) { + int i, count = 0; + for (i = 0; i < ATLAS1D_MAX_ATLASES * 2; i++) { + count += Builder1DPart_VerticesCount(&Builder_Parts[i]); + } + return count; +} + + +/*########################################################################################################################* +*----------------------------------------------------Base mesh builder----------------------------------------------------* +*#########################################################################################################################*/ +static void AddSpriteVertices(BlockID block) { + int i = Atlas1D_Index(Block_Tex(block, FACE_XMAX)); + struct Builder1DPart* part = &Builder_Parts[i]; + part->sCount += 4 * 4; +} + +static void AddVertices(BlockID block, Face face) { + int baseOffset = (Blocks.Draw[block] == DRAW_TRANSLUCENT) * ATLAS1D_MAX_ATLASES; + int i = Atlas1D_Index(Block_Tex(block, face)); + struct Builder1DPart* part = &Builder_Parts[baseOffset + i]; + part->faces.count[face] += 4; +} + +#ifdef CC_BUILD_GL11 +static void BuildPartVbs(struct ChunkPartInfo* info) { + /* Sprites vertices are stored before chunk face sides */ + int i, count, offset = info->offset + info->spriteCount; + for (i = 0; i < FACE_COUNT; i++) { + count = info->counts[i]; + + if (count) { + info->vbs[i] = Gfx_CreateVb2(&Builder_Vertices[offset], VERTEX_FORMAT_TEXTURED, count); + offset += count; + } else { + info->vbs[i] = 0; + } + } + + count = info->spriteCount; + offset = info->offset; + if (count) { + info->vbs[i] = Gfx_CreateVb2(&Builder_Vertices[offset], VERTEX_FORMAT_TEXTURED, count); + } else { + info->vbs[i] = 0; + } +} +#endif + +static cc_bool SetPartInfo(struct Builder1DPart* part, int* offset, struct ChunkPartInfo* info) { + int vCount = Builder1DPart_VerticesCount(part); + info->offset = -1; + if (!vCount) return false; + + info->offset = *offset; + *offset += vCount; + + info->counts[FACE_XMIN] = part->faces.count[FACE_XMIN]; + info->counts[FACE_XMAX] = part->faces.count[FACE_XMAX]; + info->counts[FACE_ZMIN] = part->faces.count[FACE_ZMIN]; + info->counts[FACE_ZMAX] = part->faces.count[FACE_ZMAX]; + info->counts[FACE_YMIN] = part->faces.count[FACE_YMIN]; + info->counts[FACE_YMAX] = part->faces.count[FACE_YMAX]; + info->spriteCount = part->sCount; + return true; +} + + +static void PrepareChunk(int x1, int y1, int z1) { + int xMax = min(World.Width, x1 + CHUNK_SIZE); + int yMax = min(World.Height, y1 + CHUNK_SIZE); + int zMax = min(World.Length, z1 + CHUNK_SIZE); + + int cIndex, index, tileIdx; + BlockID b; + int x, y, z, xx, yy, zz; + +#ifdef OCCLUSION + int flags = ComputeOcclusion(); +#endif +#ifdef DEBUG_OCCLUSION + FastColour col = new FastColour(60, 60, 60, 255); + if (flags & 1) col.R = 255; /* x */ + if (flags & 4) col.G = 255; /* y */ + if (flags & 2) col.B = 255; /* z */ + map.Sunlight = map.Shadowlight = col; + map.SunlightXSide = map.ShadowlightXSide = col; + map.SunlightZSide = map.ShadowlightZSide = col; + map.SunlightYBottom = map.ShadowlightYBottom = col; +#endif + + for (y = y1, yy = 0; y < yMax; y++, yy++) { + for (z = z1, zz = 0; z < zMax; z++, zz++) { + cIndex = Builder_PackChunk(0, yy, zz); + + for (x = x1, xx = 0; x < xMax; x++, xx++, cIndex++) { + b = Builder_Chunk[cIndex]; + if (Blocks.Draw[b] == DRAW_GAS) continue; + index = Builder_PackCount(xx, yy, zz); + + /* Sprites can't be stretched, nor can then be they hidden by other blocks. */ + /* Note sprites are drawn using DrawSprite and not with any of the DrawXFace. */ + if (Blocks.Draw[b] == DRAW_SPRITE) { AddSpriteVertices(b); continue; } + + Builder_X = x; Builder_Y = y; Builder_Z = z; + Builder_FullBright = Blocks.Brightness[b]; + tileIdx = b * BLOCK_COUNT; + /* All of these function calls are inlined as they can be called tens of millions to hundreds of millions of times. */ + + if (Builder_Counts[index] == 0 || + (x == 0 && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) || + (x != 0 && (Blocks.Hidden[tileIdx + Builder_Chunk[cIndex - 1]] & (1 << FACE_XMIN)) != 0)) { + Builder_Counts[index] = 0; + } else { + Builder_Counts[index] = Builder_StretchZ(index, x, y, z, cIndex, b, FACE_XMIN); + } + + index++; + if (Builder_Counts[index] == 0 || + (x == World.MaxX && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) || + (x != World.MaxX && (Blocks.Hidden[tileIdx + Builder_Chunk[cIndex + 1]] & (1 << FACE_XMAX)) != 0)) { + Builder_Counts[index] = 0; + } else { + Builder_Counts[index] = Builder_StretchZ(index, x, y, z, cIndex, b, FACE_XMAX); + } + + index++; + if (Builder_Counts[index] == 0 || + (z == 0 && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) || + (z != 0 && (Blocks.Hidden[tileIdx + Builder_Chunk[cIndex - EXTCHUNK_SIZE]] & (1 << FACE_ZMIN)) != 0)) { + Builder_Counts[index] = 0; + } else { + Builder_Counts[index] = Builder_StretchX(index, x, y, z, cIndex, b, FACE_ZMIN); + } + + index++; + if (Builder_Counts[index] == 0 || + (z == World.MaxZ && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) || + (z != World.MaxZ && (Blocks.Hidden[tileIdx + Builder_Chunk[cIndex + EXTCHUNK_SIZE]] & (1 << FACE_ZMAX)) != 0)) { + Builder_Counts[index] = 0; + } else { + Builder_Counts[index] = Builder_StretchX(index, x, y, z, cIndex, b, FACE_ZMAX); + } + + index++; + if (Builder_Counts[index] == 0 || y == 0 || + (Blocks.Hidden[tileIdx + Builder_Chunk[cIndex - EXTCHUNK_SIZE_2]] & (1 << FACE_YMIN)) != 0) { + Builder_Counts[index] = 0; + } else { + Builder_Counts[index] = Builder_StretchX(index, x, y, z, cIndex, b, FACE_YMIN); + } + + index++; + if (Builder_Counts[index] == 0 || + (Blocks.Hidden[tileIdx + Builder_Chunk[cIndex + EXTCHUNK_SIZE_2]] & (1 << FACE_YMAX)) != 0) { + Builder_Counts[index] = 0; + } else if (b < BLOCK_WATER || b > BLOCK_STILL_LAVA) { + Builder_Counts[index] = Builder_StretchX(index, x, y, z, cIndex, b, FACE_YMAX); + } else { + Builder_Counts[index] = Builder_StretchXLiquid(index, x, y, z, cIndex, b); + } + } + } + } +} + +#define ReadChunkBody(get_block)\ +for (yy = -1; yy < 17; ++yy) {\ + y = yy + y1;\ + for (zz = -1; zz < 17; ++zz) {\ +\ + index = World_Pack(x1 - 1, y, z1 + zz);\ + cIndex = Builder_PackChunk(-1, yy, zz);\ + for (xx = -1; xx < 17; ++xx, ++index, ++cIndex) {\ +\ + block = get_block;\ + allAir = allAir && Blocks.Draw[block] == DRAW_GAS;\ + allSolid = allSolid && Blocks.FullOpaque[block];\ + Builder_Chunk[cIndex] = block;\ + }\ + }\ +} + +static cc_bool ReadChunkData(int x1, int y1, int z1, cc_bool* outAllAir) { + BlockRaw* blocks = World.Blocks; + BlockRaw* blocks2; + cc_bool allAir = true, allSolid = true; + int index, cIndex; + BlockID block; + int xx, yy, zz, y; + +#ifndef EXTENDED_BLOCKS + ReadChunkBody(blocks[index]); +#else + if (World.IDMask <= 0xFF) { + ReadChunkBody(blocks[index]); + } else { + blocks2 = World.Blocks2; + ReadChunkBody(blocks[index] | (blocks2[index] << 8)); + } +#endif + + *outAllAir = allAir; + return allSolid; +} + +#define ReadBorderChunkBody(get_block)\ +for (yy = -1; yy < 17; ++yy) {\ + y = yy + y1;\ + if (y < 0) continue;\ + if (y >= World.Height) break;\ +\ + for (zz = -1; zz < 17; ++zz) {\ + z = zz + z1;\ + if (z < 0) continue;\ + if (z >= World.Length) break;\ +\ + index = World_Pack(x1 - 1, y, z);\ + cIndex = Builder_PackChunk(-1, yy, zz);\ +\ + for (xx = -1; xx < 17; ++xx, ++index, ++cIndex) {\ + x = xx + x1;\ + if (x < 0) continue;\ + if (x >= World.Width) break;\ +\ + block = get_block;\ + allAir = allAir && Blocks.Draw[block] == DRAW_GAS;\ + Builder_Chunk[cIndex] = block;\ + }\ + }\ +} + +static cc_bool ReadBorderChunkData(int x1, int y1, int z1, cc_bool* outAllAir) { + BlockRaw* blocks = World.Blocks; + BlockRaw* blocks2; + cc_bool allAir = true; + int index, cIndex; + BlockID block; + int xx, yy, zz, x, y, z; + +#ifndef EXTENDED_BLOCKS + ReadBorderChunkBody(blocks[index]); +#else + if (World.IDMask <= 0xFF) { + ReadBorderChunkBody(blocks[index]); + } else { + blocks2 = World.Blocks2; + ReadBorderChunkBody(blocks[index] | (blocks2[index] << 8)); + } +#endif + + *outAllAir = allAir; + return false; +} + +static void OutputChunkPartsMeta(int x, int y, int z, struct ChunkInfo* info) { + cc_bool hasNorm, hasTran; + int partsIndex; + int i, j, curIdx, offset; + + partsIndex = World_ChunkPack(x >> CHUNK_SHIFT, y >> CHUNK_SHIFT, z >> CHUNK_SHIFT); + offset = 0; + hasNorm = false; + hasTran = false; + + for (i = 0; i < MapRenderer_1DUsedCount; i++) { + j = i + ATLAS1D_MAX_ATLASES; + curIdx = partsIndex + i * World.ChunksCount; + + hasNorm |= SetPartInfo(&Builder_Parts[i], &offset, &MapRenderer_PartsNormal[curIdx]); + hasTran |= SetPartInfo(&Builder_Parts[j], &offset, &MapRenderer_PartsTranslucent[curIdx]); + } + + if (hasNorm) { + info->normalParts = &MapRenderer_PartsNormal[partsIndex]; + } + if (hasTran) { + info->translucentParts = &MapRenderer_PartsTranslucent[partsIndex]; + } +} + +void Builder_MakeChunk(struct ChunkInfo* info) { +#ifdef CC_BUILD_SATURN + /* The Saturn build only has 16 kb stack, not large enough */ + static BlockID chunk[EXTCHUNK_SIZE_3]; + static cc_uint8 counts[CHUNK_SIZE_3 * FACE_COUNT]; + static int bitFlags[1]; +#else + BlockID chunk[EXTCHUNK_SIZE_3]; + cc_uint8 counts[CHUNK_SIZE_3 * FACE_COUNT]; + int bitFlags[EXTCHUNK_SIZE_3]; +#endif + + cc_bool allAir, allSolid, onBorder; + int xMax, yMax, zMax, totalVerts; + int cIndex, index; + int x, y, z, xx, yy, zz; + int x1 = info->centreX - 8, y1 = info->centreY - 8, z1 = info->centreZ - 8; + + Builder_Chunk = chunk; + Builder_Counts = counts; + Builder_BitFlags = bitFlags; + Builder_PrePrepareChunk(); + + onBorder = + x1 == 0 || y1 == 0 || z1 == 0 || x1 + CHUNK_SIZE >= World.Width || + y1 + CHUNK_SIZE >= World.Height || z1 + CHUNK_SIZE >= World.Length; + + if (onBorder) { + /* less optimal case here */ + Mem_Set(chunk, BLOCK_AIR, EXTCHUNK_SIZE_3 * sizeof(BlockID)); + allSolid = ReadBorderChunkData(x1, y1, z1, &allAir); + } else { + allSolid = ReadChunkData(x1, y1, z1, &allAir); + } + + info->allAir = allAir; + if (allAir || allSolid) return; + Lighting.LightHint(x1 - 1, y1 - 1, z1 - 1); + + Mem_Set(counts, 1, CHUNK_SIZE_3 * FACE_COUNT); + xMax = min(World.Width, x1 + CHUNK_SIZE); + yMax = min(World.Height, y1 + CHUNK_SIZE); + zMax = min(World.Length, z1 + CHUNK_SIZE); + + Builder_ChunkEndX = xMax; Builder_ChunkEndZ = zMax; + PrepareChunk(x1, y1, z1); + + totalVerts = Builder_TotalVerticesCount(); + if (!totalVerts) return; + + OutputChunkPartsMeta(x1, y1, z1, info); +#ifdef OCCLUSION + if (info.NormalParts != null || info.TranslucentParts != null) + info.occlusionFlags = (cc_uint8)ComputeOcclusion(); +#endif + +#ifndef CC_BUILD_GL11 + /* add an extra element to fix crashing on some GPUs */ + Builder_Vertices = (struct VertexTextured*)Gfx_RecreateAndLockVb(&info->vb, + VERTEX_FORMAT_TEXTURED, totalVerts + 1); +#else + /* NOTE: Relies on assumption vb is ignored by GL11 Gfx_LockVb implementation */ + Builder_Vertices = (struct VertexTextured*)Gfx_LockVb(0, + VERTEX_FORMAT_TEXTURED, totalVerts + 1); +#endif + Builder_PostPrepareChunk(); + /* now render the chunk */ + + for (y = y1, yy = 0; y < yMax; y++, yy++) { + for (z = z1, zz = 0; z < zMax; z++, zz++) { + cIndex = Builder_PackChunk(0, yy, zz); + + for (x = x1, xx = 0; x < xMax; x++, xx++, cIndex++) { + Builder_Block = chunk[cIndex]; + if (Blocks.Draw[Builder_Block] == DRAW_GAS) continue; + + index = Builder_PackCount(xx, yy, zz); + Builder_ChunkIndex = cIndex; + Builder_RenderBlock(index, x, y, z); + } + } + } + +#ifdef CC_BUILD_GL11 + cIndex = World_ChunkPack(x1 >> CHUNK_SHIFT, y1 >> CHUNK_SHIFT, z1 >> CHUNK_SHIFT); + + for (index = 0; index < MapRenderer_1DUsedCount; index++) { + int curIdx = cIndex + index * World.ChunksCount; + + BuildPartVbs(&MapRenderer_PartsNormal[curIdx]); + BuildPartVbs(&MapRenderer_PartsTranslucent[curIdx]); + } +#else + Gfx_UnlockVb(info->vb); +#endif +} + +static cc_bool Builder_OccludedLiquid(int chunkIndex) { + chunkIndex += EXTCHUNK_SIZE_2; /* Checking y above */ + return + Blocks.FullOpaque[Builder_Chunk[chunkIndex]] + && Blocks.Draw[Builder_Chunk[chunkIndex - EXTCHUNK_SIZE]] != DRAW_GAS + && Blocks.Draw[Builder_Chunk[chunkIndex - 1]] != DRAW_GAS + && Blocks.Draw[Builder_Chunk[chunkIndex + 1]] != DRAW_GAS + && Blocks.Draw[Builder_Chunk[chunkIndex + EXTCHUNK_SIZE]] != DRAW_GAS; +} + +static void DefaultPrePrepateChunk(void) { + Mem_Set(Builder_Parts, 0, sizeof(Builder_Parts)); +} + +static void DefaultPostStretchChunk(void) { + int i, j, offset; + offset = 0; + for (i = 0; i < ATLAS1D_MAX_ATLASES; i++) { + j = i + ATLAS1D_MAX_ATLASES; + + offset = Builder1DPart_CalcOffsets(&Builder_Parts[i], offset); + offset = Builder1DPart_CalcOffsets(&Builder_Parts[j], offset); + } +} + +static RNGState spriteRng; +static void Builder_DrawSprite(int x, int y, int z) { + struct Builder1DPart* part; + struct VertexTextured* v; + cc_uint8 offsetType; + cc_bool bright; + PackedCol color; + TextureLoc loc; + float v1, v2; + + float X, Y, Z; + float valX, valY, valZ; + float x1,y1,z1, x2,y2,z2; + + X = (float)x; Y = (float)y; Z = (float)z; + x1 = X + 2.50f/16.0f; y1 = Y; z1 = Z + 2.50f/16.0f; + x2 = X + 13.5f/16.0f; y2 = Y + 1.0f; z2 = Z + 13.5f/16.0f; + +#define s_u1 0.0f +#define s_u2 UV2_Scale + loc = Block_Tex(Builder_Block, FACE_XMAX); + v1 = Atlas1D_RowId(loc) * Atlas1D.InvTileSize; + v2 = v1 + Atlas1D.InvTileSize * UV2_Scale; + + offsetType = Blocks.SpriteOffset[Builder_Block]; + if (offsetType >= 6 && offsetType <= 7) { + Random_Seed(&spriteRng, (x + 1217 * z) & 0x7fffffff); + valX = Random_Range(&spriteRng, -3, 3 + 1) / 16.0f; + valY = Random_Range(&spriteRng, 0, 3 + 1) / 16.0f; + valZ = Random_Range(&spriteRng, -3, 3 + 1) / 16.0f; + + x1 += valX - 1.7f/16.0f; x2 += valX + 1.7f/16.0f; + z1 += valZ - 1.7f/16.0f; z2 += valZ + 1.7f/16.0f; + if (offsetType == 7) { y1 -= valY; y2 -= valY; } + } + + bright = Blocks.Brightness[Builder_Block]; + part = &Builder_Parts[Atlas1D_Index(loc)]; + color = bright ? PACKEDCOL_WHITE : Lighting.Color_Sprite_Fast(x, y, z); + Block_Tint(color, Builder_Block); + + /* Draw Z axis */ + v = &Builder_Vertices[part->sOffset]; + v->x = x1; v->y = y1; v->z = z1; v->Col = color; v->U = s_u2; v->V = v2; v++; + v->x = x1; v->y = y2; v->z = z1; v->Col = color; v->U = s_u2; v->V = v1; v++; + v->x = x2; v->y = y2; v->z = z2; v->Col = color; v->U = s_u1; v->V = v1; v++; + v->x = x2; v->y = y1; v->z = z2; v->Col = color; v->U = s_u1; v->V = v2; v++; + + /* Draw Z axis mirrored */ + v -= 4; v += part->sCount >> 2; + v->x = x2; v->y = y1; v->z = z2; v->Col = color; v->U = s_u2; v->V = v2; v++; + v->x = x2; v->y = y2; v->z = z2; v->Col = color; v->U = s_u2; v->V = v1; v++; + v->x = x1; v->y = y2; v->z = z1; v->Col = color; v->U = s_u1; v->V = v1; v++; + v->x = x1; v->y = y1; v->z = z1; v->Col = color; v->U = s_u1; v->V = v2; v++; + + /* Draw X axis */ + v -= 4; v += part->sCount >> 2; + v->x = x1; v->y = y1; v->z = z2; v->Col = color; v->U = s_u2; v->V = v2; v++; + v->x = x1; v->y = y2; v->z = z2; v->Col = color; v->U = s_u2; v->V = v1; v++; + v->x = x2; v->y = y2; v->z = z1; v->Col = color; v->U = s_u1; v->V = v1; v++; + v->x = x2; v->y = y1; v->z = z1; v->Col = color; v->U = s_u1; v->V = v2; v++; + + /* Draw X axis mirrored */ + v -= 4; v += part->sCount >> 2; + v->x = x2; v->y = y1; v->z = z1; v->Col = color; v->U = s_u2; v->V = v2; v++; + v->x = x2; v->y = y2; v->z = z1; v->Col = color; v->U = s_u2; v->V = v1; v++; + v->x = x1; v->y = y2; v->z = z2; v->Col = color; v->U = s_u1; v->V = v1; v++; + v->x = x1; v->y = y1; v->z = z2; v->Col = color; v->U = s_u1; v->V = v2; v++; + + part->sOffset += 4; +} + + +/*########################################################################################################################* +*--------------------------------------------------Normal mesh builder----------------------------------------------------* +*#########################################################################################################################*/ +static PackedCol Normal_LightColor(int x, int y, int z, Face face, BlockID block) { + int offset = (Blocks.LightOffset[block] >> face) & 1; + + switch (face) { + case FACE_XMIN: + return x < offset ? Env.SunXSide : Lighting.Color_XSide_Fast(x - offset, y, z); + case FACE_XMAX: + return x > (World.MaxX - offset) ? Env.SunXSide : Lighting.Color_XSide_Fast(x + offset, y, z); + case FACE_ZMIN: + return z < offset ? Env.SunZSide : Lighting.Color_ZSide_Fast(x, y, z - offset); + case FACE_ZMAX: + return z > (World.MaxZ - offset) ? Env.SunZSide : Lighting.Color_ZSide_Fast(x, y, z + offset); + + case FACE_YMIN: + return Lighting.Color_YMin_Fast(x, y - offset, z); + case FACE_YMAX: + return Lighting.Color_YMax_Fast(x, y + offset, z); + } + return 0; /* should never happen */ +} + +static cc_bool Normal_CanStretch(BlockID initial, int chunkIndex, int x, int y, int z, Face face) { + BlockID cur = Builder_Chunk[chunkIndex]; + + if (cur != initial || Block_IsFaceHidden(cur, Builder_Chunk[chunkIndex + Builder_Offsets[face]], face)) return false; + if (Builder_FullBright) return true; + + return Normal_LightColor(Builder_X, Builder_Y, Builder_Z, face, initial) == Normal_LightColor(x, y, z, face, cur); +} + +static int NormalBuilder_StretchXLiquid(int countIndex, int x, int y, int z, int chunkIndex, BlockID block) { + int count = 1; cc_bool stretchTile; + if (Builder_OccludedLiquid(chunkIndex)) return 0; + + x++; + chunkIndex++; + countIndex += FACE_COUNT; + stretchTile = (Blocks.CanStretch[block] & (1 << FACE_YMAX)) != 0; + + while (x < Builder_ChunkEndX && stretchTile && Normal_CanStretch(block, chunkIndex, x, y, z, FACE_YMAX) && !Builder_OccludedLiquid(chunkIndex)) { + Builder_Counts[countIndex] = 0; + count++; + x++; + chunkIndex++; + countIndex += FACE_COUNT; + } + AddVertices(block, FACE_YMAX); + return count; +} + +static int NormalBuilder_StretchX(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face) { + int count = 1; cc_bool stretchTile; + x++; + chunkIndex++; + countIndex += FACE_COUNT; + stretchTile = (Blocks.CanStretch[block] & (1 << face)) != 0; + + while (x < Builder_ChunkEndX && stretchTile && Normal_CanStretch(block, chunkIndex, x, y, z, face)) { + Builder_Counts[countIndex] = 0; + count++; + x++; + chunkIndex++; + countIndex += FACE_COUNT; + } + AddVertices(block, face); + return count; +} + +static int NormalBuilder_StretchZ(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face) { + int count = 1; cc_bool stretchTile; + z++; + chunkIndex += EXTCHUNK_SIZE; + countIndex += CHUNK_SIZE * FACE_COUNT; + stretchTile = (Blocks.CanStretch[block] & (1 << face)) != 0; + + while (z < Builder_ChunkEndZ && stretchTile && Normal_CanStretch(block, chunkIndex, x, y, z, face)) { + Builder_Counts[countIndex] = 0; + count++; + z++; + chunkIndex += EXTCHUNK_SIZE; + countIndex += CHUNK_SIZE * FACE_COUNT; + } + AddVertices(block, face); + return count; +} + +static void NormalBuilder_RenderBlock(int index, int x, int y, int z) { + /* counters */ + int count_XMin, count_XMax, count_ZMin; + int count_ZMax, count_YMin, count_YMax; + + /* block state */ + Vec3 min, max; + int baseOffset, lightFlags; + cc_bool fullBright; + + /* per-face state */ + struct Builder1DPart* part; + TextureLoc loc; + PackedCol col; + int offset; + + if (Blocks.Draw[Builder_Block] == DRAW_SPRITE) { + Builder_DrawSprite(x, y, z); return; + } + + count_XMin = Builder_Counts[index + FACE_XMIN]; + count_XMax = Builder_Counts[index + FACE_XMAX]; + count_ZMin = Builder_Counts[index + FACE_ZMIN]; + count_ZMax = Builder_Counts[index + FACE_ZMAX]; + count_YMin = Builder_Counts[index + FACE_YMIN]; + count_YMax = Builder_Counts[index + FACE_YMAX]; + + if (!count_XMin && !count_XMax && !count_ZMin && + !count_ZMax && !count_YMin && !count_YMax) return; + + fullBright = Blocks.Brightness[Builder_Block]; + baseOffset = (Blocks.Draw[Builder_Block] == DRAW_TRANSLUCENT) * ATLAS1D_MAX_ATLASES; + lightFlags = Blocks.LightOffset[Builder_Block]; + + Drawer.MinBB = Blocks.MinBB[Builder_Block]; Drawer.MinBB.y = 1.0f - Drawer.MinBB.y; + Drawer.MaxBB = Blocks.MaxBB[Builder_Block]; Drawer.MaxBB.y = 1.0f - Drawer.MaxBB.y; + + min = Blocks.RenderMinBB[Builder_Block]; max = Blocks.RenderMaxBB[Builder_Block]; + Drawer.X1 = x + min.x; Drawer.Y1 = y + min.y; Drawer.Z1 = z + min.z; + Drawer.X2 = x + max.x; Drawer.Y2 = y + max.y; Drawer.Z2 = z + max.z; + + Drawer.Tinted = Blocks.Tinted[Builder_Block]; + Drawer.TintCol = Blocks.FogCol[Builder_Block]; + + if (count_XMin) { + loc = Block_Tex(Builder_Block, FACE_XMIN); + offset = (lightFlags >> FACE_XMIN) & 1; + part = &Builder_Parts[baseOffset + Atlas1D_Index(loc)]; + + col = fullBright ? PACKEDCOL_WHITE : + x >= offset ? Lighting.Color_XSide_Fast(x - offset, y, z) : Env.SunXSide; + Drawer_XMin(count_XMin, col, loc, &part->faces.vertices[FACE_XMIN]); + } + + if (count_XMax) { + loc = Block_Tex(Builder_Block, FACE_XMAX); + offset = (lightFlags >> FACE_XMAX) & 1; + part = &Builder_Parts[baseOffset + Atlas1D_Index(loc)]; + + col = fullBright ? PACKEDCOL_WHITE : + x <= (World.MaxX - offset) ? Lighting.Color_XSide_Fast(x + offset, y, z) : Env.SunXSide; + Drawer_XMax(count_XMax, col, loc, &part->faces.vertices[FACE_XMAX]); + } + + if (count_ZMin) { + loc = Block_Tex(Builder_Block, FACE_ZMIN); + offset = (lightFlags >> FACE_ZMIN) & 1; + part = &Builder_Parts[baseOffset + Atlas1D_Index(loc)]; + + col = fullBright ? PACKEDCOL_WHITE : + z >= offset ? Lighting.Color_ZSide_Fast(x, y, z - offset) : Env.SunZSide; + Drawer_ZMin(count_ZMin, col, loc, &part->faces.vertices[FACE_ZMIN]); + } + + if (count_ZMax) { + loc = Block_Tex(Builder_Block, FACE_ZMAX); + offset = (lightFlags >> FACE_ZMAX) & 1; + part = &Builder_Parts[baseOffset + Atlas1D_Index(loc)]; + + col = fullBright ? PACKEDCOL_WHITE : + z <= (World.MaxZ - offset) ? Lighting.Color_ZSide_Fast(x, y, z + offset) : Env.SunZSide; + Drawer_ZMax(count_ZMax, col, loc, &part->faces.vertices[FACE_ZMAX]); + } + + if (count_YMin) { + loc = Block_Tex(Builder_Block, FACE_YMIN); + offset = (lightFlags >> FACE_YMIN) & 1; + part = &Builder_Parts[baseOffset + Atlas1D_Index(loc)]; + + col = fullBright ? PACKEDCOL_WHITE : Lighting.Color_YMin_Fast(x, y - offset, z); + Drawer_YMin(count_YMin, col, loc, &part->faces.vertices[FACE_YMIN]); + } + + if (count_YMax) { + loc = Block_Tex(Builder_Block, FACE_YMAX); + offset = (lightFlags >> FACE_YMAX) & 1; + part = &Builder_Parts[baseOffset + Atlas1D_Index(loc)]; + + col = fullBright ? PACKEDCOL_WHITE : Lighting.Color_YMax_Fast(x, y + offset, z); + Drawer_YMax(count_YMax, col, loc, &part->faces.vertices[FACE_YMAX]); + } +} + +static void Builder_SetDefault(void) { + Builder_StretchXLiquid = NULL; + Builder_StretchX = NULL; + Builder_StretchZ = NULL; + Builder_RenderBlock = NULL; + + Builder_PrePrepareChunk = DefaultPrePrepateChunk; + Builder_PostPrepareChunk = DefaultPostStretchChunk; +} + +static void NormalBuilder_SetActive(void) { + Builder_SetDefault(); + Builder_StretchXLiquid = NormalBuilder_StretchXLiquid; + Builder_StretchX = NormalBuilder_StretchX; + Builder_StretchZ = NormalBuilder_StretchZ; + Builder_RenderBlock = NormalBuilder_RenderBlock; +} + + +/*########################################################################################################################* +*-------------------------------------------------Advanced mesh builder---------------------------------------------------* +*#########################################################################################################################*/ +#ifdef CC_BUILD_ADVLIGHTING +static Vec3 adv_minBB, adv_maxBB; +static int adv_initBitFlags, adv_baseOffset; +static int* adv_bitFlags; +static float adv_x1, adv_y1, adv_z1, adv_x2, adv_y2, adv_z2; +static PackedCol adv_lerp[5], adv_lerpX[5], adv_lerpZ[5], adv_lerpY[5]; +static cc_bool adv_tinted; + +enum ADV_MASK { + /* z-1 cube points */ + xM1_yM1_zM1, xM1_yCC_zM1, xM1_yP1_zM1, + xCC_yM1_zM1, xCC_yCC_zM1, xCC_yP1_zM1, + xP1_yM1_zM1, xP1_yCC_zM1, xP1_yP1_zM1, + /* z cube points */ + xM1_yM1_zCC, xM1_yCC_zCC, xM1_yP1_zCC, + xCC_yM1_zCC, xCC_yCC_zCC, xCC_yP1_zCC, + xP1_yM1_zCC, xP1_yCC_zCC, xP1_yP1_zCC, + /* z+1 cube points */ + xM1_yM1_zP1, xM1_yCC_zP1, xM1_yP1_zP1, + xCC_yM1_zP1, xCC_yCC_zP1, xCC_yP1_zP1, + xP1_yM1_zP1, xP1_yCC_zP1, xP1_yP1_zP1, +}; + +/* Bit-or the Adv_Lit flags with these to set the appropriate light values */ +#define LIT_M1 (1 << 0) +#define LIT_CC (1 << 1) +#define LIT_P1 (1 << 2) +/* Returns a 3 bit value where */ +/* - bit 0 set: Y-1 is in light */ +/* - bit 1 set: Y is in light */ +/* - bit 2 set: Y+1 is in light */ +static int Adv_Lit(int x, int y, int z, int cIndex) { + int flags, offset, lightFlags; + BlockID block; + if (y < 0 || y >= World.Height) return LIT_M1 | LIT_CC | LIT_P1; /* all faces lit */ + + /* TODO: check sides height (if sides > edges), check if edge block casts a shadow */ + if (!World_ContainsXZ(x, z)) { + return y >= Builder_EdgeLevel ? LIT_M1 | LIT_CC | LIT_P1 : y == (Builder_EdgeLevel - 1) ? LIT_CC | LIT_P1 : 0; + } + + flags = 0; + block = Builder_Chunk[cIndex]; + lightFlags = Blocks.LightOffset[block]; + + /* TODO using LIGHT_FLAG_SHADES_FROM_BELOW is wrong here, */ + /* but still produces less broken results than YMIN/YMAX */ + + /* Use fact Light(Y.YMin) == Light((Y-1).YMax) */ + offset = (lightFlags >> LIGHT_FLAG_SHADES_FROM_BELOW) & 1; + flags |= Lighting.IsLit_Fast(x, y - offset, z) ? LIT_M1 : 0; + + /* Light is same for all the horizontal faces */ + flags |= Lighting.IsLit_Fast(x, y, z) ? LIT_CC : 0; + + /* Use fact Light((Y+1).YMin) == Light(Y.YMax) */ + offset = (lightFlags >> LIGHT_FLAG_SHADES_FROM_BELOW) & 1; + flags |= Lighting.IsLit_Fast(x, (y + 1) - offset, z) ? LIT_P1 : 0; + + /* If a block is fullbright, it should also look as if that spot is lit */ + if (Blocks.Brightness[Builder_Chunk[cIndex - 324]]) flags |= LIT_M1; + if (Blocks.Brightness[block]) flags |= LIT_CC; + if (Blocks.Brightness[Builder_Chunk[cIndex + 324]]) flags |= LIT_P1; + + return flags; +} + +static int Adv_ComputeLightFlags(int x, int y, int z, int cIndex) { + if (Builder_FullBright) return (1 << xP1_yP1_zP1) - 1; /* all faces fully bright */ + + return + Adv_Lit(x - 1, y, z - 1, cIndex - 1 - 18) << xM1_yM1_zM1 | + Adv_Lit(x - 1, y, z, cIndex - 1) << xM1_yM1_zCC | + Adv_Lit(x - 1, y, z + 1, cIndex - 1 + 18) << xM1_yM1_zP1 | + Adv_Lit(x, y, z - 1, cIndex + 0 - 18) << xCC_yM1_zM1 | + Adv_Lit(x, y, z, cIndex + 0) << xCC_yM1_zCC | + Adv_Lit(x, y, z + 1, cIndex + 0 + 18) << xCC_yM1_zP1 | + Adv_Lit(x + 1, y, z - 1, cIndex + 1 - 18) << xP1_yM1_zM1 | + Adv_Lit(x + 1, y, z, cIndex + 1) << xP1_yM1_zCC | + Adv_Lit(x + 1, y, z + 1, cIndex + 1 + 18) << xP1_yM1_zP1; +} + +static int adv_masks[FACE_COUNT] = { + /* XMin face */ + (1 << xM1_yM1_zM1) | (1 << xM1_yM1_zCC) | (1 << xM1_yM1_zP1) | + (1 << xM1_yCC_zM1) | (1 << xM1_yCC_zCC) | (1 << xM1_yCC_zP1) | + (1 << xM1_yP1_zM1) | (1 << xM1_yP1_zCC) | (1 << xM1_yP1_zP1), + /* XMax face */ + (1 << xP1_yM1_zM1) | (1 << xP1_yM1_zCC) | (1 << xP1_yM1_zP1) | + (1 << xP1_yP1_zM1) | (1 << xP1_yP1_zCC) | (1 << xP1_yP1_zP1) | + (1 << xP1_yCC_zM1) | (1 << xP1_yCC_zCC) | (1 << xP1_yCC_zP1), + /* ZMin face */ + (1 << xM1_yM1_zM1) | (1 << xCC_yM1_zM1) | (1 << xP1_yM1_zM1) | + (1 << xM1_yCC_zM1) | (1 << xCC_yCC_zM1) | (1 << xP1_yCC_zM1) | + (1 << xM1_yP1_zM1) | (1 << xCC_yP1_zM1) | (1 << xP1_yP1_zM1), + /* ZMax face */ + (1 << xM1_yM1_zP1) | (1 << xCC_yM1_zP1) | (1 << xP1_yM1_zP1) | + (1 << xM1_yCC_zP1) | (1 << xCC_yCC_zP1) | (1 << xP1_yCC_zP1) | + (1 << xM1_yP1_zP1) | (1 << xCC_yP1_zP1) | (1 << xP1_yP1_zP1), + /* YMin face */ + (1 << xM1_yM1_zM1) | (1 << xM1_yM1_zCC) | (1 << xM1_yM1_zP1) | + (1 << xCC_yM1_zM1) | (1 << xCC_yM1_zCC) | (1 << xCC_yM1_zP1) | + (1 << xP1_yM1_zM1) | (1 << xP1_yM1_zCC) | (1 << xP1_yM1_zP1), + /* YMax face */ + (1 << xM1_yP1_zM1) | (1 << xM1_yP1_zCC) | (1 << xM1_yP1_zP1) | + (1 << xCC_yP1_zM1) | (1 << xCC_yP1_zCC) | (1 << xCC_yP1_zP1) | + (1 << xP1_yP1_zM1) | (1 << xP1_yP1_zCC) | (1 << xP1_yP1_zP1), +}; + + +static cc_bool Adv_CanStretch(BlockID initial, int chunkIndex, int x, int y, int z, Face face) { + BlockID cur = Builder_Chunk[chunkIndex]; + adv_bitFlags[chunkIndex] = Adv_ComputeLightFlags(x, y, z, chunkIndex); + + return cur == initial + && !Block_IsFaceHidden(cur, Builder_Chunk[chunkIndex + Builder_Offsets[face]], face) + && (adv_initBitFlags == adv_bitFlags[chunkIndex] + /* Check that this face is either fully bright or fully in shadow */ + && (adv_initBitFlags == 0 || (adv_initBitFlags & adv_masks[face]) == adv_masks[face])); +} + +static int Adv_StretchXLiquid(int countIndex, int x, int y, int z, int chunkIndex, BlockID block) { + int count = 1; cc_bool stretchTile; + if (Builder_OccludedLiquid(chunkIndex)) return 0; + adv_initBitFlags = Adv_ComputeLightFlags(x, y, z, chunkIndex); + adv_bitFlags[chunkIndex] = adv_initBitFlags; + + x++; + chunkIndex++; + countIndex += FACE_COUNT; + stretchTile = (Blocks.CanStretch[block] & (1 << FACE_YMAX)) != 0; + + while (x < Builder_ChunkEndX && stretchTile && Adv_CanStretch(block, chunkIndex, x, y, z, FACE_YMAX) && !Builder_OccludedLiquid(chunkIndex)) { + Builder_Counts[countIndex] = 0; + count++; + x++; + chunkIndex++; + countIndex += FACE_COUNT; + } + AddVertices(block, FACE_YMAX); + return count; +} + +static int Adv_StretchX(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face) { + int count = 1; cc_bool stretchTile; + adv_initBitFlags = Adv_ComputeLightFlags(x, y, z, chunkIndex); + adv_bitFlags[chunkIndex] = adv_initBitFlags; + + x++; + chunkIndex++; + countIndex += FACE_COUNT; + stretchTile = (Blocks.CanStretch[block] & (1 << face)) != 0; + + while (x < Builder_ChunkEndX && stretchTile && Adv_CanStretch(block, chunkIndex, x, y, z, face)) { + Builder_Counts[countIndex] = 0; + count++; + x++; + chunkIndex++; + countIndex += FACE_COUNT; + } + AddVertices(block, face); + return count; +} + +static int Adv_StretchZ(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face) { + int count = 1; cc_bool stretchTile; + adv_initBitFlags = Adv_ComputeLightFlags(x, y, z, chunkIndex); + adv_bitFlags[chunkIndex] = adv_initBitFlags; + + z++; + chunkIndex += EXTCHUNK_SIZE; + countIndex += CHUNK_SIZE * FACE_COUNT; + stretchTile = (Blocks.CanStretch[block] & (1 << face)) != 0; + + while (z < Builder_ChunkEndZ && stretchTile && Adv_CanStretch(block, chunkIndex, x, y, z, face)) { + Builder_Counts[countIndex] = 0; + count++; + z++; + chunkIndex += EXTCHUNK_SIZE; + countIndex += CHUNK_SIZE * FACE_COUNT; + } + AddVertices(block, face); + return count; +} + + +#define Adv_CountBits(F, a, b, c, d) (((F >> a) & 1) + ((F >> b) & 1) + ((F >> c) & 1) + ((F >> d) & 1)) + +static void Adv_DrawXMin(int count) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_XMIN); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.z, u2 = (count - 1) + adv_maxBB.z * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + int F = adv_bitFlags[Builder_ChunkIndex]; + int aY0_Z0 = Adv_CountBits(F, xM1_yM1_zM1, xM1_yCC_zM1, xM1_yM1_zCC, xM1_yCC_zCC); + int aY0_Z1 = Adv_CountBits(F, xM1_yM1_zP1, xM1_yCC_zP1, xM1_yM1_zCC, xM1_yCC_zCC); + int aY1_Z0 = Adv_CountBits(F, xM1_yP1_zM1, xM1_yCC_zM1, xM1_yP1_zCC, xM1_yCC_zCC); + int aY1_Z1 = Adv_CountBits(F, xM1_yP1_zP1, xM1_yCC_zP1, xM1_yP1_zCC, xM1_yCC_zCC); + + PackedCol tint, white = PACKEDCOL_WHITE; + PackedCol col0_0 = Builder_FullBright ? white : adv_lerpX[aY0_Z0], col1_0 = Builder_FullBright ? white : adv_lerpX[aY1_Z0]; + PackedCol col1_1 = Builder_FullBright ? white : adv_lerpX[aY1_Z1], col0_1 = Builder_FullBright ? white : adv_lerpX[aY0_Z1]; + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_XMIN]; + v.x = adv_x1; + if (aY0_Z0 + aY1_Z1 > aY0_Z1 + aY1_Z0) { + v.y = adv_y2; v.z = adv_z1; v.U = u1; v.V = v1; v.Col = col1_0; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.z = adv_z2 + (count - 1); v.U = u2; v.Col = col0_1; *vertices++ = v; + v.y = adv_y2; v.V = v1; v.Col = col1_1; *vertices++ = v; + } else { + v.y = adv_y2; v.z = adv_z2 + (count - 1); v.U = u2; v.V = v1; v.Col = col1_1; *vertices++ = v; + v.z = adv_z1; v.U = u1; v.Col = col1_0; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.z = adv_z2 + (count - 1); v.U = u2; v.Col = col0_1; *vertices++ = v; + } + part->faces.vertices[FACE_XMIN] = vertices; +} + +static void Adv_DrawXMax(int count) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_XMAX); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = (count - adv_minBB.z), u2 = (1 - adv_maxBB.z) * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + int F = adv_bitFlags[Builder_ChunkIndex]; + int aY0_Z0 = Adv_CountBits(F, xP1_yM1_zM1, xP1_yCC_zM1, xP1_yM1_zCC, xP1_yCC_zCC); + int aY0_Z1 = Adv_CountBits(F, xP1_yM1_zP1, xP1_yCC_zP1, xP1_yM1_zCC, xP1_yCC_zCC); + int aY1_Z0 = Adv_CountBits(F, xP1_yP1_zM1, xP1_yCC_zM1, xP1_yP1_zCC, xP1_yCC_zCC); + int aY1_Z1 = Adv_CountBits(F, xP1_yP1_zP1, xP1_yCC_zP1, xP1_yP1_zCC, xP1_yCC_zCC); + + PackedCol tint, white = PACKEDCOL_WHITE; + PackedCol col0_0 = Builder_FullBright ? white : adv_lerpX[aY0_Z0], col1_0 = Builder_FullBright ? white : adv_lerpX[aY1_Z0]; + PackedCol col1_1 = Builder_FullBright ? white : adv_lerpX[aY1_Z1], col0_1 = Builder_FullBright ? white : adv_lerpX[aY0_Z1]; + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_XMAX]; + v.x = adv_x2; + if (aY0_Z0 + aY1_Z1 > aY0_Z1 + aY1_Z0) { + v.y = adv_y2; v.z = adv_z1; v.U = u1; v.V = v1; v.Col = col1_0; *vertices++ = v; + v.z = adv_z2 + (count - 1); v.U = u2; v.Col = col1_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.z = adv_z1; v.U = u1; v.Col = col0_0; *vertices++ = v; + } else { + v.y = adv_y2; v.z = adv_z2 + (count - 1); v.U = u2; v.V = v1; v.Col = col1_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.z = adv_z1; v.U = u1; v.Col = col0_0; *vertices++ = v; + v.y = adv_y2; v.V = v1; v.Col = col1_0; *vertices++ = v; + } + part->faces.vertices[FACE_XMAX] = vertices; +} + +static void Adv_DrawZMin(int count) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_ZMIN); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = (count - adv_minBB.x), u2 = (1 - adv_maxBB.x) * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + int F = adv_bitFlags[Builder_ChunkIndex]; + int aX0_Y0 = Adv_CountBits(F, xM1_yM1_zM1, xM1_yCC_zM1, xCC_yM1_zM1, xCC_yCC_zM1); + int aX0_Y1 = Adv_CountBits(F, xM1_yP1_zM1, xM1_yCC_zM1, xCC_yP1_zM1, xCC_yCC_zM1); + int aX1_Y0 = Adv_CountBits(F, xP1_yM1_zM1, xP1_yCC_zM1, xCC_yM1_zM1, xCC_yCC_zM1); + int aX1_Y1 = Adv_CountBits(F, xP1_yP1_zM1, xP1_yCC_zM1, xCC_yP1_zM1, xCC_yCC_zM1); + + PackedCol tint, white = PACKEDCOL_WHITE; + PackedCol col0_0 = Builder_FullBright ? white : adv_lerpZ[aX0_Y0], col1_0 = Builder_FullBright ? white : adv_lerpZ[aX1_Y0]; + PackedCol col1_1 = Builder_FullBright ? white : adv_lerpZ[aX1_Y1], col0_1 = Builder_FullBright ? white : adv_lerpZ[aX0_Y1]; + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_ZMIN]; + v.z = adv_z1; + if (aX1_Y1 + aX0_Y0 > aX0_Y1 + aX1_Y0) { + v.x = adv_x2 + (count - 1); v.y = adv_y1; v.U = u2; v.V = v2; v.Col = col1_0; *vertices++ = v; + v.x = adv_x1; v.U = u1; v.Col = col0_0; *vertices++ = v; + v.y = adv_y2; v.V = v1; v.Col = col0_1; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_1; *vertices++ = v; + } else { + v.x = adv_x1; v.y = adv_y1; v.U = u1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.y = adv_y2; v.V = v1; v.Col = col0_1; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col1_0; *vertices++ = v; + } + part->faces.vertices[FACE_ZMIN] = vertices; +} + +static void Adv_DrawZMax(int count) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_ZMAX); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.x, u2 = (count - 1) + adv_maxBB.x * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + int F = adv_bitFlags[Builder_ChunkIndex]; + int aX0_Y0 = Adv_CountBits(F, xM1_yM1_zP1, xM1_yCC_zP1, xCC_yM1_zP1, xCC_yCC_zP1); + int aX1_Y0 = Adv_CountBits(F, xP1_yM1_zP1, xP1_yCC_zP1, xCC_yM1_zP1, xCC_yCC_zP1); + int aX0_Y1 = Adv_CountBits(F, xM1_yP1_zP1, xM1_yCC_zP1, xCC_yP1_zP1, xCC_yCC_zP1); + int aX1_Y1 = Adv_CountBits(F, xP1_yP1_zP1, xP1_yCC_zP1, xCC_yP1_zP1, xCC_yCC_zP1); + + PackedCol tint, white = PACKEDCOL_WHITE; + PackedCol col1_1 = Builder_FullBright ? white : adv_lerpZ[aX1_Y1], col1_0 = Builder_FullBright ? white : adv_lerpZ[aX1_Y0]; + PackedCol col0_0 = Builder_FullBright ? white : adv_lerpZ[aX0_Y0], col0_1 = Builder_FullBright ? white : adv_lerpZ[aX0_Y1]; + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_ZMAX]; + v.z = adv_z2; + if (aX1_Y1 + aX0_Y0 > aX0_Y1 + aX1_Y0) { + v.x = adv_x1; v.y = adv_y2; v.U = u1; v.V = v1; v.Col = col0_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_0; *vertices++ = v; + v.y = adv_y2; v.V = v1; v.Col = col1_1; *vertices++ = v; + } else { + v.x = adv_x2 + (count - 1); v.y = adv_y2; v.U = u2; v.V = v1; v.Col = col1_1; *vertices++ = v; + v.x = adv_x1; v.U = u1; v.Col = col0_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_0; *vertices++ = v; + } + part->faces.vertices[FACE_ZMAX] = vertices; +} + +static void Adv_DrawYMin(int count) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_YMIN); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.x, u2 = (count - 1) + adv_maxBB.x * UV2_Scale; + float v1 = vOrigin + adv_minBB.z * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_maxBB.z * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + int F = adv_bitFlags[Builder_ChunkIndex]; + int aX0_Z0 = Adv_CountBits(F, xM1_yM1_zM1, xM1_yM1_zCC, xCC_yM1_zM1, xCC_yM1_zCC); + int aX1_Z0 = Adv_CountBits(F, xP1_yM1_zM1, xP1_yM1_zCC, xCC_yM1_zM1, xCC_yM1_zCC); + int aX0_Z1 = Adv_CountBits(F, xM1_yM1_zP1, xM1_yM1_zCC, xCC_yM1_zP1, xCC_yM1_zCC); + int aX1_Z1 = Adv_CountBits(F, xP1_yM1_zP1, xP1_yM1_zCC, xCC_yM1_zP1, xCC_yM1_zCC); + + PackedCol tint, white = PACKEDCOL_WHITE; + PackedCol col0_1 = Builder_FullBright ? white : adv_lerpY[aX0_Z1], col1_1 = Builder_FullBright ? white : adv_lerpY[aX1_Z1]; + PackedCol col1_0 = Builder_FullBright ? white : adv_lerpY[aX1_Z0], col0_0 = Builder_FullBright ? white : adv_lerpY[aX0_Z0]; + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_YMIN]; + v.y = adv_y1; + if (aX0_Z1 + aX1_Z0 > aX0_Z0 + aX1_Z1) { + v.x = adv_x2 + (count - 1); v.z = adv_z2; v.U = u2; v.V = v2; v.Col = col1_1; *vertices++ = v; + v.x = adv_x1; v.U = u1; v.Col = col0_1; *vertices++ = v; + v.z = adv_z1; v.V = v1; v.Col = col0_0; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_0; *vertices++ = v; + } else { + v.x = adv_x1; v.z = adv_z2; v.U = u1; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.z = adv_z1; v.V = v1; v.Col = col0_0; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_0; *vertices++ = v; + v.z = adv_z2; v.V = v2; v.Col = col1_1; *vertices++ = v; + } + part->faces.vertices[FACE_YMIN] = vertices; +} + +static void Adv_DrawYMax(int count) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_YMAX); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.x, u2 = (count - 1) + adv_maxBB.x * UV2_Scale; + float v1 = vOrigin + adv_minBB.z * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_maxBB.z * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + int F = adv_bitFlags[Builder_ChunkIndex]; + int aX0_Z0 = Adv_CountBits(F, xM1_yP1_zM1, xM1_yP1_zCC, xCC_yP1_zM1, xCC_yP1_zCC); + int aX1_Z0 = Adv_CountBits(F, xP1_yP1_zM1, xP1_yP1_zCC, xCC_yP1_zM1, xCC_yP1_zCC); + int aX0_Z1 = Adv_CountBits(F, xM1_yP1_zP1, xM1_yP1_zCC, xCC_yP1_zP1, xCC_yP1_zCC); + int aX1_Z1 = Adv_CountBits(F, xP1_yP1_zP1, xP1_yP1_zCC, xCC_yP1_zP1, xCC_yP1_zCC); + + PackedCol tint, white = PACKEDCOL_WHITE; + PackedCol col0_0 = Builder_FullBright ? white : adv_lerp[aX0_Z0], col1_0 = Builder_FullBright ? white : adv_lerp[aX1_Z0]; + PackedCol col1_1 = Builder_FullBright ? white : adv_lerp[aX1_Z1], col0_1 = Builder_FullBright ? white : adv_lerp[aX0_Z1]; + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_YMAX]; + v.y = adv_y2; + if (aX0_Z0 + aX1_Z1 > aX0_Z1 + aX1_Z0) { + v.x = adv_x2 + (count - 1); v.z = adv_z1; v.U = u2; v.V = v1; v.Col = col1_0; *vertices++ = v; + v.x = adv_x1; v.U = u1; v.Col = col0_0; *vertices++ = v; + v.z = adv_z2; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_1; *vertices++ = v; + } else { + v.x = adv_x1; v.z = adv_z1; v.U = u1; v.V = v1; v.Col = col0_0; *vertices++ = v; + v.z = adv_z2; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_1; *vertices++ = v; + v.z = adv_z1; v.V = v1; v.Col = col1_0; *vertices++ = v; + } + part->faces.vertices[FACE_YMAX] = vertices; +} + +static void Adv_RenderBlock(int index, int x, int y, int z) { + Vec3 min, max; + int count_XMin, count_XMax, count_ZMin; + int count_ZMax, count_YMin, count_YMax; + + if (Blocks.Draw[Builder_Block] == DRAW_SPRITE) { + Builder_DrawSprite(x, y, z); return; + } + + count_XMin = Builder_Counts[index + FACE_XMIN]; + count_XMax = Builder_Counts[index + FACE_XMAX]; + count_ZMin = Builder_Counts[index + FACE_ZMIN]; + count_ZMax = Builder_Counts[index + FACE_ZMAX]; + count_YMin = Builder_Counts[index + FACE_YMIN]; + count_YMax = Builder_Counts[index + FACE_YMAX]; + + if (!count_XMin && !count_XMax && !count_ZMin && + !count_ZMax && !count_YMin && !count_YMax) return; + + Builder_FullBright = Blocks.Brightness[Builder_Block]; + adv_baseOffset = (Blocks.Draw[Builder_Block] == DRAW_TRANSLUCENT) * ATLAS1D_MAX_ATLASES; + adv_tinted = Blocks.Tinted[Builder_Block]; + + min = Blocks.RenderMinBB[Builder_Block]; max = Blocks.RenderMaxBB[Builder_Block]; + adv_x1 = x + min.x; adv_y1 = y + min.y; adv_z1 = z + min.z; + adv_x2 = x + max.x; adv_y2 = y + max.y; adv_z2 = z + max.z; + + adv_minBB = Blocks.MinBB[Builder_Block]; adv_maxBB = Blocks.MaxBB[Builder_Block]; + adv_minBB.y = 1.0f - adv_minBB.y; adv_maxBB.y = 1.0f - adv_maxBB.y; + + if (count_XMin) Adv_DrawXMin(count_XMin); + if (count_XMax) Adv_DrawXMax(count_XMax); + if (count_ZMin) Adv_DrawZMin(count_ZMin); + if (count_ZMax) Adv_DrawZMax(count_ZMax); + if (count_YMin) Adv_DrawYMin(count_YMin); + if (count_YMax) Adv_DrawYMax(count_YMax); +} + +static void Adv_PrePrepareChunk(void) { + int i; + DefaultPrePrepateChunk(); + adv_bitFlags = Builder_BitFlags; + + for (i = 0; i <= 4; i++) { + adv_lerp[i] = PackedCol_Lerp(Env.ShadowCol, Env.SunCol, i / 4.0f); + adv_lerpX[i] = PackedCol_Lerp(Env.ShadowXSide, Env.SunXSide, i / 4.0f); + adv_lerpZ[i] = PackedCol_Lerp(Env.ShadowZSide, Env.SunZSide, i / 4.0f); + adv_lerpY[i] = PackedCol_Lerp(Env.ShadowYMin, Env.SunYMin, i / 4.0f); + } +} + +static void AdvBuilder_SetActive(void) { + Builder_SetDefault(); + Builder_StretchXLiquid = Adv_StretchXLiquid; + Builder_StretchX = Adv_StretchX; + Builder_StretchZ = Adv_StretchZ; + Builder_RenderBlock = Adv_RenderBlock; + Builder_PrePrepareChunk = Adv_PrePrepareChunk; +} +#else +static void AdvBuilder_SetActive(void) { NormalBuilder_SetActive(); } +#endif + + + +/*########################################################################################################################* +*-------------------------------------------------Modern mesh builder-----------------------------------------------------* +*#########################################################################################################################*/ +#ifdef CC_BUILD_ADVLIGHTING +/* Fast color averaging wizardy from https://stackoverflow.com/questions/8440631/how-would-you-average-two-32-bit-colors-packed-into-an-integer */ +#define AVERAGE(a, b) ( ((((a) ^ (b)) & 0xfefefefe) >> 1) + ((a) & (b)) ) + +static cc_bool Modern_IsOccluded(int x, int y, int z) { + BlockID block = World_SafeGetBlock(x, y, z); + if (Blocks.Brightness[block] > 0) { return false; } + /* If the block we're pulling colors from is solid, return a darker version of original and increment how many are like this */ + if (Blocks.FullOpaque[block] || (Blocks.Draw[block] == DRAW_TRANSPARENT && Blocks.BlocksLight[block] && Blocks.LightOffset[block] == 0xFF)) { + return true; + } + return false; +} + +static cc_bool Modern_CanStretch(BlockID initial, int chunkIndex, int x, int y, int z, Face face) { + return false; +} + +static int Modern_StretchXLiquid(int countIndex, int x, int y, int z, int chunkIndex, BlockID block) { + int count = 1; + if (Builder_OccludedLiquid(chunkIndex)) return 0; + AddVertices(block, FACE_YMAX); + return count; +} + +static int Modern_StretchX(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face) { + int count = 1; + AddVertices(block, face); + return count; +} + +static int Modern_StretchZ(int countIndex, int x, int y, int z, int chunkIndex, BlockID block, Face face) { + int count = 1; + AddVertices(block, face); + return count; +} + +static PackedCol Modern_GetColorX(PackedCol orig, int x, int y, int z, int oY, int oZ) { + cc_bool xOccluded = Modern_IsOccluded(x, y + oY, z ); + cc_bool zOccluded = Modern_IsOccluded(x, y , z + oZ); + cc_bool xzOccluded = Modern_IsOccluded(x, y + oY, z + oZ); + + PackedCol CoX = xOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_XSide_Fast(x, y + oY, z ); + PackedCol CoZ = zOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_XSide_Fast(x, y , z + oZ); + PackedCol CoXoZ = (xzOccluded || (xOccluded && zOccluded)) ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_XSide_Fast(x, y + oY, z + oZ); + + PackedCol ab = AVERAGE(CoX, CoZ); + PackedCol cd = AVERAGE(CoXoZ, orig); + return AVERAGE(ab, cd); +} +static void Modern_DrawXMin(int count, int x, int y, int z) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_XMIN); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.z, u2 = (count - 1) + adv_maxBB.z * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + PackedCol tint, white = PACKEDCOL_WHITE; + int offset = 1;// (Blocks.LightOffset[Builder_Block] >> FACE_XMIN) & 1; + PackedCol orig = Lighting.Color_XSide_Fast(x-offset, y, z); + PackedCol col0_0 = Builder_FullBright ? white : Modern_GetColorX(orig, x-offset, y, z, -1, -1); + PackedCol col1_0 = Builder_FullBright ? white : Modern_GetColorX(orig, x-offset, y, z, 1, -1); + PackedCol col1_1 = Builder_FullBright ? white : Modern_GetColorX(orig, x-offset, y, z, 1, 1); + PackedCol col0_1 = Builder_FullBright ? white : Modern_GetColorX(orig, x-offset, y, z, -1, 1); + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_XMIN]; + v.x = adv_x1; + v.y = adv_y2; v.z = adv_z2 + (count - 1); v.U = u2; v.V = v1; v.Col = col1_1; *vertices++ = v; + v.z = adv_z1; v.U = u1; v.Col = col1_0; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.z = adv_z2 + (count - 1); v.U = u2; v.Col = col0_1; *vertices++ = v; + part->faces.vertices[FACE_XMIN] = vertices; +} + +static void Modern_DrawXMax(int count, int x, int y, int z) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_XMAX); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = (count - adv_minBB.z), u2 = (1 - adv_maxBB.z) * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + PackedCol tint, white = PACKEDCOL_WHITE; + int offset = 1;// (Blocks.LightOffset[Builder_Block] >> FACE_XMAX) & 1; + PackedCol orig = Lighting.Color_XSide_Fast(x+offset, y, z); + PackedCol col0_0 = Builder_FullBright ? white : Modern_GetColorX(orig, x+offset, y, z, -1, -1); + PackedCol col1_0 = Builder_FullBright ? white : Modern_GetColorX(orig, x+offset, y, z, 1, -1); + PackedCol col1_1 = Builder_FullBright ? white : Modern_GetColorX(orig, x+offset, y, z, 1, 1); + PackedCol col0_1 = Builder_FullBright ? white : Modern_GetColorX(orig, x+offset, y, z, -1, 1); + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_XMAX]; + v.x = adv_x2; + v.y = adv_y2; v.z = adv_z2 + (count - 1); v.U = u2; v.V = v1; v.Col = col1_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.z = adv_z1; v.U = u1; v.Col = col0_0; *vertices++ = v; + v.y = adv_y2; v.V = v1; v.Col = col1_0; *vertices++ = v; + part->faces.vertices[FACE_XMAX] = vertices; +} + +static PackedCol Modern_GetColorZ(PackedCol orig, int x, int y, int z, int oX, int oY) { + cc_bool xOccluded = Modern_IsOccluded(x + oX, y , z); + cc_bool zOccluded = Modern_IsOccluded(x, y + oY, z); + cc_bool xzOccluded = Modern_IsOccluded(x + oX, y + oY, z); + + PackedCol CoX = xOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_ZSide_Fast(x + oX, y , z); + PackedCol CoZ = zOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_ZSide_Fast(x , y + oY, z); + PackedCol CoXoZ = (xzOccluded || (xOccluded && zOccluded)) ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_ZSide_Fast(x + oX, y + oY, z); + + PackedCol ab = AVERAGE(CoX, CoZ); + PackedCol cd = AVERAGE(CoXoZ, orig); + return AVERAGE(ab, cd); +} +static void Modern_DrawZMin(int count, int x, int y, int z) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_ZMIN); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = (count - adv_minBB.x), u2 = (1 - adv_maxBB.x) * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + PackedCol tint, white = PACKEDCOL_WHITE; + int offset = 1;// (Blocks.LightOffset[Builder_Block] >> FACE_ZMIN) & 1; + PackedCol orig = Lighting.Color_ZSide_Fast(x, y, z-offset); + PackedCol col0_0 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z-offset, -1, -1); + PackedCol col1_0 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z-offset, 1, -1); + PackedCol col1_1 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z-offset, 1, 1); + PackedCol col0_1 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z-offset, -1, 1); + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_ZMIN]; + v.z = adv_z1; + v.x = adv_x1; v.y = adv_y1; v.U = u1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.y = adv_y2; v.V = v1; v.Col = col0_1; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col1_0; *vertices++ = v; + part->faces.vertices[FACE_ZMIN] = vertices; +} + +static void Modern_DrawZMax(int count, int x, int y, int z) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_ZMAX); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.x, u2 = (count - 1) + adv_maxBB.x * UV2_Scale; + float v1 = vOrigin + adv_maxBB.y * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_minBB.y * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + PackedCol tint, white = PACKEDCOL_WHITE; + int offset = 1;// (Blocks.LightOffset[Builder_Block] >> FACE_ZMAX) & 1; + PackedCol orig = Lighting.Color_ZSide_Fast(x, y, z+offset); + PackedCol col0_0 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z+offset, -1, -1); + PackedCol col1_0 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z+offset, 1, -1); + PackedCol col1_1 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z+offset, 1, 1); + PackedCol col0_1 = Builder_FullBright ? white : Modern_GetColorZ(orig, x, y, z+offset, -1, 1); + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_ZMAX]; + v.z = adv_z2; + v.x = adv_x2 + (count - 1); v.y = adv_y2; v.U = u2; v.V = v1; v.Col = col1_1; *vertices++ = v; + v.x = adv_x1; v.U = u1; v.Col = col0_1; *vertices++ = v; + v.y = adv_y1; v.V = v2; v.Col = col0_0; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_0; *vertices++ = v; + part->faces.vertices[FACE_ZMAX] = vertices; +} + +static PackedCol Modern_GetColorYMin(PackedCol orig, int x, int y, int z, int oX, int oZ) { + cc_bool xOccluded = Modern_IsOccluded(x + oX, y, z ); + cc_bool zOccluded = Modern_IsOccluded(x, y, z + oZ); + cc_bool xzOccluded = Modern_IsOccluded(x + oX, y, z + oZ); + + PackedCol CoX = xOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_YMin_Fast(x + oX, y, z ); + PackedCol CoZ = zOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_YMin_Fast(x , y, z + oZ); + PackedCol CoXoZ = (xzOccluded || (xOccluded && zOccluded)) ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color_YMin_Fast(x + oX, y, z + oZ); + + PackedCol ab = AVERAGE(CoX, CoZ); + PackedCol cd = AVERAGE(CoXoZ, orig); + return AVERAGE(ab, cd); +} +static void Modern_DrawYMin(int count, int x, int y, int z) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_YMIN); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.x, u2 = (count - 1) + adv_maxBB.x * UV2_Scale; + float v1 = vOrigin + adv_minBB.z * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_maxBB.z * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + PackedCol tint, white = PACKEDCOL_WHITE; + int offset = 1;// (Blocks.LightOffset[Builder_Block] >> FACE_YMIN) & 1; + PackedCol orig = Lighting.Color_YMin_Fast(x, y-offset, z); + PackedCol col0_0 = Builder_FullBright ? white : Modern_GetColorYMin(orig, x, y-offset, z, -1, -1); + PackedCol col1_0 = Builder_FullBright ? white : Modern_GetColorYMin(orig, x, y-offset, z, 1, -1); + PackedCol col1_1 = Builder_FullBright ? white : Modern_GetColorYMin(orig, x, y-offset, z, 1, 1); + PackedCol col0_1 = Builder_FullBright ? white : Modern_GetColorYMin(orig, x, y-offset, z, -1, 1); + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_YMIN]; + v.y = adv_y1; + v.x = adv_x1; v.z = adv_z2; v.U = u1; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.z = adv_z1; v.V = v1; v.Col = col0_0; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_0; *vertices++ = v; + v.z = adv_z2; v.V = v2; v.Col = col1_1; *vertices++ = v; + part->faces.vertices[FACE_YMIN] = vertices; +} + +static PackedCol Modern_GetColorYMax(PackedCol orig, int x, int y, int z, int oX, int oZ) { + cc_bool xOccluded = Modern_IsOccluded(x + oX, y, z ); + cc_bool zOccluded = Modern_IsOccluded(x, y, z + oZ); + cc_bool xzOccluded = Modern_IsOccluded(x + oX, y, z + oZ); + + PackedCol CoX = xOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color(x + oX, y, z ); + PackedCol CoZ = zOccluded ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color(x , y, z + oZ); + PackedCol CoXoZ = (xzOccluded || (xOccluded && zOccluded)) ? PackedCol_Scale(orig, FANCY_AO) : Lighting.Color(x + oX, y, z + oZ); + + PackedCol ab = AVERAGE(CoX, CoZ); + PackedCol cd = AVERAGE(CoXoZ, orig); + return AVERAGE(ab, cd); +} +static void Modern_DrawYMax(int count, int x, int y, int z) { + TextureLoc texLoc = Block_Tex(Builder_Block, FACE_YMAX); + float vOrigin = Atlas1D_RowId(texLoc) * Atlas1D.InvTileSize; + + float u1 = adv_minBB.x, u2 = (count - 1) + adv_maxBB.x * UV2_Scale; + float v1 = vOrigin + adv_minBB.z * Atlas1D.InvTileSize; + float v2 = vOrigin + adv_maxBB.z * Atlas1D.InvTileSize * UV2_Scale; + struct Builder1DPart* part = &Builder_Parts[adv_baseOffset + Atlas1D_Index(texLoc)]; + + PackedCol tint, white = PACKEDCOL_WHITE; + int offset = 1;// (Blocks.LightOffset[Builder_Block] >> FACE_YMAX) & 1; + PackedCol orig = Lighting.Color(x, y+offset, z); + PackedCol col0_0 = Builder_FullBright ? white : Modern_GetColorYMax(orig, x, y+offset, z, -1, -1); + PackedCol col1_0 = Builder_FullBright ? white : Modern_GetColorYMax(orig, x, y+offset, z, 1, -1); + PackedCol col1_1 = Builder_FullBright ? white : Modern_GetColorYMax(orig, x, y+offset, z, 1, 1); + PackedCol col0_1 = Builder_FullBright ? white : Modern_GetColorYMax(orig, x, y+offset, z, -1, 1); + + struct VertexTextured* vertices, v; + + if (adv_tinted) { + tint = Blocks.FogCol[Builder_Block]; + col0_0 = PackedCol_Tint(col0_0, tint); col1_0 = PackedCol_Tint(col1_0, tint); + col1_1 = PackedCol_Tint(col1_1, tint); col0_1 = PackedCol_Tint(col0_1, tint); + } + + vertices = part->faces.vertices[FACE_YMAX]; + v.y = adv_y2; + v.x = adv_x1; v.z = adv_z1; v.U = u1; v.V = v1; v.Col = col0_0; *vertices++ = v; + v.z = adv_z2; v.V = v2; v.Col = col0_1; *vertices++ = v; + v.x = adv_x2 + (count - 1); v.U = u2; v.Col = col1_1; *vertices++ = v; + v.z = adv_z1; v.V = v1; v.Col = col1_0; *vertices++ = v; + part->faces.vertices[FACE_YMAX] = vertices; +} + +static void Modern_RenderBlock(int index, int x, int y, int z) { + Vec3 min, max; + int count_XMin, count_XMax, count_ZMin; + int count_ZMax, count_YMin, count_YMax; + + if (Blocks.Draw[Builder_Block] == DRAW_SPRITE) { + Builder_DrawSprite(x, y, z); return; + } + + count_XMin = Builder_Counts[index + FACE_XMIN]; + count_XMax = Builder_Counts[index + FACE_XMAX]; + count_ZMin = Builder_Counts[index + FACE_ZMIN]; + count_ZMax = Builder_Counts[index + FACE_ZMAX]; + count_YMin = Builder_Counts[index + FACE_YMIN]; + count_YMax = Builder_Counts[index + FACE_YMAX]; + + if (!count_XMin && !count_XMax && !count_ZMin && + !count_ZMax && !count_YMin && !count_YMax) return; + + Builder_FullBright = Blocks.Brightness[Builder_Block]; + adv_baseOffset = (Blocks.Draw[Builder_Block] == DRAW_TRANSLUCENT) * ATLAS1D_MAX_ATLASES; + adv_tinted = Blocks.Tinted[Builder_Block]; + + min = Blocks.RenderMinBB[Builder_Block]; max = Blocks.RenderMaxBB[Builder_Block]; + adv_x1 = x + min.x; adv_y1 = y + min.y; adv_z1 = z + min.z; + adv_x2 = x + max.x; adv_y2 = y + max.y; adv_z2 = z + max.z; + + adv_minBB = Blocks.MinBB[Builder_Block]; adv_maxBB = Blocks.MaxBB[Builder_Block]; + adv_minBB.y = 1.0f - adv_minBB.y; adv_maxBB.y = 1.0f - adv_maxBB.y; + + if (count_XMin) Modern_DrawXMin(count_XMin, x, y, z); + if (count_XMax) Modern_DrawXMax(count_XMax, x, y, z); + if (count_ZMin) Modern_DrawZMin(count_ZMin, x, y, z); + if (count_ZMax) Modern_DrawZMax(count_ZMax, x, y, z); + if (count_YMin) Modern_DrawYMin(count_YMin, x, y, z); + if (count_YMax) Modern_DrawYMax(count_YMax, x, y, z); +} + +static void Modern_PrePrepareChunk(void) { + DefaultPrePrepateChunk(); + adv_bitFlags = Builder_BitFlags; +} + +static void ModernBuilder_SetActive(void) { + Builder_SetDefault(); + Builder_StretchXLiquid = Modern_StretchXLiquid; + Builder_StretchX = Modern_StretchX; + Builder_StretchZ = Modern_StretchZ; + Builder_RenderBlock = Modern_RenderBlock; + Builder_PrePrepareChunk = Modern_PrePrepareChunk; +} +#else +static void ModernBuilder_SetActive(void) { NormalBuilder_SetActive(); } +#endif + +/*########################################################################################################################* +*---------------------------------------------------Builder interface-----------------------------------------------------* +*#########################################################################################################################*/ +cc_bool Builder_SmoothLighting; +void Builder_ApplyActive(void) { + if (Builder_SmoothLighting) { + if (Lighting_Mode != LIGHTING_MODE_CLASSIC) { + ModernBuilder_SetActive(); + } + else { + AdvBuilder_SetActive(); + } + } else { + NormalBuilder_SetActive(); + } +} + +static void OnInit(void) { + Builder_Offsets[FACE_XMIN] = -1; + Builder_Offsets[FACE_XMAX] = 1; + Builder_Offsets[FACE_ZMIN] = -EXTCHUNK_SIZE; + Builder_Offsets[FACE_ZMAX] = EXTCHUNK_SIZE; + Builder_Offsets[FACE_YMIN] = -EXTCHUNK_SIZE_2; + Builder_Offsets[FACE_YMAX] = EXTCHUNK_SIZE_2; + + if (!Game_ClassicMode) Builder_SmoothLighting = Options_GetBool(OPT_SMOOTH_LIGHTING, false); + Builder_ApplyActive(); +} + +static void OnNewMapLoaded(void) { + Builder_SidesLevel = max(0, Env_SidesHeight); + Builder_EdgeLevel = max(0, Env.EdgeHeight); +} + +struct IGameComponent Builder_Component = { + OnInit, /* Init */ + NULL, /* Free */ + NULL, /* Reset */ + NULL, /* OnNewMap */ + OnNewMapLoaded /* OnNewMapLoaded */ +}; |