1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "IrrCompileConfig.h"
\r
6 #include "IBurningShader.h"
\r
8 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
10 // compile flag for this file
\r
27 // define render case
\r
40 // apply global override
\r
41 #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
\r
45 #ifndef SOFTWARE_DRIVER_2_SUBTEXEL
\r
49 #if BURNING_MATERIAL_MAX_COLORS < 1
\r
53 #if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER )
\r
54 #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
\r
78 class CTRGouraud2 : public IBurningShader
\r
83 CTRGouraud2(CBurningVideoDriver* driver);
\r
85 //! draws an indexed triangle list
\r
86 virtual void drawTriangle (const s4DVertex* burning_restrict a, const s4DVertex* burning_restrict b, const s4DVertex* burning_restrict c) _IRR_OVERRIDE_;
\r
87 //virtual bool canWireFrame () { return true; }
\r
90 virtual void scanline_bilinear ();
\r
95 CTRGouraud2::CTRGouraud2(CBurningVideoDriver* driver)
\r
96 : IBurningShader(driver)
\r
99 setDebugName("CTRGouraud2");
\r
107 void CTRGouraud2::scanline_bilinear ()
\r
133 sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES];
\r
136 // apply top-left fill-convention, left
\r
137 xStart = fill_convention_left( line.x[0] );
\r
138 xEnd = fill_convention_right( line.x[1] );
\r
140 dx = xEnd - xStart;
\r
146 const f32 invDeltaX = reciprocal_zero2( line.x[1] - line.x[0] );
\r
149 slopeZ = (line.z[1] - line.z[0]) * invDeltaX;
\r
152 slopeW = (line.w[1] - line.w[0]) * invDeltaX;
\r
155 slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX;
\r
158 slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX;
\r
161 slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX;
\r
165 subPixel = ( (f32) xStart ) - line.x[0];
\r
167 line.z[0] += slopeZ * subPixel;
\r
170 line.w[0] += slopeW * subPixel;
\r
173 line.c[0][0] += slopeC * subPixel;
\r
176 line.t[0][0] += slopeT[0] * subPixel;
\r
179 line.t[1][0] += slopeT[1] * subPixel;
\r
183 SOFTWARE_DRIVER_2_CLIPCHECK;
\r
184 dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart;
\r
187 z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart;
\r
193 tFixPoint r0, g0, b0;
\r
195 f32 inversew = FIX_POINT_F32_MUL * COLOR_MAX;
\r
199 for ( s32 i = 0; i <= dx; ++i )
\r
201 //if test active only first pixel
\r
202 if ( (0 == EdgeTestPass) & i ) break;
\r
204 if ( line.z[0] < z[i] )
\r
207 if (line.w[0] >= z[i] )
\r
214 inversew = fix_inverse32_color(line.w[0]);
\r
216 vec4_to_fix( r0, g0, b0, line.c[0][0],inversew );
\r
217 dst[i] = fix_to_sample( r0, g0, b0 );
\r
219 dst[i] = PrimitiveColor;
\r
232 line.z[0] += slopeZ;
\r
235 line.w[0] += slopeW;
\r
238 line.c[0][0] += slopeC;
\r
241 line.t[0][0] += slopeT[0];
\r
244 line.t[1][0] += slopeT[1];
\r
250 void CTRGouraud2::drawTriangle(const s4DVertex* burning_restrict a, const s4DVertex* burning_restrict b, const s4DVertex* burning_restrict c)
\r
252 // sort on height, y
\r
253 if ( a->Pos.y > b->Pos.y ) swapVertexPointer(&a, &b);
\r
254 if ( a->Pos.y > c->Pos.y ) swapVertexPointer(&a, &c);
\r
255 if ( b->Pos.y > c->Pos.y ) swapVertexPointer(&b, &c);
\r
257 const f32 ca = c->Pos.y - a->Pos.y;
\r
258 const f32 ba = b->Pos.y - a->Pos.y;
\r
259 const f32 cb = c->Pos.y - b->Pos.y;
\r
260 // calculate delta y of the edges
\r
262 scan.invDeltaY[0] = reciprocal_edge( ca );
\r
263 scan.invDeltaY[1] = reciprocal_edge( ba );
\r
264 scan.invDeltaY[2] = reciprocal_edge( cb );
\r
265 if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) )
\r
268 // find if the major edge is left or right aligned
\r
271 temp[0] = a->Pos.x - c->Pos.x;
\r
273 temp[2] = b->Pos.x - a->Pos.x;
\r
276 scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1;
\r
277 scan.right = 1 - scan.left;
\r
279 // calculate slopes for the major edge
\r
280 scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0];
\r
281 scan.x[0] = a->Pos.x;
\r
284 scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0];
\r
285 scan.z[0] = a->Pos.z;
\r
289 scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0];
\r
290 scan.w[0] = a->Pos.w;
\r
294 scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0];
\r
295 scan.c[0][0] = a->Color[0];
\r
299 scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0];
\r
300 scan.t[0][0] = a->Tex[0];
\r
304 scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0];
\r
305 scan.t[1][0] = a->Tex[1];
\r
308 // top left fill convention y run
\r
317 // rasterize upper sub-triangle
\r
318 if ( (f32) 0.0 != scan.invDeltaY[1] )
\r
320 // calculate slopes for top edge
\r
321 scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1];
\r
322 scan.x[1] = a->Pos.x;
\r
325 scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1];
\r
326 scan.z[1] = a->Pos.z;
\r
330 scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1];
\r
331 scan.w[1] = a->Pos.w;
\r
335 scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1];
\r
336 scan.c[0][1] = a->Color[0];
\r
340 scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1];
\r
341 scan.t[0][1] = a->Tex[0];
\r
345 scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1];
\r
346 scan.t[1][1] = a->Tex[1];
\r
349 // apply top-left fill convention, top part
\r
350 yStart = fill_convention_left( a->Pos.y );
\r
351 yEnd = fill_convention_right( b->Pos.y );
\r
354 subPixel = ( (f32) yStart ) - a->Pos.y;
\r
356 // correct to pixel center
\r
357 scan.x[0] += scan.slopeX[0] * subPixel;
\r
358 scan.x[1] += scan.slopeX[1] * subPixel;
\r
361 scan.z[0] += scan.slopeZ[0] * subPixel;
\r
362 scan.z[1] += scan.slopeZ[1] * subPixel;
\r
366 scan.w[0] += scan.slopeW[0] * subPixel;
\r
367 scan.w[1] += scan.slopeW[1] * subPixel;
\r
371 scan.c[0][0] += scan.slopeC[0][0] * subPixel;
\r
372 scan.c[0][1] += scan.slopeC[0][1] * subPixel;
\r
376 scan.t[0][0] += scan.slopeT[0][0] * subPixel;
\r
377 scan.t[0][1] += scan.slopeT[0][1] * subPixel;
\r
381 scan.t[1][0] += scan.slopeT[1][0] * subPixel;
\r
382 scan.t[1][1] += scan.slopeT[1][1] * subPixel;
\r
387 // rasterize the edge scanlines
\r
388 for( line.y = yStart; line.y <= yEnd; ++line.y)
\r
390 line.x[scan.left] = scan.x[0];
\r
391 line.x[scan.right] = scan.x[1];
\r
394 line.z[scan.left] = scan.z[0];
\r
395 line.z[scan.right] = scan.z[1];
\r
399 line.w[scan.left] = scan.w[0];
\r
400 line.w[scan.right] = scan.w[1];
\r
404 line.c[0][scan.left] = scan.c[0][0];
\r
405 line.c[0][scan.right] = scan.c[0][1];
\r
409 line.t[0][scan.left] = scan.t[0][0];
\r
410 line.t[0][scan.right] = scan.t[0][1];
\r
414 line.t[1][scan.left] = scan.t[1][0];
\r
415 line.t[1][scan.right] = scan.t[1][1];
\r
418 // render a scanline
\r
419 scanline_bilinear ();
\r
420 if ( EdgeTestPass & edge_test_first_line ) break;
\r
422 scan.x[0] += scan.slopeX[0];
\r
423 scan.x[1] += scan.slopeX[1];
\r
426 scan.z[0] += scan.slopeZ[0];
\r
427 scan.z[1] += scan.slopeZ[1];
\r
431 scan.w[0] += scan.slopeW[0];
\r
432 scan.w[1] += scan.slopeW[1];
\r
436 scan.c[0][0] += scan.slopeC[0][0];
\r
437 scan.c[0][1] += scan.slopeC[0][1];
\r
441 scan.t[0][0] += scan.slopeT[0][0];
\r
442 scan.t[0][1] += scan.slopeT[0][1];
\r
446 scan.t[1][0] += scan.slopeT[1][0];
\r
447 scan.t[1][1] += scan.slopeT[1][1];
\r
453 // rasterize lower sub-triangle
\r
454 if ( (f32) 0.0 != scan.invDeltaY[2] )
\r
456 // advance to middle point
\r
457 if( (f32) 0.0 != scan.invDeltaY[1] )
\r
459 temp[0] = b->Pos.y - a->Pos.y; // dy
\r
461 scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0];
\r
463 scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0];
\r
466 scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0];
\r
469 scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0];
\r
472 scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0];
\r
475 scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0];
\r
480 // calculate slopes for bottom edge
\r
481 scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2];
\r
482 scan.x[1] = b->Pos.x;
\r
485 scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2];
\r
486 scan.z[1] = b->Pos.z;
\r
490 scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2];
\r
491 scan.w[1] = b->Pos.w;
\r
495 scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2];
\r
496 scan.c[0][1] = b->Color[0];
\r
500 scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2];
\r
501 scan.t[0][1] = b->Tex[0];
\r
505 scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2];
\r
506 scan.t[1][1] = b->Tex[1];
\r
509 // apply top-left fill convention, top part
\r
510 yStart = fill_convention_left( b->Pos.y );
\r
511 yEnd = fill_convention_right( c->Pos.y );
\r
515 subPixel = ( (f32) yStart ) - b->Pos.y;
\r
517 // correct to pixel center
\r
518 scan.x[0] += scan.slopeX[0] * subPixel;
\r
519 scan.x[1] += scan.slopeX[1] * subPixel;
\r
522 scan.z[0] += scan.slopeZ[0] * subPixel;
\r
523 scan.z[1] += scan.slopeZ[1] * subPixel;
\r
527 scan.w[0] += scan.slopeW[0] * subPixel;
\r
528 scan.w[1] += scan.slopeW[1] * subPixel;
\r
532 scan.c[0][0] += scan.slopeC[0][0] * subPixel;
\r
533 scan.c[0][1] += scan.slopeC[0][1] * subPixel;
\r
537 scan.t[0][0] += scan.slopeT[0][0] * subPixel;
\r
538 scan.t[0][1] += scan.slopeT[0][1] * subPixel;
\r
542 scan.t[1][0] += scan.slopeT[1][0] * subPixel;
\r
543 scan.t[1][1] += scan.slopeT[1][1] * subPixel;
\r
548 // rasterize the edge scanlines
\r
549 for( line.y = yStart; line.y <= yEnd; ++line.y)
\r
551 line.x[scan.left] = scan.x[0];
\r
552 line.x[scan.right] = scan.x[1];
\r
555 line.z[scan.left] = scan.z[0];
\r
556 line.z[scan.right] = scan.z[1];
\r
560 line.w[scan.left] = scan.w[0];
\r
561 line.w[scan.right] = scan.w[1];
\r
565 line.c[0][scan.left] = scan.c[0][0];
\r
566 line.c[0][scan.right] = scan.c[0][1];
\r
570 line.t[0][scan.left] = scan.t[0][0];
\r
571 line.t[0][scan.right] = scan.t[0][1];
\r
575 line.t[1][scan.left] = scan.t[1][0];
\r
576 line.t[1][scan.right] = scan.t[1][1];
\r
579 // render a scanline
\r
580 scanline_bilinear ();
\r
581 if ( EdgeTestPass & edge_test_first_line ) break;
\r
583 scan.x[0] += scan.slopeX[0];
\r
584 scan.x[1] += scan.slopeX[1];
\r
587 scan.z[0] += scan.slopeZ[0];
\r
588 scan.z[1] += scan.slopeZ[1];
\r
592 scan.w[0] += scan.slopeW[0];
\r
593 scan.w[1] += scan.slopeW[1];
\r
597 scan.c[0][0] += scan.slopeC[0][0];
\r
598 scan.c[0][1] += scan.slopeC[0][1];
\r
602 scan.t[0][0] += scan.slopeT[0][0];
\r
603 scan.t[0][1] += scan.slopeT[0][1];
\r
607 scan.t[1][0] += scan.slopeT[1][0];
\r
608 scan.t[1][1] += scan.slopeT[1][1];
\r
618 } // end namespace video
\r
619 } // end namespace irr
\r
621 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
628 //! creates a flat triangle renderer
\r
629 IBurningShader* createTriangleRendererGouraud2(CBurningVideoDriver* driver)
\r
631 // ETR_GOURAUD . no texture
\r
632 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
633 return new CTRGouraud2(driver);
\r
636 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
640 } // end namespace video
\r
641 } // end namespace irr
\r