Browse Source

Working version in Full Fixed Point.

Manoel Trapier 1 year ago
parent
commit
650805fe61
10 changed files with 193 additions and 15 deletions
  1. BIN
      assets/C1W.png
  2. BIN
      assets/C5W.png
  3. BIN
      assets/C9W.png
  4. BIN
      assets/D1.png
  5. BIN
      assets/D5.png
  6. BIN
      assets/D9.png
  7. 52 0
      source/include/fpmath.h
  8. 4 3
      source/include/texture.h
  9. 113 10
      source/main.c
  10. 24 2
      source/texture.c

BIN
assets/C1W.png


BIN
assets/C5W.png


BIN
assets/C9W.png


BIN
assets/D1.png


BIN
assets/D5.png


BIN
assets/D9.png


+ 52 - 0
source/include/fpmath.h

@@ -0,0 +1,52 @@
+/*
+ * Voxel-a-tord
+ * fpmath.h: fixed point math implementation.
+ * Copyright (c) 2022 986-Studio. All rights reserved.
+ *
+ * Created by Manoël Trapier on 29/09/2022..
+ */
+#include <stdint.h>
+#include <math.h>
+
+#ifndef VOXELATOR_FPMATH_H
+#define VOXELATOR_FPMATH_H
+
+/* Enable to debug code without having the fix point implementation interfering */
+//#define USE_FLOATING_POINT
+
+#ifndef USE_FLOATING_POINT
+/*** Setting for the Fixed Point numbers. ***/
+typedef int32_t fp_num_t; /**< The base type used for the FP number */
+/* These defines should not be used outside of this header file */
+#define FP_DECIMAL_BITS (8) /**< Number of bit used for the decimal part */
+#define FP_DIVISOR (1 << FP_DECIMAL_BITS)
+
+#define FP_GET_INT(_fp) ((_fp) / FP_DIVISOR)
+#define FP_SET_INT(_val) (fp_num_t)((_val) * FP_DIVISOR)
+
+//#define FP_GET_FRAC(_val) (_val)
+//#define FP_SET_FLT(_val) FP_SET_INT(_val) | 1
+
+#define FP_MUL(_a, _b) (fp_num_t)(((int64_t)(_a) * (int64_t)(_b)) / FP_DIVISOR)
+#define FP_DIV(_a, _b) (fp_num_t)(((int64_t)(_a) * FP_DIVISOR) / (_b))
+
+#define fpsin(_val) (fp_num_t)(sin((_val) / 180 * M_PI) * FP_DIVISOR)
+#define fpcos(_val) (fp_num_t)(cos((_val) / 180 * M_PI) * FP_DIVISOR)
+
+#else
+typedef double fp_num_t;
+
+#define FP_GET_INT(_fp) ( floor(_fp) )
+#define FP_SET_INT(_val) (fp_num_t)(_val)
+#define FP_GET_FRAC(_val) (fp_num_t)(_val - FP_GET_INT(_val))
+#define FP_SET_FLT(_val) (fp_num_t)(_val)
+
+#define FP_MUL(_a, _b) ((_a) * (_b))
+#define FP_DIV(_a, _b) ((_a) / (_b))
+
+#define fpsin(_val) sin((_val) / 180 * M_PI)
+#define fpcos(_val) cos((_val) / 180 * M_PI)
+
+#endif
+
+#endif /* VOXELATOR_FPMATH_H */

+ 4 - 3
source/include/texture.h

@@ -13,19 +13,20 @@
 #include <upng.h>
 
 #include <colour.h>
+#include <fpmath.h>
 
 /***********************************************************************************************************************
  * Data types
  **********************************************************************************************************************/
 typedef struct tex2_t
 {
-    double u, v;
+    fp_num_t u, v;
 } tex2_t;
 
 typedef struct texture_t
 {
     upng_t *png;
-    colour_t *data;
+    void *data;
     int width;
     int height;
 } texture_t;
@@ -35,6 +36,6 @@ typedef struct texture_t
  **********************************************************************************************************************/
 void loadTextureDateFromPng(texture_t *texture, const char *filepath);
 void textureCleanup(texture_t *texture);
-colour_t getTextureColour(texture_t *texture, tex2_t position);
+colour_t getTextureColour(texture_t *texture, tex2_t *position);
 
 #endif /* VOXELATOR_SOURCE_INCLUDE_TEXTURE_H */

+ 113 - 10
source/main.c

@@ -16,6 +16,7 @@
 #include <log.h>
 #include <display.h>
 #include <texture.h>
+#include <fpmath.h>
 
 bool isRunning = false;
 int previousFrameTime = 0;
