/* scratch.c: scratch renderer routines. Used for handling intra-cluster visibility * with a Z-buffer visibility algorithm in software. */ #include "galerkinP.h" #include "scratch.h" #include "sgl.h" #include "geom.h" #include "cluster.h" #ifdef DEBUG #include "render.h" #endif /* create a scratch software renderer for various operations on clusters. */ void ScratchInit(void) { gal.scratch = sglOpen(gal.scratch_fb_size, gal.scratch_fb_size); sglDepthTesting(TRUE); } /* terminates scratch rendering */ void ScratchTerminate(void) { sglClose(gal.scratch); } /* src is a toplevel surface element. Render the corrsponding patch * with pixel value a pointer to the element. Uses global variable * eyep for backface culling. */ static POINT eyep; static void ScratchRenderElementPtr(ELEMENT *elem) { PATCH *patch = elem->pog.patch; VECTOR v[4]; int i; /* Backface culling test: only render the element if it is turned towards * the current eye point */ if (VECTORDOTPRODUCT(patch->normal, eyep) + patch->plane_constant < EPSILON) return; for (i=0; inrvertices; i++) v[i] = *patch->vertex[i]->point; sglSetColor((SGL_PIXEL)elem); sglPolygon(patch->nrvertices, v); } /* Sets up an orthographic projection of the cluster as * seen from the eye. Renders the element pointers to the elements * in clus in the scratch frame buffer and returns pointer to a boundingbox * containing the size of the virtual screen. The cluster clus nicely fits * into the virtual screen. */ float *ScratchRenderElementPtrs(ELEMENT *clus, POINT eye) { POINT centre = ElementMidpoint(clus); VECTOR up = {0., 0., 1.}, viewdir; static BOUNDINGBOX bbx; TRANSFORM lookat; SGL_CONTEXT *prev_sgl_context; int vp_size; if (clus->id == gal.lastclusid && VECTOREQUAL(eye, gal.lasteye, EPSILON)) return bbx; else { /* cache previously rendered cluster and eye point in order to * avoid rerendering the same situation next time. */ gal.lastclusid = clus->id; gal.lasteye = eye; } VECTORSUBTRACT(centre, eye, viewdir); VECTORNORMALIZE(viewdir); if (fabs(VECTORDOTPRODUCT(up, viewdir)) > 1.-EPSILON) VECTORSET(up, 0., 1., 0.); lookat = LookAt(eye, centre, up); BoundsTransform(GeomBounds(clus->pog.geom), &lookat, bbx); prev_sgl_context = sglMakeCurrent(gal.scratch); sglLoadMatrix(Ortho(bbx[MIN_X], bbx[MAX_X], bbx[MIN_Y], bbx[MAX_Y], -bbx[MAX_Z], -bbx[MIN_Z])); sglMultMatrix(lookat); /* choose a viewport depending on the relative size of the smallest * surface element in the cluster to be rendered. */ vp_size = (int)((bbx[MAX_X] - bbx[MIN_X]) * (bbx[MAX_Y] - bbx[MIN_Y]) / clus->minarea); if (vp_size > gal.scratch->width) vp_size = gal.scratch->width; if (vp_size < 32) vp_size = 32; sglViewport(0, 0, vp_size, vp_size); /* Render element pointers in the scratch frame buffer. */ eyep = eye; /* needed for backface culling test */ sglClear((SGL_PIXEL)NULL, SGL_ZMAX); IterateOverSurfaceElementsInCluster(clus, ScratchRenderElementPtr); sglMakeCurrent(prev_sgl_context); return bbx; } #ifdef DEBUG void ShowScratchBuffer(RGB bkgcol) { int i, j; RGB rgb[gal.scratch->width]; SGL_PIXEL *pix; for (j=0; jvp_height; j++) { pix = gal.scratch->fbuf + j * gal.scratch->width; for (i=0; ivp_width; i++, pix++) { ELEMENT *elem = (ELEMENT *)(*pix); if (elem) RadianceToRGB(elem->radiance[0], &rgb[i]); else rgb[i] = bkgcol; } RenderPixels(0, gal.scratch->height-j-1, gal.scratch->vp_width, rgb); } } #endif /*DEBUG*/ /* After rendering element pointers in the scratch frame buffer, this routine * computes the average radiance of the virtual screen. */ COLOR ScratchRadiance(void) { int nonbkgrnd; SGL_PIXEL *pix; COLOR rad; int i,j; #ifdef DEBUG ShowScratchBuffer(Blue); #endif COLORCLEAR(rad); nonbkgrnd = 0; for (j=0; jvp_height; j++) { pix = gal.scratch->fbuf + j * gal.scratch->width; for (i=0; ivp_width; i++, pix++) { ELEMENT *elem = (ELEMENT *)(*pix); if (elem) { if (gal.iteration_method == GAUSS_SEIDEL || gal.iteration_method == JACOBI) { COLORADD(rad, elem->radiance[0], rad); } else { COLORADD(rad, elem->unshot_radiance[0], rad); } nonbkgrnd ++; } } } if (nonbkgrnd > 0) { COLORSCALE(1./(double)(gal.scratch->vp_width*gal.scratch->vp_height), rad, rad); } return rad; } /* Computes the number of non background pixels. */ int ScratchNonBackgroundPixels(void) { int nonbkgrnd; SGL_PIXEL *pix; int i, j; #ifdef DEBUG ShowScratchBuffer(Green); #endif nonbkgrnd = 0; for (j=0; jvp_height; j++) { pix = gal.scratch->fbuf + j * gal.scratch->width; for (i=0; ivp_width; i++, pix++) { ELEMENT *elem = (ELEMENT *)(*pix); if (elem) nonbkgrnd ++; } } return nonbkgrnd; } /* Counts the number of pixels occupied by each element. The result is * accumulated in the tmp field of the elements. This field should be * initialized to zero before. */ void ScratchPixelsPerElement(void) { SGL_PIXEL *pix; int i, j; #ifdef DEBUG ShowScratchBuffer(Yellow); #endif for (j=0; jvp_height; j++) { pix = gal.scratch->fbuf + j * gal.scratch->width; for (i=0; ivp_width; i++, pix++) { ELEMENT *elem = (ELEMENT *)(*pix); if (elem) elem->tmp ++; } } }