/** 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" struct LCR_Renderer { // TODO }; S3L_Scene LCR_scene3D; S3L_Model3D LCR_models3D[3]; // TODO S3L_Unit LCR_vertices3D[LCR_SETTING_MAX_VERTICES * 3]; S3L_Index LCR_triangles3D[LCR_SETTING_MAX_TRIANGLES * 3]; void LCR_pixelFunc3D(S3L_PixelInfo *pixel) { LCR_drawPixelSafe(pixel->x,pixel->y,0xff00); } /** Builds an internal 3D model of the currently loaded map. Returns 1 on success, otherwise 0 (e.g. not enough space). */ uint8_t LCR_buildMapModel(void) { // TODO LCR_vertices3D[0] = -2000; LCR_vertices3D[1] = -100; LCR_vertices3D[2] = 1000; LCR_vertices3D[3] = 400; LCR_vertices3D[4] = -100; LCR_vertices3D[5] = 2000; LCR_vertices3D[6] = 0; LCR_vertices3D[7] = 400; LCR_vertices3D[8] = 2000; LCR_triangles3D[0] = 0; LCR_triangles3D[1] = 1; LCR_triangles3D[2] = 2; return 1; } uint8_t LCR_rendererInit(void) { if (!LCR_buildMapModel()) return 0; S3L_model3DInit(LCR_vertices3D,3,LCR_triangles3D,1,LCR_models3D); 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) { 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