152
142
int osaNr; /* The oversample number. I keep it */
153
143
/* separately here, because I treat no OSA */
154
144
/* as if it were osa=1. */
155
RE_COLBUFTYPE collector[4]; /* used throughout as pixel colour accu */
156
RE_COLBUFTYPE sampcol[RE_MAX_OSA_COUNT * 4]; /* subpixel accu buffer */
158
/* ------------------------------------------------------------------------- */
159
/* Local (for now) */
160
/* void integrateStack(struct RE_faceField* stack, */
165
void integratePerSubStack(struct RE_faceField* stack,
171
/* ------------------------------------------------------------------------- */
173
void zBufShadeAdvanced()
175
int y, keepLooping = 1;
176
float xjit = 0.0, yjit = 0.0;
178
Zjitx=Zjity= -0.5; /* jitter preset: 0.5 pixel */
180
/* EDGE: for edge rendering we should compute a larger buffer, but this */
181
/* may require modifications at a deeper level. For now, we just */
182
/* 'ignore' edge pixels. */
183
imageHeight = R.recty;
184
imageWidth = R.rectx;
185
bufferHeight = R.recty;
186
bufferWidth = R.rectx;
188
/* Set osaNr. Treat 'no osa' as 'osa = 1' */
189
if(R.r.mode & R_OSA) {
191
if(osaNr > 16) { /* check was moved from calcZBufLine */
192
printf("zBufShadeAdvanced> osa too large (internal error)\n");
205
RE_setwindowclip(0, -1); /* just to be sure, reset the view matrix */
207
initRenderBuffers(bufferWidth);
209
/* ugh! should be converted sooner!! */
210
switch (R.r.alphamode) {
212
setSkyBlendingMode(RE_ALPHA_KEY);
215
setSkyBlendingMode(RE_ALPHA_PREMUL);
217
/* not there... this is the default case */
218
/* case R_ALPHASKY: */
219
/* setSkyBlendingMode(RE_ALPHA_SKY); */
222
setSkyBlendingMode(RE_ALPHA_SKY);
226
while ( (y < bufferHeight) && keepLooping) {
230
transferColourBufferToOutput(y);
232
if(y & 1) RE_local_render_display(y-1, y, imageWidth, imageHeight, R.rectot);
234
if(RE_local_test_break()) keepLooping = 0;
239
/* Edge rendering is done purely as a post-effect */
240
if(R.r.mode & R_EDGE) {
241
addEdges((char*)R.rectot, imageWidth, imageHeight,
243
R.r.edgeint, R.r.same_mat_redux,
244
G.compat, G.notonlysolid,
245
R.r.edgeR, R.r.edgeG, R.r.edgeB);
248
add_halo_flare(); /* from rendercore */
250
if (!(R.r.mode & R_OSA)) {
255
} /* end of void zbufshadeAdvanced() */
257
/* ------------------------------------------------------------------------- */
259
void initRenderBuffers(int bwidth)
146
/* ------------------------------------------------------------------------- */
149
* Z buffer initializer, for new pipeline.
151
* <IT> AColourBuffer : colour buffer for one line
152
* <IT> APixbufExt : pixel data buffer for one line, depth RE_ZBUFLEN
155
static void initRenderBuffers(int bwidth)
157
/* bwidth+4, as in rendercore.c. I think it's too much, but yah (ton) */
158
AColourBuffer0 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow");
159
AColourBuffer1 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow");
160
AColourBuffer2 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow");
161
AColourBuffer1a = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow");
162
AColourBuffer2a = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow");
163
AColourBuffer3 = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * (bwidth+4), "Acolrow");
262
165
/* The +1 is needed because the fill-functions use a +1 offset when */
263
166
/* filling in pixels. Mind that also the buffer-clearing function needs */
264
167
/* this offset (done in calcZBufLine). */
265
168
/* The offset is wrong: it shouldn't be there. I need to fix this still. */
266
AColourBuffer = MEM_callocN(4 * sizeof(RE_COLBUFTYPE) * bwidth,
268
169
zBufferWidth = bwidth + 1;
269
170
initZbuffer(bwidth + 1);
271
172
Aminy= -1000; /* indices of lines in the z buffer: no lines buffered */
274
/* Use slider when the gamma button is pressed. */
275
if (R.r.mode & R_GAMMA) {
276
makeGammaTables(R.r.gamma);
280
Needed for spotlights! Maybe a separate gammatable would be
283
makeGammaTables(1.0);
287
} /* End of void initZBuffers(void) */
289
178
/* ------------------------------------------------------------------------- */
180
* Z buffer destructor, frees stuff from initZBuffers().
291
void freeRenderBuffers(void) {
292
if (AColourBuffer) MEM_freeN(AColourBuffer);
183
static void freeRenderBuffers(void) {
184
if (AColourBuffer0) MEM_freeN(AColourBuffer0);
185
if (AColourBuffer1) MEM_freeN(AColourBuffer1);
186
if (AColourBuffer2) MEM_freeN(AColourBuffer2);
187
if (AColourBuffer1a) MEM_freeN(AColourBuffer1a);
188
if (AColourBuffer2a) MEM_freeN(AColourBuffer2a);
189
if (AColourBuffer3) MEM_freeN(AColourBuffer3);
294
} /* End of void freeZBuffers(void) */
296
/* ------------------------------------------------------------------------- */
298
void calcZBufLine(int y)
306
/* zbuffer fix: here? */
307
Zmulx= ((float) bufferWidth)/2.0;
308
Zmuly= ((float) bufferHeight)/2.0;
311
/* use these buffer fill functions */
312
zbuffunc = zBufferFillFace;
313
zbuflinefunc = zBufferFillEdge;
315
/* (FORALL y: Aminy =< y =< Amaxy: y is buffered) */
316
if( (y < Aminy) || (y > Amaxy)) {
318
part = (y/RE_ZBUFLEN); /* These two lines are mystifying me... */
319
Aminy = part * RE_ZBUFLEN; /* Possibly for rounding things? */
320
Amaxy = Aminy + RE_ZBUFLEN - 1;
321
/* if(Amaxy >= R.recty) Amaxy = R.recty-1; */
322
if(Amaxy >= bufferHeight) Amaxy = bufferHeight - 1;
325
Zsample = 0; /* Zsample is used internally ! */
326
while ( (Zsample < osaNr) && keepLooping ) {
327
/* Apply jitter to this pixel. The jitter offsets are globals. */
328
/* They are added in zbufclip() */
329
/* Negative: these offsets are added to the vertex coordinates */
330
/* so it equals translating viewpoint over the positive vector. */
331
Zjitx= -jit[Zsample][0];
332
Zjity= -jit[Zsample][1];
334
keepLooping = fillZBufDistances();
336
if(RE_local_test_break()) keepLooping = 0;
341
} /*End of void calcZBufLine(int y) */
343
/* ------------------------------------------------------------------------- */
345
int countAndSortPixelFaces(int zrow[RE_MAX_FACES_PER_PIXEL][RE_PIXELFIELDSIZE],
192
/* ------------------------------------------------------------------------- */
195
* New fill function for z buffer, for edge-only rendering.
197
static void zBufferFillFace(unsigned int zvlnr, float *v1, float *v2, float *v3)
199
/* Coordinates of the vertices are specified in ZCS */
201
int apteller, apoffsetteller;
202
double z0; /* used as temp var*/
204
double zxd,zyd,zy0, tmp;
205
float *minv,*maxv,*midv;
206
register int zverg,zvlak,x;
207
int my0,my2,sn1,sn2,rectx,zd;
208
int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2, mask;
210
/* These used to be doubles. We may want to change them back if the */
211
/* loss of accuracy proves to be a problem? There does not seem to be */
212
/* any performance issues here, so I'll just keep the doubles. */
213
/* float vec0[3], vec1[3], vec2[3]; */
214
double vec0[3], vec1[3], vec2[3];
216
vlr= RE_findOrAddVlak( (zvlnr-1) & 0x7FFFFF);
217
if(vlr->mat->mode & MA_ZTRA) obtype= RE_POLY;
218
else obtype= RE_POLY|RE_SOLID;
221
/* sort vertices for min mid max y value */
223
if(v2[1]<v3[1]) { minv=v1; midv=v2; maxv=v3;}
224
else if(v1[1]<v3[1]) { minv=v1; midv=v3; maxv=v2;}
225
else { minv=v3; midv=v1; maxv=v2;}
228
if(v1[1]<v3[1]) { minv=v2; midv=v1; maxv=v3;}
229
else if(v2[1]<v3[1]) { minv=v2; midv=v3; maxv=v1;}
230
else { minv=v3; midv=v2; maxv=v1;}
233
if(minv[1] == maxv[1]) return; /* security to remove 'zero' size faces */
236
my2 = floor(maxv[1]);
237
omsl = floor(midv[1]);
239
/* outside the current z buffer slice: clip whole face */
240
if( (my2 < Aminy) || (my0 > Amaxy)) return;
242
if(my0<Aminy) my0= Aminy;
244
/* EDGES : THE LONGEST */
245
xx1= maxv[1]-minv[1];
246
if(xx1>2.0/65536.0) {
247
z0= (maxv[0]-minv[0])/xx1;
250
dx0= CLAMPIS(tmp, INT_MIN, INT_MAX);
252
tmp= 65536.0*(z0*(my2-minv[1])+minv[0]);
253
xs0= CLAMPIS(tmp, INT_MIN, INT_MAX);
257
xs0= 65536.0*(MIN2(minv[0],maxv[0]));
259
/* EDGES : THE TOP ONE */
260
xx1= maxv[1]-midv[1];
261
if(xx1>2.0/65536.0) {
262
z0= (maxv[0]-midv[0])/xx1;
265
dx1= CLAMPIS(tmp, INT_MIN, INT_MAX);
267
tmp= 65536.0*(z0*(my2-midv[1])+midv[0]);
268
xs1= CLAMPIS(tmp, INT_MIN, INT_MAX);
272
xs1= 65536.0*(MIN2(midv[0],maxv[0]));
274
/* EDGES : THE BOTTOM ONE */
275
xx1= midv[1]-minv[1];
276
if(xx1>2.0/65536.0) {
277
z0= (midv[0]-minv[0])/xx1;
280
dx2= CLAMPIS(tmp, INT_MIN, INT_MAX);
282
tmp= 65536.0*(z0*(omsl-minv[1])+minv[0]);
283
xs2= CLAMPIS(tmp, INT_MIN, INT_MAX);
287
xs2= 65536.0*(MIN2(minv[0],midv[0]));
291
/* xyz_1 = v_1 - v_2 */
292
MTC_diff3DFF(vec1, v1, v2);
293
/* xyz_2 = v_2 - v_3 */
294
MTC_diff3DFF(vec2, v2, v3);
295
/* xyz_0 = xyz_1 cross xyz_2 */
296
MTC_cross3Double(vec0, vec1, vec2);
298
/* cross product of two of the sides is 0 => this face is too small */
299
if(vec0[2]==0.0) return;
301
if(midv[1] == maxv[1]) omsl= my2;
302
if(omsl < Aminy) omsl= Aminy-1; /* make sure it takes the first loop entirely */
304
while (my2 > Amaxy) { /* my2 can be larger */
315
xx1= (vec0[0]*v1[0]+vec0[1]*v1[1])/vec0[2]+v1[2];
317
zxd= -vec0[0]/vec0[2];
318
zyd= -vec0[1]/vec0[2];
320
zd= (int)CLAMPIS(zxd, INT_MIN, INT_MAX);
322
/* start-ofset in rect */
323
/* rectx= R.rectx; */
324
/* I suspect this var needs very careful setting... When edge rendering */
325
/* is on, this is strange */
326
rectx = zBufferWidth;
327
apoffsetteller = rectx*(my2-Aminy);
334
MTC_swapInt(&xs0, &xs1);
335
MTC_swapInt(&dx0, &dx1);
340
for(y=my2;y>omsl;y--) {
350
if(sn2>=rectx) sn2= rectx-1;
352
zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX);
353
apteller = apoffsetteller + sn1;
359
insertObject(apteller, zvlnr, obtype, zverg, mask);
365
apoffsetteller -= rectx;
391
if(sn2>=rectx) sn2= rectx-1;
393
zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX);
394
apteller = apoffsetteller + sn1;
400
insertObject(apteller, zvlnr, obtype, zverg, mask);
407
apoffsetteller -= rectx;
410
/* ------------------------------------------------------------------------- */
412
static void zBufferFillEdge(unsigned int zvlnr, float *vec1, float *vec2)
415
int start, end, x, y, oldx, oldy, ofs;
416
int dz, vergz, mask, maxtest=0;
423
if(fabs(dx) > fabs(dy)) {
425
/* all lines from left to right */
426
if(vec1[0]<vec2[0]) {
437
end= start+floor(dx);
438
if(end >= zBufferWidth) end = zBufferWidth - 1;
445
dz= (v2[2]-v1[2])/dx;
446
if(vergz>0x70000000 && dz>0) maxtest= 1; // prevent overflow
448
apteller = zBufferWidth*(oldy-Aminy) +start;
451
if(dy<0) ofs= -zBufferWidth;
452
else ofs= zBufferWidth;
454
for(x= start; x<=end; x++, /* ap++, */ apteller++) {
462
if(x>=0 && y>=Aminy && y<=Amaxy) {
463
insertObject(apteller, zvlnr, RE_POLY, vergz, mask);
468
if(maxtest && vergz<0) vergz= 0x7FFFFFF0;
473
/* all lines from top to bottom */
474
if(vec1[1]<vec2[1]) {
485
end= start+floor(dy);
487
if(start>Amaxy || end<Aminy) return;
489
if(end>Amaxy) end= Amaxy;
496
dz= (v2[2]-v1[2])/dy;
497
if(vergz>0x70000000 && dz>0) maxtest= 1; // prevent overflow
499
apteller = zBufferWidth*(start-Aminy) +oldx;
506
for(y= start; y<=end; y++, apteller += zBufferWidth) {
514
if(x>=0 && y>=Aminy && (x < zBufferWidth)) {
515
insertObject(apteller, zvlnr, RE_POLY, vergz, mask);
520
if(maxtest && vergz<0) vergz= 0x7FFFFFF0;
524
/* ------------------------------------------------------------------------- */
527
* Count and sort the list behind ap into buf. Sorts on min. distance.
528
* Low index <=> high z
530
static int countAndSortPixelFaces(int zrow[][RE_PIXELFIELDSIZE],
346
531
RE_APixstrExt *ap)
348
533
int totvlak; /* face counter */
517
Start resolving the conflict: the stack is primed to the top-most valid
518
layer on the stack. Call this layer n. Layer n has a conflict count of c.
519
This means layers [ n - c, ..., n ]
521
int resolveConflict(struct RE_faceField* stack, int ptr, float x, float y) {
526
float ys = 0.0; /* coordinates for the render-spot */
529
for(i = 0; i< osaNr; i++) { /* per bin, buffer all faces */
535
face = 0; /* only counts covering faces ------------------- */
536
layer = 0; /* counts all faces ----------------------------- */
538
while (layer < stack[ptr].conflictCount) {
539
if ( (1<<i) & stack[ptr - layer].mask) {
542
stack[ptr - layer].data,
543
stack[ptr - layer].faceType);
544
VR_cbuf[face][1] = ptr - layer;
737
/* ------------------------------------------------------------------------- */
740
* Calculate the view depth to this object on this location, with
741
* the current view parameters in R.
743
static int calcDepth(float x, float y, void *data, int type)
747
if (type & RE_POLY) {
748
VlakRen* vlr = (VlakRen*) data;
750
float dface, div, zco, hoco_z, hoco_w;
755
/* vertex dot face normal: WCS */
756
dface= v1->co[0]*vlr->n[0]+v1->co[1]*vlr->n[1]+v1->co[2]*vlr->n[2];
758
/* jitter has been added to x, y ! */
759
/* view vector view: screen coords */
760
view[0]= (x+(R.xstart)+0.5);
762
if(R.flag & R_SEC_FIELD) {
763
if(R.r.mode & R_ODDFIELD) view[1]= (y + R.ystart)*R.ycor;
764
else view[1]= (y + R.ystart + 1.0)*R.ycor;
766
else view[1]= (y + R.ystart + 0.5)*R.ycor;
769
/* for pano, another rotation in the xz plane is needed.... */
771
/* this is ok, in WCS */
772
view[2]= -R.viewfac; /* distance to viewplane */
774
/* calculate zcoord */
775
if(R.r.mode & R_ORTHO) {
776
/* x and y 3d coordinate can be derived from pixel coord and winmat */
777
float fx= 2.0/(R.rectx*R.winmat[0][0]);
778
float fy= 2.0/(R.recty*R.winmat[1][1]);
780
fx= (0.5 + x - 0.5*R.rectx)*fx - R.winmat[3][0]/R.winmat[0][0];
781
fy= (0.5 + y - 0.5*R.recty)*fy - R.winmat[3][1]/R.winmat[1][1];
783
/* using a*x + b*y + c*z = d equation, (a b c) is normal */
784
zco= (dface - vlr->n[0]*fx - vlr->n[1]*fy)/vlr->n[2];
788
/* face normal dot view vector: but how can this work? (nzc) */
789
div = MTC_dot3Float(vlr->n, view);
790
if (div!=0.0) zco = (view[2]*dface)/div;
794
/* same as in zbuf.c */
795
hoco_z = zco*R.winmat[2][2] + R.winmat[3][2];
796
hoco_w = zco*R.winmat[2][3] + R.winmat[3][3];
798
if(hoco_w!=0.0) zbuf_co = 0x7FFFFFFF*(hoco_z/hoco_w);
799
else zbuf_co= 0x7FFFFFFF;
801
return zbuf_co; /* z component of R.co */
802
} else if (type & RE_HALO) {
803
HaloRen* har = (HaloRen*) data;
804
return har->zBufDist;
810
* Blend source over dest, and leave result in dest. 1 pixel.
812
static void blendOverFloat(int type, float* dest, float* source, void* data)
815
if (type & RE_POLY) {
816
VlakRen *ver = (VlakRen*) data;
817
if ((ver->mat != NULL) && (ver->mat->add > RE_FACE_ADD_THRESHOLD)) {
818
char addf = (char) (ver->mat->add * 255.0);
819
addalphaAddfacFloat(dest, source, addf);
549
qsort(VR_cbuf, face, sizeof(int)*2, vergzvlak);
550
for(layer = 0; layer < face; layer++) {
551
blendOverFloat(stack[VR_cbuf[layer][1]].faceType, /* type */
552
sampcol + (4 * i), /* dest */
553
stack[VR_cbuf[layer][1]].colour, /* src */
554
stack[VR_cbuf[layer][1]].data); /* data */
558
/* The number of layers that were handled. This is how many layers the */
559
/* top-level algorithm needs to skip. */
560
return stack[ptr].conflictCount;
563
/* The colour stack is blended down in a pretty straight-forward manner, or */
564
/* a part of the stack is re-evaluated to resolve the conflict. */
565
/* About 25-30% of rendering time is eaten here! */
566
void integrateStack(struct RE_faceField* stack, int ptr,
570
/* sample the colour stack: back to front ---------------------------- */
571
/* is there a possible way to ignore alpha? this would save 25% work */
573
/* Little different now: let ptr point to the topmost valid face.*/
575
if (stack[ptr].conflictCount == 0) {
577
No conflict: sample one colour into multiple bins
579
blendOverFloatRow(stack[ptr].faceType,
588
Recalc all z-values, and integrate per sub-pixel.
590
ptr -= resolveConflict(stack, ptr, x, y);
594
/* Done sampling. Now we still need to fill in pixels that were not */
595
/* covered at all It seems strange that we have to check for empty alpha */
596
/* but somehow this is necessary. Check out the cover condition :).... */
598
/* It is important that we find a more efficient algorithm here, because */
599
/* this little loop eats _lots_ of cycles. */
601
/* Should be integrated in the rest of the rendering... */
603
if(R.flag & R_LAMPHALO) {
607
renderSpotHaloPixel(x, y, halocol);
608
/* test seems to be wrong? */
609
if (halocol[3] > RE_EMPTY_COLOUR_FLOAT) {
610
for (i = 0; i < osaNr; i++) {
611
/* here's a pinch: if the pixel was only covered by a halo, */
612
/* we still need to fill spothalo. How do we detect this? */
613
if (!(VR_covered & (1 << i)))
614
/* maybe a copy is enough here... */
615
addAlphaOverFloat(sampcol + (4 * i), halocol);
822
addAlphaOverFloat(dest, source);
823
} else if (type & RE_HALO) {
824
HaloRen *har= (HaloRen*) data;
825
addalphaAddfacFloat(dest, source, har->add);
826
} else if (type & RE_SKY) {
827
addAlphaOverFloat(dest, source);
622
834
* New approach: sample substacks. Each substack is first copied into
623
835
* a stack buffer, and then blended down.
625
void integratePerSubStack(struct RE_faceField* stack,
837
static void integratePerSubStack(float *sampcol, struct RE_faceField* stack,
838
int ptr, float x, float y, int osaNr)
789
999
/* distance, and then used for rendering pixels. zrow might be replaced by */
790
1000
/* an RE_APixstrExt* array */
791
1001
/* - redo the numbering to something more logical */
792
void renderZBufLine(int y) {
793
int zrow[RE_MAX_FACES_PER_PIXEL][RE_PIXELFIELDSIZE];
794
RE_APixstrExt *ap; /* iterator for the face-lists */
1004
/* threadsafe global arrays, too large for stack */
1005
typedef struct zbufline {
1006
int zrow[RE_MAX_FACES_PER_PIXEL][RE_PIXELFIELDSIZE];
1007
struct RE_faceField osastack[RE_MAX_FACES_PER_PIXEL + 1];
1010
static zbufline zb1, zb2;
1012
static void renderZBufLine(int y, RE_COLBUFTYPE *colbuf1, RE_COLBUFTYPE *colbuf2, RE_COLBUFTYPE *colbuf3)
1014
RE_APixstrExt *ap; /* iterator for the face-lists */
1015
RE_COLBUFTYPE collector[4];
1016
RE_COLBUFTYPE sampcol[RE_MAX_OSA_COUNT * 4];
1017
RE_COLBUFTYPE *j = NULL; /* generic pixel pointer */
796
1019
int x; /* pixel counter */
797
RE_COLBUFTYPE *colbuf; /* pointer into the line buffer */
798
RE_COLBUFTYPE *j = NULL; /* generic pixel pointer */
799
1020
int i; /* yet another counter */
800
1021
int stackDepth; /* faces-behind-this-pixel counter */
801
struct RE_faceField RE_OSAstack[RE_MAX_FACES_PER_PIXEL + 1];
802
int RE_OSAstack_ptr; /* Points to the lowest empty field. The indexed */
803
/* field is NOT readable. */
1022
int osastack_ptr; /* Points to the lowest empty field. The indexed */
1025
/* thread safe row buffers */
1026
if(y & 1) zbl= &zb1;
805
/* Prepare buffers and iterators */
806
colbuf = AColourBuffer;
807
eraseColBuf(AColourBuffer);
1029
/* Prepare iterators */
808
1030
ap = APixbufExt + (zBufferWidth * (y - Aminy));
809
1031
apteller = (zBufferWidth * (y - Aminy));
811
1033
/* Rendering: give the right colour to this pixel (shade it) */
812
for( x = 0; x < bufferWidth; x++, ap++, colbuf+=4) {
1034
for( x = 0; x < R.rectx; x++, ap++, colbuf1+=4, colbuf2+=4, colbuf3+=4) {
814
1036
/* reset sample collector */
816
1038
for(i = 0; i < osaNr; i++, j+=4) {
817
j[0] = RE_ZERO_COLOUR_FLOAT; j[1] = RE_ZERO_COLOUR_FLOAT;
818
j[2] = RE_ZERO_COLOUR_FLOAT; j[3] = RE_ZERO_COLOUR_FLOAT;
1039
j[0] = 0.0f; j[1] = 0.0f;
1040
j[2] = 0.0f; j[3] = 0.0f;
821
1043
/* a. count and sort number of faces */
822
stackDepth = countAndSortPixelFaces(zrow, ap);
1044
stackDepth = countAndSortPixelFaces( zbl->zrow, ap);
824
1046
/* b,c. oversample all subpixels, then integrate */
826
RE_OSAstack_ptr = composeStack(zrow,
827
RE_OSAstack, RE_OSAstack_ptr,
828
stackDepth, x, y, osaNr);
829
integratePerSubStack(RE_OSAstack, RE_OSAstack_ptr,
832
/* d. Gamma corrected blending */
833
sampleFloatColV2FloatColV(sampcol, colbuf, osaNr);
1048
osastack_ptr = composeStack(zbl->zrow, collector, zbl->osastack, osastack_ptr,
1049
stackDepth, x, y, osaNr);
1050
integratePerSubStack(sampcol, zbl->osastack, osastack_ptr, x, y, osaNr);
1052
/* d. Gamma corrected blending and Gaussian */
1053
sampleFloatColV2FloatColVFilter(sampcol, colbuf1, colbuf2, colbuf3, osaNr);
835
1056
/* Remember to do things back-to-front! */
837
1058
/* This is a bit dirty. Depending on sky-mode, the pixel is */
838
1059
/* blended in differently. */
839
renderSkyPixelFloat(x, y);
840
cpFloatColV(collector, colbuf);
1060
renderSkyPixelFloat(collector, x, y);
1063
for(i = 0; i < osaNr; i++, j+=4) {
1064
j[0]= collector[0]; j[1]= collector[1];
1065
j[2]= collector[2]; j[3]= collector[3];
1068
sampleFloatColV2FloatColVFilter(sampcol, colbuf1, colbuf2, colbuf3, osaNr);
842
1071
/* Spothalos are part of the normal pixelshader, so for covered */
843
1072
/* pixels they are handled ok. They are 'normally' alpha blended */
844
1073
/* onto the existing colour in the collector. */
845
1074
if(R.flag & R_LAMPHALO) {
846
1075
renderSpotHaloPixel(x, y, collector);
847
addAlphaOverFloat(colbuf, collector);
1077
collector[0]= gammaCorrect(collector[0]);
1078
collector[1]= gammaCorrect(collector[1]);
1079
collector[2]= gammaCorrect(collector[2]);
1081
addAlphaOverFloat(colbuf2+4, collector);
851
} /* End of pixel loop */
853
} /* End of void renderZBufLine(int y) */
856
/* ------------------------------------------------------------------------- */
858
int fillZBufDistances()
862
keepLooping = zBufferAllFaces(); /* Solid and transparent faces*/
863
keepLooping = zBufferAllHalos() && keepLooping; /* ...and halos*/
866
} /* End of void fillZBufDistances() */
1089
* Fills in distances of faces in the z buffer.
1091
* Halo z buffering ----------------------------------------------
1093
* A halo is treated here as a billboard: no z-extension, always
1094
* oriented perpendicular to the viewer. The rest of the z-buffer
1095
* stores face-numbers first, then calculates colours as the
1096
* final image is rendered. We'll use the same approach here,
1097
* which differs from the original method (which was add halos per
1098
* scan line). This means that the z-buffer now also needs to
1099
* store info about what sort of 'thing' the index refers to.
1108
* These coordinates must be clipped to picture size.
1109
* I'm not quite certain about halo numbering.
1111
* Halos and jittering -------------------------------------------
1113
* Halos were not jittered previously. Now they are. I wonder
1114
* whether this may have some adverse effects here.
1116
* @return 1 for succes, 0 if the operation was interrupted.
868
1119
/* ------------------------------------------------------------------------- */
869
1120
/* Transparent faces and the 'Azvoordeel' */
1005
1263
return keepLooping;
1006
} /* end of int zbufferAllHalos(void) */
1008
/* ------------------------------------------------------------------------- */
1265
/* ------------------------------------------------------------------------- */
1268
* Fills in distances of all faces in a z buffer, for given jitter settings.
1270
static int fillZBufDistances()
1272
int keepLooping = 1;
1274
keepLooping = zBufferAllFaces(); /* Solid and transparent faces*/
1275
keepLooping = zBufferAllHalos() && keepLooping; /* ...and halos*/
1283
/* ------------------------------------------------------------------------- */
1285
* One more filler: fill in halo data in z buffer.
1286
* Empty so far, but may receive content of halo loop.
1009
1288
void zBufferFillHalo(void)
1011
1290
/* so far, intentionally empty */
1012
} /* end of void zBufferFillHalo(void) */
1014
/* ------------------------------------------------------------------------- */
1015
void zBufferFillFace(float *v1, float *v2, float *v3)
1017
/* Coordinates of the vertices are specified in ZCS */
1018
int apteller, apoffsetteller;
1019
double z0; /* used as temp var*/
1021
double zxd,zyd,zy0, tmp;
1022
float *minv,*maxv,*midv;
1023
register int zverg,zvlak,x;
1024
int my0,my2,sn1,sn2,rectx,zd;
1025
int y,omsl,xs0,xs1,xs2,xs3, dx0,dx1,dx2, mask;
1027
/* These used to be doubles. We may want to change them back if the */
1028
/* loss of accuracy proves to be a problem? There does not seem to be */
1029
/* any performance issues here, so I'll just keep the doubles. */
1030
/* float vec0[3], vec1[3], vec2[3]; */
1031
double vec0[3], vec1[3], vec2[3];
1034
/* sort vertices for min mid max y value */
1036
if(v2[1]<v3[1]) { minv=v1; midv=v2; maxv=v3;}
1037
else if(v1[1]<v3[1]) { minv=v1; midv=v3; maxv=v2;}
1038
else { minv=v3; midv=v1; maxv=v2;}
1041
if(v1[1]<v3[1]) { minv=v2; midv=v1; maxv=v3;}
1042
else if(v2[1]<v3[1]) { minv=v2; midv=v3; maxv=v1;}
1043
else { minv=v3; midv=v2; maxv=v1;}
1046
if(minv[1] == maxv[1]) return; /* security to remove 'zero' size faces */
1048
my0 = ceil(minv[1]);
1049
my2 = floor(maxv[1]);
1050
omsl = floor(midv[1]);
1052
/* outside the current z buffer slice: clip whole face */
1053
if( (my2 < Aminy) || (my0 > Amaxy)) return;
1055
if(my0<Aminy) my0= Aminy;
1057
/* EDGES : THE LONGEST */
1058
xx1= maxv[1]-minv[1];
1059
if(xx1>2.0/65536.0) {
1060
z0= (maxv[0]-minv[0])/xx1;
1063
dx0= CLAMPIS(tmp, INT_MIN, INT_MAX);
1065
tmp= 65536.0*(z0*(my2-minv[1])+minv[0]);
1066
xs0= CLAMPIS(tmp, INT_MIN, INT_MAX);
1070
xs0= 65536.0*(MIN2(minv[0],maxv[0]));
1072
/* EDGES : THE TOP ONE */
1073
xx1= maxv[1]-midv[1];
1074
if(xx1>2.0/65536.0) {
1075
z0= (maxv[0]-midv[0])/xx1;
1078
dx1= CLAMPIS(tmp, INT_MIN, INT_MAX);
1080
tmp= 65536.0*(z0*(my2-midv[1])+midv[0]);
1081
xs1= CLAMPIS(tmp, INT_MIN, INT_MAX);
1085
xs1= 65536.0*(MIN2(midv[0],maxv[0]));
1087
/* EDGES : THE BOTTOM ONE */
1088
xx1= midv[1]-minv[1];
1089
if(xx1>2.0/65536.0) {
1090
z0= (midv[0]-minv[0])/xx1;
1093
dx2= CLAMPIS(tmp, INT_MIN, INT_MAX);
1095
tmp= 65536.0*(z0*(omsl-minv[1])+minv[0]);
1096
xs2= CLAMPIS(tmp, INT_MIN, INT_MAX);
1100
xs2= 65536.0*(MIN2(minv[0],midv[0]));
1104
/* xyz_1 = v_1 - v_2 */
1105
MTC_diff3DFF(vec1, v1, v2);
1106
/* xyz_2 = v_2 - v_3 */
1107
MTC_diff3DFF(vec2, v2, v3);
1108
/* xyz_0 = xyz_1 cross xyz_2 */
1109
MTC_cross3Double(vec0, vec1, vec2);
1111
/* cross product of two of the sides is 0 => this face is too small */
1112
if(vec0[2]==0.0) return;
1114
if(midv[1] == maxv[1]) omsl= my2;
1115
if(omsl < Aminy) omsl= Aminy-1; /* make sure it takes the first loop entirely */
1117
while (my2 > Amaxy) { /* my2 can be larger */
1128
xx1= (vec0[0]*v1[0]+vec0[1]*v1[1])/vec0[2]+v1[2];
1130
zxd= -vec0[0]/vec0[2];
1131
zyd= -vec0[1]/vec0[2];
1133
zd= (int)CLAMPIS(zxd, INT_MIN, INT_MAX);
1135
/* start-ofset in rect */
1136
/* rectx= R.rectx; */
1137
/* I suspect this var needs very careful setting... When edge rendering */
1138
/* is on, this is strange */
1139
rectx = zBufferWidth;
1140
apoffsetteller = rectx*(my2-Aminy);
1147
MTC_swapInt(&xs0, &xs1);
1148
MTC_swapInt(&dx0, &dx1);
1153
for(y=my2;y>omsl;y--) {
1163
if(sn2>=rectx) sn2= rectx-1;
1165
zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX);
1166
apteller = apoffsetteller + sn1;
1172
insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, zverg, mask);
1178
apoffsetteller -= rectx;
1194
for(; y>=my0; y--) {
1204
if(sn2>=rectx) sn2= rectx-1;
1206
zverg= (int) CLAMPIS((sn1*zxd+zy0), INT_MIN, INT_MAX);
1207
apteller = apoffsetteller + sn1;
1213
insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, zverg, mask);
1220
apoffsetteller -= rectx;
1222
} /* end of void zBufferFillFace(float *v1, float *v2, float *v3) */
1224
/* ------------------------------------------------------------------------- */
1226
void zBufferFillEdge(float *vec1, float *vec2)
1229
int start, end, x, y, oldx, oldy, ofs;
1230
int dz, vergz, mask;
1234
dx= vec2[0]-vec1[0];
1235
dy= vec2[1]-vec1[1];
1237
if(fabs(dx) > fabs(dy)) {
1239
/* all lines from left to right */
1240
if(vec1[0]<vec2[0]) {
1250
start= floor(v1[0]);
1251
end= start+floor(dx);
1252
if(end >= zBufferWidth) end = zBufferWidth - 1;
1259
dz= (v2[2]-v1[2])/dx;
1261
apteller = zBufferWidth*(oldy-Aminy) +start;
1264
if(dy<0) ofs= -zBufferWidth;
1265
else ofs= zBufferWidth;
1267
for(x= start; x<=end; x++, /* ap++, */ apteller++) {
1275
if(x>=0 && y>=Aminy && y<=Amaxy) {
1276
insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, vergz, mask);
1285
/* all lines from top to bottom */
1286
if(vec1[1]<vec2[1]) {
1296
start= floor(v1[1]);
1297
end= start+floor(dy);
1299
if(start>Amaxy || end<Aminy) return;
1301
if(end>Amaxy) end= Amaxy;
1308
dz= (v2[2]-v1[2])/dy;
1310
apteller = zBufferWidth*(start-Aminy) +oldx;
1317
for(y= start; y<=end; y++, apteller += zBufferWidth) {
1325
if(x>=0 && y>=Aminy && (x < zBufferWidth)) {
1326
insertObject(apteller, /* RE_treat_face_as_opaque, */ Zvlnr, RE_POLY, vergz, mask);
1333
} /* End of void zBufferFillEdge(float *vec1, float *vec2) */
1336
1294
/* ------------------------------------------------------------------------- */
1337
1295
/* Colour buffer related: */
1452
} /* end of void transferColourBufferToOutput(int y) */
1421
/* used for redisplay after render. assumes size globals to be set OK! */
1422
void RE_floatbuffer_to_output(void)
1424
float *buf= R.rectftot;
1425
int pix= R.rectx*R.recty;
1426
char *target = (char *)R.rectot;
1428
if(R.rectftot==NULL) return;
1431
std_floatcol_to_charcol(buf, target);
1454
1437
/* ------------------------------------------------------------------------- */
1456
void eraseColBuf(RE_COLBUFTYPE *buf) {
1439
static void eraseColBuf(RE_COLBUFTYPE *buf)
1457
1441
/* By definition, the buffer's length is 4 * R.rectx items */
1459
/* while (i < 4 * R.rectx) { */
1460
while (i < 4 * bufferWidth) {
1461
*buf = RE_ZERO_COLOUR_FLOAT;
1444
while (i < 4 * (R.rectx+3)) {
1464
} /* End of void eraseColBuf(RE_COLBUFTYPE *buf) */
1466
1450
/* ------------------------------------------------------------------------- */
1468
int calcDepth(float x, float y, void *data, int type)
1472
if (type & RE_POLY) {
1473
VlakRen* vlr = (VlakRen*) data;
1475
float dvlak, deler, fac, hoco_z, hoco_w;
1480
/* vertex dot face normal: WCS */
1481
dvlak= v1->co[0]*vlr->n[0]+v1->co[1]*vlr->n[1]+v1->co[2]*vlr->n[2];
1483
/* jitter has been added to x, y ! */
1484
/* view vector view: screen coords */
1485
view[0]= (x+(R.xstart) + 0.5 );
1487
if(R.flag & R_SEC_FIELD) {
1488
if(R.r.mode & R_ODDFIELD) view[1]= (y + R.ystart)*R.ycor;
1489
else view[1]= (y+R.ystart + 1.0)*R.ycor;
1490
} else view[1]= (y+R.ystart + 0.5 )*R.ycor;
1493
/* for pano, another rotation in the xz plane is needed.... */
1495
/* this is ok, in WCS */
1496
view[2]= -R.viewfac; /* distance to viewplane */
1498
/* face normal dot view vector: but how can this work? */
1499
deler = MTC_dot3Float(vlr->n, view);
1500
if (deler!=0.0) fac = dvlak/deler;
1503
/* indices are wrong.... but gives almost the right value? */
1504
hoco_z = (fac*view[2]) * R.winmat[2][2] + R.winmat[3][2];
1505
hoco_w = (fac*view[2]) * R.winmat[2][3] + R.winmat[3][3];
1507
zbuf_co = 0x7FFFFFFF*(hoco_z/hoco_w);
1509
return zbuf_co; /* z component of R.co */
1510
} else if (type & RE_HALO) {
1511
HaloRen* har = (HaloRen*) data;
1512
return har->zBufDist;
1515
} /* end of int calcDepth(float x, float y, void* data, int type) */
1517
/* Maybe these two should be in pixelblendeing.c---------------------------- */
1519
void blendOverFloat(int type, float* dest, float* source, void* data)
1522
if (type & RE_POLY) {
1523
VlakRen *ver = (VlakRen*) data;
1524
if ((ver->mat != NULL) && (ver->mat->add > RE_FACE_ADD_THRESHOLD)) {
1525
char addf = (char) (ver->mat->add * 255.0);
1526
addalphaAddfacFloat(dest, source, addf);
1454
* Fill the accumulation buffer APixbufExt with face and halo indices.
1455
* Note: Uses globals.
1456
* @param y the line number to set
1458
static void calcZBufLine(int y)
1460
/* These function pointers are used for z buffer filling. */
1461
extern void (*zbuffunc)(unsigned int, float *, float *, float *);
1462
extern void (*zbuflinefunc)(unsigned int, float *, float *);
1464
int keepLooping = 1;
1468
/* zbuffer fix: here? */
1469
Zmulx= ((float) R.rectx)/2.0;
1470
Zmuly= ((float) R.recty)/2.0;
1473
/* use these buffer fill functions */
1474
zbuffunc = zBufferFillFace;
1475
zbuflinefunc = zBufferFillEdge;
1477
/* (FORALL y: Aminy =< y =< Amaxy: y is buffered) */
1478
if( (y < Aminy) || (y > Amaxy)) {
1480
/* prepare buffer */
1481
part = (y/RE_ZBUFLEN); /* These two lines are mystifying me... */
1482
Aminy = part * RE_ZBUFLEN; /* Possibly for rounding things? */
1483
Amaxy = Aminy + RE_ZBUFLEN - 1;
1484
/* if(Amaxy >= R.recty) Amaxy = R.recty-1; */
1485
if(Amaxy >= R.recty) Amaxy = R.recty - 1;
1488
Zsample = 0; /* Zsample is used internally ! */
1489
while ( (Zsample < osaNr) && keepLooping ) {
1490
/* Apply jitter to this pixel. The jitter offsets are globals. */
1491
/* They are added in zbufclip() */
1492
/* Negative: these offsets are added to the vertex coordinates */
1493
/* so it equals translating viewpoint over the positive vector. */
1494
Zjitx= -jit[Zsample][0]-0.5;
1495
Zjity= -jit[Zsample][1]-0.5;
1497
keepLooping = fillZBufDistances();
1499
if(RE_local_test_break()) keepLooping = 0;
1529
addAlphaOverFloat(dest, source);
1530
} else if (type & RE_HALO) {
1531
HaloRen *har= (HaloRen*) data;
1532
addalphaAddfacFloat(dest, source, har->add);
1533
} else if (type & RE_SKY) {
1534
addAlphaOverFloat(dest, source);
1537
} /* end of void blendOverFloat(int , float*, float*, void*) */
1539
/* ------------------------------------------------------------------------- */
1540
void blendOverFloatRow(int type, float* dest, float* source,
1541
void* data, int mask, int osaNr)
1544
if (type & RE_POLY) {
1545
VlakRen *ver = (VlakRen*) data;
1546
if ((ver->mat != NULL)
1547
&& (ver->mat->add > RE_FACE_ADD_THRESHOLD)) {
1548
char addf = (ver->mat->add * 255.0);
1549
addAddSampColF(dest, source, mask, osaNr, addf);
1551
addOverSampColF(dest, source, mask, osaNr);
1553
} else if (type & RE_HALO) {
1554
HaloRen *har = (HaloRen*) data;
1555
addAddSampColF(dest, source, mask, osaNr, har->add);
1556
} else if (type & RE_SKY) {
1557
addOverSampColF(dest, source, mask, osaNr);
1559
} /* end of void blendOverFloatRow(int, float*, float*, void*) */
1561
/* ------------------------------------------------------------------------- */
1507
/* ------------------------------------------------------------------------- */
1510
RE_COLBUFTYPE *buf1, *buf2, *buf3;
1514
static int do_renderline(void *poin)
1516
struct renderline *rl= poin;
1518
renderZBufLine(rl->y, rl->buf1, rl->buf2, rl->buf3);
1522
void zBufShadeAdvanced()
1524
RE_COLBUFTYPE *cycle;
1525
struct renderline rl1, rl2;
1526
int y, keepLooping = 1;
1527
float xjit = 0.0, yjit = 0.0;
1529
Zjitx=Zjity= -0.5; /* jitter preset: -0.5 pixel */
1531
/* Set osaNr. Treat 'no osa' as 'osa = 1' */
1532
if(R.r.mode & R_OSA) {
1534
if(osaNr > 16) { /* check was moved from calcZBufLine */
1535
printf("zBufShadeAdvanced> osa too large (internal error)\n");
1548
RE_setwindowclip(0, -1); /* just to be sure, reset the view matrix */
1550
initRenderBuffers(R.rectx);
1553
while ( (y < R.recty) && keepLooping) {
1557
rl1.buf1= AColourBuffer1;
1558
rl1.buf2= AColourBuffer2;
1559
rl1.buf3= AColourBuffer3;
1562
if(R.r.mode & R_THREADS) {
1566
thread = SDL_CreateThread(do_renderline, &rl1);
1567
if ( thread == NULL ) {
1568
fprintf(stderr, "Unable to create thread");
1573
rl2.buf1= AColourBuffer0;
1574
rl2.buf2= AColourBuffer1a;
1575
rl2.buf3= AColourBuffer2a;
1578
do_renderline(&rl2);
1580
SDL_WaitThread(thread, NULL);
1582
if(R.r.mode & R_GAUSS) {
1583
float *rb1= AColourBuffer1, *rb2= AColourBuffer2, *rb1a= AColourBuffer1a, *rb2a= AColourBuffer2a;
1584
int a= 4*(R.rectx + 4);
1588
*(rb1a++)= 0.0; rb1++;
1589
*(rb2a++)= 0.0; rb2++;
1593
cycle= AColourBuffer1a; AColourBuffer1a= AColourBuffer1; AColourBuffer1= cycle;
1597
else do_renderline(&rl1);
1600
transferColourBufferToOutput(AColourBuffer3+4, y-1);
1602
if((y & 1)==0) RE_local_render_display(y-2, y-1, R.rectx, R.recty, R.rectot);
1605
/* buffer cycling */
1606
eraseColBuf(AColourBuffer3);
1607
cycle= AColourBuffer3;
1608
AColourBuffer3= AColourBuffer2;
1609
AColourBuffer2= AColourBuffer1;
1610
AColourBuffer1= AColourBuffer0;
1611
AColourBuffer0= cycle;
1613
if(RE_local_test_break()) keepLooping = 0;
1616
if(keepLooping) transferColourBufferToOutput(AColourBuffer3+4, y-1);
1618
freeRenderBuffers();
1620
/* Edge rendering is done purely as a post-effect */
1621
if(R.r.mode & R_EDGE) {
1622
addEdges((char*)R.rectot, R.rectx, R.recty,
1624
R.r.edgeint, R.r.same_mat_redux,
1625
G.compat, G.notonlysolid,
1626
R.r.edgeR, R.r.edgeG, R.r.edgeB);
1629
if (!(R.r.mode & R_OSA)) {
1636
/* ------------------------------------------------------------------------- */
1563
1641
/* eof vanillaRenderPipe.c */