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/edgeRender.c')
-rw-r--r--source/blender/render/intern/source/edgeRender.c952
1 files changed, 952 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/edgeRender.c b/source/blender/render/intern/source/edgeRender.c
new file mode 100644
index 00000000000..d3c944efac7
--- /dev/null
+++ b/source/blender/render/intern/source/edgeRender.c
@@ -0,0 +1,952 @@
+/**
+ * $Id$
+ *
+ * ***** 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 *****
+ * Add enhanced edges on a rendered image (toon shading, edge shading).
+ */
+
+/*
+ * Edge rendering: use a mask to weigh the depth of neighbouring
+ * pixels, and do a colour correction.
+ *
+ * We need:
+ * - a buffer to store the depths (ints)
+ * - a function that alters the colours in R.rectot (copy edge_enhance?)
+ * The max. z buffer depth is 0x7FFF.FFFF (7 F's)
+ *
+ * - We 'ignore' the pixels falling outside the regular buffer (we fill)
+ * these with the max depth. This causes artefacts when rendering in
+ * parts.
+ */
+
+/* ------------------------------------------------------------------------- */
+
+/* enable extra bounds checking and tracing */
+/* #define RE_EDGERENDERSAFE */
+/* disable the actual edge correction */
+/* #define RE_EDGERENDER_NO_CORRECTION */
+
+#include <stdlib.h>
+#include <math.h>
+#include <limits.h> /* INT_MIN,MAX are used here */
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+#include "MTC_vectorops.h"
+
+#include "RE_callbacks.h"
+#include "edgeRender.h"
+#include "render.h"
+#include "render_intern.h"
+#include "zbuf.h" /* for zbufclipwire and zbufclip */
+#include "jitter.h"
+
+#ifdef RE_EDGERENDERSAFE
+char edgeRender_h[] = EDGERENDER_H;
+char edgeRender_c[] = "$Id$";
+#include "errorHandler.h"
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* the lazy way: */
+#define MIN2(x,y) ( (x)<(y) ? (x) : (y) )
+
+/* ------------------------------------------------------------------------- */
+
+ /* These function pointers are used for z buffer filling. */
+extern void (*zbuffunc)(float *, float *, float *);
+extern void (*zbuflinefunc)(float *v1, float *v2);
+extern float Zmulx, Zmuly; /* Some kind of scale? */
+extern float Zjitx,Zjity; /* The x,y values for jitter offset */
+extern unsigned int Zvlnr; /* Face rendering pointer and counter: these */
+extern VlakRen *Zvlr; /* are used for 'caching' render results. */
+
+/* ------------------------------------------------------------------------- */
+
+/* exp: */
+static Material** matBuffer; /* buffer with material indices */
+static Material* mat_cache; /* material of the face being buffered */
+
+static char* colBuffer; /* buffer with colour correction */
+static int *edgeBuffer; /* buffer with distances */
+static int bufWidth; /* x-dimension of the buffer */
+static int bufHeight; /* y-dimension of the buffer */
+static int imWidth; /* x-dimension of the image */
+static int imHeight; /* y-dimension of the image */
+static int osaCount; /* oversample count */
+static int maskBorder; /* size of the mask border */
+static short int intensity; /* edge intensity */
+static short int same_mat_redux; /* intensity reduction for boundaries with the same material */
+static int compatible_mode; /* edge positioning compatible with old rederer */
+static int selectmode; /* 0: only solid faces, 1: also transparent f's */
+
+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 */
+static char edgeR; /* Colour for the edges. The edges will receive */
+static char edgeG; /* this tint. The colour is fully used! */
+static char edgeB;
+/* static float edgeBlend; */ /* Indicate opaqueness of the edge colour. */
+
+/* Local functions --------------------------------------------------------- */
+/**
+ * Initialise the edge render buffer memory.
+ */
+void initEdgeRenderBuffer(void);
+/**
+ * Release buffer memory.
+ */
+void freeEdgeRenderBuffer(void);
+
+/**
+ * Set all distances in the distance buffer to the maximum distance.
+ */
+void resetDistanceBuffer(void);
+
+/**
+ * Insert this distance at these pixel coordinates.
+ */
+void insertInEdgeBuffer(int x, int y, int dist);
+
+/**
+ * Renders enhanced edges. Distances from distRect are used to
+ * determine a correction on colourRect
+ */
+void renderEdges(char * colourRect);
+
+/**
+ * Buffer an edge between these two vertices in the e.r. distance buffer.
+ */
+void fillEdgeRenderEdge(float *vec1, float *vec2);
+
+/**
+ * Buffer a face between these two vertices in the e.r. distance buffer.
+ */
+void fillEdgeRenderFace(float *v1, float *v2, float *v3);
+
+/**
+ * Compose the edge render colour buffer.
+ */
+void calcEdgeRenderColBuf(char * tarbuf);
+
+/**
+ * Loop over all objects that need to be edge rendered. This loop determines
+ * which objects get to be elected for edge rendering.
+ */
+int zBufferEdgeRenderObjects(void);
+
+/**
+ * Add edge pixels to the original image. It blends <bron> over <doel>.
+ */
+void addEdgeOver(char *doel, char *bron);
+
+/* ------------------------------------------------------------------------- */
+
+void addEdges(
+ char * targetbuf,
+ int iw, int ih,
+ int osanr,
+ short int intens, short int intens_redux,
+ int compat, int mode,
+ float r, float g, float b
+ )
+{
+ float rf, gf ,bf;
+ /* render parameters */
+ selectmode = mode;
+ imWidth = iw;
+ imHeight = ih;
+ compatible_mode = compat;
+ osaCount = osanr;
+ intensity = intens;
+ /* Reduction doesn't exceed intensity. */
+ same_mat_redux = ((intens_redux < intensity)? intens_redux : intensity);
+
+ rf = r * 255.0;
+ if (rf > 255) edgeR = 255; else edgeR = rf;
+ gf = g * 255.0;
+ if (gf > 255) edgeG = 255; else edgeG = gf;
+ bf = b * 255.0;
+ if (bf > 255) edgeB = 255; else edgeB = bf;
+
+ /* Go! */
+ initEdgeRenderBuffer();
+ calcEdgeRenderColBuf(targetbuf);
+ freeEdgeRenderBuffer();
+
+} /* end of void addEdges(char *, int, int, int, short int , int) */
+
+/* ------------------------------------------------------------------------- */
+
+void initEdgeRenderBuffer()
+{
+ char *ptr;
+ int i;
+
+ maskBorder = 1; /* for 3 by 3 mask*/
+
+ bufWidth = imWidth + (2 * maskBorder);
+ bufHeight = imHeight + (2 * maskBorder);
+
+ /* Experimental: store the material indices. */
+ if (same_mat_redux) {
+ matBuffer = MEM_callocN(sizeof(Material*)
+ * bufWidth * bufHeight, "matBuffer");
+ }
+
+ edgeBuffer = MEM_callocN(sizeof(int) * bufWidth * bufHeight, "edgeBuffer");
+ colBuffer = MEM_callocN(sizeof(char) * 4 * imWidth * imHeight, "colBuffer");
+
+
+ if ((edgeR != 0) || (edgeG != 0) || (edgeB != 0)) {
+ /* Set all colbuf pixels to the edge colour. Leave alpha channel */
+ /* cleared. Actually, we could blend in any image here... */
+ ptr = colBuffer;
+ for (i = 0; i < imWidth * imHeight; i++, ptr+=4)
+ {
+ ptr[0] = edgeR;
+ ptr[1] = edgeG;
+ ptr[2] = edgeB;
+ ptr[3] = 0;
+ }
+ }
+
+#ifdef RE_EDGERENDERSAFE
+ if (!edgeBuffer || !colBuffer) {
+ char *fname = "initEdgeRenderBuffer";
+ RE_error(RE_CANNOT_ALLOCATE_MEMORY, fname);
+ }
+#endif
+} /* end of void initEdgeRenderBuffer(void) */
+
+/* ------------------------------------------------------------------------- */
+void freeEdgeRenderBuffer(void)
+{
+ if(edgeBuffer) MEM_freeN(edgeBuffer);
+ if(colBuffer) MEM_freeN(colBuffer);
+ if(matBuffer) MEM_freeN(matBuffer);
+} /* end of void freeEdgeRenderBuffer(void) */
+
+/* ------------------------------------------------------------------------- */
+
+void resetDistanceBuffer(void)
+{
+ int i;
+ for(i = 0; i < bufWidth * bufHeight; i++) edgeBuffer[i] = 0x7FFFFFFF;
+} /* end of void resetDistanceBuffer(void) */
+
+/* ------------------------------------------------------------------------- */
+
+void insertInEdgeBuffer(int x, int y, int dist)
+{
+ int index;
+#ifdef RE_EDGERENDERSAFE
+ char *fname = "insertInEdgeBuffer";
+ if ((x < 0) || (x > imWidth ) ||
+ (y < 0) || (y > (imHeight-1) ) ) {
+ RE_error(RE_EDGERENDER_WRITE_OUTSIDE_BUFFER, fname);
+ return;
+ }
+#endif
+
+ /* +1? */
+ index = (y * bufWidth) + x + maskBorder;
+
+ /*exp: just dump a single index here. Maybe we can do more
+ * sophisticated things later on. */
+ if (same_mat_redux) {
+ matBuffer[index] = mat_cache;
+ }
+
+ if (edgeBuffer[index] >dist ) edgeBuffer[index] = dist;
+
+} /* end of void insertInEdgeBuffer(int x, int y, int dist) */
+
+/* ------------------------------------------------------------------------- */
+/* Modelled after rendercore.c/edge_enhance() */
+void renderEdges(char *colourRect)
+{
+ /* use zbuffer to define edges, add it to the image */
+ int val, y, x, col, *rz, *rz1, *rz2, *rz3;
+ char *cp;
+ int targetoffset, heightoffset;
+ int i;
+ int matdif; /* For now: just a bogus int, 0 when all materials
+ * under the mask are the same, non-0 otherwise*/
+ int *matptr_low = 0, *matptr_cent = 0, *matptr_high = 0;
+ int matdiffac = 0;
+
+#ifdef RE_EDGERENDER_NO_CORRECTION
+ return; /* no edge correction */
+#endif
+
+#ifdef RE_EDGERENDERSAFE
+ fprintf(stderr, "\n*** Activated full error trace on "
+ "edge rendering using:\n\t%s\n\t%s"
+ "\n*** Rendering edges at %d intensity",
+ edgeRender_c, edgeRender_h, intensity);
+#endif
+
+
+ /* Old renderer uses wrong positions! With the compat switch on, the po- */
+ /* sitions will be corrected to be offset in the same way. */
+ if (compatible_mode) {
+ targetoffset = 4 * (imWidth - 1);
+ heightoffset = -1;
+ } else {
+ targetoffset = 0;
+ heightoffset = 0;
+ }
+
+ /* Fill edges with some default values. We just copy what is in the edge */
+ /* This looks messy, but it appears to be ok. */
+ edgeBuffer[0] = edgeBuffer[bufWidth + 1];
+ edgeBuffer[bufWidth - 1] = edgeBuffer[(2 * bufWidth) - 2];
+ edgeBuffer[bufWidth * (bufHeight - 1)] =
+ edgeBuffer[bufWidth * (bufHeight - 2) + 1];
+ edgeBuffer[(bufWidth * bufHeight) - 1] =
+ edgeBuffer[(bufWidth * (bufHeight - 1)) - 2];
+ for (i = 1; i < bufWidth - 1; i++) { /* lieing edges */
+ edgeBuffer[i] = edgeBuffer[bufWidth + i]; /* bottom*/
+ edgeBuffer[((bufHeight - 1)*bufWidth) + i]
+ = edgeBuffer[((bufHeight - 2)*bufWidth) + i]; /* top */
+ }
+ for (i = 1; i < bufHeight - 2; i++) { /* standing edges */
+ edgeBuffer[i * bufWidth] = edgeBuffer[(i * bufWidth) + 1]; /* left */
+ edgeBuffer[((i + 1) * bufWidth) - 1] =
+ edgeBuffer[((i + 1) * bufWidth) - 2]; /* right */
+ }
+
+ /* same hack for the materials: */
+ if (same_mat_redux) {
+ matBuffer[0] = matBuffer[bufWidth + 1];
+ matBuffer[bufWidth - 1] = matBuffer[(2 * bufWidth) - 2];
+ matBuffer[bufWidth * (bufHeight - 1)] =
+ matBuffer[bufWidth * (bufHeight - 2) + 1];
+ matBuffer[(bufWidth * bufHeight) - 1] =
+ matBuffer[(bufWidth * (bufHeight - 1)) - 2];
+ for (i = 1; i < bufWidth - 1; i++) { /* lieing mats */
+ matBuffer[i] = matBuffer[bufWidth + i]; /* bottom*/
+ matBuffer[((bufHeight - 1)*bufWidth) + i]
+ = matBuffer[((bufHeight - 2)*bufWidth) + i]; /* top */
+ }
+ for (i = 1; i < bufHeight - 2; i++) { /* standing mats */
+ matBuffer[i * bufWidth] = matBuffer[(i * bufWidth) + 1]; /* left */
+ matBuffer[((i + 1) * bufWidth) - 1] =
+ matBuffer[((i + 1) * bufWidth) - 2]; /* right */
+ }
+ }
+
+ /* alle getallen in zbuffer 3 naar rechts shiften */
+ rz = edgeBuffer;
+ if(rz==0) return;
+
+ for(y=0; y < bufHeight * bufWidth; y++, rz++) {
+ (*rz)>>= 3;
+ }
+
+ /* Distance pointers */
+ rz1= edgeBuffer;
+ rz2= rz1 + bufWidth;
+ rz3= rz2 + bufWidth;
+
+ if (same_mat_redux) {
+ matptr_low = matBuffer;
+ matptr_cent = matptr_low + bufWidth;
+ matptr_high = matptr_cent + bufWidth;
+ }
+
+ if (osaCount == 1) {
+ cp = colourRect + targetoffset;
+ } else {
+ cp = colBuffer + targetoffset;
+ }
+
+ i = 0;
+
+ for(y = 0; y < (imHeight + heightoffset) ; y++) {
+
+
+ /* All these indices are a bit silly. I need to
+ * rewrite this, so all buffers use the same
+ * indexing. */
+ for(x = 0;
+ x < imWidth;
+ x++, rz1++, rz2++, rz3++, cp+=4,
+ matptr_low++,
+ matptr_cent++,
+ matptr_high++) {
+
+ col= abs( - rz1[0] - 2*rz1[1] - rz1[2]
+ - 2*rz2[0] + 12*rz2[1] - 2*rz2[2]
+ - rz3[0] - 2*rz3[1] - rz3[2]) / 3;
+
+ /* Several options for matdif:
+ *
+ * - suppress all boundaries with 0 dif
+ *
+ * - weaken col dif? Or decrease intensity by
+ * a factor when non 0 dif??
+ */
+
+ /* exp: matdif is non-0 if the mask-center
+ * material differs from any of the
+ * corners. */
+
+ if (same_mat_redux) {
+ matdif = abs (matptr_cent[1] - matptr_low[0])
+ + abs (matptr_cent[1] - matptr_low[1])
+ + abs (matptr_cent[1] - matptr_low[2])
+ + abs (matptr_cent[1] - matptr_cent[0])
+ + abs (matptr_cent[1] - matptr_low[2])
+ + abs (matptr_cent[1] - matptr_high[0])
+ + abs (matptr_cent[1] - matptr_high[1])
+ + abs (matptr_cent[1] - matptr_high[2]);
+
+ matdiffac = (matdif ? 0 : same_mat_redux);
+ }
+
+ col= ((intensity - matdiffac) * col)>>14;
+ if(col>255) col= 255;
+
+ /* Colour edge if
+ *
+ * 1. there is an appreciable, non-uniform
+ * gradient,
+ *
+ * 2. there are different materials bordering
+ * on the center pixel
+ */
+ if( (col>0)
+ /* && (matdif != 0) */) {
+
+ if(osaCount > 1) {
+ /* Currently done by tweaking alpha. The colBuffer is */
+ /* filled with pixels of the colour appropriate for the */
+ /* edges. This colour is alpha-blended over the image. */
+ /* This calculation determines how much colour each pixel */
+ /* gets. */
+ col/= osaCount;
+ val= cp[3]+col;
+ if(val>255) cp[3]= 255; else cp[3]= val;
+ }
+ else {
+ /* the pixel is blackened when col is too big */
+ val = cp[0] - col;
+ if(val<=0) {
+ cp[0]= edgeR;
+ } else {
+ cp[0]= val;
+ }
+ val = cp[1] - col;
+ if(val<=0) {
+ cp[1]= edgeG;
+ }else {
+ cp[1]= val;
+ }
+ val = cp[2] - col;
+ if(val<=0) {
+ cp[2]= edgeB;
+ } else {
+ cp[2]= val;
+ }
+ }
+ }
+ }
+ rz1+= 2;
+ rz2+= 2;
+ rz3+= 2;
+ if (same_mat_redux) {
+ matptr_low += 2;
+ matptr_cent += 2;
+ matptr_high += 2;
+ }
+
+ }
+
+} /* end of void renderEdges() */
+
+/* ------------------------------------------------------------------------- */
+
+void addEdgeOver(char *doel, char *bron) /* telt bron bij doel */
+{
+ float c;
+ int mul;
+
+ if( bron[3] == 0) return;
+ if( bron[3] == 255) { /* is getest, scheelt */
+ *((unsigned int *)doel)= *((unsigned int *)bron);
+ return;
+ }
+
+ /* This must be a special blend-mode, because we get a 'weird' data */
+ /* input format now. With edge = (c_e, a_e), picture = (c_p, a_p), we */
+ /* get: result = ( c_e*a_e + c_p(1 - a_e), a_p ). */
+
+ mul = 255 - bron[3];
+
+ /* Not sure if the conversion to float is really necessary here... I will*/
+ /* think about it another day. */
+ c = ((mul * doel[0] + bron[0] * bron[3])/255.0);
+ if(c>255) {doel[0]=255;} else { doel[0]= c;}
+ c = ((mul * doel[1] + bron[1] * bron[3])/255.0);
+ if(c>255) {doel[1]=255;} else { doel[1]= c;}
+ c = ((mul * doel[2] + bron[2] * bron[3])/255.0);
+ if(c>255) {doel[2]=255;} else { doel[2]= c;}
+}
+
+void calcEdgeRenderColBuf(char* colTargetBuffer)
+{
+
+/* int part; */
+ int keepLooping = 1;
+ int sample;
+
+ /* zbuffer fix: here? */
+ Zmulx= ((float) imWidth)/2.0;
+ Zmuly= ((float) imHeight)/2.0;
+
+ /* use these buffer fill functions */
+ zbuffunc = fillEdgeRenderFace;
+ zbuflinefunc = fillEdgeRenderEdge;
+
+ /* always buffer the max. extent */
+ Aminy = 0;
+ Amaxy = imHeight;
+
+ sample = 0; /* Zsample is used internally ! */
+ while ( (sample < osaCount) && keepLooping ) {
+ /* jitter */
+ Zjitx= -jit[sample][0];
+ Zjity= -jit[sample][1];
+
+ /* should reset dis buffer here */
+ resetDistanceBuffer();
+
+ /* kick all into a z buffer */
+ keepLooping = zBufferEdgeRenderObjects();
+
+ /* do filtering */
+ renderEdges(colTargetBuffer);
+
+ if(RE_local_test_break()) keepLooping = 0;
+ sample++;
+ }
+
+ /* correction for osa-sampling...*/
+ if( osaCount != 1) {
+ char *rp, *rt;
+ int a;
+
+ rt= colTargetBuffer;
+ rp= colBuffer;
+ for(a = imWidth * imHeight; a>0; a--, rt+=4, rp+=4) {
+ /* there seem to be rounding errors here... */
+ addEdgeOver(rt, rp);
+ }
+ }
+
+} /*End of void calcEdgeRenderZBuf(void) */
+
+/* ------------------------------------------------------------------------- */
+/* Clip flags etc. should still be set. When called in the span of 'normal' */
+/* rendering, this should be ok. */
+int zBufferEdgeRenderObjects(void)
+{
+ int keepLooping;
+ int faceCounter; /* counter for face number */
+ Material *ma;
+
+ keepLooping = 1;
+ ma = NULL;
+ faceCounter = 0;
+
+ while ( (faceCounter < R.totvlak) && keepLooping) {
+ if((faceCounter & 255)==0) { Zvlr= R.blovl[faceCounter>>8]; }
+ else Zvlr++;
+
+ ma= Zvlr->mat;
+
+ /*exp*/
+ mat_cache = ma;
+
+ /* face number is used in the fill functions */
+ Zvlnr = faceCounter + 1;
+
+ if(Zvlr->flag & R_VISIBLE) {
+
+ /* here we cull all transparent faces if mode == 0 */
+ if (selectmode || !(ma->mode & MA_ZTRA)) {
+ /* here we can add all kinds of extra selection criteria */
+ 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 zBufferEdgeRenderObjects(void) */
+
+/* ------------------------------------------------------------------------- */
+
+void fillEdgeRenderFace(float *v1, float *v2, float *v3)
+{
+ /* Coordinates of the vertices are specified in ZCS */
+ double z0; /* used as temp var*/
+ double xx1;
+ double zxd,zyd,zy0, tmp;
+ float *minv,*maxv,*midv;
+ int zverg,x;
+ int my0,my2,sn1,sn2,rectx,zd;
+ int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2/* , mask */;
+ int linex, liney, xoffset, yoffset; /* pointers to the pixel number */
+
+ /* 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 */
+ MTC_diff3DFF(vec1, v1, v2);
+ MTC_diff3DFF(vec2, v2, v3);
+ 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 = imWidth;
+ yoffset = my2;
+ xoffset = 0;
+
+ xs3= 0; /* flag */
+ if(dx0>dx1) {
+ MTC_swapInt(&xs0, &xs1);
+ MTC_swapInt(&dx0, &dx1);
+ xs3= 1; /* flag */
+
+ }
+
+ liney = yoffset;
+ 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);
+
+ if ((sn1 < 0) || (sn1>imWidth) ) printf("\n sn1 exceeds line");
+ linex = xoffset + sn1;
+ liney = yoffset;
+
+ x= sn2-sn1;
+
+ while(x>=0) {
+ insertInEdgeBuffer(linex , liney, zverg); /* line y not needed here */
+ zverg+= zd;
+ linex++;
+ x--;
+ }
+ zy0-= zyd;
+ yoffset--;
+ }
+
+ 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);
+
+ linex = sn1;
+ liney = yoffset;
+
+ x= sn2-sn1;
+
+ while(x>=0) {
+ insertInEdgeBuffer(linex, liney, zverg); /* line y not needed here */
+ zverg+= zd;
+ linex++;
+ x--;
+ }
+ zy0-=zyd;
+ yoffset--;
+ }
+} /* end of void fillEdgeRenderFace(float *v1, float *v2, float *v3) */
+
+/* ------------------------------------------------------------------------- */
+
+void fillEdgeRenderEdge(float *vec1, float *vec2)
+{
+ int start, end, x, y, oldx, oldy, ofs;
+ int dz, vergz/* , mask */;
+ float dx, dy;
+ float v1[3], v2[3];
+ int linex, liney;
+ int xoffset, yoffset;
+
+
+ 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 >= imWidth) end = imWidth - 1;
+
+ oldy= floor(v1[1]);
+ dy/= dx;
+
+ vergz= v1[2];
+ dz= (v2[2]-v1[2])/dx;
+
+ yoffset = oldy;
+ xoffset = start;
+
+ if(dy<0) ofs= -imWidth;
+ else ofs= imWidth;
+
+ liney = yoffset;
+ linex = xoffset;
+
+ for(x= start; x<=end; x++, xoffset++) {
+
+ y= floor(v1[1]);
+ if(y!=oldy) {
+ oldy= y;
+ liney++;
+ }
+
+ if(x>=0 && y>=Aminy && y<=Amaxy) {
+ insertInEdgeBuffer(linex , liney, vergz);
+ }
+
+ 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];
+ dz= (v2[2]-v1[2])/dy;
+
+ yoffset = start;
+ xoffset = oldx;
+
+ if(dx<0) ofs= -1;
+ else ofs= 1;
+
+ linex = xoffset;
+ liney = yoffset;
+
+ for(y= start; y<=end; y++, liney++) {
+
+ x= floor(v1[0]);
+ if(x!=oldx) {
+ oldx= x;
+ linex += ofs;
+ }
+
+ if(x>=0 && y>=Aminy && (x < imWidth)) {
+ insertInEdgeBuffer(linex, liney, vergz);
+ }
+
+ v1[0]+= dx;
+ vergz+= dz;
+ }
+ }
+} /* End of void fillEdgeRenderEdge(float *vec1, float *vec2) */
+
+/* ------------------------------------------------------------------------- */
+
+/* eof edgeRender.c */