sortof works :) master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 6 Aug 2024 23:25:42 +0000 (02:25 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 6 Aug 2024 23:25:42 +0000 (02:25 +0300)
src/main.c

index 274e543..298c542 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <math.h>
 #include <SDL/SDL.h>
 #include "cgmath/cgmath.h"
 
@@ -7,7 +8,8 @@ static int init(void);
 static void cleanup(void);
 static void update_proj_vp(void);
 static void draw(void);
-static int quadric(float *obj, int x, int y, float *retz);
+static int quadric(float *obj, cgm_vec4 *p);
+static int calc_w(float *obj, cgm_vec4 *p);
 static void proc_event(SDL_Event *ev);
 
 static int quit, resize_pending;
@@ -15,11 +17,17 @@ static int win_width, win_height;
 static float win_aspect;
 static SDL_Surface *fbsurf;
 static int frame;
+static int mouse_x, mouse_y;
+static int bnstate[8];
+static unsigned long start_msec;
 
 #define SDLFLAGS       SDL_SWSURFACE | SDL_RESIZABLE
 
+static float cam_theta, cam_phi = 0.5, cam_dist = 4;
 
 static float modelview[16], projection[16], viewport[16];
+static float invmodelview[16], invproj[16];
+static float mvadj[16], mvadjt[16];
 static float mvpmat[16], mvpadj[16], mvpadjt[16];
 
 static float objmat[16];
@@ -39,6 +47,7 @@ int main(void)
                SDL_Quit();
                return 1;
        }
+       SDL_WM_SetCaption("algebraic surface rasterization", 0);
        win_width = 800;
        win_height = 600;
        win_aspect = 1.33333333333;
@@ -49,6 +58,7 @@ int main(void)
                return 1;
        }
 
