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:
authorTon Roosendaal <ton@blender.org>2003-12-10 23:41:53 +0300
committerTon Roosendaal <ton@blender.org>2003-12-10 23:41:53 +0300
commita18cc02374e8993824cfeb12b9e67b5b067317d9 (patch)
tree92b674659affe20fcdbf521ddc1a7269d4cc696b /source/blender/render
parentcad30134cb9093650488a37803361fcbf1f1db2f (diff)
- Xmas special: shiny mirroring bells & whistles!
This is a revision of the old NeoGeo raytracer, dusted off, improved quite a lot, and nicely integrated in the rest of rendering pipeline. Enable it with F10-"Ray", and set either a 'ray-shadow' lamp or give the Material a "RayMirror" value. It has been added for 2 reasons: - get feedback on validity... I need artists to play around with it if it's actually useful. It still *is* raytracing, meaning complex scenes will easily become slow. - for educational purposes. All raytracing happens in ray.c, which can be quite easily adjusted for other effects. When too many disasters pop up with this, I'll make it a compile #ifdef. But so far, it seems to do a decent job. Demo files: http://www.blender.org/docs/ray_test.tgz An article (tech) about how it works, and about the new octree invention will be posted soon. :) Note: it doesn't work with unified render yet.
Diffstat (limited to 'source/blender/render')
-rw-r--r--source/blender/render/extern/include/render_types.h4
-rw-r--r--source/blender/render/intern/include/rendercore.h3
-rw-r--r--source/blender/render/intern/include/zbuf_int.h2
-rw-r--r--source/blender/render/intern/source/Makefile2
-rw-r--r--source/blender/render/intern/source/ray.c1676
-rw-r--r--source/blender/render/intern/source/renderPreAndPost.c8
-rw-r--r--source/blender/render/intern/source/rendercore.c63
-rw-r--r--source/blender/render/intern/source/zbuf.c10
8 files changed, 1733 insertions, 35 deletions
diff --git a/source/blender/render/extern/include/render_types.h b/source/blender/render/extern/include/render_types.h
index 9b1f0ac02e6..4ef7162e2e3 100644
--- a/source/blender/render/extern/include/render_types.h
+++ b/source/blender/render/extern/include/render_types.h
@@ -189,6 +189,7 @@ typedef struct VlakRen
char snproj, puno;
char flag, ec;
unsigned int lay;
+ unsigned int raycount;
RadFace *radface;
Object *ob;
} VlakRen;
@@ -247,6 +248,9 @@ typedef struct LampRen
/** A small depth offset to prevent self-shadowing. */
float bias;
+ float ray_soft;
+ short ray_samp;
+
/** If the lamp casts shadows, one of these is filled. For the old
* renderer, shb is used, for the new pipeline the shadowBufOb,
* which should be a shadowbuffer handle. */
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index d1ab24550ab..0be15d90776 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -45,7 +45,6 @@ unsigned int calchalo_z(struct HaloRen *har, unsigned int zz);
float spec(float inp, int hard);
-void shade_lamp_loop(void);
void add_halo_flare(void);
/**
@@ -85,7 +84,7 @@ void zbufshadeDA(void); /* Delta Accum Pixel Struct */
/**
* Also called in: zbuf.c
*/
-void shadepixel(float x, float y, int vlaknr);
+void shadepixel(float x, float y, int vlaknr, int mask);
/**
* Shade the pixel at xn, yn for halo har, and write the result to col.
diff --git a/source/blender/render/intern/include/zbuf_int.h b/source/blender/render/intern/include/zbuf_int.h
index 367162be10e..d1c5f03d3b7 100644
--- a/source/blender/render/intern/include/zbuf_int.h
+++ b/source/blender/render/intern/include/zbuf_int.h
@@ -186,7 +186,7 @@ void zbuffer_abuf(void);
/**
* Shade this face at this location in SCS.
*/
-void shadetrapixel(float x, float y, int vlak);
+void shadetrapixel(float x, float y, int vlak, int mask);
/**
* Determine the distance to the camera of this halo, in ZCS.
diff --git a/source/blender/render/intern/source/Makefile b/source/blender/render/intern/source/Makefile
index fc14bec1267..ef22a822d44 100644
--- a/source/blender/render/intern/source/Makefile
+++ b/source/blender/render/intern/source/Makefile
@@ -41,7 +41,7 @@ ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris windo
CCFLAGS += -funsigned-char
endif
-# CFLAGS += $(LEVEL_2_C_WARNINGS)
+CFLAGS += $(LEVEL_1_C_WARNINGS)
# first /include is my own includes, second is the external interface.
# The external modules follow after. There should be a nicer way to say this.
diff --git a/source/blender/render/intern/source/ray.c b/source/blender/render/intern/source/ray.c
new file mode 100644
index 00000000000..bf9fbc79652
--- /dev/null
+++ b/source/blender/render/intern/source/ray.c
@@ -0,0 +1,1676 @@
+/**
+ * $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) 1990-1998 NeoGeo BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_texture.h"
+
+#include "BLI_arithb.h"
+
+#include "render.h"
+#include "render_intern.h"
+#include "jitter.h"
+
+#define OCRES 64
+#define DDA_SHADOW 0
+#define DDA_MIRROR 1
+
+/* ********** structs *************** */
+
+typedef struct Octree {
+ struct Branch *adrbranch[256];
+ struct Node *adrnode[256];
+ float ocsize; /* ocsize: mult factor, max size octree */
+ float ocfacx,ocfacy,ocfacz;
+ float min[3], max[3];
+ /* for optimize, last intersected face */
+ VlakRen *vlr_last;
+
+} Octree;
+
+typedef struct Isect {
+ float start[3], end[3];
+ float labda, u, v;
+ struct VlakRen *vlr, *vlrcontr;
+ short isect, mode; /* mode: DDA_SHADOW or DDA_MIRROR */
+ float ddalabda;
+} Isect;
+
+typedef struct Branch
+{
+ struct Branch *b[8];
+} Branch;
+
+typedef struct OcVal
+{
+ short ocx, ocy, ocz;
+} OcVal;
+
+typedef struct Node
+{
+ struct VlakRen *v[8];
+ struct OcVal ov[8];
+ struct Node *next;
+} Node;
+
+
+/* ******** globals ***************** */
+
+static Octree g_oc; /* can be scene pointer or so later... */
+
+/* just for statistics */
+static int raycount, branchcount, nodecount;
+static int maxnodeface=0, accepted, rejected;
+
+
+/* **************** ocval method ******************* */
+/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */
+
+#define OCVALRES 15
+#define BROW(min, max) (((max)>=OCVALRES? 0xFFFF: (1<<(max+1))-1) - ((min>0)? ((1<<(min))-1):0) )
+
+static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov)
+{
+ float min[3], max[3];
+ int ocmin, ocmax;
+
+ VECCOPY(min, v1);
+ VECCOPY(max, v1);
+ DO_MINMAX(v2, min, max);
+ DO_MINMAX(v3, min, max);
+ if(v4) {
+ DO_MINMAX(v4, min, max);
+ }
+
+ ocmin= OCVALRES*(min[0]-x);
+ ocmax= OCVALRES*(max[0]-x);
+ ov->ocx= BROW(ocmin, ocmax);
+
+ ocmin= OCVALRES*(min[1]-y);
+ ocmax= OCVALRES*(max[1]-y);
+ ov->ocy= BROW(ocmin, ocmax);
+
+ ocmin= OCVALRES*(min[2]-z);
+ ocmax= OCVALRES*(max[2]-z);
+ ov->ocz= BROW(ocmin, ocmax);
+
+}
+
+static void calc_ocval_ray(OcVal *ov, float x1, float y1, float z1,
+ float x2, float y2, float z2)
+{
+ static float ox1, ox2, oy1, oy2, oz1, oz2;
+
+ if(ov==NULL) {
+ ox1= x1; ox2= x2;
+ oy1= y1; oy2= y2;
+ oz1= z1; oz2= z2;
+ }
+ else {
+ int ocmin, ocmax;
+
+ if(ox1<ox2) {
+ ocmin= OCVALRES*(ox1 - ((int)x1));
+ ocmax= OCVALRES*(ox2 - ((int)x1));
+ } else {
+ ocmin= OCVALRES*(ox2 - ((int)x1));
+ ocmax= OCVALRES*(ox1 - ((int)x1));
+ }
+ ov->ocx= BROW(ocmin, ocmax);
+
+ if(oy1<oy2) {
+ ocmin= OCVALRES*(oy1 - ((int)y1));
+ ocmax= OCVALRES*(oy2 - ((int)y1));
+ } else {
+ ocmin= OCVALRES*(oy2 - ((int)y1));
+ ocmax= OCVALRES*(oy1 - ((int)y1));
+ }
+ ov->ocy= BROW(ocmin, ocmax);
+
+ if(oz1<oz2) {
+ ocmin= OCVALRES*(oz1 - ((int)z1));
+ ocmax= OCVALRES*(oz2 - ((int)z1));
+ } else {
+ ocmin= OCVALRES*(oz2 - ((int)z1));
+ ocmax= OCVALRES*(oz1 - ((int)z1));
+ }
+ ov->ocz= BROW(ocmin, ocmax);
+
+ }
+}
+
+/* ************* octree ************** */
+
+static Branch *addbranch(Branch *br, short oc)
+{
+
+ if(br->b[oc]) return br->b[oc];
+
+ branchcount++;
+ if(g_oc.adrbranch[branchcount>>8]==0)
+ g_oc.adrbranch[branchcount>>8]= MEM_callocN(256*sizeof(Branch),"addbranch");
+
+ if(branchcount>= 256*256) {
+ printf("error; octree branches full\n");
+ branchcount=0;
+ }
+
+ return br->b[oc]=g_oc.adrbranch[branchcount>>8]+(branchcount & 255);
+}
+
+static Node *addnode(void)
+{
+
+ nodecount++;
+ if(g_oc.adrnode[nodecount>>12]==0)
+ g_oc.adrnode[nodecount>>12]= MEM_callocN(4096*sizeof(Node),"addnode");
+
+ if(nodecount> 256*4096) {
+ printf("error; octree nodes full\n");
+ nodecount=0;
+ }
+
+ return g_oc.adrnode[nodecount>>12]+(nodecount & 4095);
+}
+
+
+static void ocwrite(VlakRen *vlr, short x, short y, short z, float rtf[][3])
+{
+ Branch *br;
+ Node *no;
+ short a, oc0, oc1, oc2, oc3, oc4, oc5;
+
+ x<<=2;
+ y<<=1;
+ oc0= ((x & 128)+(y & 64)+(z & 32))>>5;
+ oc1= ((x & 64)+(y & 32)+(z & 16))>>4;
+ oc2= ((x & 32)+(y & 16)+(z & 8))>>3;
+ oc3= ((x & 16)+(y & 8)+(z & 4))>>2;
+ oc4= ((x & 8)+(y & 4)+(z & 2))>>1;
+ oc5= ((x & 4)+(y & 2)+(z & 1));
+
+ br= addbranch(g_oc.adrbranch[0],oc0);
+ br= addbranch(br,oc1);
+ br= addbranch(br,oc2);
+ br= addbranch(br,oc3);
+ br= addbranch(br,oc4);
+ no= (Node *)br->b[oc5];
+ if(no==NULL) br->b[oc5]= (Branch *)no= addnode();
+
+ while(no->next) no= no->next;
+
+ a= 0;
+ if(no->v[7]) { /* node full */
+ no->next= addnode();
+ no= no->next;
+ }
+ else {
+ while(no->v[a]!=NULL) a++;
+ }
+
+ no->v[a]= vlr;
+
+ calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x>>2, y>>1, z, &no->ov[a]);
+
+}
+
+static void d2dda(short b1, short b2, short c1, short c2, char *ocvlak, short rts[][3], float rtf[][3])
+{
+ short ocx1,ocx2,ocy1,ocy2;
+ short x,y,dx=0,dy=0;
+ float ox1,ox2,oy1,oy2;
+ float labda,labdao,labdax,labday,ldx,ldy;
+
+ ocx1= rts[b1][c1];
+ ocy1= rts[b1][c2];
+ ocx2= rts[b2][c1];
+ ocy2= rts[b2][c2];
+
+ if(ocx1==ocx2 && ocy1==ocy2) {
+ ocvlak[OCRES*ocx1+ocy1]= 1;
+ return;
+ }
+
+ ox1= rtf[b1][c1];
+ oy1= rtf[b1][c2];
+ ox2= rtf[b2][c1];
+ oy2= rtf[b2][c2];
+
+ if(ox1!=ox2) {
+ if(ox2-ox1>0.0) {
+ labdax= (ox1-ocx1-1.0)/(ox1-ox2);
+ ldx= -1.0/(ox1-ox2);
+ dx= 1;
+ } else {
+ labdax= (ox1-ocx1)/(ox1-ox2);
+ ldx= 1.0/(ox1-ox2);
+ dx= -1;
+ }
+ } else {
+ labdax=1.0;
+ ldx=0;
+ }
+
+ if(oy1!=oy2) {
+ if(oy2-oy1>0.0) {
+ labday= (oy1-ocy1-1.0)/(oy1-oy2);
+ ldy= -1.0/(oy1-oy2);
+ dy= 1;
+ } else {
+ labday= (oy1-ocy1)/(oy1-oy2);
+ ldy= 1.0/(oy1-oy2);
+ dy= -1;
+ }
+ } else {
+ labday=1.0;
+ ldy=0;
+ }
+
+ x=ocx1; y=ocy1;
+ labda= MIN2(labdax, labday);
+
+ while(TRUE) {
+
+ if(x<0 || y<0 || x>=OCRES || y>=OCRES);
+ else ocvlak[OCRES*x+y]= 1;
+
+ labdao=labda;
+ if(labdax==labday) {
+ labdax+=ldx;
+ x+=dx;
+ labday+=ldy;
+ y+=dy;
+ } else {
+ if(labdax<labday) {
+ labdax+=ldx;
+ x+=dx;
+ } else {
+ labday+=ldy;
+ y+=dy;
+ }
+ }
+ labda=MIN2(labdax,labday);
+ if(labda==labdao) break;
+ if(labda>=1.0) break;
+ }
+ ocvlak[OCRES*ocx2+ocy2]=1;
+}
+
+static void filltriangle(short c1, short c2, char *ocvlak, short *ocmin)
+{
+ short a,x,y,y1,y2,*ocmax;
+
+ ocmax=ocmin+3;
+
+ for(x=ocmin[c1];x<=ocmax[c1];x++) {
+ a= OCRES*x;
+ for(y=ocmin[c2];y<=ocmax[c2];y++) {
+ if(ocvlak[a+y]) {
+ y++;
+ while(ocvlak[a+y] && y!=ocmax[c2]) y++;
+ for(y1=ocmax[c2];y1>y;y1--) {
+ if(ocvlak[a+y1]) {
+ for(y2=y;y2<=y1;y2++) ocvlak[a+y2]=1;
+ y1=0;
+ }
+ }
+ y=ocmax[c2];
+ }
+ }
+ }
+}
+
+void freeoctree(void)
+{
+ int a= 0;
+
+ while(g_oc.adrbranch[a]) {
+ MEM_freeN(g_oc.adrbranch[a]);
+ g_oc.adrbranch[a]= NULL;
+ a++;
+ }
+
+ a= 0;
+ while(g_oc.adrnode[a]) {
+ MEM_freeN(g_oc.adrnode[a]);
+ g_oc.adrnode[a]= NULL;
+ a++;
+ }
+
+ printf("branches %d nodes %d\n", branchcount, nodecount);
+ printf("raycount %d \n", raycount);
+// printf("accepted %d rejected %d\n", accepted, rejected);
+
+ branchcount= 0;
+ nodecount= 0;
+}
+
+void makeoctree()
+{
+ VlakRen *vlr=NULL;
+ VertRen *v1, *v2, *v3, *v4;
+ float ocfac[3], t00, t01, t02;
+ float rtf[4][3];
+ int v;
+ short a,b,c, rts[4][3], oc1, oc2, oc3, oc4, ocmin[6], *ocmax, x, y, z;
+ char ocvlak[3*OCRES*OCRES + 8]; // front, top, size view of face, to fill in
+
+ ocmax= ocmin+3;
+
+ bzero(g_oc.adrnode, sizeof(g_oc.adrnode));
+ bzero(g_oc.adrbranch, sizeof(g_oc.adrbranch));
+
+ branchcount=0;
+ nodecount=0;
+ raycount=0;
+ accepted= 0;
+ rejected= 0;
+
+ g_oc.vlr_last= NULL;
+ INIT_MINMAX(g_oc.min, g_oc.max);
+
+ /* first min max octree space */
+ for(v=0;v<R.totvlak;v++) {
+ if((v & 255)==0) vlr= R.blovl[v>>8];
+ else vlr++;
+ if(vlr->mat->mode & MA_TRACEBLE) {
+
+ DO_MINMAX(vlr->v1->co, g_oc.min, g_oc.max);
+ DO_MINMAX(vlr->v2->co, g_oc.min, g_oc.max);
+ DO_MINMAX(vlr->v3->co, g_oc.min, g_oc.max);
+ if(vlr->v4) {
+ DO_MINMAX(vlr->v4->co, g_oc.min, g_oc.max);
+ }
+ }
+ }
+
+ if(g_oc.min[0] > g_oc.max[0]) return; /* empty octree */
+
+ g_oc.adrbranch[0]=(Branch *)MEM_callocN(256*sizeof(Branch),"makeoctree");
+
+ for(c=0;c<3;c++) { /* octree enlarge, still needed? */
+ g_oc.min[c]-= 0.01;
+ g_oc.max[c]+= 0.01;
+ }
+
+ t00= g_oc.max[0]-g_oc.min[0];
+ t01= g_oc.max[1]-g_oc.min[1];
+ t02= g_oc.max[2]-g_oc.min[2];
+
+ /* this minus 0.1 is old safety... seems to be needed? */
+ g_oc.ocfacx=ocfac[0]= (OCRES-0.1)/t00;
+ g_oc.ocfacy=ocfac[1]= (OCRES-0.1)/t01;
+ g_oc.ocfacz=ocfac[2]= (OCRES-0.1)/t02;
+
+ g_oc.ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */
+
+ for(v=0; v<R.totvlak; v++) {
+ if((v & 255)==0) vlr= R.blovl[v>>8];
+ else vlr++;
+
+ if(vlr->mat->mode & MA_TRACEBLE) {
+
+ v1= vlr->v1;
+ v2= vlr->v2;
+ v3= vlr->v3;
+ v4= vlr->v4;
+
+ for(c=0;c<3;c++) {
+ rtf[0][c]= (v1->co[c]-g_oc.min[c])*ocfac[c] ;
+ rts[0][c]= (short)rtf[0][c];
+ rtf[1][c]= (v2->co[c]-g_oc.min[c])*ocfac[c] ;
+ rts[1][c]= (short)rtf[1][c];
+ rtf[2][c]= (v3->co[c]-g_oc.min[c])*ocfac[c] ;
+ rts[2][c]= (short)rtf[2][c];
+ if(v4) {
+ rtf[3][c]= (v4->co[c]-g_oc.min[c])*ocfac[c] ;
+ rts[3][c]= (short)rtf[3][c];
+ }
+ }
+
+ bzero(ocvlak, sizeof(ocvlak));
+
+ for(c=0;c<3;c++) {
+ oc1= rts[0][c];
+ oc2= rts[1][c];
+ oc3= rts[2][c];
+ if(v4==NULL) {
+ ocmin[c]= MIN3(oc1,oc2,oc3);
+ ocmax[c]= MAX3(oc1,oc2,oc3);
+ }
+ else {
+ oc4= rts[3][c];
+ ocmin[c]= MIN4(oc1,oc2,oc3,oc4);
+ ocmax[c]= MAX4(oc1,oc2,oc3,oc4);
+ }
+ if(ocmax[c]>OCRES-1) ocmax[c]=OCRES-1;
+ if(ocmin[c]<0) ocmin[c]=0;
+ }
+
+ d2dda(0,1,0,1,ocvlak+OCRES*OCRES,rts,rtf);
+ d2dda(0,1,0,2,ocvlak,rts,rtf);
+ d2dda(0,1,1,2,ocvlak+2*OCRES*OCRES,rts,rtf);
+ d2dda(1,2,0,1,ocvlak+OCRES*OCRES,rts,rtf);
+ d2dda(1,2,0,2,ocvlak,rts,rtf);
+ d2dda(1,2,1,2,ocvlak+2*OCRES*OCRES,rts,rtf);
+ if(v4==NULL) {
+ d2dda(2,0,0,1,ocvlak+OCRES*OCRES,rts,rtf);
+ d2dda(2,0,0,2,ocvlak,rts,rtf);
+ d2dda(2,0,1,2,ocvlak+2*OCRES*OCRES,rts,rtf);
+ }
+ else {
+ d2dda(2,3,0,1,ocvlak+OCRES*OCRES,rts,rtf);
+ d2dda(2,3,0,2,ocvlak,rts,rtf);
+ d2dda(2,3,1,2,ocvlak+2*OCRES*OCRES,rts,rtf);
+ d2dda(3,0,0,1,ocvlak+OCRES*OCRES,rts,rtf);
+ d2dda(3,0,0,2,ocvlak,rts,rtf);
+ d2dda(3,0,1,2,ocvlak+2*OCRES*OCRES,rts,rtf);
+ }
+ /* nothing todo with triangle..., just fills :) */
+ filltriangle(0,1,ocvlak+OCRES*OCRES,ocmin);
+ filltriangle(0,2,ocvlak,ocmin);
+ filltriangle(1,2,ocvlak+2*OCRES*OCRES,ocmin);
+
+ /* this is approximation here... should calculate for real
+ if a node intersects plane */
+
+ for(x=ocmin[0];x<=ocmax[0];x++) {
+ a= OCRES*x;
+ for(y=ocmin[1];y<=ocmax[1];y++) {
+ b= OCRES*y;
+ if(ocvlak[a+y+OCRES*OCRES]) {
+ for(z=ocmin[2];z<=ocmax[2];z++) {
+ if(ocvlak[b+z+2*OCRES*OCRES] && ocvlak[a+z]) ocwrite(vlr, x,y,z, rtf);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ************ raytracer **************** */
+
+/* only for self-intersecting test with current render face (where ray left) */
+static short intersection2(float r0, float r1, float r2, float rx1, float ry1, float rz1)
+{
+ VertRen *v1,*v2,*v3,*v4=NULL;
+ float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
+ float m0, m1, m2, divdet, det, det1;
+ float u1, v, u2;
+
+ v1= R.vlr->v1;
+ v2= R.vlr->v2;
+ if(R.vlr->v4) {
+ v3= R.vlr->v4;
+ v4= R.vlr->v3;
+ }
+ else v3= R.vlr->v3;
+
+ t00= v3->co[0]-v1->co[0];
+ t01= v3->co[1]-v1->co[1];
+ t02= v3->co[2]-v1->co[2];
+ t10= v3->co[0]-v2->co[0];
+ t11= v3->co[1]-v2->co[1];
+ t12= v3->co[2]-v2->co[2];
+
+ x0= t11*r2-t12*r1;
+ x1= t12*r0-t10*r2;
+ x2= t10*r1-t11*r0;
+
+ divdet= t00*x0+t01*x1+t02*x2;
+
+ m0= rx1-v3->co[0];
+ m1= ry1-v3->co[1];
+ m2= rz1-v3->co[2];
+ det1= m0*x0+m1*x1+m2*x2;
+
+ if(divdet!=0.0) {
+ u1= det1/divdet;
+
+ if(u1<=0.0) {
+ det= t00*(m1*r2-m2*r1);
+ det+= t01*(m2*r0-m0*r2);
+ det+= t02*(m0*r1-m1*r0);
+ v= det/divdet;
+
+ if(v<=0.0 && (u1 + v) >= -1.0) {
+ return 1;
+ }
+ }
+ }
+
+ if(v4) {
+
+ t20= v3->co[0]-v4->co[0];
+ t21= v3->co[1]-v4->co[1];
+ t22= v3->co[2]-v4->co[2];
+
+ divdet= t20*x0+t21*x1+t22*x2;
+ if(divdet!=0.0) {
+ u2= det1/divdet;
+
+ if(u2<=0.0) {
+ det= t20*(m1*r2-m2*r1);
+ det+= t21*(m2*r0-m0*r2);
+ det+= t22*(m0*r1-m1*r0);
+ v= det/divdet;
+
+ if(v<=0.0 && (u2 + v) >= -1.0) {
+ return 2;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static short intersection(Isect *is)
+{
+ VertRen *v1,*v2,*v3,*v4=NULL;
+ float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2;
+ float m0, m1, m2, divdet, det, det1;
+ static short vlrisect=0;
+ short ok=0;
+
+ is->vlr->raycount= raycount;
+
+ v1= is->vlr->v1;
+ v2= is->vlr->v2;
+ if(is->vlr->v4) {
+ v3= is->vlr->v4;
+ v4= is->vlr->v3;
+ }
+ else v3= is->vlr->v3;
+
+ t00= v3->co[0]-v1->co[0];
+ t01= v3->co[1]-v1->co[1];
+ t02= v3->co[2]-v1->co[2];
+ t10= v3->co[0]-v2->co[0];
+ t11= v3->co[1]-v2->co[1];
+ t12= v3->co[2]-v2->co[2];
+
+ r0= is->start[0]-is->end[0];
+ r1= is->start[1]-is->end[1];
+ r2= is->start[2]-is->end[2];
+
+ x0= t11*r2-t12*r1;
+ x1= t12*r0-t10*r2;
+ x2= t10*r1-t11*r0;
+
+ divdet= t00*x0+t01*x1+t02*x2;
+
+ m0= is->start[0]-v3->co[0];
+ m1= is->start[1]-v3->co[1];
+ m2= is->start[2]-v3->co[2];
+ det1= m0*x0+m1*x1+m2*x2;
+
+ if(divdet!=0.0) {
+ float u= det1/divdet;
+
+ if(u<0.0) {
+ float v;
+ det= t00*(m1*r2-m2*r1);
+ det+= t01*(m2*r0-m0*r2);
+ det+= t02*(m0*r1-m1*r0);
+ v= det/divdet;
+
+ if(v<0.0 && (u + v) > -1.0) {
+ float labda;
+ det= m0*(t12*t01-t11*t02);
+ det+= m1*(t10*t02-t12*t00);
+ det+= m2*(t11*t00-t10*t01);
+ labda= det/divdet;
+
+ if(labda>0.0 && labda<1.0) {
+ is->labda= labda;
+ is->u= u; is->v= v;
+ ok= 1;
+ }
+ }
+ }
+ }
+
+ if(ok==0 && v4) {
+
+ t20= v3->co[0]-v4->co[0];
+ t21= v3->co[1]-v4->co[1];
+ t22= v3->co[2]-v4->co[2];
+
+ divdet= t20*x0+t21*x1+t22*x2;
+ if(divdet!=0.0) {
+ float u= det1/divdet;
+
+ if(u<0.0) {
+ float v;
+ det= t20*(m1*r2-m2*r1);
+ det+= t21*(m2*r0-m0*r2);
+ det+= t22*(m0*r1-m1*r0);
+ v= det/divdet;
+
+ if(v<0.0 && (u + v) > -1.0) {
+ float labda;
+ det= m0*(t12*t21-t11*t22);
+ det+= m1*(t10*t22-t12*t20);
+ det+= m2*(t11*t20-t10*t21);
+ labda= det/divdet;
+
+ if(labda>0.0 && labda<1.0) {
+ ok= 2;
+ is->labda= labda;
+ is->u= u; is->v= v;
+ }
+ }
+ }
+ }
+ }
+
+ if(ok) {
+ is->isect= ok; // wich half of the quad
+
+ if(is->mode==DDA_MIRROR) {
+ /* for mirror: large faces can be filled in too often, this prevents
+ a face being detected too soon... */
+ if(is->labda > is->ddalabda) {
+ is->vlr->raycount= 0;
+ return 0;
+ }
+ }
+
+ /* when a shadow ray leaves a face, it can be little outside the edges of it, causing
+ intersection to be detected in its neighbour face */
+
+ if(is->vlrcontr && vlrisect); // optimizing, the tests below are not needed
+ else if(is->labda< .1) {
+ short de= 0;
+
+ if(v1==R.vlr->v1 || v2==R.vlr->v1 || v3==R.vlr->v1 || v4==R.vlr->v1) de++;
+ if(v1==R.vlr->v2 || v2==R.vlr->v2 || v3==R.vlr->v2 || v4==R.vlr->v2) de++;
+ if(v1==R.vlr->v3 || v2==R.vlr->v3 || v3==R.vlr->v3 || v4==R.vlr->v3) de++;
+ if(R.vlr->v4) {
+ if(v1==R.vlr->v4 || v2==R.vlr->v4 || v3==R.vlr->v4 || v4==R.vlr->v4) de++;
+ }
+ if(de) {
+
+ /* so there's a shared edge or vertex, let's intersect ray with R.vlr
+ itself, if that's true we can safely return 1, otherwise we assume
+ the intersection is invalid, 0 */
+
+ if(is->vlrcontr==NULL) {
+ is->vlrcontr= R.vlr;
+ vlrisect= intersection2(r0, r1, r2, is->start[0], is->start[1], is->start[2]);
+ }
+
+ if(vlrisect) return 1;
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* check all faces in this node */
+static int testnode(Isect *is, Node *no, int x, int y, int z)
+{
+ VlakRen *vlr;
+ short nr=0, ocvaldone=0;
+ OcVal ocval, *ov;
+
+ if(is->mode==DDA_SHADOW) {
+ // int count= 0;
+ vlr= no->v[0];
+ while(vlr) {
+
+ //count++;
+ //if(count>maxnodeface) maxnodeface= count;
+
+ if(raycount != vlr->raycount) {
+
+ if(ocvaldone==0) {
+ calc_ocval_ray(&ocval, (float)x, (float)y, (float)z, 0.0, 0.0, 0.0);
+ ocvaldone= 1;
+ }
+
+ ov= no->ov+nr;
+ if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
+ //accepted++;
+ is->vlr= vlr;
+ if(intersection(is)) {
+ g_oc.vlr_last= vlr;
+ return 1;
+ }
+ }
+ //else rejected++;
+ }
+
+ nr++;
+ if(nr==8) {
+ no= no->next;
+ if(no==0) return 0;
+ nr=0;
+ }
+ vlr= no->v[nr];
+ }
+ }
+ else { /* else mirror and glass */
+ Isect isect;
+ int found= 0;
+
+ is->labda= 1.0; /* needed? */
+ isect= *is; /* copy for sorting */
+
+ vlr= no->v[0];
+ while(vlr) {
+
+ if(raycount != vlr->raycount) {
+
+ if(ocvaldone==0) {
+ calc_ocval_ray(&ocval, (float)x, (float)y, (float)z, 0.0, 0.0, 0.0);
+ ocvaldone= 1;
+ }
+
+ ov= no->ov+nr;
+ if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
+ //accepted++;
+
+ isect.vlr= vlr;
+ if(intersection(&isect)) {
+ if(isect.labda<is->labda) *is= isect;
+ found= 1;
+ }
+ }
+ //else rejected++;
+ }
+
+ nr++;
+ if(nr==8) {
+ no= no->next;
+ if(no==NULL) break;
+ nr=0;
+ }
+ vlr= no->v[nr];
+ }
+
+ return found;
+ }
+
+ return 0;
+}
+
+/* find the Node for the octree coord x y z */
+static Node *ocread(int x, int y, int z)
+{
+ static int mdiff=0, xo=OCRES, yo=OCRES, zo=OCRES;
+ Branch *br;
+ int oc1, diff;
+
+ diff= (xo ^ x) | (yo ^ y) | (zo ^ z);
+
+ if(diff>mdiff) {
+
+ /* outside of octree check */
+ if( (x & ~(OCRES-1)) || (y & ~(OCRES-1)) || (z & ~(OCRES-1)) ) return NULL;
+
+ xo=x; yo=y; zo=z;
+ x<<=2;
+ y<<=1;
+
+ oc1= ((x & 128)+(y & 64)+(z & 32))>>5;
+ br= g_oc.adrbranch[0]->b[oc1];
+ if(br) {
+
+ oc1= ((x & 64)+(y & 32)+(z & 16))>>4;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 32)+(y & 16)+(z & 8))>>3;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 16)+(y & 8)+(z & 4))>>2;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 8)+(y & 4)+(z & 2))>>1;
+ br= br->b[oc1];
+ if(br) {
+ mdiff=0;
+ oc1= ((x & 4)+(y & 2)+(z & 1));
+ return (Node *)br->b[oc1];
+ }
+ else mdiff=1;
+ }
+ else mdiff=3;
+ }
+ else mdiff=7;
+ }
+ else mdiff=15;
+ }
+ else mdiff=31;
+ }
+ return NULL;
+}
+
+static short cliptest(float p, float q, float *u1, float *u2)
+{
+ float r;
+
+ if(p<0.0) {
+ if(q<p) return 0;
+ else if(q<0.0) {
+ r= q/p;
+ if(r>*u2) return 0;
+ else if(r>*u1) *u1=r;
+ }
+ }
+ else {
+ if(p>0.0) {
+ if(q<0.0) return 0;
+ else if(q<p) {
+ r= q/p;
+ if(r<*u1) return 0;
+ else if(r<*u2) *u2=r;
+ }
+ }
+ else if(q<0.0) return 0;
+ }
+ return 1;
+}
+
+/* return 1: found valid intersection */
+/* starts with global R.vlr */
+static int d3dda(Isect *is)
+{
+ Node *no;
+ float u1,u2,ox1,ox2,oy1,oy2,oz1,oz2;
+ float labdao,labdax,ldx,labday,ldy,labdaz,ldz, ddalabda;
+ float vec1[3], vec2[3];
+ int dx,dy,dz;
+ int xo,yo,zo,c1=0;
+ int ocx1,ocx2,ocy1, ocy2,ocz1,ocz2;
+
+ /* clip with octree */
+ if(branchcount==0) return NULL;
+
+ /* do this before intersect calls */
+ raycount++;
+ R.vlr->raycount= raycount;
+ is->vlrcontr= NULL; /* to check shared edge */
+
+ /* only for shadow! */
+ if(is->mode==DDA_SHADOW && g_oc.vlr_last && g_oc.vlr_last!=R.vlr) {
+ is->vlr= g_oc.vlr_last;
+ if(intersection(is)) return 1;
+ }
+
+ ldx= is->end[0] - is->start[0];
+ u1= 0.0;
+ u2= 1.0;
+
+ /* clip with octree cube */
+ if(cliptest(-ldx, is->start[0]-g_oc.min[0], &u1,&u2)) {
+ if(cliptest(ldx, g_oc.max[0]-is->start[0], &u1,&u2)) {
+ ldy= is->end[1] - is->start[1];
+ if(cliptest(-ldy, is->start[1]-g_oc.min[1], &u1,&u2)) {
+ if(cliptest(ldy, g_oc.max[1]-is->start[1], &u1,&u2)) {
+ ldz= is->end[2] - is->start[2];
+ if(cliptest(-ldz, is->start[2]-g_oc.min[2], &u1,&u2)) {
+ if(cliptest(ldz, g_oc.max[2]-is->start[2], &u1,&u2)) {
+ c1=1;
+ if(u2<1.0) {
+ is->end[0]= is->start[0]+u2*ldx;
+ is->end[1]= is->start[1]+u2*ldy;
+ is->end[2]= is->start[2]+u2*ldz;
+ }
+ if(u1>0.0) {
+ is->start[0]+=u1*ldx;
+ is->start[1]+=u1*ldy;
+ is->start[2]+=u1*ldz;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if(c1==0) return 0;
+
+ /* setup 3dda to traverse octree */
+ ox1= (is->start[0]-g_oc.min[0])*g_oc.ocfacx;
+ oy1= (is->start[1]-g_oc.min[1])*g_oc.ocfacy;
+ oz1= (is->start[2]-g_oc.min[2])*g_oc.ocfacz;
+ ox2= (is->end[0]-g_oc.min[0])*g_oc.ocfacx;
+ oy2= (is->end[1]-g_oc.min[1])*g_oc.ocfacy;
+ oz2= (is->end[2]-g_oc.min[2])*g_oc.ocfacz;
+
+ ocx1= (int)ox1;
+ ocy1= (int)oy1;
+ ocz1= (int)oz1;
+ ocx2= (int)ox2;
+ ocy2= (int)oy2;
+ ocz2= (int)oz2;
+
+ if(ocx1==ocx2 && ocy1==ocy2 && ocz1==ocz2) {
+ /* no calc, this is store */
+ calc_ocval_ray(NULL, ox1, oy1, oz1, ox2, oy2, oz2);
+
+ no= ocread(ocx1, ocy1, ocz1);
+ if(no) {
+ is->ddalabda= 1.0;
+ if( testnode(is, no, ocx1, ocy1, ocz1) ) return 1;
+ }
+ }
+ else {
+ float dox, doy, doz;
+
+ dox= ox1-ox2;
+ doy= oy1-oy2;
+ doz= oz1-oz2;
+
+ /* calc labda en ld */
+ if(dox!=0.0) {
+ if(dox<0.0) {
+ labdax= (ox1-ocx1-1.0)/dox;
+ ldx= -1.0/dox;
+ dx= 1;
+ } else {
+ labdax= (ox1-ocx1)/dox;
+ ldx= 1.0/dox;
+ dx= -1;
+ }
+ } else {
+ labdax=1.0;
+ ldx=0;
+ dx= 0;
+ }
+
+ if(doy!=0.0) {
+ if(doy<0.0) {
+ labday= (oy1-ocy1-1.0)/doy;
+ ldy= -1.0/doy;
+ dy= 1;
+ } else {
+ labday= (oy1-ocy1)/doy;
+ ldy= 1.0/doy;
+ dy= -1;
+ }
+ } else {
+ labday=1.0;
+ ldy=0;
+ dy= 0;
+ }
+
+ if(doz!=0.0) {
+ if(doz<0.0) {
+ labdaz= (oz1-ocz1-1.0)/doz;
+ ldz= -1.0/doz;
+ dz= 1;
+ } else {
+ labdaz= (oz1-ocz1)/doz;
+ ldz= 1.0/doz;
+ dz= -1;
+ }
+ } else {
+ labdaz=1.0;
+ ldz=0;
+ dz= 0;
+ }
+
+ xo=ocx1; yo=ocy1; zo=ocz1;
+ ddalabda= MIN3(labdax,labday,labdaz);
+
+ // dox,y,z is negative
+ vec2[0]= ox1;
+ vec2[1]= oy1;
+ vec2[2]= oz1;
+
+ /* this loop has been constructed to make sure the first and last node of ray
+ are always included, even when ddalabda==1.0 or larger */
+ while(TRUE) {
+
+ no= ocread(xo, yo, zo);
+ if(no) {
+
+ /* calculate ray intersection with octree node */
+ VECCOPY(vec1, vec2);
+ // dox,y,z is negative
+ vec2[0]= ox1-ddalabda*dox;
+ vec2[1]= oy1-ddalabda*doy;
+ vec2[2]= oz1-ddalabda*doz;
+ /* no calc, this is store */
+ calc_ocval_ray(NULL, vec1[0], vec1[1], vec1[2], vec2[0], vec2[1], vec2[2]);
+
+ is->ddalabda= ddalabda;
+ if( testnode(is, no, xo,yo,zo) ) return 1;
+ }
+
+ labdao= ddalabda;
+
+ if(labdax<labday) {
+ if(labday<labdaz) {
+ xo+=dx;
+ labdax+=ldx;
+ } else if(labdax<labdaz) {
+ xo+=dx;
+ labdax+=ldx;
+ } else {
+ zo+=dz;
+ labdaz+=ldz;
+ if(labdax==labdaz) {
+ xo+=dx;
+ labdax+=ldx;
+ }
+ }
+ } else if(labdax<labdaz) {
+ yo+=dy;
+ labday+=ldy;
+ if(labday==labdax) {
+ xo+=dx;
+ labdax+=ldx;
+ }
+ } else if(labday<labdaz) {
+ yo+=dy;
+ labday+=ldy;
+ } else if(labday<labdax) {
+ zo+=dz;
+ labdaz+=ldz;
+ if(labdaz==labday) {
+ yo+=dy;
+ labday+=ldy;
+ }
+ } else {
+ xo+=dx;
+ labdax+=ldx;
+ yo+=dy;
+ labday+=ldy;
+ zo+=dz;
+ labdaz+=ldz;
+ }
+
+ ddalabda=MIN3(labdax,labday,labdaz);
+ if(ddalabda==labdao) break;
+ /* to make sure the last node is always checked */
+ if(labdao>=1.0) break;
+ }
+ }
+
+ /* reached end, no intersections found */
+ g_oc.vlr_last= NULL;
+ return 0;
+}
+
+/* for now; mostly a duplicate of shadepixel() itself... could be unified once */
+/* R.view has been set */
+static void shade_ray(Isect *is, int mask)
+{
+ extern void shade_lamp_loop(int );
+ VertRen *v1, *v2, *v3;
+ float n1[3], n2[3], n3[3];
+ float *o1, *o2, *o3;
+ float u, v, l;
+ int flip= 0;
+ char p1, p2, p3;
+
+ R.co[0]= is->start[0]+is->labda*(is->end[0]-is->start[0]);
+ R.co[1]= is->start[1]+is->labda*(is->end[1]-is->start[1]);
+ R.co[2]= is->start[2]+is->labda*(is->end[2]-is->start[2]);
+
+ R.vlaknr= -1; // signal to reset static variables in rendercore.c shadepixel
+
+ R.vlr= is->vlr;
+ R.mat= R.vlr->mat;
+ R.matren= R.mat->ren;
+ R.osatex= (R.matren->texco & TEXCO_OSA);
+
+ /* face normal, check for flip */
+ R.vno= R.vlr->n;
+ l= R.vlr->n[0]*R.view[0]+R.vlr->n[1]*R.view[1]+R.vlr->n[2]*R.view[2];
+ if(l<0.0) {
+ flip= 1;
+ R.vlr->n[0]= -R.vlr->n[0];
+ R.vlr->n[1]= -R.vlr->n[1];
+ R.vlr->n[2]= -R.vlr->n[2];
+ R.vlr->puno= ~(R.vlr->puno);
+ }
+
+ if(R.vlr->v4) {
+ if(is->isect==2) {
+ v1= R.vlr->v3;
+ p1= ME_FLIPV3;
+ } else {
+ v1= R.vlr->v1;
+ p1= ME_FLIPV1;
+ }
+ v2= R.vlr->v2;
+ v3= R.vlr->v4;
+ p2= ME_FLIPV2; p3= ME_FLIPV4;
+ }
+ else {
+ v1= R.vlr->v1;
+ v2= R.vlr->v2;
+ v3= R.vlr->v3;
+ p1= ME_FLIPV1; p2= ME_FLIPV2; p3= ME_FLIPV3;
+ }
+
+ if(R.vlr->flag & R_SMOOTH) { /* adjust punos (vertexnormals) */
+ if(R.vlr->puno & p1) {
+ n1[0]= -v1->n[0]; n1[1]= -v1->n[1]; n1[2]= -v1->n[2];
+ } else {
+ n1[0]= v1->n[0]; n1[1]= v1->n[1]; n1[2]= v1->n[2];
+ }
+ if(R.vlr->puno & p2) {
+ n2[0]= -v2->n[0]; n2[1]= -v2->n[1]; n2[2]= -v2->n[2];
+ } else {
+ n2[0]= v2->n[0]; n2[1]= v2->n[1]; n2[2]= v2->n[2];
+ }
+
+ if(R.vlr->puno & p3) {
+ n3[0]= -v3->n[0]; n3[1]= -v3->n[1]; n3[2]= -v3->n[2];
+ } else {
+ n3[0]= v3->n[0]; n3[1]= v3->n[1]; n3[2]= v3->n[2];
+ }
+ }
+
+ u= is->u;
+ v= is->v;
+
+ // Osa structs we leave unchanged now
+
+
+ /* UV and TEX*/
+ if( (R.vlr->flag & R_SMOOTH) || (R.matren->texco & NEED_UV)) {
+
+ l= 1.0+u+v;
+
+ if(R.vlr->flag & R_SMOOTH) {
+ R.vn[0]= l*n3[0]-u*n1[0]-v*n2[0];
+ R.vn[1]= l*n3[1]-u*n1[1]-v*n2[1];
+ R.vn[2]= l*n3[2]-u*n1[2]-v*n2[2];
+
+ Normalise(R.vn);
+ }
+ else {
+ VECCOPY(R.vn, R.vlr->n);
+ }
+
+ if(R.matren->texco & TEXCO_ORCO) {
+ if(v2->orco) {
+ o1= v1->orco;
+ o2= v2->orco;
+ o3= v3->orco;
+
+ R.lo[0]= l*o3[0]-u*o1[0]-v*o2[0];
+ R.lo[1]= l*o3[1]-u*o1[1]-v*o2[1];
+ R.lo[2]= l*o3[2]-u*o1[2]-v*o2[2];
+
+ }
+ }
+
+ if(R.matren->texco & TEXCO_GLOB) {
+ VECCOPY(R.gl, R.co);
+ Mat4MulVecfl(R.viewinv, R.gl);
+ }
+ if(R.matren->texco & TEXCO_NORM) {
+ R.orn[0]= R.vn[0];
+ R.orn[1]= -R.vn[1];
+ R.orn[2]= R.vn[2];
+ }
+
+ if((R.matren->texco & TEXCO_UV) || (R.matren->mode & (MA_VERTEXCOL|MA_FACETEXTURE))) {
+ if(R.vlr->tface) {
+ float *uv1, *uv2, *uv3;
+
+ if( R.vlr->v4 || (R.vlr->flag & R_FACE_SPLIT) ) {
+ if(is->isect==2) uv1= R.vlr->tface->uv[2];
+ else uv1= R.vlr->tface->uv[0];
+ uv2= R.vlr->tface->uv[1];
+ uv3= R.vlr->tface->uv[3];
+ }
+ else {
+ uv1= R.vlr->tface->uv[0];
+ uv2= R.vlr->tface->uv[1];
+ uv3= R.vlr->tface->uv[2];
+ }
+
+ R.uv[0]= -1.0 + 2.0*(l*uv3[0]-u*uv1[0]-v*uv2[0]);
+ R.uv[1]= -1.0 + 2.0*(l*uv3[1]-u*uv1[1]-v*uv2[1]);
+ }
+ else {
+ R.uv[0]= 2.0*(u+.5);
+ R.uv[1]= 2.0*(v+.5);
+ }
+ }
+
+ if(R.matren->mode & MA_VERTEXCOL) {
+ char *cp3, *cp2, *cp1= (char *)R.vlr->vcol;
+ if(cp1) {
+ if( R.vlr->v4 || (R.vlr->flag & R_FACE_SPLIT) ) {
+ if(is->isect==2) cp1= (char *)(R.vlr->vcol+2);
+ else cp1= (char *)(R.vlr->vcol+0);
+
+ cp2= (char *)(R.vlr->vcol+1);
+ cp3= (char *)(R.vlr->vcol+3);
+ }
+ else {
+ cp1= (char *)(R.vlr->vcol+0);
+ cp2= (char *)(R.vlr->vcol+1);
+ cp3= (char *)(R.vlr->vcol+2);
+ }
+ R.vcol[0]= (l*cp3[3]-u*cp1[3]-v*cp2[3])/255.0;
+ R.vcol[1]= (l*cp3[2]-u*cp1[2]-v*cp2[2])/255.0;
+ R.vcol[2]= (l*cp3[1]-u*cp1[1]-v*cp2[1])/255.0;
+
+ }
+ else {
+ R.vcol[0]= 0.0;
+ R.vcol[1]= 0.0;
+ R.vcol[2]= 0.0;
+ }
+ }
+ if(R.matren->mode & MA_RADIO) {
+ R.rad[0]= (l*v3->rad[0] - u*v1->rad[0] - v*v2->rad[0]);
+ R.rad[1]= (l*v3->rad[1] - u*v1->rad[1] - v*v2->rad[1]);
+ R.rad[2]= (l*v3->rad[2] - u*v1->rad[2] - v*v2->rad[2]);
+ }
+ else {
+ R.rad[0]= R.rad[1]= R.rad[2]= 0.0;
+ }
+ if(R.matren->mode & MA_FACETEXTURE) {
+ if((R.matren->mode & MA_VERTEXCOL)==0) {
+ R.vcol[0]= 1.0;
+ R.vcol[1]= 1.0;
+ R.vcol[2]= 1.0;
+ }
+ if(R.vlr->tface) render_realtime_texture();
+ }
+ }
+ else {
+ VECCOPY(R.vn, R.vlr->n);
+ }
+
+ shade_lamp_loop(mask);
+
+ if(flip) {
+ R.vlr->n[0]= -R.vlr->n[0];
+ R.vlr->n[1]= -R.vlr->n[1];
+ R.vlr->n[2]= -R.vlr->n[2];
+ R.vlr->puno= ~(R.vlr->puno);
+ }
+}
+
+/* the main recursive tracer itself */
+static void traceray(float f, short depth, float *start, float *vec, float *col, int mask)
+{
+ extern unsigned short shortcol[4]; // only for old render, which stores ushort
+ Isect isec;
+ float f1, fr, fg, fb;
+ float ref[3];
+
+ if(depth<0) return;
+
+ fr= R.mat->mirr;
+ fg= R.mat->mirg;
+ fb= R.mat->mirb;
+
+ VECCOPY(isec.start, start);
+ isec.end[0]= start[0]+g_oc.ocsize*vec[0];
+ isec.end[1]= start[1]+g_oc.ocsize*vec[1];
+ isec.end[2]= start[2]+g_oc.ocsize*vec[2];
+ isec.mode= DDA_MIRROR;
+
+ if( d3dda(&isec) ) {
+
+ /* set up view vector */
+ VECCOPY(R.view, vec);
+ Normalise(R.view);
+
+ shade_ray(&isec, mask); // returns shortcol
+
+ f1= 1.0-f;
+
+ col[0]= f*fr*(shortcol[0]/65535.0)+ f1*col[0];
+ col[1]= f*fg*(shortcol[1]/65535.0)+ f1*col[1];
+ col[2]= f*fb*(shortcol[2]/65535.0)+ f1*col[2];
+
+ /* is already new material: */
+ if(R.mat->ray_mirror>0.0) {
+ f1= -2*(R.vn[0]*R.view[0]+R.vn[1]*R.view[1]+R.vn[2]*R.view[2]);
+ if(f1> -0.2) f1= -0.2;
+
+ ref[0]= (R.view[0]+f1*R.vn[0]);
+ ref[1]= (R.view[1]+f1*R.vn[1]);
+ ref[2]= (R.view[2]+f1*R.vn[2]);
+
+ f*= R.mat->ray_mirror;
+ traceray(f, depth-1, R.co, ref, col, mask);
+ }
+ }
+ else { /* sky */
+ char skycol[4];
+
+ VECCOPY(R.view, vec);
+ Normalise(R.view);
+
+ RE_sky(skycol);
+
+ f1= 1.0-f;
+
+ f/= 255.0;
+ col[0]= f*fr*skycol[0]+ f1*col[0];
+ col[1]= f*fg*skycol[1]+ f1*col[1];
+ col[2]= f*fb*skycol[2]+ f1*col[2];
+
+ }
+}
+
+/* **************** jitter blocks ********** */
+
+static float jit_plane2[2*2*3]={0.0};
+static float jit_plane3[3*3*3]={0.0};
+static float jit_plane4[4*4*3]={0.0};
+static float jit_plane5[5*5*3]={0.0};
+static float jit_plane6[5*5*3]={0.0};
+static float jit_plane7[7*7*3]={0.0};
+static float jit_plane8[8*8*3]={0.0};
+
+static float jit_cube2[2*2*2*3]={0.0};
+static float jit_cube3[3*3*3*3]={0.0};
+static float jit_cube4[4*4*4*3]={0.0};
+static float jit_cube5[5*5*5*3]={0.0};
+
+/* table around origin, -.5 to 0.5 */
+static float *jitter_plane(int resol)
+{
+ extern float hashvectf[];
+ float dsize, *jit, *fp, *hv;
+ int x, y;
+
+ if(resol<2) resol= 2;
+ if(resol>8) resol= 8;
+
+ switch (resol) {
+ case 2: jit= jit_plane2; break;
+ case 3: jit= jit_plane3; break;
+ case 4: jit= jit_plane4; break;
+ case 5: jit= jit_plane5; break;
+ case 6: jit= jit_plane6; break;
+ case 7: jit= jit_plane7; break;
+ default: jit= jit_plane8; break;
+ }
+ if(jit[0]!=0.0) return jit;
+
+ dsize= 1.0/(resol-1.0);
+ fp= jit;
+ hv= hashvectf;
+ for(x=0; x<resol; x++) {
+ for(y=0; y<resol; y++, fp+= 3, hv+=3) {
+ fp[0]= -0.5 + (x+0.25*hv[0])*dsize;
+ fp[1]= -0.5 + (y+0.25*hv[1])*dsize;
+ fp[2]= fp[0]*fp[0] + fp[1]*fp[1];
+ if(resol>2)
+ if(fp[2]>0.3) fp[2]= 0.0;
+ }
+ }
+
+ return jit;
+}
+
+static void *jitter_cube(int resol)
+{
+ float dsize, *jit, *fp;
+ int x, y, z;
+
+ if(resol<2) resol= 2;
+ if(resol>5) resol= 5;
+
+ switch (resol) {
+ case 2: jit= jit_cube2; break;
+ case 3: jit= jit_cube3; break;
+ case 4: jit= jit_cube4; break;
+ default: jit= jit_cube5; break;
+ }
+ if(jit[0]!=0.0) return jit;
+
+ dsize= 1.0/(resol-1.0);
+ fp= jit;
+ for(x=0; x<resol; x++) {
+ for(y=0; y<resol; y++) {
+ for(z=0; z<resol; z++, fp+= 3) {
+ fp[0]= -0.5 + x*dsize;
+ fp[1]= -0.5 + y*dsize;
+ fp[2]= -0.5 + z*dsize;
+ }
+ }
+ }
+
+ return jit;
+
+}
+
+/* ***************** extern calls ************** */
+
+
+/* extern call from render loop */
+void ray_mirror(int mask)
+{
+ extern unsigned short shortcol[4];
+ float col[4];
+ float i, vec[3];
+
+ col[0]= shortcol[0]/65535.0;
+ col[1]= shortcol[1]/65535.0;
+ col[2]= shortcol[2]/65535.0;
+
+ if(R.r.mode & R_OSA) {
+ extern int usegamtab;
+ VlakRen *vlr;
+ float accum[3], rco[3], rvno[3], memcol[3], ref[3], dxref[3], dyref[3];
+ float div= 0.0;
+ int j, gamtab;
+
+ /* ungamma col! */
+ if(usegamtab) {
+ col[0]= sqrt(col[0]);
+ col[1]= sqrt(col[1]);
+ col[2]= sqrt(col[2]);
+ }
+ accum[0]= accum[1]= accum[2]= 0.0;
+
+ /* store variables which change during tracing */
+ VECCOPY(rco, R.co);
+ VECCOPY(rvno, R.vno);
+ VECCOPY(memcol, col);
+ VECCOPY(ref, R.ref);
+ VECCOPY(dxref, O.dxref);
+ VECCOPY(dyref, O.dyref);
+ gamtab= usegamtab;
+ usegamtab= 0;
+ vlr= R.vlr;
+
+ for(j=0; j<R.osa; j++) {
+ if(mask & 1<<j) {
+ vec[0]= ref[0] + 1.0*(jit[j][0]-0.5)*dxref[0] + 1.0*(jit[j][1]-0.5)*dyref[0] ;
+ vec[1]= ref[1] + 1.0*(jit[j][0]-0.5)*dxref[1] + 1.0*(jit[j][1]-0.5)*dyref[1] ;
+ vec[2]= ref[2] + 1.0*(jit[j][0]-0.5)*dxref[2] + 1.0*(jit[j][1]-0.5)*dyref[2] ;
+
+ /* prevent normal go to backside */
+ i= vec[0]*rvno[0]+ vec[1]*rvno[1]+ vec[2]*rvno[2];
+ if(i>0.0) {
+ i+= .01;
+ vec[0]-= i*rvno[0];
+ vec[1]-= i*rvno[1];
+ vec[2]-= i*rvno[2];
+ }
+
+ R.co[0]+= (jit[j][0]-0.5)*O.dxco[0] + (jit[j][1]-0.5)*O.dyco[0] ;
+ R.co[1]+= (jit[j][0]-0.5)*O.dxco[1] + (jit[j][1]-0.5)*O.dyco[1] ;
+ R.co[2]+= (jit[j][0]-0.5)*O.dxco[2] + (jit[j][1]-0.5)*O.dyco[2] ;
+
+ /* we use a new mask here, only shadow uses it */
+ traceray(R.mat->ray_mirror, R.mat->ray_depth, R.co, vec, col, 1<<j);
+
+ VecAddf(accum, accum, col);
+ div+= 1.0;
+
+ /* restore */
+ VECCOPY(R.co, rco);
+ VECCOPY(col, memcol);
+ R.vlr= vlr;
+ R.mat= vlr->mat;
+ R.matren= R.mat->ren;
+ }
+ }
+ usegamtab= gamtab;
+ col[0]= accum[0]/div;
+ col[1]= accum[1]/div;
+ col[2]= accum[2]/div;
+ if(usegamtab) {
+ col[0]*= col[0];
+ col[1]*= col[1];
+ col[2]*= col[2];
+ }
+ }
+ else {
+ i= -2.0*(R.vn[0]*R.view[0]+R.vn[1]*R.view[1]+R.vn[2]*R.view[2]);
+
+ vec[0]= (R.view[0]+i*R.vn[0]);
+ vec[1]= (R.view[1]+i*R.vn[1]);
+ vec[2]= (R.view[2]+i*R.vn[2]);
+
+ /* test phong normals, then we should prevent vector going to the back */
+ if(R.vlr->flag & R_SMOOTH) {
+ i= vec[0]*R.vno[0]+ vec[1]*R.vno[1]+ vec[2]*R.vno[2];
+ if(i>0.0) {
+ i+= .01;
+ vec[0]-= i*R.vno[0];
+ vec[1]-= i*R.vno[1];
+ vec[2]-= i*R.vno[2];
+ }
+ }
+
+ traceray(R.mat->ray_mirror, R.mat->ray_depth, R.co, vec, col, mask);
+ }
+
+ shortcol[0]= (col[0]>=1.0?65535:col[0]*65535.0);
+ shortcol[1]= (col[1]>=1.0?65535:col[1]*65535.0);
+ shortcol[2]= (col[2]>=1.0?65535:col[2]*65535.0);
+
+
+}
+
+/* extern call from shade_lamp_loop */
+float ray_shadow(LampRen *lar, int mask)
+{
+ Isect isec;
+ float fac, div=0.0, lampco[3];
+
+ isec.mode= DDA_SHADOW;
+
+ if(lar->type==LA_SUN || lar->type==LA_HEMI) {
+ lampco[0]= R.co[0] - g_oc.ocsize*lar->vec[0];
+ lampco[1]= R.co[1] - g_oc.ocsize*lar->vec[1];
+ lampco[2]= R.co[2] - g_oc.ocsize*lar->vec[2];
+ }
+ else {
+ VECCOPY(lampco, lar->co);
+ }
+
+ if(lar->ray_samp<2) {
+ if(R.r.mode & R_OSA) {
+ int j;
+ fac= 0.0;
+ for(j=0; j<R.osa; j++) {
+ if(mask & 1<<j) {
+ isec.start[0]= R.co[0] + (jit[j][0]-0.5)*O.dxco[0] + (jit[j][1]-0.5)*O.dyco[0] ;
+ isec.start[1]= R.co[1] + (jit[j][0]-0.5)*O.dxco[1] + (jit[j][1]-0.5)*O.dyco[1] ;
+ isec.start[2]= R.co[2] + (jit[j][0]-0.5)*O.dxco[2] + (jit[j][1]-0.5)*O.dyco[2] ;
+ VECCOPY(isec.end, lampco);
+ if( d3dda(&isec) ) fac+= 1.0;
+ div+= 1.0;
+ }
+ }
+ return fac/div;
+ }
+ else {
+ VECCOPY(isec.start, R.co);
+ VECCOPY(isec.end, lampco);
+ if( d3dda(&isec)) return 1.0;
+ }
+ }
+ else {
+ float *jitlamp;
+ float vec[3];
+ int a, j=0;
+
+ VECCOPY(isec.start, R.co);
+
+ fac= 0.0;
+ a= lar->ray_samp*lar->ray_samp;
+ jitlamp= jitter_plane(lar->ray_samp);
+
+ while(a--) {
+ if(jitlamp[2]!=0.0) {
+ vec[0]= lar->ray_soft*jitlamp[0];
+ vec[1]= lar->ray_soft*jitlamp[1];
+ vec[2]= 0.0;
+ Mat3TransMulVecfl(lar->imat, vec);
+
+ isec.end[0]= lampco[0]+vec[0];
+ isec.end[1]= lampco[1]+vec[1];
+ isec.end[2]= lampco[2]+vec[2];
+
+ if(R.r.mode & R_OSA) {
+ isec.start[0]= R.co[0] + (jit[j][0]-0.5)*O.dxco[0] + (jit[j][1]-0.5)*O.dyco[0] ;
+ isec.start[1]= R.co[1] + (jit[j][0]-0.5)*O.dxco[1] + (jit[j][1]-0.5)*O.dyco[1] ;
+ isec.start[2]= R.co[2] + (jit[j][0]-0.5)*O.dxco[2] + (jit[j][1]-0.5)*O.dyco[2] ;
+ j++;
+ if(j>=R.osa) j= 0;
+ }
+
+ if( d3dda(&isec) ) fac+= 1.0;
+ div+= 1.0;
+ }
+ jitlamp+= 3;
+ }
+ return fac/div;
+ }
+ return 0.0;
+}
+
diff --git a/source/blender/render/intern/source/renderPreAndPost.c b/source/blender/render/intern/source/renderPreAndPost.c
index 63a59bc659b..fd33d054e64 100644
--- a/source/blender/render/intern/source/renderPreAndPost.c
+++ b/source/blender/render/intern/source/renderPreAndPost.c
@@ -55,7 +55,7 @@
void prepareScene()
{
int a;
-
+ extern void makeoctree(void);
if(R.rectot) MEM_freeN(R.rectot);
R.rectot= 0;
@@ -85,12 +85,18 @@ void prepareScene()
/* ENVIRONMENT MAPS */
make_envmaps();
+
+ /* octree */
+ if(R.r.mode & R_RAYTRACE) makeoctree();
}
void finalizeScene(void)
{
+ extern void freeoctree(void);
+
/* Among other things, it releases the shadow buffers. */
RE_local_free_renderdata();
+ if(R.r.mode & R_RAYTRACE) freeoctree();
}
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index d4af7fe26b7..2a7bad2f96e 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -1552,7 +1552,8 @@ void RE_calc_R_ref()
}
-void shade_lamp_loop()
+/* mask is used to define the amount of rays/samples */
+void shade_lamp_loop(int mask)
{
LampRen *lar;
Material *ma;
@@ -1615,7 +1616,7 @@ void shade_lamp_loop()
ma->b= R.vcol[2];
}
- /* mirror reflection colour */
+ /* mirror reflection colour textures (envmap) */
R.refcol[0]= R.refcol[1]= R.refcol[2]= R.refcol[3]= 0.0;
if(ma->texco) {
@@ -1807,16 +1808,29 @@ void shade_lamp_loop()
/* shadow and spec */
if(inp> -0.41) { /* heuristic value */
shadfac= 1.0;
- if(lar->shb) {
+ if(i>0.0 && (R.r.mode & R_SHADOW)) {
if(ma->mode & MA_SHADOW) {
- shadfac = testshadowbuf(lar->shb, inp);
- if(shadfac==0.0) continue;
- i*= shadfac;
+
+ if(lar->shb) {
+ shadfac = testshadowbuf(lar->shb, inp);
+ if(shadfac==0.0) continue;
+ i*= shadfac;
+ }
+ else if(lar->mode & LA_SHAD_RAY) {
+ if(R.r.mode & R_RAYTRACE) {
+ extern float ray_shadow(LampRen *, int);
+ /* hurms, single sided? */
+ if( R.vlr->n[0]*lv[0] + R.vlr->n[1]*lv[1] + R.vlr->n[2]*lv[2] > -0.01) {
+ shadfac= (1.0-ray_shadow(lar, mask));
+ i*= shadfac;
+ }
+ }
+ }
}
}
+
/* specularity */
-
- if(ma->spec!=0.0 && !(lar->mode & LA_NO_SPEC)) {
+ if(shadfac>0.0 && ma->spec!=0.0 && !(lar->mode & LA_NO_SPEC)) {
if(lar->type==LA_HEMI) {
/* hemi uses no spec shaders (yet) */
@@ -1859,6 +1873,7 @@ void shade_lamp_loop()
}
}
}
+
/* in case 'no diffuse' we still do most calculus, spec can be in shadow */
if(i>0.0 && !(lar->mode & LA_NO_DIFF)) {
ir+= i*lar->r;
@@ -1916,7 +1931,7 @@ void shade_lamp_loop()
}
-void shadepixel(float x, float y, int vlaknr)
+void shadepixel(float x, float y, int vlaknr, int mask)
/* x,y: window coordinate from 0 to rectx,y */
{
static VlakRen *vlr;
@@ -2035,12 +2050,7 @@ void shadepixel(float x, float y, int vlaknr)
}
/* COXYZ */
- if( (G.special1 & G_HOLO) && ((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) {
- R.view[0]= (x+(R.xstart)+1.0+holoofs);
- }
- else {
- R.view[0]= (x+(R.xstart)+1.0);
- }
+ R.view[0]= (x+(R.xstart)+1.0);
if(R.flag & R_SEC_FIELD) {
if(R.r.mode & R_ODDFIELD) R.view[1]= (y+R.ystart+0.5)*R.ycor;
@@ -2133,7 +2143,7 @@ void shadepixel(float x, float y, int vlaknr)
Normalise(R.vn);
if(R.osatex && (R.matren->texco & (TEXCO_NORM+TEXCO_REFL)) ) {
- dl= O.dxuv[0]+O.dxuv[1];
+ dl= O.dxuv[0]+O.dxuv[1];
O.dxno[0]= dl*n3[0]-O.dxuv[0]*n1[0]-O.dxuv[1]*n2[0];
O.dxno[1]= dl*n3[1]-O.dxuv[0]*n1[1]-O.dxuv[1]*n2[1];
O.dxno[2]= dl*n3[2]-O.dxuv[0]*n1[2]-O.dxuv[1]*n2[2];
@@ -2315,8 +2325,7 @@ void shadepixel(float x, float y, int vlaknr)
R.winco[1]= (y+(R.ystart))/(float)R.afmy;
}
-
- shade_lamp_loop();
+ shade_lamp_loop(mask);
/* MIST */
if( (R.wrld.mode & WO_MIST) && (R.matren->mode & MA_NOMIST)==0 ){
@@ -2324,8 +2333,12 @@ void shadepixel(float x, float y, int vlaknr)
}
else alpha= 1.0;
- /* RAYTRACE WAS HERE! */
-
+ /* RAYTRACE IS BACK HERE! */
+ if(R.r.mode & R_RAYTRACE) {
+ extern void ray_mirror(int);
+ if(R.matren->ray_mirror!=0.0) ray_mirror(mask);
+ }
+
if(R.matren->alpha!=1.0 || alpha!=1.0) {
fac= alpha*(R.matren->alpha);
@@ -2714,7 +2727,7 @@ void zbufshadeDA(void) /* Delta Accum Pixel Struct */
xs= (float)x+centLut[b & 15];
ys= (float)y+centLut[b>>4];
- shadepixel(xs, ys, ps->vlak);
+ shadepixel(xs, ys, ps->vlak, ps->mask);
if(shortcol[3]) {
add_filt_mask(ps->mask, shortcol, rb1, rb2, rb3);
@@ -2730,14 +2743,14 @@ void zbufshadeDA(void) /* Delta Accum Pixel Struct */
xs= (float)x+centLut[b & 15];
ys= (float)y+centLut[b>>4];
- shadepixel(xs, ys, ps->vlak0);
+ shadepixel(xs, ys, ps->vlak0, mask);
if(shortcol[3]) {
add_filt_mask(mask, shortcol, rb1, rb2, rb3);
}
}
else {
- shadepixel((float)x, (float)y, (int)*rd);
+ shadepixel((float)x, (float)y, (int)*rd, fullmask);
if(shortcol[3]) {
add_filt_mask(fullmask, shortcol, rb1, rb2, rb3);
}
@@ -2863,7 +2876,7 @@ void zbufshade(void)
for(x=0; x<R.rectx; x++, rp++, acol+= 4) {
/* spothalo's added here... *rp is the target colour? */
- shadepixel((float)x, fy, *rp);
+ shadepixel((float)x, fy, *rp, 0);
if(acol[3]) addAlphaOverShort(shortcol, acol);
@@ -2879,7 +2892,7 @@ void zbufshade(void)
}
else {
for(x=0; x<R.rectx; x++, rp++) {
- shadepixel((float)x, fy, *rp);
+ shadepixel((float)x, fy, *rp, 0);
if(shortcol[3]) {
rt= (char *)rp;
rt[0]= charcol[0];
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 608b274de41..6410bd44fa5 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -2170,14 +2170,14 @@ int vergzvlak(const void *a1, const void *a2)
return 0;
}
-void shadetrapixel(float x, float y, int vlak)
+void shadetrapixel(float x, float y, int vlak, int mask)
{
if( (vlak & 0x7FFFFF) > R.totvlak) {
printf("error in shadetrapixel nr: %d\n", (vlak & 0x7FFFFF));
return;
}
- shadepixel(x, y, vlak);
+ shadepixel(x, y, vlak, mask);
}
extern unsigned short usegamtab;
@@ -2253,7 +2253,7 @@ void abufsetrow(int y)
else {
xs= x; ys= y;
}
- shadetrapixel(xs, ys, ap->p[0]);
+ shadetrapixel(xs, ys, ap->p[0], ap->mask[0]);
nr= count_mask(ap->mask[0]);
if( (R.r.mode & R_OSA) && nr<R.osa) {
@@ -2297,7 +2297,7 @@ void abufsetrow(int y)
else {
xs= x; ys= y;
}
- shadetrapixel(xs, ys, zrow[totvlak][1]);
+ shadetrapixel(xs, ys, zrow[totvlak][1], 0xFFFF);
a= count_mask(zrow[totvlak][2]);
if( (R.r.mode & R_OSA ) && a<R.osa) {
@@ -2316,7 +2316,7 @@ void abufsetrow(int y)
xs= (float)x+centLut[b & 15];
ys= (float)y+centLut[b>>4];
- shadetrapixel(xs, ys, zrow[totvlak][1]);
+ shadetrapixel(xs, ys, zrow[totvlak][1], zrow[totvlak][2]);
sval= addtosampcol(sampcol, shortcol, zrow[totvlak][2]);
}
scol= sampcol;