2023-09-16 22:52:03 +02:00
|
|
|
/**
|
|
|
|
3D renderer: implements 3D rendering.
|
|
|
|
*/
|
|
|
|
|
2023-09-13 20:51:07 +02:00
|
|
|
#ifndef _LCR_RENDERER_H
|
|
|
|
#define _LCR_RENDERER_H
|
|
|
|
|
2023-09-16 20:35:01 +02:00
|
|
|
#define S3L_RESOLUTION_X LCR_SETTING_RESOLUTION_X
|
|
|
|
#define S3L_RESOLUTION_Y LCR_SETTING_RESOLUTION_Y
|
|
|
|
#define S3L_PIXEL_FUNCTION LCR_pixelFunc3D
|
|
|
|
|
2023-09-17 15:42:46 +02:00
|
|
|
#define S3L_Z_BUFFER 2
|
|
|
|
|
2023-09-16 20:35:01 +02:00
|
|
|
#include "small3dlib.h"
|
|
|
|
|
2024-07-24 20:28:57 +02:00
|
|
|
/// Renderer specific unit, length of one map square.
|
2024-07-23 19:57:29 +02:00
|
|
|
#define LCR_RENDERER_UNIT S3L_FRACTIONS_PER_UNIT
|
|
|
|
|
2023-09-13 20:51:07 +02:00
|
|
|
struct LCR_Renderer
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
};
|
|
|
|
|
2023-09-16 20:35:01 +02:00
|
|
|
S3L_Scene LCR_scene3D;
|
|
|
|
S3L_Model3D LCR_models3D[3]; // TODO
|
|
|
|
|
2024-07-22 01:16:16 +02:00
|
|
|
S3L_Model3D *LCR_mapModel;
|
|
|
|
S3L_Unit LCR_mapVertices[LCR_SETTING_MAX_MAP_VERTICES * 3];
|
|
|
|
S3L_Index LCR_mapTriangles[LCR_SETTING_MAX_MAP_TRIANGLES * 3];
|
2023-09-16 20:35:01 +02:00
|
|
|
|
|
|
|
void LCR_pixelFunc3D(S3L_PixelInfo *pixel)
|
|
|
|
{
|
2024-07-24 20:28:57 +02:00
|
|
|
LCR_drawPixelXYSafe(pixel->x,pixel->y,0xff00 + (pixel->triangleID % 16) * 16 );
|
2024-07-22 01:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
S3L_Index _LCR_addMapVertex(S3L_Unit x, S3L_Unit y, S3L_Unit z)
|
|
|
|
{
|
|
|
|
S3L_Index index = 0;
|
|
|
|
S3L_Unit *vertices = LCR_mapVertices;
|
|
|
|
|
|
|
|
while (index < LCR_mapModel->vertexCount) // if exists, return vertex index
|
|
|
|
{
|
|
|
|
if (vertices[0] == x && vertices[1] == y && vertices[2] == z)
|
|
|
|
return index;
|
|
|
|
|
|
|
|
vertices += 3;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if it doesn't exist, add it
|
|
|
|
if (LCR_mapModel->vertexCount < LCR_SETTING_MAX_MAP_VERTICES)
|
|
|
|
{
|
|
|
|
*vertices = x;
|
|
|
|
vertices++;
|
|
|
|
*vertices = y;
|
|
|
|
vertices++;
|
|
|
|
*vertices = z;
|
|
|
|
LCR_mapModel->vertexCount++;
|
|
|
|
return LCR_mapModel->vertexCount - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: error print
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _LCR_addMapTriangle(S3L_Index a, S3L_Index b, S3L_Index c)
|
|
|
|
{
|
|
|
|
if (LCR_mapModel->triangleCount < LCR_SETTING_MAX_MAP_TRIANGLES)
|
|
|
|
{
|
2024-07-24 20:28:57 +02:00
|
|
|
S3L_Index *t = &(LCR_mapTriangles[LCR_mapModel->triangleCount * 3]);
|
2024-07-22 01:16:16 +02:00
|
|
|
|
|
|
|
*t = a;
|
|
|
|
t++;
|
|
|
|
*t = b;
|
|
|
|
t++;
|
|
|
|
*t = c;
|
|
|
|
|
|
|
|
LCR_mapModel->triangleCount++;
|
|
|
|
}
|
2023-09-16 20:35:01 +02:00
|
|
|
}
|
|
|
|
|
2024-07-24 23:16:13 +02:00
|
|
|
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]))
|
2024-07-28 02:00:36 +02:00
|
|
|
return 0x03;
|
2024-07-24 23:16:13 +02:00
|
|
|
|
2024-07-28 02:00:36 +02:00
|
|
|
uint8_t result = 0;
|
|
|
|
int plane = -1;
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
if (LCR_mapVertices[3 * t1[0] + i] == LCR_mapVertices[3 * t1[1] + i] &&
|
|
|
|
LCR_mapVertices[3 * t1[1] + i] == LCR_mapVertices[3 * t1[2] + i] &&
|
|
|
|
LCR_mapVertices[3 * t1[2] + i] == LCR_mapVertices[3 * t2[0] + i] &&
|
|
|
|
LCR_mapVertices[3 * t2[0] + i] == LCR_mapVertices[3 * t2[1] + i] &&
|
|
|
|
LCR_mapVertices[3 * t2[1] + i] == LCR_mapVertices[3 * t2[2] + i])
|
|
|
|
{
|
|
|
|
plane = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (plane >= 0) // both triangles in the same plane => then do more checks
|
|
|
|
{
|
|
|
|
for (int j = 0; j < 2; ++j)
|
|
|
|
{
|
|
|
|
S3L_Unit points2D[14]; // tri1, quad (tri2 + 1 extra vert)
|
|
|
|
|
|
|
|
int coordX = plane == 0 ? 1 : 0,
|
|
|
|
coordY = plane == 2 ? 1 : 2;
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
points2D[i * 2] = LCR_mapVertices[3 * t1[i] + coordX];
|
|
|
|
points2D[i * 2 + 1] = LCR_mapVertices[3 * t1[i] + coordY];
|
|
|
|
points2D[6 + i * 2] = LCR_mapVertices[3 * t2[i] + coordX];
|
|
|
|
points2D[6 + i * 2 + 1] = LCR_mapVertices[3 * t2[i] + coordY];
|
|
|
|
}
|
|
|
|
|
|
|
|
points2D[12] = (4 * points2D[6] + 3 * points2D[8] + points2D[10]) / 8;
|
|
|
|
points2D[13] = (4 * points2D[7] + 3 * points2D[9] + points2D[11]) / 8;
|
|
|
|
|
|
|
|
// first: does the triangle alone cover the other one?
|
|
|
|
if (_LCR_quadCoversTriangle(points2D + 6,points2D))
|
|
|
|
result |= 1 << j;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// now check if this triangle along with a neighbor cover the other one
|
|
|
|
|
|
|
|
S3L_Index *t3 = LCR_mapTriangles;
|
|
|
|
|
|
|
|
for (int i = 0; i < LCR_mapModel->triangleCount; ++i)
|
|
|
|
{
|
|
|
|
uint8_t sharedVerts =
|
|
|
|
(t3[0] == t2[0] || t3[0] == t2[1] || t3[0] == t2[2]) |
|
|
|
|
((t3[1] == t2[0] || t3[1] == t2[1] || t3[1] == t2[2]) << 1) |
|
|
|
|
((t3[2] == t2[0] || t3[2] == t2[1] || t3[2] == t2[2]) << 2);
|
|
|
|
|
|
|
|
if (
|
|
|
|
t3 != t1 && t3 != t2 &&
|
|
|
|
(sharedVerts == 3 || sharedVerts == 5 || sharedVerts == 6) &&
|
|
|
|
LCR_mapVertices[3 * t3[0] + plane] ==
|
|
|
|
LCR_mapVertices[3 * t3[1] + plane] &&
|
|
|
|
LCR_mapVertices[3 * t3[1] + plane] ==
|
|
|
|
LCR_mapVertices[3 * t3[2] + plane] &&
|
|
|
|
LCR_mapVertices[3 * t3[0] + plane] ==
|
|
|
|
LCR_mapVertices[3 * t1[0] + plane]
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// here shares exactly two vertices and is in the same plane
|
|
|
|
|
|
|
|
uint8_t freeVert =
|
|
|
|
sharedVerts == 3 ? 2 : (sharedVerts == 5 ? 1 : 0);
|
|
|
|
|
|
|
|
points2D[12] = LCR_mapVertices[3 * t3[freeVert] + coordX];
|
|
|
|
points2D[13] = LCR_mapVertices[3 * t3[freeVert] + coordY];
|
|
|
|
|
|
|
|
if (_LCR_quadCoversTriangle(points2D + 6,points2D))
|
|
|
|
{
|
|
|
|
result |= 1 << j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
t3 += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const S3L_Index *tmp = t1;
|
|
|
|
t1 = t2;
|
|
|
|
t2 = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int _LCR_quadCoversTriangle(const S3L_Unit quad[8], const S3L_Unit tri[6])
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 3; ++i) // for each triangle point
|
|
|
|
{
|
|
|
|
int covered = 0;
|
|
|
|
|
|
|
|
for (int j = 0; j < 3; ++j) // for each quad subtriangle
|
|
|
|
{
|
|
|
|
uint8_t winds = 0;
|
|
|
|
|
|
|
|
for (int k = 0; k < 3; ++k) // for each subtriangle side
|
|
|
|
{
|
|
|
|
S3L_Unit w = // triangle winding
|
|
|
|
(quad[(2 * (j + ((k + 1) % 3))) % 8 + 1] -
|
|
|
|
quad[(2 * (j + k)) % 8 + 1]) *
|
|
|
|
(tri[2 * i] - quad[(2 * (j + (k + 1) % 3)) % 8]) -
|
|
|
|
(quad[(2 * (j + ((k + 1) % 3))) % 8] - quad[(2 * (j + k)) % 8])
|
|
|
|
* (tri[2 * i + 1] - quad[(2 * (j + (k + 1) % 3)) % 8 + 1]);
|
|
|
|
|
|
|
|
if (w > 0)
|
|
|
|
winds |= 1;
|
|
|
|
else if (w < 0)
|
|
|
|
winds |= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (winds != 3) // no opposite winds?
|
|
|
|
{
|
|
|
|
covered = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!covered)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
2024-07-24 23:16:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
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;
|
|
|
|
|
|
|
|
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--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-24 20:28:57 +02:00
|
|
|
/**
|
|
|
|
Builds an internal 3D model of the currently loaded map. Returns 1 on success,
|
|
|
|
otherwise 0 (e.g. not enough space).
|
|
|
|
*/
|
2024-07-22 01:16:16 +02:00
|
|
|
uint8_t _LCR_rendererBuildMapModel(void)
|
2023-09-16 20:35:01 +02:00
|
|
|
{
|
2024-07-22 01:16:16 +02:00
|
|
|
uint8_t blockShapeBytes[LCR_MAP_BLOCK_SHAPE_MAX_BYTES];
|
|
|
|
uint8_t blockShapeByteCount;
|
|
|
|
|
|
|
|
S3L_model3DInit(LCR_mapVertices,0,LCR_mapTriangles,0,LCR_mapModel);
|
|
|
|
|
2024-07-24 20:28:57 +02:00
|
|
|
for (int j = 0; j < LCR_currentMap.blockCount; ++j)
|
2024-07-22 01:16:16 +02:00
|
|
|
{
|
2024-07-24 20:28:57 +02:00
|
|
|
uint8_t bx, by, bz;
|
2024-07-24 23:16:13 +02:00
|
|
|
LCR_mapBlockGetCoords(LCR_currentMap.blocks + j * LCR_BLOCK_SIZE,
|
|
|
|
&bx,&by,&bz);
|
2024-07-24 20:28:57 +02:00
|
|
|
|
2024-07-24 23:16:13 +02:00
|
|
|
LCR_mapGetBlockShape(LCR_currentMap.blocks[j * LCR_BLOCK_SIZE],
|
|
|
|
LCR_mapBlockGetTransform(LCR_currentMap.blocks + j * LCR_BLOCK_SIZE),
|
2024-07-24 20:28:57 +02:00
|
|
|
blockShapeBytes,&blockShapeByteCount);
|
|
|
|
|
|
|
|
uint8_t vx, vy, vz, vi = 0;
|
|
|
|
uint8_t *bytes = blockShapeBytes;
|
|
|
|
S3L_Index triangleIndices[3];
|
|
|
|
|
|
|
|
S3L_Unit originOffset = -1 * LCR_MAP_SIZE_BLOCKS / 2 * LCR_RENDERER_UNIT;
|
|
|
|
|
|
|
|
for (int i = 0; i < blockShapeByteCount; ++i)
|
|
|
|
{
|
|
|
|
LCR_decodeMapBlockCoords(blockShapeBytes[i],&vx,&vy,&vz);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (vi < 2)
|
|
|
|
vi++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_LCR_addMapTriangle(
|
|
|
|
triangleIndices[0],triangleIndices[1],triangleIndices[2]);
|
|
|
|
vi = 0;
|
|
|
|
}
|
|
|
|
}
|
2024-07-22 01:16:16 +02:00
|
|
|
}
|
2023-09-16 20:35:01 +02:00
|
|
|
|
2024-07-24 23:16:13 +02:00
|
|
|
_LCR_rendererPruneHiddenMapTriangles();
|
|
|
|
|
2023-09-16 20:35:01 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t LCR_rendererInit(void)
|
|
|
|
{
|
2024-07-22 01:16:16 +02:00
|
|
|
LCR_mapModel = LCR_models3D;
|
|
|
|
|
|
|
|
if (!_LCR_rendererBuildMapModel())
|
2023-09-16 20:35:01 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
S3L_sceneInit(LCR_models3D,1,&LCR_scene3D);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-09-17 13:21:19 +02:00
|
|
|
void LCR_rendererMoveCamera(LCR_SpaceUnit forwRightUpOffset[3],
|
|
|
|
LCR_SpaceUnit yawPitchOffset[2])
|
|
|
|
{
|
|
|
|
S3L_Vec4 f, r, u;
|
|
|
|
|
|
|
|
S3L_rotationToDirections(LCR_scene3D.camera.transform.rotation,
|
|
|
|
S3L_FRACTIONS_PER_UNIT,&f,&r,&u);
|
|
|
|
|
|
|
|
LCR_scene3D.camera.transform.translation.x +=
|
|
|
|
((f.x * forwRightUpOffset[0] + r.x * forwRightUpOffset[1] +
|
|
|
|
u.x * forwRightUpOffset[2]) * S3L_FRACTIONS_PER_UNIT) / LCR_SQUARE_SIDE_LEN;
|
|
|
|
|
|
|
|
LCR_scene3D.camera.transform.translation.y +=
|
|
|
|
((f.y * forwRightUpOffset[0] + r.y * forwRightUpOffset[1] +
|
|
|
|
u.y * forwRightUpOffset[2]) * S3L_FRACTIONS_PER_UNIT) / LCR_SQUARE_SIDE_LEN;
|
|
|
|
|
|
|
|
LCR_scene3D.camera.transform.translation.z +=
|
|
|
|
((f.z * forwRightUpOffset[0] + r.z * forwRightUpOffset[1] +
|
|
|
|
u.z * forwRightUpOffset[2]) * S3L_FRACTIONS_PER_UNIT) / LCR_SQUARE_SIDE_LEN;
|
|
|
|
|
|
|
|
LCR_scene3D.camera.transform.rotation.y +=
|
|
|
|
(yawPitchOffset[0] * S3L_FRACTIONS_PER_UNIT) / LCR_SQUARE_SIDE_LEN;
|
|
|
|
|
|
|
|
LCR_scene3D.camera.transform.rotation.x +=
|
|
|
|
(yawPitchOffset[1] * S3L_FRACTIONS_PER_UNIT) / LCR_SQUARE_SIDE_LEN;
|
|
|
|
|
2023-09-17 15:42:46 +02:00
|
|
|
if (LCR_scene3D.camera.transform.rotation.x > S3L_FRACTIONS_PER_UNIT / 4)
|
|
|
|
LCR_scene3D.camera.transform.rotation.x = S3L_FRACTIONS_PER_UNIT / 4;
|
2023-09-16 22:52:03 +02:00
|
|
|
|
2023-09-17 15:42:46 +02:00
|
|
|
if (LCR_scene3D.camera.transform.rotation.x < -1 * S3L_FRACTIONS_PER_UNIT / 4)
|
|
|
|
LCR_scene3D.camera.transform.rotation.x = -1 * S3L_FRACTIONS_PER_UNIT / 4;
|
2023-09-16 22:52:03 +02:00
|
|
|
}
|
|
|
|
|
2023-09-17 13:21:19 +02:00
|
|
|
void LCR_rendererDraw(void)
|
2023-09-16 20:35:01 +02:00
|
|
|
{
|
|
|
|
S3L_newFrame();
|
|
|
|
S3L_drawScene(LCR_scene3D);
|
|
|
|
}
|
|
|
|
|
2023-09-13 20:51:07 +02:00
|
|
|
void LCR_drawBackground(int verticalOffset)
|
|
|
|
{
|
2024-07-22 01:16:16 +02:00
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
for (int y = 0; y < LCR_EFFECTIVE_RESOLUTION_Y; ++y)
|
|
|
|
for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x)
|
|
|
|
LCR_drawPixelXYUnsafe(x,y,0xffff);
|
|
|
|
|
|
|
|
/*
|
2023-09-13 20:51:07 +02:00
|
|
|
uint16_t color = LCR_skyImages[LCR_skyImages[256] & 0x00ff] ; // TODO
|
|
|
|
int limit = verticalOffset - LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE / 2;
|
|
|
|
|
|
|
|
if (limit >= LCR_EFFECTIVE_RESOLUTION_Y)
|
|
|
|
limit = LCR_EFFECTIVE_RESOLUTION_Y - 1;
|
|
|
|
|
|
|
|
for (int y = 0; y <= limit; ++y)
|
|
|
|
for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x)
|
|
|
|
LCR_drawPixelUnsafe(x,y,color);
|
|
|
|
|
|
|
|
color = LCR_skyImages[LCR_skyImages[255 + (128 * 128) / 2] >> 8]; // TODO
|
|
|
|
limit = verticalOffset + LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE / 2 -
|
|
|
|
LCR_SETTING_SKY_SIZE;
|
|
|
|
|
|
|
|
if (limit < 0)
|
|
|
|
limit = 0;
|
|
|
|
|
|
|
|
for (int y = LCR_EFFECTIVE_RESOLUTION_Y - 1; y >= limit; --y)
|
|
|
|
for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x)
|
|
|
|
LCR_drawPixelUnsafe(x,y,color);
|
2024-07-22 01:16:16 +02:00
|
|
|
*/
|
2023-09-13 20:51:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void LCR_drawSkyStrip(int verticalOffset, uint8_t horizontalOffset)
|
|
|
|
{
|
|
|
|
#if LCR_SETTING_SKY_SIZE != 0
|
2024-07-22 01:16:16 +02:00
|
|
|
/*
|
2023-09-13 20:51:07 +02:00
|
|
|
verticalOffset -= (LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE) / 2;
|
|
|
|
|
|
|
|
int finalY = verticalOffset + LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE;
|
|
|
|
|
|
|
|
finalY = (finalY / LCR_SETTING_SKY_SIZE) * LCR_SETTING_SKY_SIZE;
|
|
|
|
|
|
|
|
if (finalY >= LCR_EFFECTIVE_RESOLUTION_Y)
|
|
|
|
finalY = LCR_EFFECTIVE_RESOLUTION_Y - 1;
|
|
|
|
|
|
|
|
const uint16_t *skyLine = LCR_skyImages + 256;
|
|
|
|
|
|
|
|
if (verticalOffset < 0)
|
|
|
|
{
|
|
|
|
skyLine += (-1 * verticalOffset / LCR_SETTING_SKY_SIZE) * (LCR_SKY_IMAGE_SIZE / 2);
|
|
|
|
verticalOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (verticalOffset < finalY)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < LCR_EFFECTIVE_RESOLUTION_X; ++i)
|
|
|
|
{
|
2023-09-17 15:42:46 +02:00
|
|
|
// only diraw background on empty pixels
|
|
|
|
if (S3L_zBufferRead(i,verticalOffset) == S3L_MAX_DEPTH)
|
|
|
|
{
|
|
|
|
int offsetX = (i / LCR_SETTING_SKY_SIZE + horizontalOffset)
|
|
|
|
% LCR_SKY_IMAGE_SIZE;
|
2023-09-13 20:51:07 +02:00
|
|
|
|
2023-09-17 15:42:46 +02:00
|
|
|
uint16_t pixel = *(skyLine + offsetX / 2);
|
2023-09-13 20:51:07 +02:00
|
|
|
|
2023-09-17 15:42:46 +02:00
|
|
|
pixel = offsetX % 2 ? (pixel >> 8) : (pixel & 0x00ff);
|
2023-09-13 20:51:07 +02:00
|
|
|
|
2023-09-17 15:42:46 +02:00
|
|
|
LCR_drawPixelUnsafe(i,verticalOffset,LCR_skyImages[pixel]);
|
|
|
|
}
|
2023-09-13 20:51:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
verticalOffset++;
|
|
|
|
|
|
|
|
if (verticalOffset % LCR_SETTING_SKY_SIZE == 0)
|
|
|
|
skyLine += LCR_SKY_IMAGE_SIZE / 2;
|
|
|
|
}
|
2024-07-22 01:16:16 +02:00
|
|
|
*/
|
2023-09-13 20:51:07 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-09-17 15:42:46 +02:00
|
|
|
LCR_SpaceUnit LCR_rendererGetCameraYaw(void)
|
|
|
|
{
|
|
|
|
return (LCR_scene3D.camera.transform.rotation.y * LCR_SQUARE_SIDE_LEN) /
|
|
|
|
S3L_FRACTIONS_PER_UNIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
LCR_SpaceUnit LCR_rendererGetCameraPitch(void)
|
|
|
|
{
|
|
|
|
return (LCR_scene3D.camera.transform.rotation.x * LCR_SQUARE_SIDE_LEN) /
|
|
|
|
S3L_FRACTIONS_PER_UNIT;
|
|
|
|
}
|
|
|
|
|
2023-09-13 20:51:07 +02:00
|
|
|
#endif // guard
|