+       start_msec = SDL_GetTicks();
        for(;;) {
                while(SDL_PollEvent(&ev)) {
                        proc_event(&ev);
@@ -71,12 +81,23 @@ end:
        return 0;
 }
 
+static const float sphere[] = {
+       1, 0, 0, 0,
+       0, 1, 0, 0,
+       0, 0, 1, 0,
+       0, 0, 0, -1
+};
+static const float cone[] = {
+       1, 0, 0, 0,
+       0, 1, 0, 0,
+       0, 0, -1, 0,
+       0, 0, 0, 0
+};
+
+
 static int init(void)
 {
-       cgm_mzero(objmat);
-       objmat[0] = objmat[5] = objmat[10] = 1;
-       objmat[15] = -1;
-
+       memcpy(objmat, sphere, sizeof objmat);
 
        return 0;
 }
@@ -88,6 +109,8 @@ static void cleanup(void)
 static void update_proj_vp(void)
 {
        cgm_mperspective(projection, cgm_deg_to_rad(50), win_aspect, 0.5, 500.0f);
+       cgm_mcopy(invproj, projection);
+       cgm_minverse(invproj);
 
        cgm_mtranslation(viewport, 1, 1, 0);
        cgm_mscale(viewport, win_width * 0.5f, win_height * 0.5f, 1);
@@ -97,36 +120,123 @@ static void draw(void)
 {
        int i, j;
        uint32_t *fbptr;
-       float objp[16];
+       float objp[16], objv[16];
+       static const cgm_vec3 lpos = {-6, 10, 10};
+       cgm_vec3 ldir, hvec;
+       float t;
+       unsigned long msec;
+
+       msec = SDL_GetTicks() - start_msec;
+       t = (float)msec / 1000.0f;
 
        if(SDL_MUSTLOCK(fbsurf)) {
                SDL_LockSurface(fbsurf);
        }
-       fbptr = fbsurf->pixels;
 
-       cgm_mtranslation(modelview, 0, 0, 5);
+       cgm_midentity(modelview);
+       /* view matrix */
+       cgm_mpretranslate(modelview, 0, -0.5, -cam_dist);
+       cgm_mprerotate_x(modelview, cam_phi);
+       cgm_mprerotate_y(modelview, cam_theta);
+
+       ldir = lpos; cgm_vmul_m4v3(&ldir, modelview);
+       cgm_vnormalize(&ldir);
+
+
+       /* model matrix */
+       cgm_mpretranslate(modelview, 0, fabs(cos(t)), 0);
+
+       cgm_mcopy(invmodelview, modelview);
+       cgm_minverse(invmodelview);
 
        cgm_mcopy(mvpmat, modelview);
        cgm_mmul(mvpmat, projection);
        cgm_mmul(mvpmat, viewport);
        /* calculate the adjoint, and the adjoint-transpose */
-       cgm_mcopy(mvpadj, mvpmat); cgm_minverse(mvpadj);
+       cgm_mcopy(mvpadj, mvpmat); cgm_mcofmatrix(mvpadj); cgm_mtranspose(mvpadj);
        cgm_mcopy(mvpadjt, mvpadj);     cgm_mtranspose(mvpadjt);
 
-       /* transform object */
+       cgm_mcopy(mvadj, modelview); cgm_mcofmatrix(mvadj); cgm_mtranspose(mvadj);
+       cgm_mcopy(mvadjt, mvadj); cgm_mtranspose(mvadjt);
+
+       /* transform object to screen space */
        cgm_mcopy(objp, mvpadj);
        cgm_mmul(objp, objmat);
        cgm_mmul(objp, mvpadjt);
 
+       /* transform object to view space */
+       cgm_mcopy(objv, mvadj);
+       cgm_mmul(objv, objmat);
+       cgm_mmul(objv, mvadjt);
+
+       hvec.x = ldir.x * 0.5f;
+       hvec.y = ldir.y * 0.5f;
+       hvec.z = (ldir.z + 1.0f) * 0.5f;
+       cgm_vnormalize(&hvec);
+
+       fbptr = (uint32_t*)fbsurf->pixels + (win_height - 1) * win_width;
        for(i=0; i<win_height; i++) {
                for(j=0; j<win_width; j++) {
-                       float z;
-                       if(quadric(objp, j, i, &z)) {
-                               *fbptr++ = 0xff0000;
+                       cgm_vec4 p;
+                       cgm_vec3 n;
+                       float ndotl, ndoth, spec;
+                       int r, g, b;
+                       float u, v;
+
+                       p.x = j;
+                       p.y = i;
+                       if(quadric(objp, &p)) {
+                               /* transform back to local space */
+                               p.x = p.x * 2.0f / win_width - 1.0f;
+                               p.y = p.y * 2.0f / win_height - 1.0f;
+                               p.w = 1.0f;
+                               cgm_wmul_m4v4(&p, invproj);
+
+                               /* compute the normal in view space */
+                               n.x = p.x * objv[0] + p.y * objv[1] + p.z * objv[2] + p.w * objv[3];
+                               n.y = p.x * objv[4] + p.y * objv[5] + p.z * objv[6] + p.w * objv[7];
+                               n.z = p.x * objv[8] + p.y * objv[9] + p.z * objv[10] + p.w * objv[11];
+                               cgm_vnormalize(&n);
+
+                               /* transofrm p to local space to compute uv mapping */
+                               cgm_wmul_m4v4(&p, invmodelview);
+                               cgm_wscale(&p, 1.0f / p.w);
+                               u = atan2(p.z, p.x) * 0.5f / CGM_PI + CGM_PI/2;
+                               v = acos(p.y) / CGM_PI;
+
+                               ndotl = cgm_vdot(&n, &ldir);
+                               if(ndotl < 0) ndotl = 0;
+                               ndoth = cgm_vdot(&n, &hvec);
+                               if(ndoth < 0) ndoth = 0;
+                               spec = pow(ndoth, 60.0f);
+
+                               u *= 16.0f;
+                               v *= 8.0f;
+                               u = u - floor(u);
+                               v = v - floor(v);
+                               if(u < 0.15 || v < 0.15) {
+                                       r = 64;
+                                       g = 128;
+                                       b = 255;
+                               } else {
+                                       r = 255;
+                                       g = 80;
+                                       b = 80;
+                               }
+
+                               r = (int)(ndotl * r + spec * 192.0f) + r / 16;
+                               g = (int)(ndotl * g + spec * 192.0f) + g / 16;
+                               b = (int)(ndotl * b + spec * 192.0f) + b / 16;
+                               if(r > 255) r = 255;
+                               if(g > 255) g = 255;
+                               if(b > 255) b = 255;
+
+                               fbptr[j] = (r << 16) | (g << 8) | b;
                        } else {
-                               *fbptr++ = 0;
+                               fbptr[j] = 0;
                        }
                }
+               fbptr -= win_width;
        }
 
        if(SDL_MUSTLOCK(fbsurf)) {
@@ -136,19 +246,19 @@ static void draw(void)
        SDL_Flip(fbsurf);
 }
 
-static int quadric(float *obj, int xpix, int ypix, float *retz)
+static int quadric(float *obj, cgm_vec4 *p)
 {
        float x, y, a, b, c, d, sqrtd, a2, z0, z1;
 
-       x = (float)xpix;
-       y = (float)ypix;
+       x = p->x;
+       y = p->y;
 
        a = obj[10];
        b = (x * obj[2] + y * obj[6] + obj[11]) * 2.0f;
        c = x * x * obj[0] + y * y * obj[5] + (x * y * obj[1] + x * obj[3] +
                        y * obj[7]) * 2.0f + obj[15];
 
-       d = b * b - 4 * a * c;
+       d = b * b - 4.0f * a * c;
        if(d <= 0.0f) return 0;
 
        sqrtd = sqrt(d);
@@ -160,12 +270,40 @@ static int quadric(float *obj, int xpix, int ypix, float *retz)
        if(z0 < 0.0f) z0 = z1;
        if(z1 < 0.0f) z1 = z0;
 
-       *retz = z0 < z1 ? z0 : z1;
+       p->z = z0 < z1 ? z0 : z1;
+       return 1;
+}
+
+static int calc_w(float *obj, cgm_vec4 *p)
+{
+       float x, y, z, a, b, c, d, sqrtd, a2, w0, w1;
+
+       x = p->x;
+       y = p->y;
+       z = p->z;
+
+       a = obj[15];
+       b = (x * obj[3] + y * obj[7] + z * obj[11]) * 2.0f;
+       c = x * x * obj[0] + y * y * obj[5] + z * z * obj[10] +
+               (x * y * obj[1] + x * z * obj[2] + y * z * obj[6]) * 2.0f;
+
+       d = b * b - 4.0f * a * c;
+       if(d <= 0.0f) return 0;
+
+       sqrtd = sqrt(d);
+       a2 = a * 2.0f;
+
+       w0 = (-b + sqrtd) / a2;
+       w1 = (-b - sqrtd) / a2;
+
+       p->w = w0 < w1 ? w0 : w1;       /* ???? */
        return 1;
 }
 
 static void proc_event(SDL_Event *ev)
 {
+       int bidx, dx, dy;
+
        switch(ev->type) {
        case SDL_KEYDOWN:
                if(ev->key.keysym.sym == SDLK_ESCAPE) {
@@ -181,5 +319,31 @@ static void proc_event(SDL_Event *ev)
                        resize_pending = 1;
                }
                break;
+
+       case SDL_MOUSEBUTTONDOWN:
+       case SDL_MOUSEBUTTONUP:
+               bidx = ev->button.button - SDL_BUTTON_LEFT;
+               bnstate[bidx] = ev->button.state == SDL_PRESSED ? 1 : 0;
+               mouse_x = ev->button.x;
+               mouse_y = ev->button.y;
+               break;
+
+       case SDL_MOUSEMOTION:
+               dx = ev->motion.xrel;
+               dy = ev->motion.yrel;
+
+               if((dx | dy)) {
+                       if(bnstate[0]) {
+                               cam_theta += dx * 0.01;
+                               cam_phi += dy * 0.01;
+                               if(cam_phi < -CGM_PI/2) cam_phi = -CGM_PI/2;
+                               if(cam_phi > CGM_PI/2) cam_phi = CGM_PI/2;
+                       }
+                       if(bnstate[2]) {
+                               cam_dist += dy * 0.1;
+                               if(cam_dist < 0) cam_dist = 0;
+                       }
+               }
+               break;
        }
 }