From 4ed5e5fd842322a39e6394318a25a4321e775b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 22 Jun 2019 14:41:30 +0200 Subject: [PATCH] Add screen projection function --- programs/level.c | 28 +++++++++++++++++++++ small3dlib.h | 63 ++++++++++++++++++++++++++++++++++++++++-------- todo.txt | 2 +- 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/programs/level.c b/programs/level.c index 0dc38b7..65b2f1c 100644 --- a/programs/level.c +++ b/programs/level.c @@ -29,6 +29,8 @@ S3L_Model3D models[3]; S3L_Scene scene; +S3L_Vec4 teleportPoint; + uint32_t pixels[S3L_RESOLUTION_X * S3L_RESOLUTION_Y]; uint32_t frame = 0; @@ -80,6 +82,20 @@ void sampleTxture(S3L_Unit u, S3L_Unit v, uint8_t *r, uint8_t *g, uint8_t *b) *b = texture[index]; } +void drawTeleport(int16_t x, int16_t y, S3L_ScreenCoord size) +{ + int16_t halfSize = size / 2; + + S3L_ScreenCoord x0 = S3L_max(0,x - halfSize); + S3L_ScreenCoord x1 = S3L_min(S3L_RESOLUTION_X - 1,x + halfSize); + S3L_ScreenCoord y0 = S3L_max(0,y - halfSize); + S3L_ScreenCoord y1 = S3L_min(S3L_RESOLUTION_Y - 1,y + halfSize); + + for (S3L_ScreenCoord j = y0; j < y1; ++j) + for (S3L_ScreenCoord i = x0; i < x1; ++i) + setPixel(i,j,255,0,0); +} + void drawPixel(S3L_PixelInfo *p) { if (p->triangleID != previousTriangle) @@ -142,6 +158,13 @@ void draw() S3L_drawScene(scene); + S3L_Vec4 screenPoint; + + project3DPointToScreen(teleportPoint,scene.camera,&screenPoint); + + if (screenPoint.z < S3L_zBufferRead(screenPoint.x,screenPoint.y)) + drawTeleport(screenPoint.x,screenPoint.y,screenPoint.w); + clock_t nowT = clock(); double timeDiff = ((double) (nowT - nextT)) / CLOCKS_PER_SEC; @@ -167,6 +190,11 @@ int main() SDL_Surface *screenSurface = SDL_GetWindowSurface(window); SDL_Event event; + teleportPoint.x = 6 * S3L_FRACTIONS_PER_UNIT; + teleportPoint.y = -3 * S3L_FRACTIONS_PER_UNIT; + teleportPoint.z = 2 * S3L_FRACTIONS_PER_UNIT; + teleportPoint.w = S3L_FRACTIONS_PER_UNIT; + nextT = clock(); S3L_initCamera(&scene.camera); diff --git a/small3dlib.h b/small3dlib.h index 44a67db..b553e7d 100644 --- a/small3dlib.h +++ b/small3dlib.h @@ -512,6 +512,15 @@ static inline S3L_Unit S3L_cos(S3L_Unit x); S3L_Unit S3L_vec3Length(S3L_Vec4 v); S3L_Unit S3L_sqrt(S3L_Unit value); +/** Projects a single point from 3D space to the screen space (pixels), which + can be useful e.g. for drawing sprites. The w component of input and result + holds the point size. If this size is 0 in the result, the sprite is outside + the view. */ +void project3DPointToScreen( + S3L_Vec4 point, + S3L_Camera camera, + S3L_Vec4 *result); + /** Computes a normalized normal of given triangle. */ void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2, S3L_Vec4 *n); @@ -1419,6 +1428,50 @@ void S3L_initTransoform3D(S3L_Transform3D *t) t->scale.w = 0; } +/** + Performs perspecive division (z-divide). Does NOT check for division by zero. +*/ +static inline void S3L_perspectiveDivide(S3L_Vec4 *vector, + S3L_Unit focalLength) +{ + vector->x = (vector->x * focalLength) / vector->z; + vector->y = (vector->y * focalLength) / vector->z; +} + +void project3DPointToScreen( + S3L_Vec4 point, + S3L_Camera camera, + S3L_Vec4 *result) +{ + S3L_Mat4 m; + S3L_makeCameraMatrix(camera.transform,&m); + + S3L_Unit s = point.w; + + point.w = S3L_FRACTIONS_PER_UNIT; + + S3L_vec3Xmat4(&point,&m); + + point.z = S3L_nonZero(point.z); + + S3L_perspectiveDivide(&point,camera.focalLength); + + S3L_ScreenCoord x, y; + + S3L_mapProjectionPlaneToScreen(point,&x,&y); + + result->x = x; + result->y = y; + result->z = point.z; + + result->w = + (point.z < 0) ? 0 : + ( + (s * camera.focalLength * S3L_RESOLUTION_X) / + (point.z * S3L_FRACTIONS_PER_UNIT) + ); +} + void S3L_lookAt(S3L_Vec4 pointTo, S3L_Transform3D *t) { S3L_Vec4 v; @@ -2296,16 +2349,6 @@ void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 *m) S3L_mat4Xmat4(m,&r); } -/** - Performs perspecive division (z-divide). Does NOT check for division by zero. -*/ -static inline void S3L_perspectiveDivide(S3L_Vec4 *vector, - S3L_Unit focalLength) -{ - vector->x = (vector->x * focalLength) / vector->z; - vector->y = (vector->y * focalLength) / vector->z; -} - int8_t S3L_triangleWinding( S3L_ScreenCoord x0, S3L_ScreenCoord y0, diff --git a/todo.txt b/todo.txt index f344893..289348c 100644 --- a/todo.txt +++ b/todo.txt @@ -16,7 +16,7 @@ features: - function to set/clear stencil buffer -- can be useful - function to map one point in 3D space to screen, along with size (for mapping - billboards/sprites etc.) + billboards/sprites etc.) DONE - Optimize persp. correction!