1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4
5 #include "IrrCompileConfig.h"
6 #include "IBurningShader.h"
7
8 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
9
10 // compile flag for this file
11 #undef USE_ZBUFFER
12 #undef IPOL_Z
13 #undef CMP_Z
14 #undef WRITE_Z
15
16 #undef IPOL_W
17 #undef CMP_W
18 #undef WRITE_W
19
20 #undef SUBTEXEL
21 #undef INVERSE_W
22
23 #undef IPOL_C0
24 #undef IPOL_T0
25 #undef IPOL_T1
26
27 // define render case
28 #define SUBTEXEL
29 #define INVERSE_W
30
31 #define USE_ZBUFFER
32 #define IPOL_W
33 #define CMP_W
34 #define WRITE_W
35
36 //#define IPOL_C0
37 #define IPOL_T0
38 //#define IPOL_T1
39
40 // apply global override
41 #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
42 #undef INVERSE_W
43 #endif
44
45 #ifndef SOFTWARE_DRIVER_2_SUBTEXEL
46 #undef SUBTEXEL
47 #endif
48
49 #ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR
50 #undef IPOL_C0
51 #endif
52
53 #if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER )
54 #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
55 #undef IPOL_W
56 #endif
57 #define IPOL_Z
58
59 #ifdef CMP_W
60 #undef CMP_W
61 #define CMP_Z
62 #endif
63
64 #ifdef WRITE_W
65 #undef WRITE_W
66 #define WRITE_Z
67 #endif
68
69 #endif
70
71
72
73 namespace irr
74 {
75
76 namespace video
77 {
78
79 class CTRTextureGouraudAdd2 : public IBurningShader
80 {
81 public:
82
83 //! constructor
84 CTRTextureGouraudAdd2(CBurningVideoDriver* driver);
85
86 //! draws an indexed triangle list
87 virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c );
88
89
90 private:
91 void scanline_bilinear ();
92 sScanLineData line;
93
94 };
95
96 //! constructor
CTRTextureGouraudAdd2(CBurningVideoDriver * driver)97 CTRTextureGouraudAdd2::CTRTextureGouraudAdd2(CBurningVideoDriver* driver)
98 : IBurningShader(driver)
99 {
100 #ifdef _DEBUG
101 setDebugName("CTRTextureGouraudAdd2");
102 #endif
103 }
104
105
106
107 /*!
108 */
scanline_bilinear()109 void CTRTextureGouraudAdd2::scanline_bilinear ()
110 {
111 tVideoSample *dst;
112
113 #ifdef USE_ZBUFFER
114 fp24 *z;
115 #endif
116
117 s32 xStart;
118 s32 xEnd;
119 s32 dx;
120
121
122 #ifdef SUBTEXEL
123 f32 subPixel;
124 #endif
125
126 #ifdef IPOL_Z
127 f32 slopeZ;
128 #endif
129 #ifdef IPOL_W
130 fp24 slopeW;
131 #endif
132 #ifdef IPOL_C0
133 sVec4 slopeC;
134 #endif
135 #ifdef IPOL_T0
136 sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES];
137 #endif
138
139 // apply top-left fill-convention, left
140 xStart = core::ceil32( line.x[0] );
141 xEnd = core::ceil32( line.x[1] ) - 1;
142
143 dx = xEnd - xStart;
144
145 if ( dx < 0 )
146 return;
147
148 // slopes
149 const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] );
150
151 #ifdef IPOL_Z
152 slopeZ = (line.z[1] - line.z[0]) * invDeltaX;
153 #endif
154 #ifdef IPOL_W
155 slopeW = (line.w[1] - line.w[0]) * invDeltaX;
156 #endif
157 #ifdef IPOL_C0
158 slopeC = (line.c[1] - line.c[0]) * invDeltaX;
159 #endif
160 #ifdef IPOL_T0
161 slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX;
162 #endif
163 #ifdef IPOL_T1
164 slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX;
165 #endif
166
167 #ifdef SUBTEXEL
168 subPixel = ( (f32) xStart ) - line.x[0];
169 #ifdef IPOL_Z
170 line.z[0] += slopeZ * subPixel;
171 #endif
172 #ifdef IPOL_W
173 line.w[0] += slopeW * subPixel;
174 #endif
175 #ifdef IPOL_C0
176 line.c[0] += slopeC * subPixel;
177 #endif
178 #ifdef IPOL_T0
179 line.t[0][0] += slopeT[0] * subPixel;
180 #endif
181 #ifdef IPOL_T1
182 line.t[1][0] += slopeT[1] * subPixel;
183 #endif
184 #endif
185
186 dst = (tVideoSample*)RenderTarget->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart;
187
188 #ifdef USE_ZBUFFER
189 z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart;
190 #endif
191
192
193 #ifdef INVERSE_W
194 f32 inversew;
195 #endif
196
197
198 #ifdef BURNINGVIDEO_RENDERER_FAST
199 u32 dIndex = ( line.y & 3 ) << 2;
200
201 #else
202 tFixPoint tx0;
203 tFixPoint ty0;
204
205 tFixPoint r0, g0, b0;
206 tFixPoint r1, g1, b1;
207 #endif
208
209
210 for ( s32 i = 0; i <= dx; ++i )
211 {
212 #ifdef CMP_Z
213 if ( line.z[0] < z[i] )
214 #endif
215 #ifdef CMP_W
216 if ( line.w[0] >= z[i] )
217 #endif
218
219 {
220
221
222 #ifdef BURNINGVIDEO_RENDERER_FAST
223
224 const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ];
225
226
227 #ifdef INVERSE_W
228 inversew = fix_inverse32 ( line.w[0] );
229
230 dst[i] = PixelAdd32 (
231 dst[i],
232 getTexel_plain ( &IT[0], d + tofix ( line.t[0][0].x,inversew),
233 d + tofix ( line.t[0][0].y,inversew) )
234 );
235 #else
236 dst[i] = PixelAdd32 (
237 dst[i],
238 getTexel_plain ( &IT[0], d + tofix ( line.t[0][0].x),
239 d + tofix ( line.t[0][0].y) )
240 );
241
242 #endif
243 #else
244
245 #ifdef INVERSE_W
246 inversew = fix_inverse32 ( line.w[0] );
247
248 tx0 = tofix ( line.t[0][0].x,inversew);
249 ty0 = tofix ( line.t[0][0].y,inversew);
250 #else
251 tx0 = tofix ( line.t[0][0].x );
252 ty0 = tofix ( line.t[0][0].y );
253 #endif
254 getSample_texture ( r0, g0, b0, &IT[0], tx0,ty0 );
255
256 color_to_fix ( r1, g1, b1, dst[i] );
257
258 dst[i] = fix_to_color ( clampfix_maxcolor ( r1 + r0 ),
259 clampfix_maxcolor ( g1 + g0 ),
260 clampfix_maxcolor ( b1 + b0 )
261 );
262 #endif
263
264 #ifdef WRITE_Z
265 z[i] = line.z[0];
266 #endif
267 #ifdef WRITE_W
268 z[i] = line.w[0];
269 #endif
270
271 }
272
273 #ifdef IPOL_Z
274 line.z[0] += slopeZ;
275 #endif
276 #ifdef IPOL_W
277 line.w[0] += slopeW;
278 #endif
279 #ifdef IPOL_C0
280 line.c[0] += slopeC;
281 #endif
282 #ifdef IPOL_T0
283 line.t[0][0] += slopeT[0];
284 #endif
285 #ifdef IPOL_T1
286 line.t[1][0] += slopeT[1];
287 #endif
288 }
289
290 }
291
drawTriangle(const s4DVertex * a,const s4DVertex * b,const s4DVertex * c)292 void CTRTextureGouraudAdd2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c )
293 {
294 sScanConvertData scan;
295
296 // sort on height, y
297 if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b);
298 if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c);
299 if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b);
300
301 const f32 ca = c->Pos.y - a->Pos.y;
302 const f32 ba = b->Pos.y - a->Pos.y;
303 const f32 cb = c->Pos.y - b->Pos.y;
304 // calculate delta y of the edges
305 scan.invDeltaY[0] = core::reciprocal( ca );
306 scan.invDeltaY[1] = core::reciprocal( ba );
307 scan.invDeltaY[2] = core::reciprocal( cb );
308
309 // find if the major edge is left or right aligned
310 f32 temp[4];
311
312 temp[0] = a->Pos.x - c->Pos.x;
313 temp[1] = -ca;
314 temp[2] = b->Pos.x - a->Pos.x;
315 temp[3] = ba;
316
317 scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1;
318 scan.right = 1 - scan.left;
319
320 // calculate slopes for the major edge
321 scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0];
322 scan.x[0] = a->Pos.x;
323
324 #ifdef IPOL_Z
325 scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0];
326 scan.z[0] = a->Pos.z;
327 #endif
328
329 #ifdef IPOL_W
330 scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0];
331 scan.w[0] = a->Pos.w;
332 #endif
333
334 #ifdef IPOL_C0
335 scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0];
336 scan.c[0] = a->Color[0];
337 #endif
338
339 #ifdef IPOL_T0
340 scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0];
341 scan.t[0][0] = a->Tex[0];
342 #endif
343
344 #ifdef IPOL_T1
345 scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0];
346 scan.t[1][0] = a->Tex[1];
347 #endif
348
349 // top left fill convention y run
350 s32 yStart;
351 s32 yEnd;
352
353 #ifdef SUBTEXEL
354 f32 subPixel;
355 #endif
356
357 // rasterize upper sub-triangle
358 if ( F32_GREATER_0 ( scan.invDeltaY[1] ) )
359 {
360 // calculate slopes for top edge
361 scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1];
362 scan.x[1] = a->Pos.x;
363
364 #ifdef IPOL_Z
365 scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1];
366 scan.z[1] = a->Pos.z;
367 #endif
368
369 #ifdef IPOL_W
370 scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1];
371 scan.w[1] = a->Pos.w;
372 #endif
373
374 #ifdef IPOL_C0
375 scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1];
376 scan.c[1] = a->Color[0];
377 #endif
378
379 #ifdef IPOL_T0
380 scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1];
381 scan.t[0][1] = a->Tex[0];
382 #endif
383
384 #ifdef IPOL_T1
385 scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1];
386 scan.t[1][1] = a->Tex[1];
387 #endif
388
389 // apply top-left fill convention, top part
390 yStart = core::ceil32( a->Pos.y );
391 yEnd = core::ceil32( b->Pos.y ) - 1;
392
393 #ifdef SUBTEXEL
394 subPixel = ( (f32) yStart ) - a->Pos.y;
395
396 // correct to pixel center
397 scan.x[0] += scan.slopeX[0] * subPixel;
398 scan.x[1] += scan.slopeX[1] * subPixel;
399
400 #ifdef IPOL_Z
401 scan.z[0] += scan.slopeZ[0] * subPixel;
402 scan.z[1] += scan.slopeZ[1] * subPixel;
403 #endif
404
405 #ifdef IPOL_W
406 scan.w[0] += scan.slopeW[0] * subPixel;
407 scan.w[1] += scan.slopeW[1] * subPixel;
408 #endif
409
410 #ifdef IPOL_C0
411 scan.c[0] += scan.slopeC[0] * subPixel;
412 scan.c[1] += scan.slopeC[1] * subPixel;
413 #endif
414
415 #ifdef IPOL_T0
416 scan.t[0][0] += scan.slopeT[0][0] * subPixel;
417 scan.t[0][1] += scan.slopeT[0][1] * subPixel;
418 #endif
419
420 #ifdef IPOL_T1
421 scan.t[1][0] += scan.slopeT[1][0] * subPixel;
422 scan.t[1][1] += scan.slopeT[1][1] * subPixel;
423 #endif
424
425 #endif
426
427 // rasterize the edge scanlines
428 for( line.y = yStart; line.y <= yEnd; ++line.y)
429 {
430 line.x[scan.left] = scan.x[0];
431 line.x[scan.right] = scan.x[1];
432
433 #ifdef IPOL_Z
434 line.z[scan.left] = scan.z[0];
435 line.z[scan.right] = scan.z[1];
436 #endif
437
438 #ifdef IPOL_W
439 line.w[scan.left] = scan.w[0];
440 line.w[scan.right] = scan.w[1];
441 #endif
442
443 #ifdef IPOL_C0
444 line.c[scan.left] = scan.c[0];
445 line.c[scan.right] = scan.c[1];
446 #endif
447
448 #ifdef IPOL_T0
449 line.t[0][scan.left] = scan.t[0][0];
450 line.t[0][scan.right] = scan.t[0][1];
451 #endif
452
453 #ifdef IPOL_T1
454 line.t[1][scan.left] = scan.t[1][0];
455 line.t[1][scan.right] = scan.t[1][1];
456 #endif
457
458 // render a scanline
459 scanline_bilinear ();
460
461 scan.x[0] += scan.slopeX[0];
462 scan.x[1] += scan.slopeX[1];
463
464 #ifdef IPOL_Z
465 scan.z[0] += scan.slopeZ[0];
466 scan.z[1] += scan.slopeZ[1];
467 #endif
468
469 #ifdef IPOL_W
470 scan.w[0] += scan.slopeW[0];
471 scan.w[1] += scan.slopeW[1];
472 #endif
473
474 #ifdef IPOL_C0
475 scan.c[0] += scan.slopeC[0];
476 scan.c[1] += scan.slopeC[1];
477 #endif
478
479 #ifdef IPOL_T0
480 scan.t[0][0] += scan.slopeT[0][0];
481 scan.t[0][1] += scan.slopeT[0][1];
482 #endif
483
484 #ifdef IPOL_T1
485 scan.t[1][0] += scan.slopeT[1][0];
486 scan.t[1][1] += scan.slopeT[1][1];
487 #endif
488
489 }
490 }
491
492 // rasterize lower sub-triangle
493 if ( (f32) 0.0 != scan.invDeltaY[2] )
494 {
495 // advance to middle point
496 if( (f32) 0.0 != scan.invDeltaY[1] )
497 {
498 temp[0] = b->Pos.y - a->Pos.y; // dy
499
500 scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0];
501 #ifdef IPOL_Z
502 scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0];
503 #endif
504 #ifdef IPOL_W
505 scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0];
506 #endif
507 #ifdef IPOL_C0
508 scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0];
509 #endif
510 #ifdef IPOL_T0
511 scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0];
512 #endif
513 #ifdef IPOL_T1
514 scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0];
515 #endif
516
517 }
518
519 // calculate slopes for bottom edge
520 scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2];
521 scan.x[1] = b->Pos.x;
522
523 #ifdef IPOL_Z
524 scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2];
525 scan.z[1] = b->Pos.z;
526 #endif
527
528 #ifdef IPOL_W
529 scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2];
530 scan.w[1] = b->Pos.w;
531 #endif
532
533 #ifdef IPOL_C0
534 scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2];
535 scan.c[1] = b->Color[0];
536 #endif
537
538 #ifdef IPOL_T0
539 scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2];
540 scan.t[0][1] = b->Tex[0];
541 #endif
542
543 #ifdef IPOL_T1
544 scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2];
545 scan.t[1][1] = b->Tex[1];
546 #endif
547
548 // apply top-left fill convention, top part
549 yStart = core::ceil32( b->Pos.y );
550 yEnd = core::ceil32( c->Pos.y ) - 1;
551
552 #ifdef SUBTEXEL
553
554 subPixel = ( (f32) yStart ) - b->Pos.y;
555
556 // correct to pixel center
557 scan.x[0] += scan.slopeX[0] * subPixel;
558 scan.x[1] += scan.slopeX[1] * subPixel;
559
560 #ifdef IPOL_Z
561 scan.z[0] += scan.slopeZ[0] * subPixel;
562 scan.z[1] += scan.slopeZ[1] * subPixel;
563 #endif
564
565 #ifdef IPOL_W
566 scan.w[0] += scan.slopeW[0] * subPixel;
567 scan.w[1] += scan.slopeW[1] * subPixel;
568 #endif
569
570 #ifdef IPOL_C0
571 scan.c[0] += scan.slopeC[0] * subPixel;
572 scan.c[1] += scan.slopeC[1] * subPixel;
573 #endif
574
575 #ifdef IPOL_T0
576 scan.t[0][0] += scan.slopeT[0][0] * subPixel;
577 scan.t[0][1] += scan.slopeT[0][1] * subPixel;
578 #endif
579
580 #ifdef IPOL_T1
581 scan.t[1][0] += scan.slopeT[1][0] * subPixel;
582 scan.t[1][1] += scan.slopeT[1][1] * subPixel;
583 #endif
584
585 #endif
586
587 // rasterize the edge scanlines
588 for( line.y = yStart; line.y <= yEnd; ++line.y)
589 {
590 line.x[scan.left] = scan.x[0];
591 line.x[scan.right] = scan.x[1];
592
593 #ifdef IPOL_Z
594 line.z[scan.left] = scan.z[0];
595 line.z[scan.right] = scan.z[1];
596 #endif
597
598 #ifdef IPOL_W
599 line.w[scan.left] = scan.w[0];
600 line.w[scan.right] = scan.w[1];
601 #endif
602
603 #ifdef IPOL_C0
604 line.c[scan.left] = scan.c[0];
605 line.c[scan.right] = scan.c[1];
606 #endif
607
608 #ifdef IPOL_T0
609 line.t[0][scan.left] = scan.t[0][0];
610 line.t[0][scan.right] = scan.t[0][1];
611 #endif
612
613 #ifdef IPOL_T1
614 line.t[1][scan.left] = scan.t[1][0];
615 line.t[1][scan.right] = scan.t[1][1];
616 #endif
617
618 // render a scanline
619 scanline_bilinear ();
620
621 scan.x[0] += scan.slopeX[0];
622 scan.x[1] += scan.slopeX[1];
623
624 #ifdef IPOL_Z
625 scan.z[0] += scan.slopeZ[0];
626 scan.z[1] += scan.slopeZ[1];
627 #endif
628
629 #ifdef IPOL_W
630 scan.w[0] += scan.slopeW[0];
631 scan.w[1] += scan.slopeW[1];
632 #endif
633
634 #ifdef IPOL_C0
635 scan.c[0] += scan.slopeC[0];
636 scan.c[1] += scan.slopeC[1];
637 #endif
638
639 #ifdef IPOL_T0
640 scan.t[0][0] += scan.slopeT[0][0];
641 scan.t[0][1] += scan.slopeT[0][1];
642 #endif
643
644 #ifdef IPOL_T1
645 scan.t[1][0] += scan.slopeT[1][0];
646 scan.t[1][1] += scan.slopeT[1][1];
647 #endif
648
649 }
650 }
651
652 }
653
654
655 } // end namespace video
656 } // end namespace irr
657
658 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
659
660 namespace irr
661 {
662 namespace video
663 {
664
665 //! creates a flat triangle renderer
createTRTextureGouraudAdd2(CBurningVideoDriver * driver)666 IBurningShader* createTRTextureGouraudAdd2(CBurningVideoDriver* driver)
667 {
668 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
669 return new CTRTextureGouraudAdd2(driver);
670 #else
671 return 0;
672 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
673 }
674
675
676 } // end namespace video
677 } // end namespace irr
678
679
680
681