#include #include #include #include #include "common.hpp" #include #include #include #ifndef SERVER #ifndef LEGACY_GL MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chunkWorldX, int chunkWorldY, uint8_t sideMask) { MeshData out = {0}; out.vertexCount = 0; out.indexCount = 0; std::vector positions; std::vector normals; std::vector uvs; std::vector colors; std::vector indices; int face = 0; for (int x = 0; x < CHUNK_SIZE; ++x) for (int y = 0; y < WORLD_HEIGHT; ++y) for (int z = 0; z < CHUNK_SIZE; ++z) { int index = GetIndexChunk(x,y,z); uint8_t crdata = chunkRenderData.sides[index]; if (crdata == 0) continue; int this_block = fetch_block(chunk, x,y,z); BlockDef definition = BLOCKS[this_block]; UVCorners UVside = GetUVTex(definition.textureSide); UVCorners UVtop = GetUVTex(definition.textureTop); UVCorners UVbtm = GetUVTex(definition.textureBottom); bool left, right, up, down, back, front; unpack6(crdata & sideMask, &left, &right, &up, &down, &back, &front); bool shaded = chunk.highestBlock[GetIndexChunk2D(x, z)] != y; Color color = {255, 255, 255, 255}; Color colorShaded = {128, 128, 172, 255}; float wx = (float)(chunkWorldX * CHUNK_SIZE + x); float wy = (float)(y); float wz = (float)(chunkWorldY * CHUNK_SIZE + z); /*if(GetCloud(wx, wz)) { color = ColorLerp(color, colorShaded, 0.5f); }*/ if (left) { Vector3 verts[4] = { {wx - 0.5f, wy - 0.5f, wz - 0.5f}, // bottom-left {wx - 0.5f, wy - 0.5f, wz + 0.5f}, // bottom-right {wx - 0.5f, wy + 0.5f, wz + 0.5f}, // top-right {wx - 0.5f, wy + 0.5f, wz - 0.5f} // top-left }; Vector3 normal = {-1.0f, 0.0f, 0.0f}; Vector2 corners[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; positions.push_back(verts[0]); positions.push_back(verts[1]); positions.push_back(verts[2]); positions.push_back(verts[3]); normals.push_back(normal); colors.push_back(colorShaded); uvs.push_back(corners[0]); uvs.push_back(corners[1]); uvs.push_back(corners[2]); uvs.push_back(corners[3]); unsigned short indbase = face*4; unsigned short tri[6] = { indbase + 0, indbase + 1, indbase + 2, indbase + 0, indbase + 2, indbase + 3 }; indices.insert(indices.end(), tri, tri + 6); face++; } // Right face (+X) if (right) { Vector3 verts[4] = { {wx + 0.5f, wy - 0.5f, wz + 0.5f}, // bottom-left (from +X side) {wx + 0.5f, wy - 0.5f, wz - 0.5f}, // bottom-right {wx + 0.5f, wy + 0.5f, wz - 0.5f}, // top-right {wx + 0.5f, wy + 0.5f, wz + 0.5f} // top-left }; Vector3 normal = {1.0f, 0.0f, 0.0f}; Vector2 corners[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; positions.push_back(verts[0]); positions.push_back(verts[1]); positions.push_back(verts[2]); positions.push_back(verts[3]); normals.push_back(normal); colors.push_back(colorShaded); uvs.push_back(corners[0]); uvs.push_back(corners[1]); uvs.push_back(corners[2]); uvs.push_back(corners[3]); unsigned short indbase = face*4; unsigned short tri[6] = { indbase + 0, indbase + 1, indbase + 2, indbase + 0, indbase + 2, indbase + 3 }; indices.insert(indices.end(), tri, tri + 6); face++; } // Down (-Y) if (down) { Vector3 verts[4] = { {wx - 0.5f, wy - 0.5f, wz - 0.5f}, // bottom-left {wx + 0.5f, wy - 0.5f, wz - 0.5f}, // bottom-right {wx + 0.5f, wy - 0.5f, wz + 0.5f}, // top-right {wx - 0.5f, wy - 0.5f, wz + 0.5f} // top-left }; Vector3 normal = {0.0f, -1.0f, 0.0f}; Vector2 corners[4] = { UVbtm.corner0, UVbtm.corner1, UVbtm.corner2, UVbtm.corner3 }; positions.push_back(verts[0]); positions.push_back(verts[1]); positions.push_back(verts[2]); positions.push_back(verts[3]); normals.push_back(normal); colors.push_back(colorShaded); uvs.push_back(corners[0]); uvs.push_back(corners[1]); uvs.push_back(corners[2]); uvs.push_back(corners[3]); unsigned short indbase = face*4; unsigned short tri[6] = { indbase + 0, indbase + 1, indbase + 2, indbase + 0, indbase + 2, indbase + 3 }; indices.insert(indices.end(), tri, tri + 6); face++; } // Up (+Y) if (up) { Vector3 verts[4] = { {wx - 0.5f, wy + 0.5f, wz + 0.5f}, // bottom-left (from +Y side) {wx + 0.5f, wy + 0.5f, wz + 0.5f}, // bottom-right {wx + 0.5f, wy + 0.5f, wz - 0.5f}, // top-right {wx - 0.5f, wy + 0.5f, wz - 0.5f} // top-left }; Vector3 normal = {0.0f, 1.0f, 0.0f}; Vector2 corners[4] = { UVtop.corner0, UVtop.corner1, UVtop.corner2, UVtop.corner3 }; positions.push_back(verts[0]); positions.push_back(verts[1]); positions.push_back(verts[2]); positions.push_back(verts[3]); normals.push_back(normal); if(shaded) { colors.push_back(colorShaded); } else { colors.push_back(color); } uvs.push_back(corners[0]); uvs.push_back(corners[1]); uvs.push_back(corners[2]); uvs.push_back(corners[3]); unsigned short indbase = face*4; unsigned short tri[6] = { indbase + 0, indbase + 1, indbase + 2, indbase + 0, indbase + 2, indbase + 3 }; indices.insert(indices.end(), tri, tri + 6); face++; } // Front (+Z) if (front) { Vector3 verts[4] = { {wx - 0.5f, wy - 0.5f, wz + 0.5f}, // bottom-left {wx + 0.5f, wy - 0.5f, wz + 0.5f}, // bottom-right {wx + 0.5f, wy + 0.5f, wz + 0.5f}, // top-right {wx - 0.5f, wy + 0.5f, wz + 0.5f} // top-left }; Vector3 normal = {0.0f, 0.0f, 1.0f}; Vector2 corners[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; positions.push_back(verts[0]); positions.push_back(verts[1]); positions.push_back(verts[2]); positions.push_back(verts[3]); normals.push_back(normal); colors.push_back(colorShaded); uvs.push_back(corners[0]); uvs.push_back(corners[1]); uvs.push_back(corners[2]); uvs.push_back(corners[3]); unsigned short indbase = face*4; unsigned short tri[6] = { indbase + 0, indbase + 1, indbase + 2, indbase + 0, indbase + 2, indbase + 3 }; indices.insert(indices.end(), tri, tri + 6); face++; } // Back (-Z) if (back) { Vector3 verts[4] = { {wx + 0.5f, wy - 0.5f, wz - 0.5f}, // bottom-left (from -Z side) {wx - 0.5f, wy - 0.5f, wz - 0.5f}, // bottom-right {wx - 0.5f, wy + 0.5f, wz - 0.5f}, // top-right {wx + 0.5f, wy + 0.5f, wz - 0.5f} // top-left }; Vector3 normal = {0.0f, 0.0f, -1.0f}; Vector2 corners[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; positions.push_back(verts[0]); positions.push_back(verts[1]); positions.push_back(verts[2]); positions.push_back(verts[3]); normals.push_back(normal); colors.push_back(colorShaded); uvs.push_back(corners[0]); uvs.push_back(corners[1]); uvs.push_back(corners[2]); uvs.push_back(corners[3]); unsigned short indbase = face*4; unsigned short tri[6] = { indbase + 0, indbase + 1, indbase + 2, indbase + 0, indbase + 2, indbase + 3 }; indices.insert(indices.end(), tri, tri + 6); face++; } } out.positions = (float*)malloc(sizeof(float) * 3 * positions.size()); out.uvs = (float*)malloc(sizeof(float) * 2 * uvs.size()); out.indices = (unsigned short*)malloc(sizeof(unsigned short) * indices.size()); out.normals = (float*)malloc(sizeof(float) * 3 * 4 * normals.size()); out.colors = (unsigned char*)malloc(sizeof(unsigned char) * 4 * 4 * colors.size()); int s = 0; for (Vector3 v : positions) { out.positions[s] = v.x; out.positions[s+1] = v.y; out.positions[s+2] = v.z; s += 3; } s = 0; for (Vector3 n : normals) { for (size_t _ = 0; _ < 4; _++) { out.normals[s] = n.x; out.normals[s+1] = n.y; out.normals[s+2] = n.z; s += 3; } } s = 0; for (Color c : colors) { for (size_t _ = 0; _ < 4; _++) { out.colors[s] = c.r; out.colors[s+1] = c.g; out.colors[s+2] = c.b; out.colors[s+3] = c.a; s += 4; } } s = 0; for (Vector2 uv : uvs) { out.uvs[s] = uv.x; out.uvs[s+1] = uv.y; s += 2; } s = 0; for (unsigned short i : indices) { out.indices[s] = i; s += 1; } out.vertexCount = positions.size(); out.indexCount = indices.size(); positions.clear(); normals.clear(); uvs.clear(); indices.clear(); return out; } MeshData MergeMeshData(const MeshData &a, const MeshData &b) { MeshData out = {0}; // initial counts int aPosCount = a.positions ? (a.vertexCount * 3) : 0; int aNormCount = a.normals ? (a.vertexCount * 3) : 0; int aUvCount = a.uvs ? (a.vertexCount * 2) : 0; int aColCount = a.colors ? (a.vertexCount * 4) : 0; int aIdxCount = a.indices ? (a.indexCount) : 0; int bPosCount = b.positions ? (b.vertexCount * 3) : 0; int bNormCount = b.normals ? (b.vertexCount * 3) : 0; int bUvCount = b.uvs ? (b.vertexCount * 2) : 0; int bColCount = b.colors ? (b.vertexCount * 4) : 0; int bIdxCount = b.indices ? (b.indexCount) : 0; // allocate combined buffers int totalVert = a.vertexCount + b.vertexCount; int totalPos = totalVert * 3; int totalNorm = totalVert * 3; int totalUv = totalVert * 2; int totalCol = totalVert * 4; int totalIdx = a.indexCount + b.indexCount; if (totalPos > 0) { out.positions = (float*)malloc(totalPos * sizeof(float)); memcpy(out.positions, a.positions ? a.positions : nullptr, aPosCount * sizeof(float)); } else out.positions = nullptr; if (totalNorm > 0) { out.normals = (float*)malloc(totalNorm * sizeof(float)); memcpy(out.normals, a.normals ? a.normals : nullptr, aNormCount * sizeof(float)); } else out.normals = nullptr; if (totalUv > 0) { out.uvs = (float*)malloc(totalUv * sizeof(float)); memcpy(out.uvs, a.uvs ? a.uvs : nullptr, aUvCount * sizeof(float)); } else out.uvs = nullptr; if (totalCol > 0) { out.colors = (unsigned char*)malloc(totalCol * sizeof(unsigned char)); memcpy(out.colors, a.colors ? a.colors : nullptr, aColCount * sizeof(unsigned char)); } else out.colors = nullptr; if (totalIdx > 0) { out.indices = (unsigned short*)malloc(totalIdx * sizeof(unsigned short)); if (a.indices && aIdxCount > 0) memcpy(out.indices, a.indices, aIdxCount * sizeof(unsigned short)); } else out.indices = nullptr; // copy B data appending with index offset // positions if (bPosCount > 0) { memcpy(out.positions + aPosCount, b.positions, bPosCount * sizeof(float)); } // normals if (bNormCount > 0) { memcpy(out.normals + aNormCount, b.normals, bNormCount * sizeof(float)); } // uvs if (bUvCount > 0) { memcpy(out.uvs + aUvCount, b.uvs, bUvCount * sizeof(float)); } // colors if (bColCount > 0) { memcpy(out.colors + aColCount, b.colors, bColCount * sizeof(unsigned char)); } // indices (need to offset b indices by a.vertexCount) if (bIdxCount > 0) { unsigned short idxOffset = (unsigned short)(a.vertexCount); for (int i = 0; i < bIdxCount; ++i) { out.indices[aIdxCount + i] = (unsigned short)(b.indices[i] + idxOffset); } } out.vertexCount = totalVert; out.indexCount = totalIdx; return out; } MeshData CreateCubeMeshData(const BlockDef &def, float cx, float cy, float cz) { MeshData out = {0}; // 4 verts * 6 faces = 24 vertices const int vertsPerFace = 4; const int faces = 6; const int totalVerts = vertsPerFace * faces; const int totalPos = totalVerts * 3; const int totalNorm = totalVerts * 3; const int totalUv = totalVerts * 2; const int totalCol = totalVerts * 4; const int totalIdx = faces * 6; out.vertexCount = totalVerts; out.indexCount = totalIdx; out.positions = (float*)malloc(totalPos * sizeof(float)); out.normals = (float*)malloc(totalNorm * sizeof(float)); out.uvs = (float*)malloc(totalUv * sizeof(float)); out.colors = (unsigned char*)malloc(totalCol * sizeof(unsigned char)); out.indices = (unsigned short*)malloc(totalIdx * sizeof(unsigned short)); int p = 0, n = 0, u = 0, c = 0, ix = 0; Color baseColor = {255,255,255,255}; auto pushPos = [&](float x, float y, float z) { out.positions[p++] = x; out.positions[p++] = y; out.positions[p++] = z; }; auto pushNorm = [&](float x, float y, float z) { out.normals[n++] = x; out.normals[n++] = y; out.normals[n++] = z; }; auto pushUV = [&](float uu, float vv) { out.uvs[u++] = uu; out.uvs[u++] = vv; }; auto pushCol = [&](unsigned char r, unsigned char g, unsigned char b, unsigned char a) { out.colors[c++] = r; out.colors[c++] = g; out.colors[c++] = b; out.colors[c++] = a; }; auto pushTriIdx = [&](unsigned short a, unsigned short b, unsigned short c2) { out.indices[ix++] = a; out.indices[ix++] = b; out.indices[ix++] = c2; }; // get UV corners for faces UVCorners UVside = GetUVTex(def.textureSide); UVCorners UVtop = GetUVTex(def.textureTop); UVCorners UVbtm = GetUVTex(def.textureBottom); // face builder: verts in CCW for the outside-facing side auto buildFace = [&](const Vector3 faceVerts[4], const Vector3 &normal, const Vector2 faceUVs[4]) { unsigned short base = (unsigned short)((p/3)); // current vertex index Color clr = baseColor; for (int i=0;i<4;i++) { pushPos(faceVerts[i].x, faceVerts[i].y, faceVerts[i].z); pushNorm(normal.x, normal.y, normal.z); pushUV(faceUVs[i].x, faceUVs[i].y); pushCol(clr.r, clr.g, clr.b, clr.a); } // two tris (0,1,2) (0,2,3) pushTriIdx(base + 0, base + 1, base + 2); pushTriIdx(base + 0, base + 2, base + 3); }; float hx = 0.5f, hy = 0.5f, hz = 0.5f; // Left (-X) { Vector3 verts[4] = { {cx - hx, cy - hy, cz - hz}, {cx - hx, cy - hy, cz + hz}, {cx - hx, cy + hy, cz + hz}, {cx - hx, cy + hy, cz - hz} }; Vector2 uvs[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; Vector3 normal = {-1,0,0}; buildFace(verts, normal, uvs); } // Right (+X) { Vector3 verts[4] = { {cx + hx, cy - hy, cz + hz}, {cx + hx, cy - hy, cz - hz}, {cx + hx, cy + hy, cz - hz}, {cx + hx, cy + hy, cz + hz} }; Vector2 uvs[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; Vector3 normal = {1,0,0}; buildFace(verts, normal, uvs); } // Down (-Y) { Vector3 verts[4] = { {cx - hx, cy - hy, cz - hz}, {cx + hx, cy - hy, cz - hz}, {cx + hx, cy - hy, cz + hz}, {cx - hx, cy - hy, cz + hz} }; Vector2 uvs[4] = { UVbtm.corner0, UVbtm.corner1, UVbtm.corner2, UVbtm.corner3 }; Vector3 normal = {0,-1,0}; buildFace(verts, normal, uvs); } // Up (+Y) { Vector3 verts[4] = { {cx - hx, cy + hy, cz + hz}, {cx + hx, cy + hy, cz + hz}, {cx + hx, cy + hy, cz - hz}, {cx - hx, cy + hy, cz - hz} }; Vector2 uvs[4] = { UVtop.corner0, UVtop.corner1, UVtop.corner2, UVtop.corner3 }; Vector3 normal = {0,1,0}; buildFace(verts, normal, uvs); } // Front (+Z) { Vector3 verts[4] = { {cx - hx, cy - hy, cz + hz}, {cx + hx, cy - hy, cz + hz}, {cx + hx, cy + hy, cz + hz}, {cx - hx, cy + hy, cz + hz} }; Vector2 uvs[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; Vector3 normal = {0,0,1}; buildFace(verts, normal, uvs); } // Back (-Z) { Vector3 verts[4] = { {cx + hx, cy - hy, cz - hz}, {cx - hx, cy - hy, cz - hz}, {cx - hx, cy + hy, cz - hz}, {cx + hx, cy + hy, cz - hz} }; Vector2 uvs[4] = { UVside.corner0, UVside.corner1, UVside.corner2, UVside.corner3 }; Vector3 normal = {0,0,-1}; buildFace(verts, normal, uvs); } return out; } Mesh GenChunkMesh(MeshData meshData) { Mesh mesh = { 0 }; mesh.indices = meshData.indices; mesh.vertexCount = meshData.vertexCount; mesh.triangleCount = meshData.indexCount / 3; mesh.vertices = meshData.positions; mesh.texcoords = meshData.uvs; mesh.normals = meshData.normals; mesh.colors = meshData.colors; UploadMesh(&mesh, false); return mesh; } #endif #endif