diff --git a/s3l.h b/s3l.h index ba0eb87..1adcde5 100644 --- a/s3l.h +++ b/s3l.h @@ -125,6 +125,38 @@ on. */ #endif +#ifndef S3L_RENDER_STRATEGY +#define S3L_RENDER_STRATEGY S3L_STRATEGY_Z_BUFFER /**< Strategy used for + visibility + determination -- see + S3L_STRATEGY_* + consts. */ +#endif + +#define S3L_STRATEGY_NONE 0 /**< No strategy -- can be sufficient in + some cases. */ +#define S3L_STRATEGY_Z_BUFFER 1 /**< Use z-buffer (depth buffer). + Accurate and fast, but requires a lot + of memory. */ +#define S3L_STRATEGY_BACK_TO_FRONT 2 /**< Sort and draw triangles from back to + front (painter's algorithm). Requires + less memory, but can be slower than + Z-buffer and can't handle + intersecting triangles. */ +#define S3L_STRATEGY_FRONT_TO_BACK 3 /**< Sort and draw triangles from front to + back (reverse painter's algorithm). + Requires a bit more memory than back + to front, but can also be faster + (doesn't draw over already drawn + pixels). */ + +#ifndef S3L_MAX_TRIANGES_DRAWN +#define S3L_MAX_TRIANGES_DRAWN 128 /**< Maximum number of triangles that can + be drawn in sorted modes. This + affects the size of a cache used for + triangle sorting. */ +#endif + #ifndef S3L_PERSPECTIVE_CORRECTION #define S3L_PERSPECTIVE_CORRECTION 0 /**< Specifies what type of perspective correction (PC) to use. Remember @@ -198,6 +230,8 @@ typedef uint16_t S3L_Index; /* 7 back, top, left */\ -S3L_FRACTIONS_PER_UNIT/2,S3L_FRACTIONS_PER_UNIT/2,S3L_FRACTIONS_PER_UNIT/2 +#define S3L_CUBE_VERTEX_COUNT 8 + /** Predefined triangle indices of a cube, to be used with S3L_CUBE_VERTICES and S3L_CUBE_TEXCOORDS. */ #define S3L_CUBE_TRIANGLES\ @@ -214,6 +248,8 @@ typedef uint16_t S3L_Index; 4, 1, 0, /* bottom */\ 4, 5, 1 +#define S3L_CUBE_TRIANGLE_COUNT 12 + /** Predefined texture coordinates of a cube, corresponding to triangles (NOT vertices), to be used with S3L_CUBE_VERTICES and S3L_CUBE_TRIANGLES. */ #define S3L_CUBE_TEXCOORDS(m)\ @@ -332,12 +368,37 @@ void S3L_mat4Xmat4(S3L_Mat4 *m1, S3L_Mat4 *m2); typedef struct { - S3L_Unit focalLength; ///< Defines the field of view (FOV). + S3L_Unit focalLength; ///< Defines the field of view (FOV). S3L_Transform3D transform; } S3L_Camera; static inline void S3L_initCamera(S3L_Camera *c); +typedef struct +{ + uint8_t backfaceCulling; + uint8_t mode; +} S3L_DrawConfig; + +void S3L_initDrawConfig(S3L_DrawConfig *config); + +typedef struct +{ + S3L_Unit *vertices; + S3L_Index vertexCount; + S3L_Index *triangles; + S3L_Index triangleCount; + S3L_Transform3D transform; + S3L_DrawConfig config; +} S3L_Model3D; ///< Represents a 3D model. + +typedef struct +{ + S3L_Model3D *models; + S3L_Index modelCount; + S3L_Camera camera; +} S3L_Scene; ///< Represent the 3D scene to be rendered. + typedef struct { S3L_ScreenCoord x; ///< Screen X coordinate. @@ -351,7 +412,8 @@ typedef struct S3L_FRACTIONS_PER_UNIT. */ S3L_Unit barycentric1; ///< Baryc. coord 1 (corresponds to 2nd vertex). S3L_Unit barycentric2; ///< Baryc. coord 2 (corresponds to 3rd vertex). - S3L_Index triangleID; + S3L_Index triangleID; ///< Triangle index. + S3L_Index modelID; S3L_Unit depth; ///< Depth (only if depth is turned on). } S3L_PixelInfo; /**< Used to pass the info about a rasterized pixel (fragment) to the user-defined drawing func. */ @@ -366,14 +428,6 @@ static inline void S3L_initPixelInfo(S3L_PixelInfo *p); #define S3L_MODE_LINES 1 #define S3L_MODE_POINTS 2 -typedef struct -{ - uint8_t backfaceCulling; - uint8_t mode; -} S3L_DrawConfig; - -void S3L_initDrawConfig(S3L_DrawConfig *config); - // general helper functions static inline S3L_Unit S3L_abs(S3L_Unit value); static inline S3L_Unit S3L_min(S3L_Unit v1, S3L_Unit v2); @@ -1653,57 +1707,61 @@ static inline void S3L_perspectiveDivide(S3L_Vec4 *vector, vector->y = (vector->y * focalLength) / divisor; } -void S3L_drawModelIndexed( - const S3L_Unit coords[], - const S3L_Index triangleVertexIndices[], - uint16_t triangleCount, - S3L_Transform3D modelTransform, - const S3L_Camera *camera, - const S3L_DrawConfig *config) +void S3L_drawScene(S3L_Scene scene) { - S3L_Index triangleIndex = 0; - S3L_Index coordIndex = 0; - - S3L_Vec4 pointModel, transformed0, transformed1, transformed2; - S3L_Unit indexIndex = 0; - - pointModel.w = S3L_FRACTIONS_PER_UNIT; // has to be "1.0" for translation - - S3L_Mat4 mat1, mat2; - - S3L_makeWorldMatrix(modelTransform,&mat1); - S3L_makeCameraMatrix(camera->transform,&mat2); - - S3L_mat4Xmat4(&mat1,&mat2); - - while (triangleIndex < triangleCount) + for (S3L_Index modelIndex; modelIndex < scene.modelCount; ++modelIndex) { - #define project(n)\ - indexIndex = triangleVertexIndices[coordIndex] * 3;\ - pointModel.x = coords[indexIndex];\ - ++indexIndex; /* TODO: put into square brackets? */\ - pointModel.y = coords[indexIndex];\ - ++indexIndex;\ - pointModel.z = coords[indexIndex];\ - ++coordIndex;\ - S3L_vec3Xmat4(&pointModel,&mat1);\ - transformed##n.x = pointModel.x;\ - transformed##n.y = pointModel.y;\ - transformed##n.z = pointModel.z;\ - transformed##n.w = S3L_FRACTIONS_PER_UNIT;\ - S3L_perspectiveDivide(&transformed##n,camera->focalLength); + S3L_Unit *vertices = scene.models[modelIndex].vertices; + S3L_Index *triangles = scene.models[modelIndex].triangles; + + S3L_Index triangleIndex = 0; + S3L_Index coordIndex = 0; - /* TODO: maybe create an option that would use a cache here to not - transform the same point twice? */ + S3L_Vec4 pointModel, transformed0, transformed1, transformed2; + S3L_Unit indexIndex = 0; - project(0) - project(1) - project(2) + pointModel.w = S3L_FRACTIONS_PER_UNIT; // has to be "1.0" for translation - S3L_drawTriangle(transformed0,transformed1,transformed2,config,camera, - triangleIndex); + S3L_Mat4 mat1, mat2; - ++triangleIndex; + S3L_makeWorldMatrix(scene.models[modelIndex].transform,&mat1); + S3L_makeCameraMatrix(scene.camera.transform,&mat2); + + S3L_mat4Xmat4(&mat1,&mat2); + + S3L_Index triangleCount = scene.models[modelIndex].triangleCount; + + while (triangleIndex < triangleCount) + { + #define project(n)\ + indexIndex = triangles[coordIndex] * 3;\ + pointModel.x = vertices[indexIndex];\ + ++indexIndex; /* TODO: put into square brackets? */\ + pointModel.y = vertices[indexIndex];\ + ++indexIndex;\ + pointModel.z = vertices[indexIndex];\ + ++coordIndex;\ + S3L_vec3Xmat4(&pointModel,&mat1);\ + transformed##n.x = pointModel.x;\ + transformed##n.y = pointModel.y;\ + transformed##n.z = pointModel.z;\ + transformed##n.w = S3L_FRACTIONS_PER_UNIT;\ + S3L_perspectiveDivide(&transformed##n,scene.camera.focalLength); + + /* TODO: maybe create an option that would use a cache here to not + transform the same point twice? */ + + project(0) + project(1) + project(2) + + #undef project + + S3L_drawTriangle(transformed0,transformed1,transformed2, + &(scene.models[modelIndex].config),&(scene.camera),triangleIndex); + + ++triangleIndex; + } } } diff --git a/testSDL.c b/testSDL.c index 78857cd..a1722cd 100644 --- a/testSDL.c +++ b/testSDL.c @@ -35,6 +35,9 @@ const S3L_Unit ver[] = { S3L_CUBE_VERTICES }; const S3L_Index tri[] = { S3L_CUBE_TRIANGLES }; const S3L_Unit tex_coords[] = { S3L_CUBE_TEXCOORDS(16) }; +S3L_Model3D models[2]; +S3L_Scene scene; + int8_t keys[256]; const uint8_t testTexture[] = @@ -126,7 +129,6 @@ setPixel(p->x,p->y,sss,sss,sss); // setPixel(p->x,p->y,p->barycentric0 / ((float) S3L_FRACTIONS_PER_UNIT) * 255,p->barycentric1 / ((float) S3L_FRACTIONS_PER_UNIT) * 255,p->barycentric2 / ((float) S3L_FRACTIONS_PER_UNIT) * 255); } -S3L_Camera camera; S3L_Transform3D modelTransform; S3L_DrawConfig conf; @@ -136,11 +138,11 @@ void draw() if (frame % 128 == 0) { printf("frame: %d\n",frame); - printf("camera:\n"); + printf("scene.camera:\n"); printf(" translation: "); - S3L_writeVec4(camera.transform.translation); + S3L_writeVec4(scene.camera.transform.translation); printf(" rotation: "); - S3L_writeVec4(camera.transform.rotation); + S3L_writeVec4(scene.camera.transform.rotation); } */ @@ -150,22 +152,26 @@ void draw() uint32_t f = frame; - modelTransform.rotation.z = f * 0.1; - modelTransform.rotation.x = f * 0.3; + scene.models[0].transform.rotation.z = f * 0.1; + scene.models[0].transform.rotation.x = f * 0.3; // modelTransform.translation.x = sin(f >> 7) * 700; // modelTransform.translation.y = sin(f >> 8) * 600; - S3L_drawModelIndexed(ver,tri,12,modelTransform,&camera,&conf); +/* + S3L_drawModelIndexed(ver,tri,12,modelTransform,&scene.camera,&conf); modelTransform.translation.x += 2 * S3L_FRACTIONS_PER_UNIT; - S3L_drawModelIndexed(ver,tri,12,modelTransform,&camera,&conf); + S3L_drawModelIndexed(ver,tri,12,modelTransform,&scene.camera,&conf); modelTransform.translation.x -= 2 * S3L_FRACTIONS_PER_UNIT; +*/ + + S3L_drawScene(scene); if (offScreenPixels > 0) printf("offscreen pixels: %d\n",offScreenPixels); -// S3L_drawModelIndexed(ver,tri,1,modelTransform,&camera,&conf); +// S3L_drawModelIndexed(ver,tri,1,modelTransform,&scene.camera,&conf); /* conf.backfaceCulling = S3L_BACKFACE_CULLING_NONE; @@ -216,12 +222,25 @@ int main() SDL_Surface *screenSurface = SDL_GetWindowSurface(window); SDL_Event event; - S3L_initCamera(&camera); + S3L_initCamera(&scene.camera); - camera.transform.translation.z = -S3L_FRACTIONS_PER_UNIT * 2; + scene.camera.transform.translation.z = -S3L_FRACTIONS_PER_UNIT * 2; + scene.modelCount = 2; + scene.models = ⊧ -// camera.transform.translation.x = S3L_FRACTIONS_PER_UNIT; -// camera.transform.translation.y = S3L_FRACTIONS_PER_UNIT; + scene.models[0].vertices = ver; + scene.models[0].vertexCount = S3L_CUBE_VERTEX_COUNT; + scene.models[0].triangles = tri; + scene.models[0].triangleCount = S3L_CUBE_TRIANGLE_COUNT; + S3L_initTransoform3D(&(scene.models[0].transform)); + S3L_initDrawConfig(&(scene.models[0].config)); + scene.models[0].transform.translation.x = S3L_FRACTIONS_PER_UNIT; + + scene.models[1] = scene.models[0]; + scene.models[1].transform.translation.x = -1 * S3L_FRACTIONS_PER_UNIT; + +// scene.camera.transform.translation.x = S3L_FRACTIONS_PER_UNIT; +// scene.camera.transform.translation.y = S3L_FRACTIONS_PER_UNIT; S3L_initTransoform3D(&modelTransform); S3L_initDrawConfig(&conf); @@ -261,47 +280,47 @@ int main() int step = 10; S3L_rotationToDirections( - camera.transform.rotation, + scene.camera.transform.rotation, step, &camF, &camR, &camU); if (keys['w']) - S3L_vec3Add(&camera.transform.translation,camF); + S3L_vec3Add(&scene.camera.transform.translation,camF); if (keys['s']) - S3L_vec3Sub(&camera.transform.translation,camF); + S3L_vec3Sub(&scene.camera.transform.translation,camF); if (keys['d']) - S3L_vec3Add(&camera.transform.translation,camR); + S3L_vec3Add(&scene.camera.transform.translation,camR); if (keys['a']) - S3L_vec3Sub(&camera.transform.translation,camR); + S3L_vec3Sub(&scene.camera.transform.translation,camR); if (keys['c']) - S3L_vec3Add(&camera.transform.translation,camU); + S3L_vec3Add(&scene.camera.transform.translation,camU); if (keys['x']) - S3L_vec3Sub(&camera.transform.translation,camU); + S3L_vec3Sub(&scene.camera.transform.translation,camU); if (keys['q']) - camera.transform.rotation.y -= 1; + scene.camera.transform.rotation.y -= 1; if (keys['e']) - camera.transform.rotation.y += 1; + scene.camera.transform.rotation.y += 1; if (keys['r']) - camera.transform.rotation.x -= 1; + scene.camera.transform.rotation.x -= 1; if (keys['t']) - camera.transform.rotation.x += 1; + scene.camera.transform.rotation.x += 1; if (keys['f']) - camera.transform.rotation.z -= 1; + scene.camera.transform.rotation.z -= 1; if (keys['g']) - camera.transform.rotation.z += 1; + scene.camera.transform.rotation.z += 1; SDL_RenderClear(renderer); SDL_RenderCopy(renderer,texture,NULL,NULL);