diff --git a/TODO.txt b/TODO.txt index f65fc13..047249e 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,3 +1,7 @@ +- based viewing distance idea: limit number of rendered map triangles to N, keep + sorting the triangle array by distance continually! e.g. in each frame handle + one of the N visible triangles like this -- in the non-visible triangles + find one that is closer than this and switch them (if found). - sky images could be just composed of 4x4 normal images? then we only need one type of image - map actually in ASCII format? how will humans edit it? diff --git a/assets.h b/assets.h index 3368afe..c6b4528 100644 --- a/assets.h +++ b/assets.h @@ -15,7 +15,15 @@ static const uint8_t map1[] = 0, LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0), LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0), - LCR_MAP_BLOCK(LCR_BLOCK_RAMP_CURVED_WALL,34,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0), + + LCR_MAP_BLOCK(LCR_BLOCK_RAMP_CURVED_WALL,34,32,32,LCR_BLOCK_MATERIAL_CONCRETE,LCR_BLOCK_TRANSFORM_ROT_90), + + LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,33,32,LCR_BLOCK_MATERIAL_CONCRETE,0), + LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,33,32,LCR_BLOCK_MATERIAL_CONCRETE,0), + LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,33,33,LCR_BLOCK_MATERIAL_CONCRETE,0), + LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,33,33,LCR_BLOCK_MATERIAL_CONCRETE,0), + LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,32,33,LCR_BLOCK_MATERIAL_CONCRETE,0), + LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,32,33,LCR_BLOCK_MATERIAL_CONCRETE,0), LCR_MAP_TERMINATOR }; diff --git a/map.h b/map.h index 59309f4..bd51607 100644 --- a/map.h +++ b/map.h @@ -45,8 +45,6 @@ coordinate number. */ -#define LCR_BLOCK_TRANSFORM_ROT_MASK 0x60 - #define LCR_BLOCK_TRANSFORM_FLIP_H 0x10 #define LCR_BLOCK_TRANSFORM_ROT_90 0x20 #define LCR_BLOCK_TRANSFORM_ROT_180 0x40 @@ -59,10 +57,9 @@ #define LCR_MAP_MAGIC_NUMBER2 'M' #define LCR_MAP_MAGIC_NUMBER LCR_MAP_MAGIC_NUMBER1, LCR_MAP_MAGIC_NUMBER2 #define LCR_MAP_TERMINATOR 0xff -#define LCR_MAP_BLOCK(t,x,y,z,m,r) t,(unsigned char) (x | (y << 6)), \ - (unsigned char) ((y >> 2) | (z << 4)), \ - (unsigned char) ((z >> 4) | (m << 2) | \ - (r << 4)) +#define LCR_MAP_BLOCK(t,x,y,z,m,r) t,(uint8_t) (x | (y << 6)), \ + (uint8_t) ((y >> 2) | (z << 4)), \ + (uint8_t) ((z >> 4) | (m << 2) | (r)) #define LCR_BLOCK_SIZE 4 ///< size of map block, in bytes @@ -136,6 +133,11 @@ void LCR_mapBlockGetCoords(const uint8_t block[LCR_BLOCK_SIZE], *z = (block[2] >> 4) | ((block[3] & 0x03) << 4); } +uint8_t LCR_mapBlockGetTransform(const uint8_t block[LCR_BLOCK_SIZE]) +{ + return block[3] & 0xf0; +} + uint32_t LCR_mapBlockGetCoordNumber(const uint8_t block[LCR_BLOCK_SIZE]) { return block[1] | (((uint32_t) block[2]) << 8) | diff --git a/renderer.h b/renderer.h index d31fbac..4424223 100644 --- a/renderer.h +++ b/renderer.h @@ -79,6 +79,126 @@ void _LCR_addMapTriangle(S3L_Index a, S3L_Index b, S3L_Index c) } } +void _LCR_rendererSwapTriangles(S3L_Index *t1, S3L_Index *t2) +{ + S3L_Index tmp; + + for (int i = 0; i < 3; ++i) + { + tmp = t1[i]; + t1[i] = t2[i]; + t2[i] = tmp; + } +} + +/** + Checks whether two triangles (and potenrially their neighbors) cover each + other, in return values lowest bit means whether t1 is covered and the second + lowest bit means whether t2 is covered. +*/ +uint8_t _LCR_rendererCheckMapTriangleCover(const S3L_Index *t1, + const S3L_Index *t2) +{ + if ((t1[0] == t2[0] || t1[0] == t2[1] || t1[0] == t2[2]) && + (t1[1] == t2[0] || t1[1] == t2[1] || t1[1] == t2[2]) && + (t1[2] == t2[0] || t1[2] == t2[1] || t1[2] == t2[2])) + return 0x03; // same indices => both are covered + + return 0; +} + +/** + Removes map triangles that are covered by other triangles (and also vertices + that by this become unused). This makes the map model smaller, faster and + prevents bleeding through due to z-bugger imprecisions. +*/ +void _LCR_rendererPruneHiddenMapTriangles(void) +{ + int n = 0; // number of removed elements + int i = 0; + + S3L_Index *t1 = LCR_mapTriangles, *t2; + + /* + We'll be moving the covered triangles to the end of the array, then at the + end we'll just shorten the array. + */ + while (i < LCR_mapModel->triangleCount - n) + { + t2 = t1 + 3; + + int t1Covered = 0; + + for (int j = i + 1; j < LCR_mapModel->triangleCount; ++j) + { + uint8_t cover = _LCR_rendererCheckMapTriangleCover(t1,t2); + + t1Covered |= cover & 0x01; + + if (cover & 0x02) + { + if (j < LCR_mapModel->triangleCount - n) + { + _LCR_rendererSwapTriangles(t2, + LCR_mapTriangles + (LCR_mapModel->triangleCount - 1 - n) * 3); + + n++; + } + } + + t2 += 3; + } + + if (t1Covered) + { + _LCR_rendererSwapTriangles(t1, + LCR_mapTriangles + (LCR_mapModel->triangleCount - 1 - n) * 3); + n++; + } + else + { + t1 += 3; + i++; + } + } + + LCR_mapModel->triangleCount -= n; + + // remove unused vertices: + + i = 0; + +printf("ASASA %d\n",LCR_mapModel->vertexCount); + + while (i < LCR_mapModel->vertexCount) + { + int used = 0; + + for (int j = 0; j < LCR_mapModel->triangleCount * 3; ++j) + if (LCR_mapTriangles[j] == i) + { + used = 1; + break; + } + + if (used) + i++; + else + { + for (int j = 0; j < 3; ++j) + LCR_mapVertices[3 * i + j] = + LCR_mapVertices[(LCR_mapModel->vertexCount - 1) * 3 + j]; + + for (int j = 0; j < LCR_mapModel->triangleCount * 3; ++j) + if (LCR_mapTriangles[j] == LCR_mapModel->vertexCount - 1) + LCR_mapTriangles[j] = i; + + LCR_mapModel->vertexCount--; + } + } +printf("ASASA %d\n",LCR_mapModel->vertexCount); +} + /** Builds an internal 3D model of the currently loaded map. Returns 1 on success, otherwise 0 (e.g. not enough space). @@ -93,9 +213,11 @@ uint8_t _LCR_rendererBuildMapModel(void) for (int j = 0; j < LCR_currentMap.blockCount; ++j) { uint8_t bx, by, bz; - LCR_mapBlockGetCoords(LCR_currentMap.blocks + j * LCR_BLOCK_SIZE,&bx,&by,&bz); + LCR_mapBlockGetCoords(LCR_currentMap.blocks + j * LCR_BLOCK_SIZE, + &bx,&by,&bz); - LCR_mapGetBlockShape(LCR_currentMap.blocks[j * LCR_BLOCK_SIZE],0, + LCR_mapGetBlockShape(LCR_currentMap.blocks[j * LCR_BLOCK_SIZE], + LCR_mapBlockGetTransform(LCR_currentMap.blocks + j * LCR_BLOCK_SIZE), blockShapeBytes,&blockShapeByteCount); uint8_t vx, vy, vz, vi = 0; @@ -124,6 +246,8 @@ uint8_t _LCR_rendererBuildMapModel(void) } } +_LCR_rendererPruneHiddenMapTriangles(); + return 1; }