Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/render/intern/source/vanillaRenderPipe.c')
-rw-r--r--source/blender/render/intern/source/vanillaRenderPipe.c1654
1 files changed, 1654 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/vanillaRenderPipe.c b/source/blender/render/intern/source/vanillaRenderPipe.c
new file mode 100644
index 00000000000..5f78e1b25c9
--- /dev/null
+++ b/source/blender/render/intern/source/vanillaRenderPipe.c
@@ -0,0 +1,1654 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * vanillaRenderPipe.c
+ *
+ * 28-06-2000 nzc
+ *
+ * $Id$
+ *
+ */
+
+/*
+ The render pipe
+ ---------------
+
+ The overall results of the render pass should end up in R.rectot. This
+ buffer already exists, and although its contents may change, its location
+ may not. A lot of other routines depend on it!
+
+*/
+
+/* global includes */
+#include <math.h>
+#include <limits.h> /* INT_MIN,MAX are used here */
+#include <stdlib.h>
+#include "MTC_vectorops.h"
+#include "MTC_matrixops.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_object_types.h"
+#include "BKE_global.h"
+
+/* local includes (from the render module) */
+#include "RE_callbacks.h"
+#include "render.h" /* all kinds of stuff */
+#include "render_intern.h"
+#include "zbuf.h" /* for vergzvlak, zbufclip, zbufclipwire */
+#include "edgeRender.h" /* all edge rendering stuff */
+#include "pixelshading.h" /* painting the pixels */
+#include "rendercore.h"
+
+/* general calculus and data manipulation, also local */
+#include "gammaCorrectionTables.h"
+#include "jitter.h"
+#include "pixelblending.h"
+#include "zbufferdatastruct.h"
+
+/* own includes */
+#include "vanillaRenderPipe.h"
+#include "vanillaRenderPipe_int.h"
+
+/* crud */
+#define MIN2(x,y) ( (x)<(y) ? (x) : (y) )
+
+/* ------------------------------------------------------------------------- */
+/* Debug defines: disable all for production level code. */
+/* These variables control faking of rendered colours, extra tracing, */
+/* extra error checking and such. */
+/* ------------------------------------------------------------------------- */
+
+/* if defined: _very_ explicit tracing and checking enabled */
+/* #define RE_FULL_SAFETY */
+/* if defined: use 'simple' alpha thresholding on oversampling */
+/* #define RE_SIMPLE_ALPHA_THRESHOLD */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef RE_FULL_SAFETY
+/* Full safety does the following: */
+/* - add extra bounds checking */
+/* - add extra type checking */
+/* - do a little performance analysis */
+/* - trace the original sources */
+
+/* trace the version of the source */
+char vanillaRenderPipe_ext_h[] = VANILLARENDERPIPE_EXT_H;
+char vanillaRenderPipe_int_h[] = VANILLARENDERPIPE_INT_H;
+char vanillaRenderPipe_types_h[] = VANILLARENDERPIPE_TYPES_H;
+char vanillaRenderPipe_c[] =
+"$Id$";
+/* counters for error handling */
+static int conflictsresolved; /* number of conflicts in one frame */
+
+#include "errorHandler.h"
+#endif /* RE_FULL_SAFETY stuff */
+
+/* ------------------------------------------------------------------------- */
+
+/* External : -------------------------------------------------------------- */
+
+extern float centLut[16]; /* Lookup for jitter offsets. */
+extern unsigned int Zsample; /* Nr. of the currently active oversample. This */
+ /* counter must be set explicitly by the */
+ /* function that builds the z-buffer. */
+ /* The buffer-filling functions use it. */
+extern float Zjitx,Zjity; /* The x,y values for jitter offset */
+
+extern float Zmulx, Zmuly; /* Some kind of scale? */
+
+extern unsigned int Zvlnr; /* Face rendering pointer and counter: these */
+extern VlakRen *Zvlr; /* are used for 'caching' render results. */
+
+ /* These function pointers are used for z buffer filling. */
+extern void (*zbuffunc)(float *, float *, float *);
+extern void (*zbuflinefunc)(float *, float *);
+
+extern char cmask[256]; /* When a pixel is supersampled, we must */
+extern char *centmask; /* compute its colour on a point _on_ the face. */
+ /* These two are used to compute an offset to */
+ /* guarantee we use valid coordinates. */
+
+/* unsorted */
+extern float holoofs, fmask[256];
+extern unsigned short usegamtab, shortcol[4],
+ *mask1[9], *mask2[9],/* *igamtab1, */ *igamtab2/*, *gamtab */;
+
+extern RE_APixstrExt *APixbufExt;/*Zbuffer: linked list of face, halo indices*/
+
+/* Globals : --------------------------------------------------------------- */
+
+RE_COLBUFTYPE *AColourBuffer; /* Buffer for colours of 1 line of pixels */
+static int Aminy; /* y value of first line in the accu buffer */
+static int Amaxy; /* y value of last line in the accu buffer */
+ /* -also used to clip when zbuffering */
+
+/* Buffer width refers to the size of the buffers we build. Image size is */
+/* the same as R.rectx, R.recty. */
+static int imageHeight; /* image size in pixels in y direction */
+static int imageWidth; /* image size in pixels in x direction */
+static int bufferHeight; /* image size in pixels in y direction */
+static int bufferWidth; /* image size in pixels in x direction */
+static int zBufferWidth; /* special width because zbuffer needs to be */
+ /* wider */
+
+static int Azvoordeel; /* A small offset for transparent rendering. */
+int alphaLUT[32]; /* alpha lookuptable, for oversampling */
+ /* Its function has been superceded because */
+ /* pixels are always integrated. This */
+ /* performs the same normalization. */
+int osaNr; /* The oversample number. I keep it */
+ /* separately here, because I treat no OSA */
+ /* as if it were osa=1. */
+RE_COLBUFTYPE collector[4]; /* used throughout as pixel colour accu */
+RE_COLBUFTYPE sampcol[RE_MAX_OSA_COUNT * 4]; /* subpixel accu buffer */
+
+/* ------------------------------------------------------------------------- */
+/* Local (for now) */
+/* void integrateStack(struct RE_faceField* stack, */
+/* int ptr, */
+/* float x, */
+/* float y, */
+/* int osaNr); */
+void integratePerSubStack(struct RE_faceField* stack,
+ int ptr,
+ float x,
+ float y,
+ int osaNr);
+
+/* ------------------------------------------------------------------------- */
+
+void zBufShadeAdvanced()
+{
+ int y, keepLooping = 1;
+ float xjit = 0.0, yjit = 0.0;
+
+#ifdef RE_FULL_SAFETY
+ /* reset trace */
+ RE_errortrace_reset();
+ conflictsresolved = 0;
+ fprintf(stderr, "\n*** Activated full error trace on "
+ "unified renderer using:\n\t%s\n\t%s\n\t%s\n\t%s",
+ vanillaRenderPipe_c, vanillaRenderPipe_ext_h,
+ vanillaRenderPipe_int_h, vanillaRenderPipe_types_h);
+#endif
+
+ Zjitx=Zjity= -0.5; /* jitter preset: 0.5 pixel */
+
+ /* EDGE: for edge rendering we should compute a larger buffer, but this */
+ /* may require modifications at a deeper level. For now, we just */
+ /* 'ignore' edge pixels. */
+ imageHeight = R.recty;
+ imageWidth = R.rectx;
+ bufferHeight = R.recty;
+ bufferWidth = R.rectx;
+
+ /* Set osaNr. Treat 'no osa' as 'osa = 1' */
+ if(R.r.mode & R_OSA) {
+ osaNr = R.osa;
+ if(osaNr > 16) { /* check was moved from calcZBufLine */
+ printf("zBufShadeAdvanced> osa too large (internal error)\n");
+ G.afbreek= 1;
+ return;
+ }
+ } else {
+ /* little hack */
+ osaNr = 1;
+ xjit = jit[0][0];
+ yjit = jit[0][1];
+ jit[0][0] = 0.45;
+ jit[0][1] = 0.45;
+ }
+
+ RE_setwindowclip(0, -1); /* just to be sure, reset the view matrix */
+
+ initRenderBuffers(bufferWidth);
+
+ /* ugh! should be converted sooner!! */
+ switch (R.r.alphamode) {
+ case R_ALPHAKEY:
+ setSkyBlendingMode(RE_ALPHA_KEY);
+ break;
+ case R_ALPHAPREMUL:
+ setSkyBlendingMode(RE_ALPHA_PREMUL);
+ break;
+/* not there... this is the default case */
+/* case R_ALPHASKY: */
+/* setSkyBlendingMode(RE_ALPHA_SKY); */
+/* break; */
+ default:
+ setSkyBlendingMode(RE_ALPHA_SKY);
+ }
+
+ y = 0;
+ while ( (y < bufferHeight) && keepLooping) {
+ calcZBufLine(y);
+ R.vlaknr= -1; /* huh? why reset this counter? for shadePixel! */
+ renderZBufLine(y);
+ transferColourBufferToOutput(y);
+
+ if((y & 1) && G.background!=1) RE_local_render_display(y-1, y,
+ imageWidth,
+ imageHeight,
+ R.rectot);
+
+ if(RE_local_test_break()) keepLooping = 0;
+ y++;
+ }
+ freeRenderBuffers();
+
+ /* Edge rendering is done purely as a post-effect */
+ if(R.r.mode & R_EDGE) {
+ addEdges((char*)R.rectot, imageWidth, imageHeight,
+ osaNr,
+ R.r.edgeint, R.r.same_mat_redux,
+ G.compat, G.notonlysolid,
+ R.r.edgeR, R.r.edgeG, R.r.edgeB);
+ }
+
+ add_halo_flare(); /* from rendercore */
+
+#ifdef RE_FULL_SAFETY
+ fprintf(stderr, "\n--- resolved %d conflicts", conflictsresolved);
+ fflush(stderr);
+#endif
+
+ if (!(R.r.mode & R_OSA)) {
+ jit[0][0] = xjit;
+ jit[0][1] = yjit;
+ }
+
+} /* end of void zbufshadeAdvanced() */
+
+/* ------------------------------------------------------------------------- */
+
+void initRenderBuffers(int bwidth)
+{
+
+ /* The +1 is needed because the fill-functions use a +1 offset when */
+ /* filling in pixels. Mind that also the buffer-clearing function needs */
+ /* this offset (done in calcZBufLine). */
+ /* The offset is wrong: it shouldn't be there. I need to fix this still. */
+ AColourBuffer = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * bwidth,
+ "Acolrow");
+ zBufferWidth = bwidth + 1;
+ initZbuffer(bwidth + 1);
+
+ Aminy= -1000; /* indices of lines in the z buffer: no lines buffered */
+ Amaxy= -1000;
+
+ /* Use slider when the gamma button is pressed. */
+ if (R.r.mode & R_GAMMA) {
+ makeGammaTables(R.r.gamma);
+ setDoGamma(1);
+ } else {
+ /*
+ Needed for spotlights! Maybe a separate gammatable would be
+ required here
+ */
+ makeGammaTables(1.0);
+ setDoGamma(0);
+ }
+
+} /* End of void initZBuffers(void) */
+
+/* ------------------------------------------------------------------------- */
+
+void freeRenderBuffers(void) {
+ if (AColourBuffer) MEM_freeN(AColourBuffer);
+ freeZbuffer();
+} /* End of void freeZBuffers(void) */
+
+/* ------------------------------------------------------------------------- */
+
+void calcZBufLine(int y)
+{
+
+ int part;
+ int keepLooping = 1;
+
+ if(y<0) return;
+
+ /* zbuffer fix: here? */
+ Zmulx= ((float) bufferWidth)/2.0;
+ Zmuly= ((float) bufferHeight)/2.0;
+
+
+ /* use these buffer fill functions */
+ zbuffunc = zBufferFillFace;
+ zbuflinefunc = zBufferFillEdge;
+
+ /* (FORALL y: Aminy =< y =< Amaxy: y is buffered) */
+ if( (y < Aminy) || (y > Amaxy)) {
+ /* prepare buffer */
+ part = (y/RE_ZBUFLEN); /* These two lines are mystifying me... */
+ Aminy = part * RE_ZBUFLEN; /* Possibly for rounding things? */
+ Amaxy = Aminy + RE_ZBUFLEN - 1;
+/* if(Amaxy >= R.recty) Amaxy = R.recty-1; */
+ if(Amaxy >= bufferHeight) Amaxy = bufferHeight - 1;
+ resetZbuffer();
+
+ Zsample = 0; /* Zsample is used internally ! */
+ while ( (Zsample < osaNr) && keepLooping ) {
+ /* Apply jitter to this pixel. The jitter offsets are globals. */
+ /* They are added in zbufclip() */
+ /* Negative: these offsets are added to the vertex coordinates */
+ /* so it equals translating viewpoint over the positive vector. */
+ Zjitx= -jit[Zsample][0];
+ Zjity= -jit[Zsample][1];
+
+ keepLooping = fillZBufDistances();
+
+ if(RE_local_test_break()) keepLooping = 0;
+ Zsample++;
+ }
+ };
+
+} /*End of void calcZBufLine(int y) */
+
+/* ------------------------------------------------------------------------- */
+
+int countAndSortPixelFaces(int zrow[RE_MAX_FACES_PER_PIXEL][RE_PIXELFIELDSIZE],
+ RE_APixstrExt *ap)
+{
+#ifdef RE_FULL_SAFETY
+ char fname[] = "countAndSortPixelFaces";
+#endif
+ int totvlak; /* face counter */
+ int i; /* generic counter */
+
+ totvlak= 0;
+ while(ap) {
+ for(i=0; i<4; i++) {
+ if(ap->t[i]) {
+ zrow[totvlak][0] = ap->zmin[i];
+ zrow[totvlak][1] = ap->p[i];
+ zrow[totvlak][2] = ap->mask[i];
+ zrow[totvlak][3] = ap->t[i];
+ zrow[totvlak][4] = ap->zmax[i];
+ totvlak++;
+ if(totvlak > (RE_MAX_FACES_PER_PIXEL - 1))
+ {
+ totvlak = (RE_MAX_FACES_PER_PIXEL - 1);
+#ifdef RE_FULL_SAFETY
+ RE_error(RE_TOO_MANY_FACES, fname);
+#endif
+ }
+ } else break;
+ };
+ ap= ap->next;
+ }
+
+ if(totvlak==2) { /* Sort faces ----------------------------- */
+ if(zrow[0][0] < zrow[1][0]) {
+ i= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= i;
+ i= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= i;
+ i= zrow[0][2]; zrow[0][2]= zrow[1][2]; zrow[1][2]= i;
+ i= zrow[0][3]; zrow[0][3]= zrow[1][3]; zrow[1][3]= i;
+ i= zrow[0][4]; zrow[0][4]= zrow[1][4]; zrow[1][4]= i;
+ } /* else: two faces, and ordering is ok */
+ } else if (totvlak != 1) qsort(zrow, totvlak,
+ sizeof(int)*RE_PIXELFIELDSIZE, vergzvlak);
+ return totvlak;
+} /* end of int countAndSortPixelFaces(int* zrow,RE_APixstrExt *ap ) */
+
+/* ------------------------------------------------------------------------- */
+/* Oversampler v3 - check CVS for older versions */
+/* */
+/* In this version, I have split up the rendering into several parts, so I */
+/* can generate better profiles. */
+/* */
+/* - multiple blend functions ? */
+/* - x-rays? */
+/* - volumetric stuff ? */
+/* - maybe the oversampling should move to the shading part */
+/* */
+/* ------------------------------------------------------------------------- */
+
+/* These variables describe the buffers needed for the oversampling. */
+/* 1. A bit vector with flags to indicate which pixels have received colour. */
+static int VR_covered = 0;
+/* 2. The local vector collector, for resolving conflicts only. */
+static int VR_cbuf[RE_MAX_FACES_PER_PIXEL][2];
+
+/**
+ * Analyze the z-buffer, and pre-sample the colours.
+ */
+int composeStack(int zrow[RE_MAX_FACES_PER_PIXEL][RE_PIXELFIELDSIZE],
+ struct RE_faceField* stack, int ptr,
+ int totvlak, float x, float y, int osaNr) {
+
+#ifdef RE_FULL_SAFETY
+ char* fname = "composeStack";
+#endif
+ float xs = 0.0;
+ float ys = 0.0; /* coordinates for the render-spot */
+
+ float alphathreshold[RE_MAX_OSA_COUNT];
+ int inconflict = 0;
+ int saturationthreshold = 0;
+ int saturated = 0;
+ int i = 0;
+ int Ccount = 0;
+ int Cthresh = 0;
+ int save_totvlak = totvlak;
+ int fullsubpixelflags = 0;
+
+ VR_covered = 0;
+ for(i = 0; i < osaNr; i++) alphathreshold[i] = 0.0;
+ saturationthreshold = ( (1<<osaNr) - 1);
+
+ while ( (!saturated || (saturated && inconflict) ) && (totvlak > 0) ) {
+ totvlak--;
+
+ i= centmask[ zrow[totvlak][RE_MASK] ]; /* recenter sample position - */
+ xs= (float)x+centLut[i & 15];
+ ys= (float)y+centLut[i >> 4];
+
+ /* stack face ----------- */
+ stack[ptr].data = renderPixel(xs, ys, zrow[totvlak]);
+ stack[ptr].faceType = zrow[totvlak][RE_TYPE];
+ cpFloatColV(collector, stack[ptr].colour);
+ stack[ptr].mask = zrow[totvlak][RE_MASK];
+
+ /* This is done so that spothalos are properly overlayed on halos */
+ /* maybe we need to check the colour here... */
+ if(zrow[totvlak][RE_TYPE] & RE_POLY) VR_covered |= zrow[totvlak][RE_MASK];
+
+ /* calculate conflict parameters: ---------------------------------- */
+ if( zrow[totvlak][RE_ZMIN] < Cthresh ) {
+ inconflict = 1;
+ /* Prevent from switching on bad data. This may be done more */
+ /* efficiently later on. It is _quite_ important. */
+ if (totvlak == save_totvlak - 1) Ccount = 0;
+ else if(Ccount == 0) Ccount = 2;
+ else Ccount++;
+ stack[ptr].conflictCount = Ccount;
+ if (zrow[totvlak][RE_ZMAX] > Cthresh)
+ Cthresh = zrow[totvlak][RE_ZMAX];
+#ifdef RE_FULL_SAFETY
+ if (Ccount == 2) conflictsresolved++;
+#endif
+ } else {
+ Cthresh = zrow[totvlak][RE_ZMAX];
+ Ccount = 0;
+ stack[ptr].conflictCount = 0;
+ if (totvlak > 0 )
+ inconflict = (zrow[totvlak-1][RE_ZMIN] < Cthresh);
+ else inconflict = 0;
+ }
+
+ ptr++;
+
+ /* alpha threshold ------------------------------------------------- */
+ /* There are currently two ways of blending: alpha-over, and add. */
+ /* Add-blending does strange things, in the sense that alpha is */
+ /* simply added, and colour is sort of alpha-over blended. Using the */
+ /* same thresholding relation seems to work ok. For less than unity */
+ /* add factor, the alpha threshold may rise faster, but currently we */
+ /* do not check for this factor. */
+ for(i = 0; i < osaNr; i++) {
+ if ( zrow[totvlak][RE_MASK] & (1<<i)) {
+ alphathreshold[i] +=
+ ((1.0 - alphathreshold[i]) * collector[3]);
+ if (alphathreshold[i] > RE_FULL_ALPHA_FLOAT)
+ fullsubpixelflags |= (1<<i);
+ }
+ }
+ saturated = (fullsubpixelflags >= saturationthreshold);
+
+ } /* done stacking ----------------------------------------------------- */
+
+ /*
+ STACK_SKY Sometimes, a sky pixel is needed. Since there are
+ some issues with mist/ ztra/ env, I always put the sky here.
+ */
+/* if (!saturated) { */
+ totvlak--;
+
+ xs= (float)x;
+ ys= (float)y;
+
+ renderSkyPixelFloat(xs, ys);
+
+ stack[ptr].faceType = RE_SKY;
+ cpFloatColV(collector, stack[ptr].colour);
+ stack[ptr].data = NULL;
+ stack[ptr].mask = 0xFFFF;
+ stack[ptr].conflictCount = 0;
+ ptr++;
+/* } */
+
+ /* Index of the top of the stack */
+ return ptr;
+}
+
+/*
+ Start resolving the conflict: the stack is primed to the top-most valid
+ layer on the stack. Call this layer n. Layer n has a conflict count of c.
+ This means layers [ n - c, ..., n ]
+ */
+int resolveConflict(struct RE_faceField* stack, int ptr, float x, float y) {
+#ifdef RE_FULL_SAFETY
+ char* fname = "resolveConflicts";
+#endif
+ int face;
+ int layer;
+ float dx, dy;
+ float xs = 0.0;
+ float ys = 0.0; /* coordinates for the render-spot */
+ int i;
+
+ for(i = 0; i< osaNr; i++) { /* per bin, buffer all faces */
+ dx = jit[i][0];
+ dy = jit[i][1];
+ xs = (float)x + dx;
+ ys = (float)y + dy;
+
+ face = 0; /* only counts covering faces ------------------- */
+ layer = 0; /* counts all faces ----------------------------- */
+
+ while (layer < stack[ptr].conflictCount) {
+ if ( (1<<i) & stack[ptr - layer].mask) {
+ VR_cbuf[face][0] =
+ calcDepth(xs, ys,
+ stack[ptr - layer].data,
+ stack[ptr - layer].faceType);
+ VR_cbuf[face][1] = ptr - layer;
+ face++;
+ }
+ layer++;
+ }
+ qsort(VR_cbuf, face, sizeof(int)*2, vergzvlak);
+ for(layer = 0; layer < face; layer++) {
+ blendOverFloat(stack[VR_cbuf[layer][1]].faceType, /* type */
+ sampcol + (4 * i), /* dest */
+ stack[VR_cbuf[layer][1]].colour, /* src */
+ stack[VR_cbuf[layer][1]].data); /* data */
+ }
+ }
+
+ /* The number of layers that were handled. This is how many layers the */
+ /* top-level algorithm needs to skip. */
+ return stack[ptr].conflictCount;
+}
+
+/* The colour stack is blended down in a pretty straight-forward manner, or */
+/* a part of the stack is re-evaluated to resolve the conflict. */
+/* About 25-30% of rendering time is eaten here! */
+void integrateStack(struct RE_faceField* stack, int ptr,
+ float x,
+ float y,
+ int osaNr) {
+ /* sample the colour stack: back to front ---------------------------- */
+ /* is there a possible way to ignore alpha? this would save 25% work */
+ ptr--;
+ /* Little different now: let ptr point to the topmost valid face.*/
+ while (ptr >= 0) {
+ if (stack[ptr].conflictCount == 0) {
+ /*
+ No conflict: sample one colour into multiple bins
+ */
+ blendOverFloatRow(stack[ptr].faceType,
+ sampcol,
+ stack[ptr].colour,
+ stack[ptr].data,
+ stack[ptr].mask,
+ osaNr);
+ ptr--;
+ } else {
+ /*
+ Recalc all z-values, and integrate per sub-pixel.
+ */
+ ptr -= resolveConflict(stack, ptr, x, y);
+ }
+ }
+
+ /* Done sampling. Now we still need to fill in pixels that were not */
+ /* covered at all It seems strange that we have to check for empty alpha */
+ /* but somehow this is necessary. Check out the cover condition :).... */
+
+ /* It is important that we find a more efficient algorithm here, because */
+ /* this little loop eats _lots_ of cycles. */
+
+ /* Should be integrated in the rest of the rendering... */
+
+ if((R.flag & R_LAMPHALO)
+ /*&&
+ ( VR_covered < ((1 << osaNr) - 1 ) )*/
+ ) {
+ float halocol[4];
+ int i;
+ renderSpotHaloPixel(x, y, halocol);
+ /* test seems to be wrong? */
+ if (halocol[3] > RE_EMPTY_COLOUR_FLOAT) {
+ for (i = 0; i < osaNr; i++) {
+ /* here's a pinch: if the pixel was only covered by a halo, */
+ /* we still need to fill spothalo. How do we detect this? */
+ if (!(VR_covered & (1 << i)))
+ /* maybe a copy is enough here... */
+ addAlphaOverFloat(sampcol + (4 * i), halocol);
+ }
+ }
+ }
+}
+
+/**
+ * New approach: sample substacks. Each substack is first copied into
+ * a stack buffer, and then blended down.
+ * */
+void integratePerSubStack(struct RE_faceField* stack,
+ int ptr,
+ float x,
+ float y,
+ int osaNr) {
+ int i = 0;
+ int j = 0;
+ int k = 0;
+ int l = 0;
+ int filterMask = 0;
+ /* next step would be to improve on the substack, I guess */
+ int subStack[RE_MAX_FACES_PER_PIXEL + 1];
+ float colSubStack[4 * (RE_MAX_FACES_PER_PIXEL + 1)];
+ int subStackPtr = 0;
+ int subStackSize = 0;
+ float xs, ys;
+
+
+ while (i < osaNr) {
+ xs = x + jit[i][0];
+ ys = y + jit[i][1];
+
+ /*
+ * 1. Copy all relevant faces. Mind that stack is built from
+ * low index = low z to high index =high z. The sub-stack is
+ * exactly the other way around! (low index = high z)
+ */
+ filterMask = (1 << i);
+ subStackPtr = 0;
+ j = ptr - 1; /* the topmost valid face */
+ while (j >= 0) {
+ if (stack[j].conflictCount) {
+ /* Conflict: we sort the faces for distance right
+ * away. We could adapt conflict count, and adjust the
+ * stack later on, but that's really doing too much,
+ * too complicated. This is just fine.
+ * */
+ k = 0;
+ l = 0;
+ /* check whether the face intersects, and if so,
+ * stores depth */
+ while (k < stack[j].conflictCount) {
+ if (stack[j - k].mask & filterMask) {
+ VR_cbuf[l][0] = calcDepth(xs, ys,
+ stack[j - k].data,
+ stack[j - k].faceType);
+ VR_cbuf[l][1] = j - k;
+ l++;
+ }
+ k++;
+ }
+ /* VR_cbuf now contains l pairs (distance, stackindex) */
+ qsort(VR_cbuf, l, sizeof(int)*2, vergzvlak);
+ /*
+ * Now we put the sorted indices on the
+ * substack. qsort delivers low index = low z, which
+ * is the right wrong order for the substack */
+ k = 0;
+ while (k < l) {
+ subStack[subStackPtr] = VR_cbuf[k][1];
+ cpFloatColV(stack[VR_cbuf[k][1]].colour, &colSubStack[4*subStackPtr]);
+ subStackPtr++;
+ k++;
+ }
+
+ j -= stack[j].conflictCount;
+ } else {
+ /* no conflict */
+ if (stack[j].mask & filterMask) {
+ subStack[subStackPtr] = j;
+ cpFloatColV(stack[j].colour, &colSubStack[4*subStackPtr]);
+ subStackPtr++;
+ }
+ j--;
+ }
+ }
+ subStackSize = subStackPtr;
+
+ /* 2. Operations on the faces can go here for now. I might
+ * want to mix this code with the blending. Currently, I only
+ * handle env/ztra faces. It's a dirty patch now...*/
+ subStackPtr = subStackSize - 1;
+ while (subStackPtr >= 0) {
+ /* we can make a general meachanism here for operations */
+ if (stack[subStack[subStackPtr]].faceType == RE_POLY){
+ VlakRen* vlr = (VlakRen*) stack[subStack[subStackPtr]].data;
+ if (vlr->mat) {
+ /* ENV faces */
+ if (vlr->mat->mode & MA_ENV) {
+ int m;
+ colSubStack[4*subStackPtr] = 0.0;
+ colSubStack[(4*subStackPtr) + 1] = 0.0;
+ colSubStack[(4*subStackPtr) + 2] = 0.0;
+ colSubStack[(4*subStackPtr) + 3] = 0.0;
+ m = subStackPtr - 1;
+ while (m >= 0) {
+ if (stack[subStack[m]].faceType != RE_SKY) {
+ colSubStack[4*m] = 0.0;
+ colSubStack[(4*m) + 1] = 0.0;
+ colSubStack[(4*m) + 2] = 0.0;
+ colSubStack[(4*m) + 3] = 0.0;
+ }
+ m--;
+ }
+ }
+ /* ZTRA faces */
+ else if (!(vlr->mat->mode & MA_ZTRA)) {
+ int m;
+ m = subStackPtr - 1;
+ while (m >= 0) {
+ if (stack[subStack[m]].faceType != RE_SKY) {
+ colSubStack[4*m] = 0.0;
+ colSubStack[(4*m) + 1] = 0.0;
+ colSubStack[(4*m) + 2] = 0.0;
+ colSubStack[(4*m) + 3] = 0.0;
+ }
+ m--;
+ }
+ }
+ }
+ }
+ subStackPtr--;
+ }
+
+ /* 3. blend down */
+ subStackPtr = 0;
+ while( subStackPtr < subStackSize ) {
+ blendOverFloat(stack[subStack[subStackPtr]].faceType, /* type */
+ sampcol + (4 * i), /* dest */
+ &colSubStack[4 * subStackPtr],
+ stack[subStack[subStackPtr]].data); /* data */
+ subStackPtr++;
+ }
+
+ i++;
+ }
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Rendering: per line */
+/* */
+/* For each pixel in this line, we render as follows: */
+/* a. Count the number of objects buffered for this pixel, and sort on z */
+/* ------- Result is left in zrow */
+/* b. Shade the pixel: */
+/* 1. From front to back: calculate the colour for this object */
+/* 2. Blend this colour in with the already calculated colour */
+/* Repeat 1. and 2. until no faces remain. */
+/* For each pixel, a face is only rendered once, even if it is */
+/* jittered. All subpixels get the colour of the weighted centre */
+/* of the jitter-positions this face covers. */
+/* ------- Result is left in sampcol[] */
+/* c. Copy the result to the colour buffer */
+/* d. Do gamma-corrected blending */
+/* */
+/* zrow may need some clarification: */
+/* 0 - min. distance */
+/* 1 - face/halo index */
+/* 2 - masks */
+/* 3 - type RE_POLY or RE_HALO */
+/* 4 - max. distance */
+/* It is used to store copies of RE_APixstrExt records. These are sorted for */
+/* distance, and then used for rendering pixels. zrow might be replaced by */
+/* an RE_APixstrExt* array */
+/* - redo the numbering to something more logical */
+void renderZBufLine(int y) {
+ int zrow[RE_MAX_FACES_PER_PIXEL][RE_PIXELFIELDSIZE];
+ RE_APixstrExt *ap; /* iterator for the face-lists */
+ int apteller;
+ int x; /* pixel counter */
+ RE_COLBUFTYPE *colbuf; /* pointer into the line buffer */
+ RE_COLBUFTYPE *j = NULL; /* generic pixel pointer */
+ int i; /* yet another counter */
+ int stackDepth; /* faces-behind-this-pixel counter */
+ struct RE_faceField RE_OSAstack[RE_MAX_FACES_PER_PIXEL + 1];
+ int RE_OSAstack_ptr; /* Points to the lowest empty field. The indexed */
+ /* field is NOT readable. */
+
+ /* Prepare buffers and iterators */
+ colbuf = AColourBuffer;
+ eraseColBuf(AColourBuffer);
+ ap = APixbufExt + (zBufferWidth * (y - Aminy));
+ apteller = (zBufferWidth * (y - Aminy));
+
+ /* Rendering: give the right colour to this pixel (shade it) */
+ for( x = 0; x < bufferWidth; x++, ap++, colbuf+=4) {
+ if(ap->t[0]) {
+ /* reset sample collector */
+ j = sampcol;
+ for(i = 0; i < osaNr; i++, j+=4) {
+ j[0] = RE_ZERO_COLOUR_FLOAT; j[1] = RE_ZERO_COLOUR_FLOAT;
+ j[2] = RE_ZERO_COLOUR_FLOAT; j[3] = RE_ZERO_COLOUR_FLOAT;
+ };
+
+ /* a. count and sort number of faces */
+ stackDepth = countAndSortPixelFaces(zrow, ap);
+
+ /* b,c. oversample all subpixels, then integrate */
+ RE_OSAstack_ptr = 0;
+ RE_OSAstack_ptr = composeStack(zrow,
+ RE_OSAstack, RE_OSAstack_ptr,
+ stackDepth, x, y, osaNr);
+/* #ifdef RE_OLD_INTEGRATION */
+/* printf("Performing old integration\n"); */
+/* integrateStack(RE_OSAstack, RE_OSAstack_ptr, */
+/* x, y, osaNr); */
+/* #endif */
+/* #ifndef RE_OLD_INTEGRATION */
+/* printf("Performing new integration\n"); */
+ integratePerSubStack(RE_OSAstack, RE_OSAstack_ptr,
+ x, y, osaNr);
+/* #endif */
+
+ /* d. Gamma corrected blending */
+ sampleFloatColV2FloatColV(sampcol, colbuf, osaNr);
+ } else {
+ /* Remember to do things back-to-front! */
+
+ /* This is a bit dirty. Depending on sky-mode, the pixel is */
+ /* blended in differently. */
+ renderSkyPixelFloat(x, y);
+ cpFloatColV(collector, colbuf);
+
+ /* Spothalos are part of the normal pixelshader, so for covered */
+ /* pixels they are handled ok. They are 'normally' alpha blended */
+ /* onto the existing colour in the collector. */
+ if(R.flag & R_LAMPHALO) {
+ renderSpotHaloPixel(x, y, collector);
+ }
+ addAlphaOverFloat(colbuf, collector);
+ }
+ } /* End of pixel loop */
+
+} /* End of void renderZBufLine(int y) */
+
+
+/* ------------------------------------------------------------------------- */
+
+int fillZBufDistances()
+{
+ int keepLooping = 1;
+
+ keepLooping = zBufferAllFaces(); /* Solid and transparent faces*/
+ keepLooping = zBufferAllHalos() && keepLooping; /* ...and halos*/
+ return keepLooping;
+
+} /* End of void fillZBufDistances() */
+
+/* ------------------------------------------------------------------------- */
+/* Transparent faces and the 'Azvoordeel' */
+/* A transparent face can get a z-offset, which is a */
+/* way of pretending the face is a bit closer than it */
+/* actually is. This is used in animations, when faces */
+/* that are used to glue on animated characters, items, */
+/* et. need their shadows to be drawn on top of the */
+/* objects they stand on. The Azvoordeel is added to */
+/* the calculated z-coordinate in the buffer-fill */
+/* procedures. */
+
+/* static int RE_treat_face_as_opaque; */
+
+int zBufferAllFaces(void)
+{
+ int keepLooping = 1;
+ int faceCounter; /* counter for face number */
+ float vec[3], hoco[4], mul, zval, fval;
+ Material *ma=0;
+
+ faceCounter = 0;
+
+/* printf("Going to buffer faces:\n"); */
+/* printf("\tfirst pass:\n"); */
+
+/* RE_treat_face_as_opaque = 1; */
+
+ while ( (faceCounter < R.totvlak) && keepLooping) {
+ if((faceCounter & 255)==0) { Zvlr= R.blovl[faceCounter>>8]; }
+ else Zvlr++;
+
+ ma= Zvlr->mat;
+
+ /* VERY dangerous construction... zoffs is set by a slide in the ui */
+ /* so it should be safe... */
+ if((ma->mode & (MA_ZTRA)) && (ma->zoffs != 0.0)) {
+ mul= 0x7FFFFFFF;
+ zval= mul*(1.0+Zvlr->v1->ho[2]/Zvlr->v1->ho[3]);
+
+ VECCOPY(vec, Zvlr->v1->co);
+ /* z is negatief, wordt anders geclipt */
+ vec[2]-= ma->zoffs;
+ RE_projectverto(vec, hoco); /* vec onto hoco */
+ fval= mul*(1.0+hoco[2]/hoco[3]);
+
+ Azvoordeel= (int) fabs(zval - fval );
+ } else {
+ Azvoordeel= 0;
+ }
+ /* face number is used in the fill functions */
+ Zvlnr = faceCounter + 1;
+
+ if(Zvlr->flag & R_VISIBLE) { /* might test for this sooner... */
+
+ if(ma->mode & (MA_WIRE)) zbufclipwire(Zvlr);
+ else {
+ zbufclip(Zvlr->v1->ho, Zvlr->v2->ho, Zvlr->v3->ho,
+ Zvlr->v1->clip, Zvlr->v2->clip, Zvlr->v3->clip);
+ if(Zvlr->v4) {
+ Zvlnr+= 0x800000; /* in a sense, the 'adjoint' face */
+ zbufclip(Zvlr->v1->ho, Zvlr->v3->ho, Zvlr->v4->ho,
+ Zvlr->v1->clip, Zvlr->v3->clip, Zvlr->v4->clip);
+ }
+ }
+ }
+ if(RE_local_test_break()) keepLooping = 0;
+ faceCounter++;
+ }
+
+ return keepLooping;
+} /* End of int zBufferAllFaces(void) */
+
+/* ------------------------------------------------------------------------- */
+/* We cheat a little here: we only fill the halo on the first pass, and we */
+/* set a full complement of mask flags. This can be done because we consider */
+/* halos to be flat (billboards), so we do not have to correct the z range */
+/* every time we insert a halo. Also, halos fall off to zero at the edges, */
+/* so we can safely render them in pixels where they do not exist. */
+int zBufferAllHalos(void)
+{
+ HaloRen *har = NULL;
+ unsigned int haloCounter = 0;
+ int dist = 0;
+ int keepLooping = 1;
+ short miny = 0, maxy = 0, minx = 0, maxx = 0;
+ short ycount = 0, xcount = 0;
+ RE_APixstrExt *ap, *apoffset;
+ int mask; /* jitter mask */
+
+ if (!Zsample)
+ {
+ mask = (1 << osaNr) - 1 ; /* Fill all samples together */
+
+ while ( (haloCounter < R.tothalo) && keepLooping) {
+ if((haloCounter & 255)==0) har= R.bloha[haloCounter>>8];
+ else har++;
+
+ /* Halos are sometimes wrongly kicked out of the box they belong */
+ /* in... */
+
+ /* Only buffer the current alpha buffer contents!!! The line */
+ /* indices have already been clipped to picture size. */
+ minx = floor(har->xs - har->rad) - 1; /* assume min =< max is true*/
+ if (minx < 0 ) minx = 0;
+ maxx = ceil(har->xs + har->rad ) + 1;
+ /* Do the extra -1 because of the +1 later on. I guess halos might */
+ /* have to start one pixel sooner? Or maybe the lower clip should */
+ /* be adjusted */
+ if (maxx >= zBufferWidth - 1) maxx = zBufferWidth - 2;
+
+ miny = har->miny;
+ if (miny < Aminy) miny = Aminy;
+ maxy = har->maxy;
+ if (maxy > Amaxy) maxy = Amaxy;
+
+ if ( (minx <= maxx) && (miny <= maxy)) {
+ /* distance to this halo? */
+ dist = har->zBufDist /* * R.ycor */;
+ /* strange that the ycor influences the z coordinate ..*/
+ ycount = miny;
+ while (ycount <= maxy) {
+ apoffset = APixbufExt + (zBufferWidth * (ycount - Aminy));
+ ap = apoffset + minx;
+ xcount = minx;
+ while (xcount <= maxx) {
+ insertFlatObjectNoOsa(ap, haloCounter, RE_HALO, dist, mask);
+ xcount++;
+ ap++;
+ }
+ ycount++;
+ }
+ }
+ if(RE_local_test_break()) keepLooping = 0;
+ haloCounter++;
+ }
+ }
+
+ return keepLooping;
+} /* end of int zbufferAllHalos(void) */
+
+/* ------------------------------------------------------------------------- */
+void zBufferFillHalo(void)
+{
+ /* so far, intentionally empty */
+} /* end of void zBufferFillHalo(void) */
+
+/* ------------------------------------------------------------------------- */
+void zBufferFillFace(float *v1, float *v2, float *v3)
+{
+ /* Coordinates of the vertices are specified in ZCS */
+ int apteller, apoffsetteller;
+ double z0; /* used as temp var*/
+ double xx1;
+ double zxd,zyd,zy0, tmp;
+ float *minv,*maxv,*midv;
+ register int zverg,zvlak,x;
+ int my0,my2,sn1,sn2,rectx,zd;
+ int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2, mask;
+
+ /* These used to be doubles. We may want to change them back if the */
+ /* loss of accuracy proves to be a problem? There does not seem to be */
+ /* any performance issues here, so I'll just keep the doubles. */
+ /* float vec0[3], vec1[3], vec2[3]; */
+ double vec0[3], vec1[3], vec2[3];
+
+ /* MIN MAX */
+ /* sort vertices for min mid max y value */
+ if(v1[1]<v2[1]) {
+ if(v2[1]<v3[1]) { minv=v1; midv=v2; maxv=v3;}
+ else if(v1[1]<v3[1]) { minv=v1; midv=v3; maxv=v2;}
+ else { minv=v3; midv=v1; maxv=v2;}
+ }
+ else {
+ if(v1[1]<v3[1]) { minv=v2; midv=v1; maxv=v3;}
+ else if(v2[1]<v3[1]) { minv=v2; midv=v3; maxv=v1;}
+ else { minv=v3; midv=v2; maxv=v1;}
+ }
+
+ if(minv[1] == maxv[1]) return; /* beveiliging 'nul' grote vlakken */
+
+ my0 = ceil(minv[1]);
+ my2 = floor(maxv[1]);
+ omsl = floor(midv[1]);
+
+ /* outside the current z buffer slice: clip whole face */
+ if( (my2 < Aminy) || (my0 > Amaxy)) return;
+
+ if(my0<Aminy) my0= Aminy;
+
+ /* EDGES : DE LANGSTE */
+ xx1= maxv[1]-minv[1];
+ if(xx1>2.0/65536.0) {
+ z0= (maxv[0]-minv[0])/xx1;
+
+ tmp= (-65536.0*z0);
+ dx0= CLAMPIS(tmp, INT_MIN, INT_MAX);
+
+ tmp= 65536.0*(z0*(my2-minv[1])+minv[0]);
+ xs0= CLAMPIS(tmp, INT_MIN, INT_MAX);
+ }
+ else {
+ dx0= 0;
+ xs0= 65536.0*(MIN2(minv[0],maxv[0]));
+ }
+ /* EDGES : DE BOVENSTE */
+ xx1= maxv[1]-midv[1];
+ if(xx1>2.0/65536.0) {
+ z0= (maxv[0]-midv[0])/xx1;
+
+ tmp= (-65536.0*z0);
+ dx1= CLAMPIS(tmp, INT_MIN, INT_MAX);
+
+ tmp= 65536.0*(z0*(my2-midv[1])+midv[0]);
+ xs1= CLAMPIS(tmp, INT_MIN, INT_MAX);
+ }
+ else {
+ dx1= 0;
+ xs1= 65536.0*(MIN2(midv[0],maxv[0]));
+ }
+ /* EDGES : DE ONDERSTE */
+ xx1= midv[1]-minv[1];
+ if(xx1>2.0/65536.0) {
+ z0= (midv[0]-minv[0])/xx1;
+
+ tmp= (-65536.0*z0);
+ dx2= CLAMPIS(tmp, INT_MIN, INT_MAX);
+
+ tmp= 65536.0*(z0*(omsl-minv[1])+minv[0]);
+ xs2= CLAMPIS(tmp, INT_MIN, INT_MAX);
+ }
+ else {
+ dx2= 0;
+ xs2= 65536.0*(MIN2(minv[0],midv[0]));
+ }
+
+ /* ZBUF DX DY */
+ /* xyz_1 = v_1 - v_2 */
+ MTC_diff3DFF(vec1, v1, v2);
+ /* xyz_2 = v_2 - v_3 */
+ MTC_diff3DFF(vec2, v2, v3);
+ /* xyz_0 = xyz_1 cross xyz_2 */
+ MTC_cross3Double(vec0, vec1, vec2);
+
+ /* cross product of two of the sides is 0 => this face is too small */
+ if(vec0[2]==0.0) return;
+
+ if(midv[1] == maxv[1]) omsl= my2;
+ if(omsl < Aminy) omsl= Aminy-1; /* dan neemt ie de eerste lus helemaal */
+
+ while (my2 > Amaxy) { /* my2 kan groter zijn */
+ xs0+=dx0;
+ if (my2<=omsl) {
+ xs2+= dx2;
+ }
+ else{
+ xs1+= dx1;
+ }
+ my2--;
+ }
+
+ xx1= (vec0[0]*v1[0]+vec0[1]*v1[1])/vec0[2]+v1[2];
+
+ zxd= -vec0[0]/vec0[2];
+ zyd= -vec0[1]/vec0[2];
+ zy0= my2*zyd+xx1;
+ zd= (int)CLAMPIS(zxd, INT_MIN, INT_MAX);
+
+ /* start-ofset in rect */
+ /* rectx= R.rectx; */
+ /* I suspect this var needs very careful setting... When edge rendering */
+ /* is on, this is strange */
+ rectx = zBufferWidth;
+ apoffsetteller = rectx*(my2-Aminy);
+
+ mask= 1<<Zsample;
+ zvlak= Zvlnr;
+
+ xs3= 0; /* flag */
+ if(dx0>dx1) {
+ MTC_swapInt(&xs0, &xs1);
+ MTC_swapInt(&dx0, &dx1);
+ xs3= 1; /* flag */
+
+ }
+
+ for(y=my2;y>omsl;y--) {
+
+ sn1= xs0>>16;
+ xs0+= dx0;
+
+ sn2= xs1>>16;
+ xs1+= dx1;
+
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+ zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX);
+ apteller = apoffsetteller + sn1;
+ x= sn2-sn1;
+
+ zverg-= Azvoordeel;
+
+ while(x>=0) {
+ insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, zverg, mask);
+ zverg+= zd;
+ apteller++;
+ x--;
+ }
+ zy0-= zyd;
+ apoffsetteller -= rectx;
+ }
+
+ if(xs3) {
+ xs0= xs1;
+ dx0= dx1;
+ }
+ if(xs0>xs2) {
+ xs3= xs0;
+ xs0= xs2;
+ xs2= xs3;
+ xs3= dx0;
+ dx0= dx2;
+ dx2= xs3;
+ }
+
+ for(; y>=my0; y--) {
+
+ sn1= xs0>>16;
+ xs0+= dx0;
+
+ sn2= xs2>>16;
+ xs2+= dx2;
+
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+ zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX);
+ apteller = apoffsetteller + sn1;
+ x= sn2-sn1;
+
+ zverg-= Azvoordeel;
+
+ while(x>=0) {
+ insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, zverg, mask);
+ zverg+= zd;
+ apteller++;
+ x--;
+ }
+
+ zy0-=zyd;
+ apoffsetteller -= rectx;
+ }
+} /* end of void zBufferFillFace(float *v1, float *v2, float *v3) */
+
+/* ------------------------------------------------------------------------- */
+
+void zBufferFillEdge(float *vec1, float *vec2)
+{
+ int apteller;
+ int start, end, x, y, oldx, oldy, ofs;
+ int dz, vergz, mask;
+ float dx, dy;
+ float v1[3], v2[3];
+
+ dx= vec2[0]-vec1[0];
+ dy= vec2[1]-vec1[1];
+
+ if(fabs(dx) > fabs(dy)) {
+
+ /* alle lijnen van links naar rechts */
+ if(vec1[0]<vec2[0]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[0]);
+ end= start+floor(dx);
+ if(end >= zBufferWidth) end = zBufferWidth - 1;
+
+ oldy= floor(v1[1]);
+ dy/= dx;
+
+ vergz= v1[2];
+ vergz-= Azvoordeel;
+ dz= (v2[2]-v1[2])/dx;
+
+ apteller = zBufferWidth*(oldy-Aminy) +start;
+ mask = 1<<Zsample;
+
+ if(dy<0) ofs= -zBufferWidth;
+ else ofs= zBufferWidth;
+
+ for(x= start; x<=end; x++, /* ap++, */ apteller++) {
+
+ y= floor(v1[1]);
+ if(y!=oldy) {
+ oldy= y;
+ apteller += ofs;
+ }
+
+ if(x>=0 && y>=Aminy && y<=Amaxy) {
+ insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, vergz, mask);
+ }
+
+ v1[1]+= dy;
+ vergz+= dz;
+ }
+ }
+ else {
+
+ /* alle lijnen van onder naar boven */
+ if(vec1[1]<vec2[1]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[1]);
+ end= start+floor(dy);
+
+ if(start>Amaxy || end<Aminy) return;
+
+ if(end>Amaxy) end= Amaxy;
+
+ oldx= floor(v1[0]);
+ dx/= dy;
+
+ vergz= v1[2];
+ vergz-= Azvoordeel;
+ dz= (v2[2]-v1[2])/dy;
+
+ apteller = zBufferWidth*(start-Aminy) +oldx;
+
+ mask= 1<<Zsample;
+
+ if(dx<0) ofs= -1;
+ else ofs= 1;
+
+ for(y= start; y<=end; y++, apteller += zBufferWidth) {
+
+ x= floor(v1[0]);
+ if(x!=oldx) {
+ oldx= x;
+ apteller += ofs;
+ }
+
+ if(x>=0 && y>=Aminy && (x < zBufferWidth)) {
+ insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, vergz, mask);
+ }
+
+ v1[0]+= dx;
+ vergz+= dz;
+ }
+ }
+} /* End of void zBufferFillEdge(float *vec1, float *vec2) */
+
+
+/* ------------------------------------------------------------------------- */
+/* Colour buffer related: */
+/* This transforms the 4 inputvalues RE_COLBUFTYPE to a new value */
+/* It expects the values R.r.postigamma, R.r.postmul and R.r.postadd. */
+/* This is the standard transformation, more elaborate tools are for later. */
+/* ------------------------------------------------------------------------- */
+void std_transFloatColV2CharColV( RE_COLBUFTYPE *buf, char *target)
+{
+ float fval;
+
+ /* alpha */
+ if(buf[3]<=0.0) target[3]= 0;
+ else if(buf[3]>1.0) target[3]= 255;
+ else target[3]= 255.0*buf[3];
+
+ if(R.r.postgamma==1.0) {
+ /* r */
+ fval= R.r.postmul*buf[0] + R.r.postadd;
+ if(fval<=0.0) target[0]= 0;
+ else if(fval>1.0) target[0]= 255;
+ else target[0]= 255.0*fval;
+
+ /* g */
+ fval= R.r.postmul*buf[1] + R.r.postadd;
+ if(fval<=0.0) target[1]= 0;
+ else if(fval>1.0) target[1]= 255;
+ else target[1]= 255.0*fval;
+
+ /* b */
+ fval= R.r.postmul*buf[2] + R.r.postadd;
+ if(fval<=0.0) target[2]= 0;
+ else if(fval>1.0) target[2]= 255;
+ else target[2]= 255.0*fval;
+
+ }
+ else {
+ /* putting the postmul within the pow() gives an
+ * easier control for the user, values from 1.0-2.0
+ * are relevant then
+ */
+
+
+ /* r */
+ fval= pow(R.r.postmul*buf[0], R.r.postigamma) + R.r.postadd;
+ if(fval<=0.0) target[0]= 0;
+ else if(fval>1.0) target[0]= 255;
+ else target[0]= 255.0*fval;
+
+ /* g */
+ fval=pow( R.r.postmul*buf[1], R.r.postigamma) + R.r.postadd;
+ if(fval<=0.0) target[1]= 0;
+ else if(fval>1.0) target[1]= 255;
+ else target[1]= 255.0*fval;
+
+ /* b */
+ fval= pow(R.r.postmul*buf[2], R.r.postigamma) + R.r.postadd;
+ if(fval<=0.0) target[2]= 0;
+ else if(fval>1.0) target[2]= 255;
+ else target[2]= 255.0*fval;
+ }
+
+} /* end of void std_transFloatColV2CharColV( RE_COLBUFTYPE *buf, uchar *target) */
+
+
+/* ----------------------------------------------------------------------------
+
+ Colour buffer related:
+
+ The colour buffer is a buffer of a single screen line. It contains
+ four fields of type RE_COLBUFTYPE per pixel.
+
+ We can do several post-process steps. I would prefer to move them outside
+ the render module later on, but it's ok to leave it here for now. For the
+ time being, we have:
+ - post-process function
+ Does some operations with the colours.
+ - Multiply with some factor
+ - Add constant offset
+ - Apply extra gamma correction (seems weird...)
+ - key-alpha correction
+ Key alpha means 'un-applying' the alpha. For fully covered pixels, this
+ operation has no effect.
+
+---------------------------------------------------------------------------- */
+void transferColourBufferToOutput(int y)
+{
+ /* Copy the contents of AColourBuffer to R.rectot + y * R.rectx */
+ int x = 0;
+ RE_COLBUFTYPE *buf = AColourBuffer;
+ char *target = (char*) (R.rectot + (y * imageWidth));
+
+#ifdef RE_FULL_SAFETY
+ /* since the R.rectot always has size imageWidth * imageHeight, this */
+ /* check is possible. I may want to check this per assignment later on. */
+ if ( (y < 0) || ((y > (imageHeight - 1) ))) {
+ char fname[] = "transferColourBufferToOutput";
+ RE_error_int(RE_WRITE_OUTSIDE_COLOUR_BUFFER, fname, y);
+ return;
+ }
+#endif
+
+ /* Copy the first <imageWidth> pixels. We can do some more clipping on */
+ /* the z buffer, I think. */
+ while (x < imageWidth) {
+
+ std_transFloatColV2CharColV(buf, target);
+
+ /* old function was: leave it for test */
+/* cpFloatColV2CharColV(buf, target); */
+
+ /*
+ Key-alpha mode:
+ Need to un-apply alpha if alpha is non-full. For full alpha,
+ the operation doesn't have effect. Do this after the post-
+ processing, so we can still use the benefits of that.
+
+ */
+
+ if (getSkyBlendingMode() == RE_ALPHA_KEY) {
+ applyKeyAlphaCharCol(target);
+ }
+
+ target+=4;
+ buf+=4;
+ x++;
+ }
+} /* end of void transferColourBufferToOutput(int y) */
+
+/* ------------------------------------------------------------------------- */
+
+void eraseColBuf(RE_COLBUFTYPE *buf) {
+ /* By definition, the buffer's length is 4 * R.rectx items */
+ int i = 0;
+/* while (i < 4 * R.rectx) { */
+ while (i < 4 * bufferWidth) {
+ *buf = RE_ZERO_COLOUR_FLOAT;
+ buf++; i++;
+ }
+} /* End of void eraseColBuf(RE_COLBUFTYPE *buf) */
+
+/* ------------------------------------------------------------------------- */
+
+int calcDepth(float x, float y, void* data, int type)
+{
+#ifdef RE_FULL_SAFETY
+ char fname[] = "calcDepth";
+ if (data == NULL) {
+ RE_error(RE_BAD_DATA_POINTER, fname);
+ return 0;
+ }
+#endif
+
+ if (type & RE_POLY) {
+ VlakRen* vlr = (VlakRen*) data;
+ VertRen* v1;
+ float dvlak, deler, fac, hoco_z, hoco_w;
+ int zbuf_co;
+
+ v1 = vlr->v1;
+
+ /* vertex dot face normal: WCS */
+ dvlak= v1->co[0]*vlr->n[0]+v1->co[1]*vlr->n[1]+v1->co[2]*vlr->n[2];
+
+ /* jitter has been added to x, y ! */
+ /* view vector R.view: screen coords */
+ if( (G.special1 & G_HOLO) &&
+ ((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) {
+ R.view[0]= (x+(R.xstart) + 0.5 +holoofs);
+ } else R.view[0]= (x+(R.xstart) + 0.5 );
+
+ if(R.flag & R_SEC_FIELD) {
+ if(R.r.mode & R_ODDFIELD) R.view[1]= (y + R.ystart)*R.ycor;
+ else R.view[1]= (y+R.ystart + 1.0)*R.ycor;
+ } else R.view[1]= (y+R.ystart + 0.5 )*R.ycor;
+
+
+ /* for pano, another rotation in the xz plane is needed.... */
+
+ /* this is ok, in WCS */
+ R.view[2]= -R.viewfac; /* distance to viewplane */
+
+ /* face normal dot view vector: but how can this work? */
+ deler = MTC_dot3Float(vlr->n, R.view);
+ if (deler!=0.0) fac = dvlak/deler;
+ else fac = 0.0;
+
+ /* indices are wrong.... but gives almost the right value? */
+ hoco_z = (fac*R.view[2]) * R.winmat[2][2] + R.winmat[3][2];
+ hoco_w = (fac*R.view[2]) * R.winmat[2][3] + R.winmat[3][3];
+
+ zbuf_co = 0x7FFFFFFF*(hoco_z/hoco_w);
+
+ return zbuf_co; /* z component of R.co */
+ } else if (type & RE_HALO) {
+ HaloRen* har = (HaloRen*) data;
+ return har->zBufDist;
+ }
+#ifdef RE_FULL_SAFETY
+ else RE_error(RE_BAD_FACE_TYPE, fname);
+#endif /* RE_FULL_SAFETY */
+ return 0;
+} /* end of int calcDepth(float x, float y, void* data, int type) */
+
+/* Maybe these two should be in pixelblendeing.c---------------------------- */
+
+void blendOverFloat(int type, float* dest, float* source, void* data)
+{
+#ifdef RE_FULL_SAFETY
+ char fname[] = "blendOverFloat";
+ if (data == NULL){
+ RE_error(RE_BAD_DATA_POINTER, fname);
+ return;
+ }
+#endif
+
+ if (type & RE_POLY) {
+ VlakRen *ver = (VlakRen*) data;
+ if ((ver->mat != NULL) && (ver->mat->add > RE_FACE_ADD_THRESHOLD)) {
+ char addf = (char) (ver->mat->add * 255.0);
+ addalphaAddfacFloat(dest, source, addf);
+ }
+ else
+ addAlphaOverFloat(dest, source);
+ } else if (type & RE_HALO) {
+ HaloRen *har= (HaloRen*) data;
+ addalphaAddfacFloat(dest, source, har->add);
+ } else if (type & RE_SKY) {
+ addAlphaOverFloat(dest, source);
+ }
+#ifdef RE_FULL_SAFETY
+ else RE_error(RE_BAD_FACE_TYPE, fname);
+#endif
+
+} /* end of void blendOverFloat(int , float*, float*, void*) */
+
+/* ------------------------------------------------------------------------- */
+void blendOverFloatRow(int type, float* dest, float* source,
+ void* data, int mask, int osaNr)
+{
+#ifdef RE_FULL_SAFETY
+ char* fname = "blendOverFloatRow";
+ if ((data == NULL) && ((type & RE_POLY) || (type & RE_HALO))) {
+ RE_error(RE_BAD_DATA_POINTER, fname);
+ return;
+ }
+#endif
+
+ if (type & RE_POLY) {
+ VlakRen *ver = (VlakRen*) data;
+ if ((ver->mat != NULL)
+ && (ver->mat->add > RE_FACE_ADD_THRESHOLD)) {
+ char addf = (ver->mat->add * 255.0);
+ addAddSampColF(dest, source, mask, osaNr, addf);
+ } else {
+ addOverSampColF(dest, source, mask, osaNr);
+ }
+ } else if (type & RE_HALO) {
+ HaloRen *har = (HaloRen*) data;
+ addAddSampColF(dest, source, mask, osaNr, har->add);
+ } else if (type & RE_SKY) {
+ addOverSampColF(dest, source, mask, osaNr);
+ }
+#ifdef RE_FULL_SAFETY
+ else RE_error(RE_BAD_FACE_TYPE, fname);
+#endif
+} /* end of void blendOverFloatRow(int, float*, float*, void*) */
+
+/* ------------------------------------------------------------------------- */
+
+/* eof vanillaRenderPipe.c */