From 672c17eec1a109ad1ca98b9efa67b97fb1130171 Mon Sep 17 00:00:00 2001 From: Miloslav Ciz Date: Tue, 6 Aug 2024 01:34:38 +0200 Subject: [PATCH] Start map chunks --- assets.h | 21 +++--- map.h | 21 ++++-- renderer.h | 215 +++++++++++++++++++++++++++++++++++++++++++++++------ settings.h | 7 ++ 4 files changed, 224 insertions(+), 40 deletions(-) diff --git a/assets.h b/assets.h index 8cf565e..29bd7d2 100644 --- a/assets.h +++ b/assets.h @@ -25,25 +25,26 @@ static const uint8_t map1[] = 10, 10, 0, - + LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,32,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0), - LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,3,4,5,0,0), + LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,3,4,4,0,0), LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,40,34,33,LCR_BLOCK_MATERIAL_CONCRETE,0), - LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,6,7,2,0,0), + LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,4,3,2,0,0), -/* LCR_MAP_BLOCK(LCR_BLOCK_FULL,50,20,20,LCR_BLOCK_MATERIAL_GRASS,0), - LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,5,5,5,0,0), + LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,5,5,5,0,0), LCR_MAP_BLOCK(LCR_BLOCK_FULL,10,10,10,LCR_BLOCK_MATERIAL_GRASS,0), - LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,7,3,8,0,0), + LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,3,3,3,0,0), - LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,15,30,LCR_BLOCK_MATERIAL_GRASS,0), - LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,7,4,8,0,0), -*/ + LCR_MAP_BLOCK(LCR_BLOCK_FULL,2,25,50,LCR_BLOCK_MATERIAL_GRASS,0), + LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,3,3,3,0,0), /* + LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,15,0,LCR_BLOCK_MATERIAL_GRASS,0), + LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,7,4,8,0,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_GRASS,0), LCR_MAP_BLOCK(LCR_BLOCK_RAMP_CURVED_WALL,34,32,32,LCR_BLOCK_MATERIAL_GRASS,0), @@ -84,7 +85,7 @@ const uint8_t *_LCR_currentImage; #define LCR_IMAGE_GROUND_DIRT 4 #define LCR_IMAGE_GROUND_ICE 5 #define LCR_IMAGE_GROUND_ACCEL 6 -#define LCR_IMAGE_GROUND_STICKER 7 +#define LCR_IMAGE_GROUND_FAN 7 static const uint8_t LCR_images[] = { diff --git a/map.h b/map.h index a6cb5f7..b460465 100644 --- a/map.h +++ b/map.h @@ -83,7 +83,7 @@ #define LCR_BLOCK_RAMP_CURVED_WALL 0x09 #define LCR_BLOCK_FULL_ACCEL 0x20 -#define LCR_BLOCK_FULL_STICKER 0x30 +#define LCR_BLOCK_FULL_FAN 0x30 #define LCR_BLOCK_CHECKPOINT_0 0x40 ///< checkpoint, not taken #define LCR_BLOCK_CHECKPOINT_1 0x41 ///< checkpoint, taken @@ -285,6 +285,7 @@ uint8_t LCR_mapLoad(const uint8_t *map) switch (*map) { case LCR_BLOCK_CUBOID_FILL: + case LCR_BLOCK_CUBOID_HOLLOW: { const uint8_t *prevBlock = map - LCR_BLOCK_SIZE; uint8_t x, y, z, w, h, d, mat, transform; @@ -301,13 +302,17 @@ uint8_t LCR_mapLoad(const uint8_t *map) for (uint8_t k = 0; k < d; ++k) for (uint8_t j = 0; j < h; ++j) for (uint8_t i = 0; i < w; ++i) - { - LCR_makeMapBlock(prevBlock[0],x + i,y + j,z + k,mat,transform, - tmpBlock); + if (*map == LCR_BLOCK_CUBOID_FILL || + k == 0 || k == d - 1 || + j == 0 || j == h - 1 || + i == 0 || i == w - 1) + { + LCR_makeMapBlock(prevBlock[0],x + i,y + j,z + k,mat,transform, + tmpBlock); - if (!_LCR_mapAddBlock(tmpBlock)) - return 0; - } + if (!_LCR_mapAddBlock(tmpBlock)) + return 0; + } break; } @@ -413,7 +418,7 @@ void LCR_mapGetBlockShape(uint8_t blockType, uint8_t transform, case LCR_BLOCK_BOTTOM_LEFT: case LCR_BLOCK_BOTTOM_LEFT_FRONT: case LCR_BLOCK_FULL_ACCEL: - case LCR_BLOCK_FULL_STICKER: + case LCR_BLOCK_FULL_FAN: { uint8_t xRight = 6, yTop = 4, zBack = 6 >> (blockType == LCR_BLOCK_BOTTOM_LEFT_FRONT); diff --git a/renderer.h b/renderer.h index 1ba610a..1e3e9f0 100644 --- a/renderer.h +++ b/renderer.h @@ -10,7 +10,7 @@ #define S3L_PIXEL_FUNCTION LCR_pixelFunc3D #define S3L_PERSPECTIVE_CORRECTION 2 -#define S3L_NEAR_CROSS_STRATEGY 0 +#define S3L_NEAR_CROSS_STRATEGY 1 #define S3L_Z_BUFFER 1 @@ -19,15 +19,32 @@ /// Renderer specific unit, length of one map square. #define LCR_RENDERER_UNIT S3L_FRACTIONS_PER_UNIT +#define LCR_RENDERER_CHUNK_RESOLUTION 4 + +#define LCR_RENDERER_CHUNK_SIZE_HORIZONTAL \ + ((LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT) / LCR_RENDERER_CHUNK_RESOLUTION) + +#define LCR_RENDERER_CHUNKS_TOTAL (LCR_RENDERER_CHUNK_RESOLUTION * \ + LCR_RENDERER_CHUNK_RESOLUTION * LCR_RENDERER_CHUNK_RESOLUTION) + struct { S3L_Scene scene; - S3L_Model3D models[3]; // TODO + S3L_Model3D models[9]; /**< 0: whole map model, + 1, 2, 3, 4, 5, 6, 7, 8: nearest map chunks + models */ + /* TODO: separate the whole model from the array? it's confusing if it's + in the array and then doesn't get rendered? */ + + uint8_t loadedChunks[8]; S3L_Model3D *mapModel; S3L_Unit mapVerts[LCR_SETTING_MAX_MAP_VERTICES * 3]; S3L_Index mapTris[LCR_SETTING_MAX_MAP_TRIANGLES * 3]; + + S3L_Index chunkStarts[LCR_RENDERER_CHUNKS_TOTAL]; + /** Additional data for triangles. 4 higher bits hold direction (for lighting): 0 is floor, 1 is wall, 2 is wall (90 degrees). 4 lower bits hold the @@ -38,22 +55,37 @@ struct // pixel function precomputed values: int previousTriID; int triUVs[6]; + uint8_t texSubsampleCount; } LCR_renderer; +uint16_t ccc; +int cnt = 0; + void LCR_pixelFunc3D(S3L_PixelInfo *pixel) { // once we get a new triangle, we precompute things for it: if (pixel->triangleIndex != LCR_renderer.previousTriID) { - S3L_Index *t = LCR_renderer.mapTris + 3 * pixel->triangleIndex; + const S3L_Index *t = + LCR_renderer.models[1 + pixel->modelIndex].triangles + + 3 * pixel->triangleIndex; S3L_Unit *v[3]; +#if LCR_SETTING_TEXTURE_SUBSAMPLE != 0 + LCR_renderer.texSubsampleCount = 0; +#endif + for (int i = 0; i < 3; ++i) v[i] = LCR_renderer.mapVerts + 3 * t[i]; - uint8_t type = LCR_renderer.mapTriangleData[pixel->triangleID] >> 4; + const uint8_t *triData = + LCR_renderer.mapTriangleData + + LCR_renderer.chunkStarts[LCR_renderer.loadedChunks[ + pixel->modelIndex]]; - LCR_loadImage(LCR_renderer.mapTriangleData[pixel->triangleID] & 0x0f); + uint8_t type = triData[pixel->triangleIndex] >> 4; + + LCR_loadImage(triData[pixel->triangleIndex] & 0x0f); if (type == 0) // floor? { @@ -106,21 +138,34 @@ void LCR_pixelFunc3D(S3L_PixelInfo *pixel) LCR_renderer.previousTriID = pixel->triangleIndex; } - int barycentric[3]; + uint16_t color; - barycentric[0] = pixel->barycentric[0] / 8; - barycentric[1] = pixel->barycentric[1] / 8; - barycentric[2] = pixel->barycentric[2] / 8; +#if LCR_SETTING_TEXTURE_SUBSAMPLE != 0 + if (LCR_renderer.texSubsampleCount == 0) + { +#endif + int barycentric[3]; - uint16_t color = LCR_sampleImage( - (barycentric[0] * LCR_renderer.triUVs[0] + - barycentric[1] * LCR_renderer.triUVs[2] + - barycentric[2] * LCR_renderer.triUVs[4]) - / (S3L_FRACTIONS_PER_UNIT / 8), - (barycentric[0] * LCR_renderer.triUVs[1] + - barycentric[1] * LCR_renderer.triUVs[3] + - barycentric[2] * LCR_renderer.triUVs[5]) - / (S3L_FRACTIONS_PER_UNIT / 8)); + barycentric[0] = pixel->barycentric[0] / 8; + barycentric[1] = pixel->barycentric[1] / 8; + barycentric[2] = pixel->barycentric[2] / 8; + + color = LCR_sampleImage( + (barycentric[0] * LCR_renderer.triUVs[0] + + barycentric[1] * LCR_renderer.triUVs[2] + + barycentric[2] * LCR_renderer.triUVs[4]) + / (S3L_FRACTIONS_PER_UNIT / 8), + (barycentric[0] * LCR_renderer.triUVs[1] + + barycentric[1] * LCR_renderer.triUVs[3] + + barycentric[2] * LCR_renderer.triUVs[5]) + / (S3L_FRACTIONS_PER_UNIT / 8)); + +#if LCR_SETTING_TEXTURE_SUBSAMPLE != 0 + LCR_renderer.texSubsampleCount = LCR_SETTING_TEXTURE_SUBSAMPLE; + } + + LCR_renderer.texSubsampleCount--; +#endif LCR_drawPixelXYUnsafe(pixel->x,pixel->y,color); } @@ -445,6 +490,47 @@ void _LCR_cullHiddenMapTris(void) } } +void _LCR_makeMapChunks(void) +{ + LCR_log("making map chunks"); + + S3L_Index start = 0; + + for (int chunkNo = 0; chunkNo < LCR_RENDERER_CHUNKS_TOTAL; ++chunkNo) + { + S3L_Unit chunkCorner[3]; + const S3L_Index *tri = LCR_renderer.mapTris + 3 * start; + + LCR_renderer.chunkStarts[chunkNo] = start; + + chunkCorner[0] = (chunkNo & 0x03) * LCR_RENDERER_CHUNK_SIZE_HORIZONTAL; + chunkCorner[1] = ((chunkNo >> 2) & 0x03) * (LCR_RENDERER_CHUNK_SIZE_HORIZONTAL / 2); + chunkCorner[2] = ((chunkNo >> 4) & 0x03) * LCR_RENDERER_CHUNK_SIZE_HORIZONTAL; + + chunkCorner[0] -= LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 2; + chunkCorner[1] -= LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 4; + chunkCorner[2] -= LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 2; + + for (int i = start; i < LCR_renderer.mapModel->triangleCount; ++i) + { + const S3L_Unit *v = LCR_renderer.mapVerts + 3 * tri[0]; + + if (v[0] >= chunkCorner[0] && + v[0] < chunkCorner[0] + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL && + v[1] >= chunkCorner[1] && + v[1] < chunkCorner[1] + (LCR_RENDERER_CHUNK_SIZE_HORIZONTAL / 2) && + v[2] >= chunkCorner[2] && + v[2] < chunkCorner[2] + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL) + { + _LCR_swapMapTris(i,start); + start++; + } + + tri += 3; + } + } +} + /** Builds the internal 3D model of the currently loaded map. Returns 1 on success, 0 otherwise (e.g. not enough space). @@ -524,15 +610,15 @@ uint8_t _LCR_buildMapModel(void) ((blockMat == LCR_BLOCK_MATERIAL_CONCRETE) || (blockMat == LCR_BLOCK_MATERIAL_ICE) || (blockType == LCR_BLOCK_FULL_ACCEL) || - (blockType == LCR_BLOCK_FULL_STICKER)) ? + (blockType == LCR_BLOCK_FULL_FAN)) ? LCR_IMAGE_WALL_CONCRETE : LCR_IMAGE_WALL_WOOD; } else { // TODO: tidy this mess? if (blockType == LCR_BLOCK_FULL_ACCEL) triData |= LCR_IMAGE_GROUND_ACCEL; - else if (blockType == LCR_BLOCK_FULL_STICKER) - triData |= LCR_IMAGE_GROUND_STICKER; + else if (blockType == LCR_BLOCK_FULL_FAN) + triData |= LCR_IMAGE_GROUND_FAN; else switch (blockMat) { @@ -583,7 +669,10 @@ uint8_t LCR_rendererInit(void) if (!_LCR_buildMapModel()) return 0; - S3L_sceneInit(LCR_renderer.models,1,&LCR_renderer.scene); + _LCR_makeMapChunks(); + + S3L_sceneInit( + LCR_renderer.models + 1,8,&LCR_renderer.scene); return 1; } @@ -619,6 +708,18 @@ void LCR_rendererMoveCamera(LCR_SpaceUnit forwRightUpOffset[3], if (LCR_renderer.scene.camera.transform.rotation.x < -1 * S3L_FRACTIONS_PER_UNIT / 4) LCR_renderer.scene.camera.transform.rotation.x = -1 * S3L_FRACTIONS_PER_UNIT / 4; + +#define chk(o,c,l) \ + if (LCR_renderer.scene.camera.transform.translation.c o l) \ + LCR_renderer.scene.camera.transform.translation.c = l; + +chk(<,x,-1 * LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 2) +chk(>,x,LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 2) +chk(<,y,-1 * LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 4) +chk(>,y,LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 4) +chk(<,z,-1 * LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 2) +chk(>,z,LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT / 2) + } /** @@ -749,11 +850,81 @@ void LCR_rendererDrawSky(int sky, S3L_Unit offsetH, S3L_Unit offsetV) } } +void _LCR_loadMapChunk(uint8_t chunk, int8_t x, int8_t y, int8_t z) +{ + LCR_renderer.models[chunk + 1] = LCR_renderer.models[0]; + + if (x < 0 || x >= LCR_RENDERER_CHUNK_RESOLUTION || + y < 0 || y >= LCR_RENDERER_CHUNK_RESOLUTION || + z < 0 || z >= LCR_RENDERER_CHUNK_RESOLUTION) + { + LCR_renderer.models[chunk + 1].triangleCount = 0; + LCR_renderer.loadedChunks[chunk] = 0; + } + else + { + int blockNum = x | (y << 2) | (z << 4); + + LCR_renderer.loadedChunks[chunk] = blockNum; + + int triCount = + (blockNum == LCR_RENDERER_CHUNKS_TOTAL - 1 ? + (LCR_renderer.mapModel->triangleCount - 1) : + LCR_renderer.chunkStarts[blockNum + 1]) + - LCR_renderer.chunkStarts[blockNum]; + + if (triCount < 0) + triCount = 0; + + LCR_renderer.models[chunk + 1].triangles = + LCR_renderer.mapTris + LCR_renderer.chunkStarts[blockNum] * 3; + + LCR_renderer.models[chunk + 1].triangleCount = triCount; + } +} + +void _LCR_loadMapChunks(void) +{ + int8_t camChunk[3], chunkOffsets[3]; + S3L_Vec4 cp = LCR_renderer.scene.camera.transform.translation; + + camChunk[0] = (cp.x + (LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT) / 2) + / LCR_RENDERER_CHUNK_SIZE_HORIZONTAL; + + camChunk[1] = (cp.y + (LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT) / 4) + / (LCR_RENDERER_CHUNK_SIZE_HORIZONTAL / 2); + + camChunk[2] = ((cp.z + (LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT) / 2) + / LCR_RENDERER_CHUNK_SIZE_HORIZONTAL); + + uint8_t camRot = S3L_wrap(LCR_renderer.scene.camera.transform.rotation.y + + S3L_FRACTIONS_PER_UNIT / 8,S3L_FRACTIONS_PER_UNIT) / + (S3L_FRACTIONS_PER_UNIT / 4); + + uint8_t camSide = (((camRot % 2) ? cp.x : cp.z) % + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL) >= + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL / 2; + + chunkOffsets[(camRot % 2) ? 0 : 2] = (camRot == 1 || camRot == 2) ? -1 : 1; + chunkOffsets[(camRot % 2) ? 2 : 0] = (camSide == (camRot < 2)) ? 1 : -1; + + chunkOffsets[1] = + LCR_renderer.scene.camera.transform.rotation.x <= 0 ? -1 : 1; + + for (uint8_t i = 0; i < 8; ++i) + _LCR_loadMapChunk(i, + camChunk[0] + ((i & 0x01) ? chunkOffsets[0] : 0), + camChunk[1] + ((i & 0x02) ? chunkOffsets[1] : 0), + camChunk[2] + ((i & 0x04) ? chunkOffsets[2] : 0)); +} + void LCR_rendererDraw(void) { LCR_renderer.previousTriID = -1; S3L_newFrame(); + _LCR_loadMapChunks(); + LCR_rendererDrawSky(2, LCR_renderer.scene.camera.transform.rotation.y, -4 * LCR_renderer.scene.camera.transform.rotation.x); diff --git a/settings.h b/settings.h index b86a9ba..556c4aa 100644 --- a/settings.h +++ b/settings.h @@ -63,4 +63,11 @@ #define LCR_SETTING_TRIANGLE_CULLING_PERIOD 64 #endif +#ifndef LCR_SETTING_TEXTURE_SUBSAMPLE + /** Sets texture subsampling: 0 means no subsampling, higher value N means a + texture will be sampled once per N rasterized pixels. Higher value can + increase performance. */ + #define LCR_SETTING_TEXTURE_SUBSAMPLE 4 +#endif + #endif // guard