This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/render/intern/source/edgeRender.c
T
Ton Roosendaal 610cec55c7 Biiig commit! Thanks to 2-3 weeks of cvs freeze...
Render:
- New; support for dual CPU render (SDL thread)
  Currently only works with alternating scanlines, but gives excellent
  performance. For both normal render as unified implemented.
  Note the "mutex" locks on z-transp buffer render and imbuf loads.
- This has been made possible by major cleanups in render code, especially
  getting rid of globals (example Tin Tr Tg Tb Ta for textures) or struct
  OSA or using Materials or Texture data to write to.
- Made normal render fully 4x32 floats too, and removed all old optimizes
  with chars or shorts.
- Made normal render and unified render use same code for sky and halo
  render, giving equal (and better) results for halo render. Old render
  now also uses PostProcess options (brightness, mul, gamma)
- Added option ("FBuf") in F10 Output Panel, this keeps a 4x32 bits buffer
  after render. Using PostProcess menu you will note an immediate re-
  display of image too (32 bits RGBA)
- Added "Hue" and "Saturation" sliders to PostProcess options

- Render module is still not having a "nice" API, but amount of dependencies
  went down a lot. Next todo: remove abusive "previewrender" code.
  The last main global in Render (struct Render) now can be re-used for fully
  controlling a render, to allow multiple "instances" of render to open.

- Renderwindow now displays a smal bar on top with the stats, and keeps the
  stats after render too. Including "spare" page support.
  Not only easier visible that way, but also to remove the awkward code that
  was drawing stats in the Info header (extreme slow on some ATIs too)

- Cleaned up blendef.h and BKE_utildefines.h, these two had overlapping
  defines.

- I might have forgotten stuff... and will write a nice doc on the architecture!
2004-12-27 19:28:52 +00:00

967 lines
25 KiB
C

/**
* $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 <string.h>
#include <limits.h> /* INT_MIN,MAX are used here */
#include <stdio.h>
#include "MEM_guardedalloc.h"
#include "MTC_vectorops.h"
#include "BKE_utildefines.h"
#include "RE_callbacks.h"
#include "edgeRender.h"
#include "render.h"
#include "zbuf.h" /* for zbufclipwire and zbufclip */
#include "jitter.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef RE_EDGERENDERSAFE
char edgeRender_h[] = EDGERENDER_H;
char edgeRender_c[] = "$Id$";
#include "errorHandler.h"
#endif
/* ------------------------------------------------------------------------- */
/* These function pointers are used for z buffer filling. */
extern void (*zbuffunc)(unsigned int, float *, float *, float *);
extern void (*zbuflinefunc)(unsigned int, float *, float *);
extern float Zmulx, Zmuly; /* Some kind of scale? */
extern float Zjitx,Zjity; /* The x,y values for jitter offset */
/* ------------------------------------------------------------------------- */
/* 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.
*/
static void fillEdgeRenderEdge(unsigned int, float *vec1, float *vec2);
/**
* Buffer a face between these two vertices in the e.r. distance buffer.
*/
static void fillEdgeRenderFace(unsigned int, 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(unsigned char *dst, unsigned char *src);
/* ------------------------------------------------------------------------- */
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);
edgeBuffer= NULL;
if(colBuffer) MEM_freeN(colBuffer);
colBuffer= NULL;
if(matBuffer) MEM_freeN(matBuffer);
matBuffer= NULL;
} /* 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 */
}
}
/* shift values in zbuffer 3 to the right */
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 = (int *) 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() */
/* ------------------------------------------------------------------------- */
/* adds src to dst */
void addEdgeOver(unsigned char *dst, unsigned char *src)
{
unsigned char inverse;
unsigned char alpha;
unsigned int c;
alpha = src[3];
if( alpha == 0) return;
if( alpha == 255) {
/* when full opacity, just copy the pixel */
/* this code assumes an int is 32 bit, fix
*(( unsigned int *)dst)= *((unsigned int *)src);
replaced with memcpy
*/
memcpy(dst,src,4);
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 ). */
inverse = 255 - alpha;
c = ((unsigned int)inverse * (unsigned int) dst[0] + (unsigned int)src[0] *
(unsigned int)alpha) >> 8;
dst[0] = c;
c = ((unsigned int)inverse * (unsigned int) dst[1] + (unsigned int)src[1] *
(unsigned int)alpha) >> 8;
dst[1] = c;
c = ((unsigned int)inverse * (unsigned int) dst[2] + (unsigned int)src[2] *
(unsigned int)alpha) >> 8;
dst[2] = c;
}
void calcEdgeRenderColBuf(char* colTargetBuffer)
{
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)
{
VlakRen *vlr= NULL;
unsigned int zvlnr;
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) { vlr= R.blovl[faceCounter>>8]; }
else vlr++;
ma= vlr->mat;
/*exp*/
mat_cache = ma;
/* face number is used in the fill functions */
zvlnr = faceCounter + 1;
if(vlr->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(zvlnr, vlr);
else {
zbufclip(zvlnr, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho,
vlr->v1->clip, vlr->v2->clip, vlr->v3->clip);
if(vlr->v4) {
zvlnr+= 0x800000; /* in a sense, the 'adjoint' face */
zbufclip(zvlnr, vlr->v1->ho, vlr->v3->ho, vlr->v4->ho,
vlr->v1->clip, vlr->v3->clip, vlr->v4->clip);
}
}
}
};
if(RE_local_test_break()) keepLooping = 0;
faceCounter++;
}
return keepLooping;
} /* End of int zBufferEdgeRenderObjects(void) */
/* ------------------------------------------------------------------------- */
static void fillEdgeRenderFace(unsigned int zvlnr, 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; /* security, for 'zero' size faces */
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 : THE LONGEST */
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 : THE TOP ONE */
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 : THE BOTTOM ONE */
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; /* that way it does the first loop entirely */
while (my2 > Amaxy) { /* my2 can really be larger */
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);
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) */
/* ------------------------------------------------------------------------- */
static void fillEdgeRenderEdge(unsigned int zvlnr, 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 lines from left to right */
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= -1;
else ofs= 1;
liney = yoffset;
linex = xoffset;
for(x= start; x<=end; x++, linex++) {
y= floor(v1[1]);
if(y!=oldy) {
oldy= y;
liney+= ofs;
}
if(x>=0 && y>=Aminy && y<=Amaxy) {
insertInEdgeBuffer(linex , liney, vergz);
}
v1[1]+= dy;
vergz+= dz;
}
}
else {
/* all lines from top to bottom */
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 */