Improve renderer, handle textures

This commit is contained in:
Miloslav Ciz 2024-08-01 21:41:21 +02:00
parent 2b4516f408
commit 2241b4d635
5 changed files with 191 additions and 59 deletions

View file

@ -1,3 +1,4 @@
- maybe change sticker to fan? could me more fun: TEST and see
- 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

View file

@ -25,14 +25,24 @@ static const uint8_t map1[] =
10,
10,
0,
LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,0,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,63,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*/0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,32,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,33,32,32,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,34,32,32,LCR_BLOCK_MATERIAL_GRASS,LCR_BLOCK_TRANSFORM_ROT_90),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,35,32,32,LCR_BLOCK_MATERIAL_CONCRETE,LCR_BLOCK_TRANSFORM_ROT_90),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,36,32,32,LCR_BLOCK_MATERIAL_ICE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,37,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,38,32,32,LCR_BLOCK_MATERIAL_ICE,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,LCR_BLOCK_TRANSFORM_ROT_90),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP_CURVED_WALL,35,32,32,LCR_BLOCK_MATERIAL_CONCRETE,LCR_BLOCK_TRANSFORM_ROT_90),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,38,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,39,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,40,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,63,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,35,32,LCR_BLOCK_MATERIAL_ICE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,40,35,32,LCR_BLOCK_MATERIAL_DIRT,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,41,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,42,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,43,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
@ -46,6 +56,8 @@ static const uint8_t map1[] =
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
};
@ -57,6 +69,15 @@ uint16_t _LCR_currentImagePalette[256];
const uint8_t *_LCR_currentImagePixel;
const uint8_t *_LCR_currentImage;
#define LCR_IMAGE_WALL_CONCRETE 0
#define LCR_IMAGE_WALL_WOOD 1
#define LCR_IMAGE_GROUND_CONCRETE 2
#define LCR_IMAGE_GROUND_GRASS 3
#define LCR_IMAGE_GROUND_DIRT 4
#define LCR_IMAGE_GROUND_ICE 5
#define LCR_IMAGE_GROUND_ACCEL 6
#define LCR_IMAGE_GROUND_STICKER 7
static const uint8_t LCR_images[] =
{
// 0: wall concrete

3
game.h
View file

@ -113,8 +113,7 @@ void LCR_gameInit(void)
LCR_rendererInit();
LCR_loadImage(0);
LCR_loadImage(0); // ???
}
void LCR_gameEnd(void)

22
map.h
View file

