Licar/renderer.h

275 lines
7.2 KiB
C

/**
3D renderer: implements 3D rendering.
*/
#ifndef _LCR_RENDERER_H
#define _LCR_RENDERER_H
#define S3L_RESOLUTION_X LCR_SETTING_RESOLUTION_X
#define S3L_RESOLUTION_Y LCR_SETTING_RESOLUTION_Y
#define S3L_PIXEL_FUNCTION LCR_pixelFunc3D
#define S3L_Z_BUFFER 2
#include "small3dlib.h"
/// Renderer specific unit, length of one map square.
#define LCR_RENDERER_UNIT S3L_FRACTIONS_PER_UNIT
struct LCR_Renderer
{
// TODO
};
S3L_Scene LCR_scene3D;
S3L_Model3D LCR_models3D[3]; // TODO
S3L_Model3D *LCR_mapModel;
S3L_Unit LCR_mapVertices[LCR_SETTING_MAX_MAP_VERTICES * 3];
S3L_Index LCR_mapTriangles[LCR_SETTING_MAX_MAP_TRIANGLES * 3];
void LCR_pixelFunc3D(S3L_PixelInfo *pixel)
{
LCR_drawPixelXYSafe(pixel->x,pixel->y,0xff00 + (pixel->triangleID % 16) * 16 );
}
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)
{
S3L_Index *t = &(LCR_mapTriangles[LCR_mapModel->triangleCount * 3]);
*t = a;
t++;
*t = b;
t++;
*t = c;
LCR_mapModel->triangleCount++;
}
}
/**
Builds an internal 3D model of the currently loaded map. Returns 1 on success,
otherwise 0 (e.g. not enough space).
*/
uint8_t _LCR_rendererBuildMapModel(void)
{
uint8_t blockShapeBytes[LCR_MAP_BLOCK_SHAPE_MAX_BYTES];
uint8_t blockShapeByteCount;
S3L_model3DInit(LCR_mapVertices,0,LCR_mapTriangles,0,LCR_mapModel);
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],0,
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;
}
}
}
return 1;
}
uint8_t LCR_rendererInit(void)
{
LCR_mapModel = LCR_models3D;
if (!_LCR_rendererBuildMapModel())
return 0;
S3L_sceneInit(LCR_models3D,1,&LCR_scene3D);
return 1;
}
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;
if (LCR_scene3D.camera.transform.rotation.x > S3L_FRACTIONS_PER_UNIT / 4)
LCR_scene3D.camera.transform.rotation.x = S3L_FRACTIONS_PER_UNIT / 4;
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;
}
void LCR_rendererDraw(void)
{
S3L_newFrame();
S3L_drawScene(LCR_scene3D);
}
void LCR_drawBackground(int verticalOffset)
{
// 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);
/*
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);
*/
}
void LCR_drawSkyStrip(int verticalOffset, uint8_t horizontalOffset)
{
#if LCR_SETTING_SKY_SIZE != 0
/*
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)
{
// 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;
uint16_t pixel = *(skyLine + offsetX / 2);
pixel = offsetX % 2 ? (pixel >> 8) : (pixel & 0x00ff);
LCR_drawPixelUnsafe(i,verticalOffset,LCR_skyImages[pixel]);
}
}
verticalOffset++;
if (verticalOffset % LCR_SETTING_SKY_SIZE == 0)
skyLine += LCR_SKY_IMAGE_SIZE / 2;
}
*/
#endif
}
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;
}
#endif // guard