@@ -24,6 +25,17 @@ double deltaTime = 0;
 static double updateTime, renderTime, waitTime;
 static int windowHeight;
 static int windowWidth;
+static texture_t heightMap;
+static texture_t colourMap;
+static fp_num_t *yBuffer;
+
+static fp_num_t playerHeight = FP_SET_INT(70);
+static fp_num_t playerX = FP_SET_INT(444);
+static fp_num_t playerY = FP_SET_INT(299);
+static fp_num_t playerRot = FP_SET_INT(0);
+static fp_num_t cameraHorizon = FP_SET_INT(55);
+static fp_num_t scaleFactor = FP_SET_INT(90);
+static fp_num_t renderDistance = FP_SET_INT(300);
 
 uint32_t getMicroSecTime()
 {
@@ -35,6 +47,9 @@ uint32_t getMicroSecTime()
 void processInput()
 {
     SDL_Event event;
+    double direction = 1;
+    double dx, dy;
+
     while(SDL_PollEvent(&event))
     {
         switch (event.type)
@@ -48,13 +63,31 @@ void processInput()
             {
             case SDLK_ESCAPE: isRunning = false; break;
 
-            case SDLK_LEFT: break;
-            case SDLK_RIGHT: break;
-            case SDLK_UP:  break;
-            case SDLK_DOWN: break;
+            case SDLK_LEFT: playerRot = playerRot + 90 * deltaTime; break;
+            case SDLK_RIGHT: playerRot = playerRot - 90 * deltaTime; break;
+
+            case SDLK_DOWN:
+                direction = -1;
+                /* fall-trough */
+
+            case SDLK_UP:
+                dx = cos(playerRot) * 75 * deltaTime;
+                dy = sin(playerRot) * 75 * deltaTime;
+                playerX += (dx * direction);
+                playerY += (dy * direction);
+                break;
+
+            case SDLK_PAGEUP: playerHeight = playerHeight + 50 * deltaTime; break;
+            case SDLK_PAGEDOWN: playerHeight = playerHeight - 50 * deltaTime; break;
 
-            case SDLK_PAGEUP: break;
-            case SDLK_PAGEDOWN: break;
+            case SDLK_HOME: cameraHorizon = cameraHorizon + 50 * deltaTime; break;
+            case SDLK_END: cameraHorizon = cameraHorizon - 50 * deltaTime; break;
+
+            case SDLK_KP_MULTIPLY: scaleFactor = scaleFactor + 30 * deltaTime; break;
+            case SDLK_KP_DIVIDE: scaleFactor = scaleFactor - 30 * deltaTime; break;
+
+            case SDLK_KP_PLUS: renderDistance = renderDistance + 30 * deltaTime; break;
+            case SDLK_KP_MINUS: renderDistance = renderDistance - 30 * deltaTime; break;
             }
             break;
 
@@ -66,13 +99,16 @@ void processInput()
 
 void setup()
 {
+    loadTextureDateFromPng(&heightMap, "assets/D1.png");
+    loadTextureDateFromPng(&colourMap, "assets/C1W.png");
+
+    yBuffer = (fp_num_t *)calloc(windowWidth, sizeof(fp_num_t));
 
     isRunning = true;
 }
 
 void update()
 {
-    int i;
     uint32_t timeToWait = FRAME_TARGET_TIME - (SDL_GetTicks() - previousFrameTime);
     uint32_t ticks = getMicroSecTime();
 
@@ -91,10 +127,67 @@ void update()
     updateTime = (updateTime + (getMicroSecTime() - ticks) / 1000.) / 2.0;
 }
 
+void renderVoxels(tex2_t *p, fp_num_t angle, fp_num_t height, fp_num_t horizon, fp_num_t scaleHeight, fp_num_t renderDistance)
+{
+    fp_num_t angleSin = fpsin(angle);
+    fp_num_t angleCos = fpcos(angle);
+    fp_num_t dz = FP_SET_INT(1), z = FP_SET_INT(1);
+    int i;
+
+    for(i = 0; i < windowWidth; i++)
+    {
+        yBuffer[i] = FP_SET_INT(windowHeight);
+    }
+
+    while(z < renderDistance)
+    {
+        tex2_t pleft;
+        pleft.u = -FP_MUL(angleCos, z) - FP_MUL(angleSin, z) + p->u;
+        pleft.v = FP_MUL(angleSin, z) - FP_MUL(angleCos, z) + p->v;
+        tex2_t pright;
+        pright.u = FP_MUL(angleCos, z) - FP_MUL(angleSin, z) + p->u;
+        pright.v = -FP_MUL(angleSin, z) - FP_MUL(angleCos, z) + p->v;
+
+        fp_num_t dx = (pright.u - pleft.u);
+        dx = FP_DIV(dx, FP_SET_INT(windowWidth));
+        fp_num_t dy = (pright.v - pleft.v);
+        dy = FP_DIV(dy, FP_SET_INT(windowWidth));
+
+        for(i = 0; i < windowWidth; i++)
+        {
+            fp_num_t voxelHeight = height - FP_SET_INT(getTextureColour(&heightMap, &pleft));
+            voxelHeight = FP_DIV(voxelHeight, z);
+            voxelHeight = FP_MUL(voxelHeight, scaleHeight);
+
+            fp_num_t heightOnScreen = voxelHeight + horizon;
+            colour_t voxelColour = getTextureColour(&colourMap, &pleft);
+            if (heightOnScreen < yBuffer[i])
+            {
+                drawVLine(i, FP_GET_INT(yBuffer[i]), FP_GET_INT(heightOnScreen), voxelColour);
+                yBuffer[i] = heightOnScreen;
+            }
+            pleft.u += dx;
+            pleft.v += dy;
+        }
+
+        z += dz;
+#ifdef USE_FLOATING_POINT
+        dz += 0.01;
+#else
+        dz += (fp_num_t)(0.05 * FP_DIVISOR);
+#endif
+    }
+}
+
 void render()
 {
     uint32_t ticks = getMicroSecTime();
+    tex2_t origin = { .u = playerX, .v = playerY };
+
+    clearFrameBuffer(MAKE_RGB(0, 0, 0));
+    drawGrid(20, MAKE_RGB(27, 2, 27));
 
+    renderVoxels(& origin, playerRot, playerHeight, cameraHorizon, scaleFactor, renderDistance);
 
     renderFrameBuffer();
 
@@ -104,20 +197,30 @@ void render()
     drawText(5, 17, 0x11FF22, "Update time: %02.2f ms", updateTime);
     drawText(5, 29, 0x11FF22, "Render time: %02.2f ms", renderTime);
     drawText(5, 41, 0x11FF22, "FPS: %.1f | dT: %.3f", 1000 / (waitTime + updateTime + renderTime), deltaTime);
+#ifdef USE_FLOATING_POINT
+    drawText(5, 53, 0x11FF22, "P: (%.1f;%.1f) | PH: %.1f | CH: %.1f | SF: %.1f | RD: %.1f", playerX, playerY, playerHeight, cameraHorizon, scaleFactor, renderDistance);
+#else
+    drawText(5, 53, 0x11FF22, "P: (%d;%d) | PH: %d | CH: %d | SF: %d | RD: %d", FP_GET_INT(playerX),
+             FP_GET_INT(playerY),
+             FP_GET_INT(playerHeight),
+             FP_GET_INT(cameraHorizon),
+             FP_GET_INT(scaleFactor),
+             FP_GET_INT(renderDistance));
+#endif
 
     displayWindowRender();
 }
 
 int main(int argc, char *argv[])
 {
-    int param_i, i;
+    int param_i;
     bool fullScreen = false;
     MAX_DEBUG_LEVEL = TLOG_DEBUG;
 
     Log(TLOG_ALWAYS, NULL, "Starting Voxel Engine (version %s)!", VERSION);
 
-    windowWidth = 320;
-    windowHeight = 240;
+    windowWidth = 800;
+    windowHeight = 600;
 
     for (param_i = 1 ; (param_i < argc) && (argv[param_i][0] == '-') ; param_i++)
     {

+ 24 - 2
source/texture.c

@@ -48,8 +48,30 @@ void textureCleanup(texture_t *tex)
     tex->data = NULL;
 }
 
-colour_t getTextureColour(texture_t *texture, tex2_t position)
+colour_t getTextureColour(texture_t *texture, tex2_t *position)
 {
+    colour_t ret = 0;
+    int32_t texX = FP_GET_INT(position->u);
+    int32_t texY = FP_GET_INT(position->v);
 
-    return 0;
+    while(texX < 0) { texX += texture->width; }
+    while(texY < 0) { texY += texture->height; }
+    texX = texX % texture->width;
+    texY = texY % texture->height;
+
+    switch(upng_get_format(texture->png))
+    {
+    case UPNG_LUMINANCE8:
+        ret = ((uint8_t *)texture->data)[(texY * texture->width) + texX];
+        break;
+
+    case UPNG_RGBA8:
+        ret = ((colour_t *)texture->data)[(texY * texture->width) + texX];
+        break;
+
+    default:
+        break;
+    }
+
+    return ret;
 }