192 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
	
		
			5 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"
 | |
| 
 | |
| 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
 |