From 55b6edfcb0eac5dd0d71e78036ba08d0afbee92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 8 Jun 2019 16:56:54 +0200 Subject: [PATCH] Add helloTerminal --- programs/helloTerminal.c | 120 +++++++++++++++++++++++++++++++++++++++ programs/modelViewer.c | 5 +- small3dlib.h | 46 +++++++++++++-- 3 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 programs/helloTerminal.c diff --git a/programs/helloTerminal.c b/programs/helloTerminal.c new file mode 100644 index 0000000..3dfaaa3 --- /dev/null +++ b/programs/helloTerminal.c @@ -0,0 +1,120 @@ +/* + Simple example of small3dlib, rendering in terminal. + + license: CC0 1.0 +*/ + +#include // for usleep + +// we need to define screen resolution before including the library: + +#define S3L_RESOLUTION_X 80 +#define S3L_RESOLUTION_Y 40 + +// and a name of the function we'll be using to draw individual pixels: + +#define S3L_PIXEL_FUNCTION drawPixel + +// now include the library: + +#include "../small3dlib.h" + +// we'll use a predefined geometry of a cube that's in the library: + +S3L_Unit cubeVertices[] = { S3L_CUBE_VERTICES(S3L_FRACTIONS_PER_UNIT) }; +S3L_Index cubeTriangles[] = { S3L_CUBE_TRIANGLES }; + +S3L_Model3D cubeModel; // 3D model, has a geometry, position, rotation etc. +S3L_Scene scene; // scene we'll be rendring (can have multiple models) + +uint8_t screen[S3L_RESOLUTION_X * S3L_RESOLUTION_Y]; // our screen + +/* This function will be called by the library to draw individual rasterized + pixels to the screen. We should try to make this function as fast as possible + as it tends to be the performance bottle neck. */ + +void drawPixel(S3L_PixelInfo *p) +{ + uint8_t c; // ASCII pixel we'll write to the screen + + /* We'll draw different triangles with different ASCII symbols to give the + illusion of lighting. */ + + if (p->triangleIndex == 0 || p->triangleIndex == 1 || + p->triangleIndex == 4 || p->triangleIndex == 5) + c = '#'; + else if (p->triangleIndex == 2 || p->triangleIndex == 3 || + p->triangleIndex == 6 || p->triangleIndex == 7) + c = 'x'; + else + c = '.'; + + screen[p->y * S3L_RESOLUTION_X + p->x] = c; // draw the pixel to the screen +} + +void clearScreen() +{ + for (int j = 0; j < S3L_RESOLUTION_X * S3L_RESOLUTION_Y; ++j) + screen[j] = ' '; +} + +// This function prints out the content of the screen to the terminal. + +void drawScreen() +{ + for (int i = 0; i < 20; ++i) + printf("\n"); + + int pos = 0; + + for (int y = 0; y < S3L_RESOLUTION_Y; ++y) + { + for (int x = 0; x < S3L_RESOLUTION_X; ++x) + { + printf("%c",screen[pos]); + pos++; + } + + printf("\n"); + } +} + +int main() +{ + S3L_initModel3D( + cubeVertices, + S3L_CUBE_VERTEX_COUNT, + cubeTriangles, + S3L_CUBE_TRIANGLE_COUNT, + &cubeModel); + + S3L_initScene( // Initialize the scene we'll be rendering. + &cubeModel, /* We only have one model (the cube), this is like an array + with only one model in it. */ + 1, + &scene); + + // shift the camera a little bit backwards so that it's not inside the cube: + + scene.camera.transform.translation.z = -2 * S3L_FRACTIONS_PER_UNIT; + + for (int i = 0; i < 200; ++i) // render 200 frames + { + clearScreen(); + + S3L_drawScene(scene); /* This starts the scene rendering. The drawPixel + function will be called to draw it. */ + drawScreen(); + + usleep(100000); // wait a bit to let the user see the frame + + // now move and rotate the cube a little to see some movement: + + scene.models[0].transform.rotation.y += 10; + scene.models[0].transform.rotation.x += 4; + scene.models[0].transform.translation.x = S3L_sin(i * 4); + scene.models[0].transform.translation.y = S3L_sin(i * 2) / 2; + } + + return 0; +} diff --git a/programs/modelViewer.c b/programs/modelViewer.c index 4c2ca93..b27de8a 100644 --- a/programs/modelViewer.c +++ b/programs/modelViewer.c @@ -417,7 +417,7 @@ int main() S3L_normalizeVec3(&toLight); - S3L_initCamera(&scene.camera); + S3L_initScene(&model,1,&scene); scene.camera.transform.translation.z = -S3L_FRACTIONS_PER_UNIT * 8; @@ -425,9 +425,6 @@ int main() catModel.vertices = catVertices; animate(0); - scene.modelCount = 1; - scene.models = &model; - int8_t modelIndex = 0; int8_t modelsTotal = 4; setModel(0); diff --git a/small3dlib.h b/small3dlib.h index d6239e7..e90ae70 100644 --- a/small3dlib.h +++ b/small3dlib.h @@ -390,7 +390,7 @@ typedef struct S3L_Transform3D transform; } S3L_Camera; -static inline void S3L_initCamera(S3L_Camera *c); +void S3L_initCamera(S3L_Camera *camera); typedef struct { @@ -414,6 +414,13 @@ typedef struct S3L_DrawConfig config; } S3L_Model3D; ///< Represents a 3D model. +void S3L_initModel3D( + S3L_Unit *vertices, + S3L_Unit vertexCount, + S3L_Index *triangles, + S3L_Index triangleCount, + S3L_Model3D *model); + typedef struct { S3L_Model3D *models; @@ -421,6 +428,11 @@ typedef struct S3L_Camera camera; } S3L_Scene; ///< Represent the 3D scene to be rendered. +void S3L_initScene( + S3L_Model3D *models, + S3L_Index modelCount, + S3L_Scene *scene); + typedef struct { S3L_ScreenCoord x; ///< Screen X coordinate. @@ -1319,10 +1331,10 @@ void S3L_setTransform3D( t->scale.z = sz; } -void S3L_initCamera(S3L_Camera *c) +void S3L_initCamera(S3L_Camera *camera) { - c->focalLength = S3L_FRACTIONS_PER_UNIT; - S3L_initTransoform3D(&(c->transform)); + camera->focalLength = S3L_FRACTIONS_PER_UNIT; + S3L_initTransoform3D(&(camera->transform)); } void S3L_rotationToDirections( @@ -1373,6 +1385,32 @@ void S3L_initPixelInfo(S3L_PixelInfo *p) // TODO: maybe non-pointer for p p->previousZ = 0; } +void S3L_initModel3D( + S3L_Unit *vertices, + S3L_Unit vertexCount, + S3L_Index *triangles, + S3L_Index triangleCount, + S3L_Model3D *model) +{ + model->vertices = vertices; + model->vertexCount = vertexCount; + model->triangles = triangles; + model->triangleCount = triangleCount; + + S3L_initTransoform3D(&(model->transform)); + S3L_initDrawConfig(&(model->config)); +} + +void S3L_initScene( + S3L_Model3D *models, + S3L_Index modelCount, + S3L_Scene *scene) +{ + scene->models = models; + scene->modelCount = modelCount; + S3L_initCamera(&(scene->camera)); +} + void S3L_initDrawConfig(S3L_DrawConfig *config) { config->backfaceCulling = 2;