/* sgl.c: Small Graphics Library. Software rendering into a user * accessible memory buffer. E.g. for clustering where a small number * of patches needs to be ID rendered very often. */ #include #include "../SGL/poly.h" /* make sure we include the one in this directory */ #include "../SGL/line.h" #include "sgl.h" #include "pools.h" #include "error.h" #include "mymath.h" Poly_vert *poly_dummy; /* used superficially by POLY_MASK macro */ SGL_CONTEXT *current_sgl_context = (SGL_CONTEXT *)NULL; SGL_CONTEXT *sglOpen(int width, int height) { SGL_CONTEXT *context = (SGL_CONTEXT *)Alloc(sizeof(SGL_CONTEXT)); current_sgl_context = context; /* frame buffer */ context->width = width; context->height = height; context->fbuf = (SGL_PIXEL *)Alloc(width * height * sizeof(SGL_PIXEL)); /* no Z buffer */ context->zbuf = (SGL_ZVAL *)NULL; /* transform stack and current transform */ context->curtrans = context->transform_stack; *context->curtrans = IdentityTransform; context->curpixel = 0; context->clipping = TRUE; /* default viewport and depth range */ context->vp_x = 0; context->vp_y = 0; context->vp_width = width; context->vp_height = height; context->near = 0.; context->far = 1.; return context; } void sglClose(SGL_CONTEXT *context) { Free((char *)context->fbuf, context->width * context->height * sizeof(SGL_PIXEL)); if (context->zbuf) Free((char *)context->zbuf, context->width * context->height * sizeof(SGL_ZVAL)); Free((char *)context, sizeof(SGL_CONTEXT)); if (context == current_sgl_context) current_sgl_context = (SGL_CONTEXT *)NULL; } SGL_CONTEXT *sglMakeCurrent(SGL_CONTEXT *context) { SGL_CONTEXT *old_context = current_sgl_context; current_sgl_context = context; return old_context; } void sglClearFrameBuffer(SGL_PIXEL backgroundcol) { SGL_PIXEL *pix, *lpix; int i, j; lpix = current_sgl_context->fbuf + current_sgl_context->vp_y * current_sgl_context->width + current_sgl_context->vp_x; for (j=0; jvp_height; j++, lpix += current_sgl_context->width) { for (pix = lpix, i=0; ivp_width; i++) *pix++ = backgroundcol; } } void sglClearZBuffer(SGL_ZVAL defzval) { SGL_ZVAL *zval, *lzval; int i, j; lzval = current_sgl_context->zbuf + current_sgl_context->vp_y * current_sgl_context->width + current_sgl_context->vp_x; for (j=0; jvp_height; j++, lzval += current_sgl_context->width) { for (zval = lzval, i=0; ivp_width; i++) *zval++ = defzval; } } void sglClear(SGL_PIXEL backgroundcol, SGL_ZVAL defzval) { sglClearFrameBuffer(backgroundcol); sglClearZBuffer(defzval); } void sglDepthTesting(SGL_BOOLEAN on) { if (on) { if (current_sgl_context->zbuf) return; else { current_sgl_context->zbuf = (SGL_ZVAL *)Alloc(current_sgl_context->width * current_sgl_context->height * sizeof(SGL_ZVAL)); } } else { if (current_sgl_context->zbuf) { Free((char *)current_sgl_context->zbuf, current_sgl_context->width * current_sgl_context->height * sizeof(SGL_ZVAL)); current_sgl_context->zbuf = (SGL_ZVAL *)NULL; } else return; } } void sglClipping(SGL_BOOLEAN on) { current_sgl_context->clipping = on; } void sglPushMatrix(void) { TRANSFORM *oldtrans; if (current_sgl_context->curtrans - current_sgl_context->transform_stack >= SGL_TRANSFORM_STACK_SIZE-1) { Error("sglPushMatrix", "Matrix stack overflow"); return; } oldtrans = current_sgl_context->curtrans; current_sgl_context->curtrans++; *current_sgl_context->curtrans = *oldtrans; } void sglPopMatrix(void) { if (current_sgl_context->curtrans <= current_sgl_context->transform_stack) { Error("sglPopMatrix", "Matrix stack underflow"); return; } current_sgl_context->curtrans--; } void sglLoadMatrix(TRANSFORM xf) { *current_sgl_context->curtrans = xf; } void sglMultMatrix(TRANSFORM xf) { *current_sgl_context->curtrans = TransCompose(*current_sgl_context->curtrans, xf); } void sglSetColor(SGL_PIXEL col) { current_sgl_context->curpixel = col; } void sglViewport(int x, int y, int width, int height) { current_sgl_context->vp_x = x; current_sgl_context->vp_y = y; current_sgl_context->vp_width = width; current_sgl_context->vp_height = height; } void sglDepthRange(double near, double far) { current_sgl_context->near = near; current_sgl_context->far = far; } void sglPolygon(int nrverts, VECTOR *verts) { Poly pol; Poly_vert *pv; Window win; Poly_box clip_box = {-1., 1., -1., 1., -1., 1.}; int i; if (nrverts > (current_sgl_context->clipping ? (POLY_NMAX-6) : POLY_NMAX)) { Error("sglPolygon", "Too many vertices (max. %d)", POLY_NMAX); return; } /* transform the vertices and fill in a Poly struct */ for (i=0, pv=&pol.vert[0]; icurtrans, v, v); if (v.w > -EPSILON && v.w < EPSILON) return; pv->sx = v.x; pv->sy = v.y; pv->sz = v.z; pv->sw = v.w; } pol.n = nrverts; pol.mask = 0; if (current_sgl_context->clipping) { pol.mask = POLY_MASK(sx) | POLY_MASK(sy) | POLY_MASK(sz) | POLY_MASK(sw); if (poly_clip_to_box(&pol, &clip_box) == POLY_CLIP_OUT) return; } /* perspective divide and transformation to viewport and depth range */ for (i=0, pv=&pol.vert[0]; isx = (double)current_sgl_context->vp_x + (pv->sx/pv->sw + 1.) * (double)current_sgl_context->vp_width * 0.5; pv->sy = (double)current_sgl_context->vp_y + (pv->sy/pv->sw + 1.) * (double)current_sgl_context->vp_height * 0.5; pv->sz = (current_sgl_context->near + (pv->sz/pv->sw + 1.) * current_sgl_context->far * 0.5) * (double)SGL_ZMAX; } /* window */ win.x0 = current_sgl_context->vp_x; win.y0 = current_sgl_context->vp_y; win.x1 = current_sgl_context->vp_x+current_sgl_context->vp_width-1; win.y1 = current_sgl_context->vp_y+current_sgl_context->vp_height-1; /* scan convert the polygon: use optimized version for flat shading * with or without Z buffering. */ if (!current_sgl_context->zbuf) poly_scan_flat(&pol, &win); else poly_scan_z(&pol, &win); }