@ -64,7 +64,9 @@
#define LCR_BLOCK_SIZE 4 ///< size of map block, in bytes
#define LCR_BLOCK_MATERIAL_CONCRETE 0x00
#define LCR_BLOCK_MATERIAL_DIRT 0x01
#define LCR_BLOCK_MATERIAL_GRASS 0x01
#define LCR_BLOCK_MATERIAL_DIRT 0x02
#define LCR_BLOCK_MATERIAL_ICE 0x03
#define LCR_MAP_COUNT 1
@ -80,9 +82,12 @@
#define LCR_BLOCK_RAMP_CURVED_SHORT 0x08
#define LCR_BLOCK_RAMP_CURVED_WALL 0x09
#define LCR_BLOCK_CHECKPOINT_0 0x10 ///< checkpoint, not taken
#define LCR_BLOCK_CHECKPOINT_1 0x11 ///< checkpoint, taken
#define LCR_BLOCK_FINISH 0x12 ///< finish
#define LCR_BLOCK_FULL_ACCEL 0x40
#define LCR_BLOCK_FULL_STICKER 0x60
#define LCR_BLOCK_CHECKPOINT_0 0x10 ///< checkpoint, not taken
#define LCR_BLOCK_CHECKPOINT_1 0x11 ///< checkpoint, taken
#define LCR_BLOCK_FINISH 0x12 ///< finish
// special blocks:
#define LCR_BLOCK_NONE 0x80 /**< no block, can be used e.g to make
@ -138,6 +143,11 @@ uint8_t LCR_mapBlockGetTransform(const uint8_t block[LCR_BLOCK_SIZE])
return block[3] & 0xf0;
}
uint8_t LCR_mapBlockGetMaterial(const uint8_t block[LCR_BLOCK_SIZE])
{
return (block[3] >> 2) & 0x03;
}
uint32_t LCR_mapBlockGetCoordNumber(const uint8_t block[LCR_BLOCK_SIZE])
{
return block[1] | (((uint32_t) block[2]) << 8) |
@ -301,6 +311,8 @@ void _LCR_decodeMapBlockCoords(uint8_t byte, uint8_t *x, uint8_t *y, uint8_t *z)
*z = (byte / 35);
}
#define LCR_BLOCK_SHAPE_COORD_MAX 12
/**
Decodes XYZ coordinates encoded in a byte returned by LCR_mapGetBlockShape.
Each coordinate will be in range 0 to 12 (including both). This unusual range
@ -357,6 +369,8 @@ void LCR_mapGetBlockShape(uint8_t blockType, uint8_t transform,
case LCR_BLOCK_LEFT:
case LCR_BLOCK_BOTTOM_LEFT:
case LCR_BLOCK_BOTTOM_LEFT_FRONT:
case LCR_BLOCK_FULL_ACCEL:
case LCR_BLOCK_FULL_STICKER:
{
uint8_t xRight = 6, yTop = 4,
zBack = 6 >> (blockType == LCR_BLOCK_BOTTOM_LEFT_FRONT);

View file

@ -28,6 +28,13 @@ struct
S3L_Unit mapVertices[LCR_SETTING_MAX_MAP_VERTICES * 3];
S3L_Index mapTriangles[LCR_SETTING_MAX_MAP_TRIANGLES * 3];
/**
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
texture index.
*/
uint8_t mapTriangleData[LCR_SETTING_MAX_MAP_TRIANGLES];
// pixel function precomputed values:
int previousTriangleID;
int triangleUVs[6];
@ -45,16 +52,15 @@ void LCR_pixelFunc3D(S3L_PixelInfo *pixel)
for (int i = 0; i < 3; ++i)
v[i] = LCR_renderer.mapVertices + 3 * t[i];
uint8_t type = // 0: floor, 1: wall, 2: wall 90 degrees
(v[0][0] == v[1][0] && v[1][0] == v[2][0]) +
2 * (v[0][2] == v[1][2] && v[1][2] == v[2][2]);
uint8_t type = LCR_renderer.mapTriangleData[pixel->triangleID] >> 4;
if (type == 0)
LCR_loadImage(LCR_renderer.mapTriangleData[pixel->triangleID] & 0x0f);
if (type == 0) // floor?
{
LCR_loadImage(3);
if (v[0][1] != v[1][1] || v[1][1] != v[2][1])
if (v[0][1] != v[1][1] || v[1][1] != v[2][1]) // angled floor?
LCR_imageChangeBrightness(1);
for (int i = 0; i < 6; ++i)
LCR_renderer.triangleUVs[i] = ((
(v[i / 2][(i % 2) * 2]) *
@ -62,8 +68,6 @@ void LCR_pixelFunc3D(S3L_PixelInfo *pixel)
}
else
{
LCR_loadImage(1);
if (type == 1)
LCR_imageChangeBrightness(0);
@ -79,6 +83,27 @@ void LCR_pixelFunc3D(S3L_PixelInfo *pixel)
}
}
// shift the UVs to the origin (prevent high values of UV coords)
for (int i = 0; i < 2; ++i)
{
uint8_t minCoord = LCR_renderer.triangleUVs[i] <
LCR_renderer.triangleUVs[2 + i] ? (0 + i) : (2 + i);
if (LCR_renderer.triangleUVs[4 + i] < LCR_renderer.triangleUVs[minCoord])
minCoord = 4 + i;
S3L_Unit shiftBy = LCR_renderer.triangleUVs[minCoord] % LCR_IMAGE_SIZE;
if (shiftBy < 0)
shiftBy += LCR_IMAGE_SIZE;
shiftBy -= LCR_renderer.triangleUVs[minCoord];
LCR_renderer.triangleUVs[i] += shiftBy;
LCR_renderer.triangleUVs[2 + i] += shiftBy;
LCR_renderer.triangleUVs[4 + i] += shiftBy;
}
LCR_renderer.previousTriangleID = pixel->triangleIndex;
}
@ -119,10 +144,8 @@ S3L_Index _LCR_addMapVertex(S3L_Unit x, S3L_Unit y, S3L_Unit z)
// if it doesn't exist, add it
if (LCR_renderer.mapModel->vertexCount < LCR_SETTING_MAX_MAP_VERTICES)
{
*vertices = x;
vertices++;
*vertices = y;
vertices++;
*vertices = x; vertices++;
*vertices = y; vertices++;
*vertices = z;
LCR_renderer.mapModel->vertexCount++;
return LCR_renderer.mapModel->vertexCount - 1;
@ -132,30 +155,42 @@ S3L_Index _LCR_addMapVertex(S3L_Unit x, S3L_Unit y, S3L_Unit z)
return 0;
}
void _LCR_addMapTriangle(S3L_Index a, S3L_Index b, S3L_Index c)
void _LCR_addMapTriangle(S3L_Index a, S3L_Index b, S3L_Index c, uint8_t mat)
{
if (LCR_renderer.mapModel->triangleCount < LCR_SETTING_MAX_MAP_TRIANGLES)
{
S3L_Index *t = &(LCR_renderer.mapTriangles[LCR_renderer.mapModel->triangleCount * 3]);
S3L_Index *t =
&(LCR_renderer.mapTriangles[LCR_renderer.mapModel->triangleCount * 3]);
*t = a; t++;
*t = b; t++;
*t = c;
LCR_renderer.mapTriangleData[LCR_renderer.mapModel->triangleCount] =
mat;
LCR_renderer.mapModel->triangleCount++;
}
}
void _LCR_rendererSwapTriangles(S3L_Index *t1, S3L_Index *t2)
void _LCR_rendererSwapMapTriangles(unsigned int index1, unsigned int index2)
{
S3L_Index tmp;
uint8_t tmpMat;
S3L_Index tmpIndex,
*t1 = LCR_renderer.mapTriangles + index1 * 3,
*t2 = LCR_renderer.mapTriangles + index2 * 3;
for (int i = 0; i < 3; ++i)
{
tmp = t1[i];
tmpIndex = t1[i];
t1[i] = t2[i];
t2[i] = tmp;
t2[i] = tmpIndex;
}
tmpMat = LCR_renderer.mapTriangleData[index1];
LCR_renderer.mapTriangleData[index1] =
LCR_renderer.mapTriangleData[index2];
LCR_renderer.mapTriangleData[index2] = tmpMat;
}
int _LCR_quadCoversTriangle(const S3L_Unit quad[8], const S3L_Unit tri[6])
@ -288,7 +323,6 @@ uint8_t _LCR_rendererCheckMapTriangleCover(const S3L_Index *t1,
t3 += 3;
}
}
const S3L_Index *tmp = t1;
@ -332,8 +366,9 @@ void _LCR_rendererCullHiddenMapTriangles(void)
{
if (j < LCR_renderer.mapModel->triangleCount - n)
{
_LCR_rendererSwapTriangles(t2,LCR_renderer.mapTriangles +
(LCR_renderer.mapModel->triangleCount - 1 - n) * 3);
_LCR_rendererSwapMapTriangles(j,
LCR_renderer.mapModel->triangleCount - 1 - n);
n++;
}
@ -344,8 +379,9 @@ void _LCR_rendererCullHiddenMapTriangles(void)
if (t1Covered)
{
_LCR_rendererSwapTriangles(t1,LCR_renderer.mapTriangles +
(LCR_renderer.mapModel->triangleCount - 1 - n) * 3);
_LCR_rendererSwapMapTriangles(i,
LCR_renderer.mapModel->triangleCount - 1 - n);
n++;
// we stay at this position because we've swapped the triangle here
}
@ -403,45 +439,106 @@ 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_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,
isAtFloor = by == 0,
isAtCeiling = by == LCR_MAP_SIZE_BLOCKS - 1;
S3L_Index triangleIndices[3];
S3L_Unit originOffset = -1 * LCR_MAP_SIZE_BLOCKS / 2 * LCR_RENDERER_UNIT;
S3L_Index triangleIndices[3];
const uint8_t *block = LCR_currentMap.blocks + j * LCR_BLOCK_SIZE;
uint8_t
blockType = block[0],
edgeBits, // bottom, top, left, right, front, bottom
bx, by, bz, // block coords
vx, vy, vz, // vertex coords
vi = 0; // vertex index (0, 1 or 2)
LCR_mapBlockGetCoords(block,&bx,&by,&bz);
LCR_mapGetBlockShape(blockType,LCR_mapBlockGetTransform(block),
blockShapeBytes,&blockShapeByteCount);
for (int i = 0; i < blockShapeByteCount; ++i)
{
if (vi == 0)
edgeBits = (by == 0) |
((by == LCR_MAP_SIZE_BLOCKS - 1) << 1) |
((bx == 0) << 2) |
((bx == LCR_MAP_SIZE_BLOCKS - 1) << 3) |
((bz == 0) << 4) |
((bz == LCR_MAP_SIZE_BLOCKS - 1) << 5);
LCR_decodeMapBlockCoords(blockShapeBytes[i],&vx,&vy,&vz);
isAtFloor &= vy == 0;
isAtCeiling &= vy == 12;
edgeBits &= (vy == 0) | ((vy == LCR_BLOCK_SHAPE_COORD_MAX) << 1) |
((vx == 0) << 2) | ((vx == LCR_BLOCK_SHAPE_COORD_MAX) << 3) |
((vz == 0) << 4) | ((vz == LCR_BLOCK_SHAPE_COORD_MAX) << 5);
triangleIndices[vi] = _LCR_addMapVertex(
originOffset + (((S3L_Unit) bx) * LCR_RENDERER_UNIT) + (LCR_RENDERER_UNIT * ((S3L_Unit) vx)) / 12,
(originOffset + (((S3L_Unit) by) * LCR_RENDERER_UNIT)) / 2 + (LCR_RENDERER_UNIT / 2 * ((S3L_Unit) vy)) / 12,
originOffset + (((S3L_Unit) bz) * LCR_RENDERER_UNIT) + (LCR_RENDERER_UNIT * ((S3L_Unit) vz)) / 12);
originOffset + (((S3L_Unit) bx) * LCR_RENDERER_UNIT) +
(LCR_RENDERER_UNIT * ((S3L_Unit) vx)) / LCR_BLOCK_SHAPE_COORD_MAX,
(originOffset + (((S3L_Unit) by) * LCR_RENDERER_UNIT)) / 2 +
(LCR_RENDERER_UNIT / 2 * ((S3L_Unit) vy)) / LCR_BLOCK_SHAPE_COORD_MAX,
originOffset + (((S3L_Unit) bz) * LCR_RENDERER_UNIT) +
(LCR_RENDERER_UNIT * ((S3L_Unit) vz)) / LCR_BLOCK_SHAPE_COORD_MAX);
if (vi < 2)
vi++;
else
{
// don't add triangles completely at the floor or ceiling of the map
if (!isAtFloor && !isAtCeiling)
if (!edgeBits)
{
#define VERT(n,c) LCR_renderer.mapVertices[3 * n + c]
uint8_t blockMat = LCR_mapBlockGetMaterial(block);
uint8_t triangleData =
(((VERT(triangleIndices[0],0) == VERT(triangleIndices[1],0)) &&
(VERT(triangleIndices[1],0) == VERT(triangleIndices[2],0))) << 4) |
(((VERT(triangleIndices[0],2) == VERT(triangleIndices[1],2)) &&
(VERT(triangleIndices[1],2) == VERT(triangleIndices[2],2))) << 5);
#undef VERT
if (triangleData & 0xf0) // wall?
{
triangleData |=
((blockMat == LCR_BLOCK_MATERIAL_CONCRETE) ||
(blockMat == LCR_BLOCK_MATERIAL_ICE) ||
(blockType == LCR_BLOCK_FULL_ACCEL) ||
(blockType == LCR_BLOCK_FULL_STICKER)) ?
LCR_IMAGE_WALL_CONCRETE : LCR_IMAGE_WALL_WOOD;
}
else
{ // TODO: tidy this mess?
if (blockType == LCR_BLOCK_FULL_ACCEL)
triangleData |= LCR_IMAGE_GROUND_ACCEL;
else if (blockType == LCR_BLOCK_FULL_STICKER)
triangleData |= LCR_IMAGE_GROUND_STICKER;
else
switch (blockMat)
{
case LCR_BLOCK_MATERIAL_CONCRETE:
triangleData |= LCR_IMAGE_GROUND_CONCRETE;
break;
case LCR_BLOCK_MATERIAL_GRASS:
triangleData |= LCR_IMAGE_GROUND_GRASS;
break;
case LCR_BLOCK_MATERIAL_DIRT:
triangleData |= LCR_IMAGE_GROUND_DIRT;
break;
case LCR_BLOCK_MATERIAL_ICE:
triangleData |= LCR_IMAGE_GROUND_ICE;
break;
default:
break;
}
}
_LCR_addMapTriangle(
triangleIndices[0],triangleIndices[1],triangleIndices[2]);
triangleIndices[0],triangleIndices[1],triangleIndices[2],
triangleData);
}
vi = 0;
isAtFloor = by == 0;
isAtCeiling = by == LCR_MAP_SIZE_BLOCKS - 1;
}
}
}