SHOW:
|
|
- or go back to the newest paste.
| 1 | // in the snippet following variables will be needed: | |
| 2 | // chunkSizeX/Y/Z - the size of one chunk in the x/y/z-direction | |
| 3 | // sectionHeight - the height of one section inside a chunk, e.g.: sectionHeight = 16 and chunkSizeY=256 makes 16 sections | |
| 4 | // currentChunk - reference to a Chunk structure | |
| 5 | ||
| 6 | ||
| 7 | enum Face | |
| 8 | {
| |
| 9 | North = 1, | |
| 10 | East = 2, | |
| 11 | South = 4, | |
| 12 | West = 8, | |
| 13 | Top = 16, | |
| 14 | Bottom = 32 | |
| 15 | }; | |
| 16 | ||
| 17 | struct Block | |
| 18 | {
| |
| 19 | int Type; | |
| 20 | Face VisibleFaces; | |
| 21 | }; | |
| 22 | ||
| 23 | struct Chunk | |
| 24 | {
| |
| 25 | float x, y, z; | |
| 26 | Block blockData[]; | |
| 27 | }; | |
| 28 | ||
| 29 | ||
| 30 | int numBlocksPerSection = chunkSizeX * sectionHeight * chunkSizeZ; | |
| 31 | bool handled[] = new bool[numBlocksPerSection]; | |
| 32 | Face activeFace = (Face)1; | |
| 33 | ||
| 34 | // iterate over all 6 faces | |
| 35 | for (int f = 0; f < 6; ++f) | |
| 36 | {
| |
| 37 | // reset all blocks not to be handled | |
| 38 | memset(handled, FALSE, numBlocksPerSection); | |
| 39 | ||
| 40 | for(int x = 0; x < chunkSizeX; ++x) | |
| 41 | {
| |
| 42 | for(int y = 0; y < sectionHeight; ++y) | |
| 43 | {
| |
| 44 | for(int z = 0; z < chunkSizeZ; ++z) | |
| 45 | {
| |
| 46 | // global and relative indices | |
| 47 | int iGlobal = x + chunkSizeX * ((y + currentSection * sectionHeight) + chunkSizeY * z); | |
| 48 | int iRelative = x + chunkSizeX * (y + sectionHeight * z); | |
| 49 | ||
| 50 | Face faces = currentChunk.blockData[iGlobal].VisibleFaces; | |
| 51 | ||
| 52 | // continue if face is not visible or was handled already | |
| 53 | if(!(faces & activeFace) || handled[iRelative]) | |
| 54 | {
| |
| 55 | handled[iRelative] = true; | |
| 56 | continue; | |
| 57 | } | |
| 58 | ||
| 59 | int width = 1, height = 1, depth = 1; | |
| 60 | ||
| 61 | // skip width check if activeFace is East or West -> no width | |
| 62 | if(!(activeFace & East || activeFace & West)) | |
| 63 | {
| |
| 64 | // calculate width for same faces being adjacent to current block | |
| 65 | for(; width < chunkSizeX - x && | |
| 66 | currentChunk.blockData[SHIFT_INDEX_X(iGlobal, width)].VisibleFaces & tmp && | |
| 67 | currentChunk.blockData[iGlobal].Type == currentChunk.blockData[SHIFT_INDEX_X(iGlobal, width)].Type && | |
| 68 | && !handled[SHIFT_SECTIONINDEX_X(iRelative, width)]; ++width); | |
| 69 | } | |
| 70 | ||
| 71 | bool done = false; | |
| 72 | ||
| 73 | // skip depth check if activeFace is North or South -> no depth | |
| 74 | if(!(activeFace & North || activeFace & South)) | |
| 75 | {
| |
| 76 | // calculate depth for same faces being adjacent to current block | |
| 77 | for(; depth < chunkSizeZ - z; ++depth) | |
| 78 | {
| |
| 79 | // this time add another loop, to make sure, only increment depth if all blocks inside the width range are same | |
| 80 | for(int u = 0; u < width; ++u) | |
| 81 | {
| |
| 82 | int indexGlobal = SHIFT_INDEX_X(SHIFT_INDEX_Z(iGlobal, depth), u); | |
| 83 | int indexRelative = SHIFT_RELATIVEINDEX_X(SHIFT_RELATIVEINDEX_Z(iRelative, depth), u); | |
| 84 | if(!(currentChunk.blockData[indexGlobal].VisibleFaces & activeFace && | |
| 85 | currentChunk.blockData[iGlobal].Type == currentChunk.blockData[indexGlobal].Type) || | |
| 86 | handled[indexRelative]) | |
| 87 | {
| |
| 88 | done = true; | |
| 89 | break; | |
| 90 | } | |
| 91 | } | |
| 92 | if(done) | |
| 93 | break; | |
| 94 | } | |
| 95 | } | |
| 96 | ||
| 97 | done = false; | |
| 98 | ||
| 99 | // skip height check if activeFace is Top or Bottom -> no height | |
| 100 | if(!(activeFace & Top || activeFace & Bottom)) | |
| 101 | {
| |
| 102 | // calculate height | |
| 103 | for(; height < sectionHeight - y; ++height) | |
| 104 | {
| |
| 105 | // add loops for width and depth | |
| 106 | for(int u = 0; u < width; ++u) | |
| 107 | {
| |
| 108 | for(int v = 0; v < depth; ++v) | |
| 109 | {
| |
| 110 | int indexGlobal = SHIFT_INDEX_X(SHIFT_INDEX_Y(SHIFT_INDEX_Z(iGlobal, v), height), u); | |
| 111 | int indexRelative = SHIFT_RELATIVEINDEX_X(SHIFT_RELATIVEINDEX_Y(SHIFT_RELATIVEINDEX_Z(iRelative, v), height), u); | |
| 112 | if(!(currentChunk.blockData[indexGlobal].VisibleFaces & activeFace || | |
| 113 | currentChunk.blockData[iGlobal].Type == currentChunk.blockData[indexGlobal].Type) || | |
| 114 | handled[indexRelative]) | |
| 115 | {
| |
| 116 | done = true; | |
| 117 | break; | |
| 118 | } | |
| 119 | } | |
| 120 | if(done) break; | |
| 121 | } | |
| 122 | if(done) break; | |
| 123 | } | |
| 124 | } | |
| 125 | ||
| 126 | // make sure we add the calculated face range to the handled array | |
| 127 | for(int a = 0; a < width; ++a) | |
| 128 | for(int b = 0; b < height; ++b) | |
| 129 | for(int c = 0; c < depth; ++c) | |
| 130 | handled[SHIFT_RELATIVEINDEX_X(SHIFT_RELATIVEINDEX_Y(SHIFT_RELATIVEINDEX_Z(iRelative, c), b), a)] = true; | |
| 131 | ||
| 132 | // add the quad's vertices here, dependent on the activeFace, | |
| 133 | // e.g. for North and a counter-clockwise ordering: | |
| 134 | // position1 = vector3(width + x + currentChunk.x, y + currentChunk.y, depth + z + currentChunk.z); | |
| 135 | // position2 = vector3(width + x + currentChunk.x, y + height + currentChunk.y, depth + z + currentChunk.z); | |
| 136 | // position3 = vector3(x + currentChunk.x, y + height + currentChunk.y, depth + z + currentChunk.z); | |
| 137 | // position4 = vector3(x + currentChunk.x, y + currentChunk.y, depth + z + currentChunk.z); | |
| 138 | } | |
| 139 | } | |
| 140 | } | |
| 141 | ||
| 142 | activeFace = (Face)(activeFace * 2); | |
| 143 | } |