| TGX 1.1.3 A tiny 2D/3D graphics library optimized for 32 bits microcontrollers.

Loading...
Searching...
No Matches
Shaders.h
Go to the documentation of this file.
1
5//
6// Copyright 2020 Arvind Singh
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Lesser General Public
10// License as published by the Free Software Foundation; either
11// version 2.1 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
16// Lesser General Public License for more details.
17//
18// You should have received a copy of the GNU Lesser General Public
19// License along with this library; If not, see <http://www.gnu.org/licenses/>.
20#ifndef _TGX_SHADERS_H_
21#define _TGX_SHADERS_H_
22
23
24// only C++, no plain C
25#ifdef __cplusplus
26
27
28#include "ShaderParams.h"
29
30 namespace tgx
31{
32
34 inline TGX_INLINE int shaderclip(int v, int maxv)
35 {
36 return ((v < 0) ? 0 : ((v > maxv) ? maxv : v));
37 }
38
39
40
44 template<typename color_t, typename ZBUFFER_t>
45 void shader_test(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
46 const int32_t dx1, const int32_t dy1, int32_t O1, const tgx::RasterizerVec4& fP1,
47 const int32_t dx2, const int32_t dy2, int32_t O2, const tgx::RasterizerVec4& fP2,
48 const int32_t dx3, const int32_t dy3, int32_t O3, const tgx::RasterizerVec4& fP3,
49 const tgx::RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
50 {
51 color_t col = (color_t)tgx::RGB32_Red; //data.facecolor;
52 const int32_t stride = data.im->stride();
53 color_t* buf = data.im->data() + oox + (ooy * stride);
54
55 for (int y = 0; y < ly; y++)
56 {
57 for (int x = 0; x < lx; x++)
58 {
59 const int32_t o1 = O1 + dx1 * x + dy1 * y;
60 const int32_t o2 = O2 + dx2 * x + dy2 * y;
61 const int32_t o3 = O3 + dx3 * x + dy3 * y;
62 if ((o1 >= 0) && (o2 >= 0) && (o3 >= 0))
63 {
64 buf[x + stride * y].blend256(col, 128);
65 }
66 }
67 }
68 }
69
70
71
72
73TGX_INLINE inline int tgx_clamp_i32(const int x, const int lo, const int hi)
74 {
75 return (x < lo) ? lo : ((x > hi) ? hi : x);
76 }
77
78
79TGX_INLINE inline uint16_t tgx_rgb565_pack_raw_u16(const int r, const int g, const int b)
80 {
81 #if TGX_SHADER_RGB565_FAST_CLAMP
82 const uint32_t rr = (uint32_t)tgx_clamp_i32(r, 0, 31);
83 const uint32_t gg = (uint32_t)tgx_clamp_i32(g, 0, 63);
84 const uint32_t bb = (uint32_t)tgx_clamp_i32(b, 0, 31);
85 #if TGX_RGB565_ORDER_BGR
86 return (uint16_t)((rr << 11) | (gg << 5) | bb);
87 #else
88 return (uint16_t)((bb << 11) | (gg << 5) | rr);
89 #endif
90 #else // Same spirit as RGB565 bitfields: keep only the useful low bits.
91 #if TGX_RGB565_ORDER_BGR
92 return (uint16_t)(((uint32_t)r << 11) | ((uint32_t)g << 5) | (uint32_t)b);
93 #else
94 return (uint16_t)(((uint32_t)b << 11) | ((uint32_t)g << 5) | (uint32_t)r);
95 #endif
96 #endif
97 }
98
99
100TGX_INLINE inline int tgx_rgb565_r5(const RGB565 c)
101 {
102 #if TGX_RGB565_ORDER_BGR
103 return (int)((c.val >> 11) & 31u);
104 #else
105 return (int)(c.val & 31u);
106 #endif
107 }
108
109
110TGX_INLINE inline int tgx_rgb565_g6(const RGB565 c)
111 {
112 return (int)((c.val >> 5) & 63u);
113 }
114
115
116TGX_INLINE inline int tgx_rgb565_b5(const RGB565 c)
117 {
118 #if TGX_RGB565_ORDER_BGR
119 return (int)(c.val & 31u);
120 #else
121 return (int)((c.val >> 11) & 31u);
122 #endif
123 }
124
125
126TGX_INLINE inline RGB565 tgx_rgb565_modulate256(const RGB565 c, const int mr, const int mg, const int mb)
127 {
128 const int r = (tgx_rgb565_r5(c) * mr) >> 8;
129 const int g = (tgx_rgb565_g6(c) * mg) >> 8;
130 const int b = (tgx_rgb565_b5(c) * mb) >> 8;
131 return RGB565(tgx_rgb565_pack_raw_u16(r, g, b));
132 }
133
134
135TGX_INLINE inline RGB565 tgx_rgb565_bilinear_fast(const RGB565& C00, const RGB565& C10, const RGB565& C01, const RGB565& C11, const float ax, const float ay)
136 {
137 const int iax = (int)(ax * 256);
138 const int iay = (int)(ay * 256);
139 const int rax = 256 - iax;
140 const int ray = 256 - iay;
141 const int R = rax * (ray * tgx_rgb565_r5(C00) + iay * tgx_rgb565_r5(C01)) + iax * (ray * tgx_rgb565_r5(C10) + iay * tgx_rgb565_r5(C11));
142 const int G = rax * (ray * tgx_rgb565_g6(C00) + iay * tgx_rgb565_g6(C01)) + iax * (ray * tgx_rgb565_g6(C10) + iay * tgx_rgb565_g6(C11));
143 const int B = rax * (ray * tgx_rgb565_b5(C00) + iay * tgx_rgb565_b5(C01)) + iax * (ray * tgx_rgb565_b5(C10) + iay * tgx_rgb565_b5(C11));
144 return RGB565(tgx_rgb565_pack_raw_u16(R >> 16, G >> 16, B >> 16));
145 }
146
147
148TGX_INLINE inline RGB565 tgx_rgb565_bilinear_modulate256(const RGB565& C00, const RGB565& C10, const RGB565& C01, const RGB565& C11, const float ax, const float ay,const int mr, const int mg, const int mb)
149 {
150 const int iax = (int)(ax * 256);
151 const int iay = (int)(ay * 256);
152 const int rax = 256 - iax;
153 const int ray = 256 - iay;
154 const int R = rax * (ray * tgx_rgb565_r5(C00) + iay * tgx_rgb565_r5(C01)) + iax * (ray * tgx_rgb565_r5(C10) + iay * tgx_rgb565_r5(C11));
155 const int G = rax * (ray * tgx_rgb565_g6(C00) + iay * tgx_rgb565_g6(C01)) + iax * (ray * tgx_rgb565_g6(C10) + iay * tgx_rgb565_g6(C11));
156 const int B = rax * (ray * tgx_rgb565_b5(C00) + iay * tgx_rgb565_b5(C01)) + iax * (ray * tgx_rgb565_b5(C10) + iay * tgx_rgb565_b5(C11));
157 const int r = (R * mr) >> 24;
158 const int g = (G * mg) >> 24;
159 const int b = (B * mb) >> 24;
160 return RGB565(tgx_rgb565_pack_raw_u16(r, g, b));
161 }
162
163
164TGX_INLINE inline RGB565 tgx_make_rgb565_from_raw(const int r, const int g, const int b)
165 {
166 return RGB565(tgx_rgb565_pack_raw_u16(r, g, b));
167 }
168
169
170
171
172
177 template<typename color_t, typename ZBUFFER_t,
178 bool USE_ZBUFFER, bool USE_GOURAUD, bool USE_TEXTURE,
179 bool USE_ORTHO, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP,
180 bool USE_UNLIT, bool USE_TEXTURE_AFFINE>
181 TGX_UBER_SHADER_INLINE inline void uber_shader_inline(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
182 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
183 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
184 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
185 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
186 {
187 static_assert(!(USE_GOURAUD && USE_UNLIT), "UNLIT and GOURAUD shader variants are mutually exclusive.");
188 static_assert((!USE_UNLIT) || USE_TEXTURE, "The dedicated UNLIT shader variant is only useful for textured rendering.");
189 constexpr bool USE_PERSPECTIVE_TEXTURE = USE_TEXTURE && !USE_ORTHO && !USE_TEXTURE_AFFINE;
190
191 // --- Common setup for all shaders ---
192 const int32_t stride = data.im->stride();
193 color_t* buf = data.im->data() + oox + (ooy * stride);
194
195 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
196 const int32_t pa = O1 + O2 + O3;
197 const int32_t E = ((pa == 0) ? 1 : 0);
198 const int32_t aera = pa + E;
199 const float faera = (float)aera;
200
201 // --- Z-Buffer setup ---
202 ZBUFFER_t* zbuf = nullptr;
203 int32_t zstride = 0;
204 float wa = 0.0f, wb = 0.0f;
205 float fP1a_z = 0.0f, fP2a_z = 0.0f, fP3a_z = 0.0f;
206 float fP1a_z_aera = 0.0f;
207 float fP21a_z = 0.0f, fP31a_z = 0.0f;
208 float dw_z = 0.0f;
209
210 float invaera = 0.0f;
211 if constexpr (USE_ZBUFFER || USE_TEXTURE)
212 {
213 invaera = fast_inv((float)aera);
214 }
215#if TGX_SHADER_GOURAUD_RGB565_FLOAT_INCREMENTAL
216 else if constexpr (USE_GOURAUD && !USE_TEXTURE && std::is_same<color_t, RGB565>::value)
217 {
218 invaera = fast_inv((float)aera);
219 }
220#endif
221
222 if constexpr (USE_ZBUFFER)
223 {
224 zstride = data.im->lx();
225 zbuf = data.zbuf + oox + (ooy * zstride);
226 wa = data.wa;
227 wb = data.wb;
228
229 if constexpr (!USE_PERSPECTIVE_TEXTURE)
230 {
231 // Normal z path, needed for:
232 // - no texture
233 // - orthographic texture
234 // - affine texture
235 //
236 // Use base+delta form:
237 // cw_z = fP1a_z*aera + C2*(fP2a_z-fP1a_z) + C3*(fP3a_z-fP1a_z)
238 // because C1 + C2 + C3 = aera.
239 const float invaera_wa_factor = USE_ORTHO ? 1.0f : wa;
240
241 fP1a_z = fP1.w * invaera * invaera_wa_factor;
242 fP2a_z = fP2.w * invaera * invaera_wa_factor;
243 fP3a_z = fP3.w * invaera * invaera_wa_factor;
244
245 fP21a_z = fP2a_z - fP1a_z;
246 fP31a_z = fP3a_z - fP1a_z;
247 fP1a_z_aera = fP1a_z * faera;
248
249 dw_z = (dx2 * fP21a_z) + (dx3 * fP31a_z);
250 }
251 }
252
253 // --- Shading & Texturing setup ---
254 color_t flat_color;
255 color_t col1_g, col2_g, col3_g;
256 int shiftC = 0, aeraShifted = 0;
257 int fPR = 0, fPG = 0, fPB = 0; // Flat color components
258 int fP1R = 0, fP1G = 0, fP1B = 0; // Gouraud color components
259 int fP21R = 0, fP21G = 0, fP21B = 0;
260 int fP31R = 0, fP31G = 0, fP31B = 0;
261
262#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
263 float fP21Rf = 0.0f, fP21Gf = 0.0f, fP21Bf = 0.0f;
264 float fP31Rf = 0.0f, fP31Gf = 0.0f, fP31Bf = 0.0f;
265 float dGR = 0.0f, dGG = 0.0f, dGB = 0.0f;
266#endif
267
268#if TGX_SHADER_GOURAUD_RGB565_FLOAT_INCREMENTAL
269 float g565P1R = 0.0f, g565P1G = 0.0f, g565P1B = 0.0f;
270 float g565P21R = 0.0f, g565P21G = 0.0f, g565P21B = 0.0f;
271 float g565P31R = 0.0f, g565P31G = 0.0f, g565P31B = 0.0f;
272 float g565dR = 0.0f, g565dG = 0.0f, g565dB = 0.0f;
273#endif
274
275 float invaera_persp = 0.0f;
276 float fP1a_p = 0.0f, fP2a_p = 0.0f, fP3a_p = 0.0f;
277 float dw_p = 0.0f;
278
279 const color_t* tex = nullptr;
280 int32_t texsize_x_mm = 0, texsize_y_mm = 0, texstride = 0;
281 float dtx = 0.0f, dty = 0.0f;
282 fVec2 T1, T2, T3;
283
284 float T1x_aera = 0.0f, T1y_aera = 0.0f;
285 float T21x = 0.0f, T31x = 0.0f;
286 float T21y = 0.0f, T31y = 0.0f;
287
288 float fP1a_p_aera = 0.0f;
289 float fP21a_p = 0.0f, fP31a_p = 0.0f;
290
291 if constexpr (USE_GOURAUD)
292 {
293 if constexpr (USE_TEXTURE)
294 {
295 const RGBf& cf1 = fP1.color;
296 const RGBf& cf2 = fP2.color;
297 const RGBf& cf3 = fP3.color;
298
299 fP1R = (int)(256 * cf1.R); fP1G = (int)(256 * cf1.G); fP1B = (int)(256 * cf1.B);
300 fP21R = (int)(256 * (cf2.R - cf1.R)); fP21G = (int)(256 * (cf2.G - cf1.G)); fP21B = (int)(256 * (cf2.B - cf1.B));
301 fP31R = (int)(256 * (cf3.R - cf1.R)); fP31G = (int)(256 * (cf3.G - cf1.G)); fP31B = (int)(256 * (cf3.B - cf1.B));
302
303 shiftC = (aera > (1 << 22)) ? 10 : 0;
304 aeraShifted = aera >> shiftC;
305
306#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
307 fP21Rf = (float)fP21R; fP21Gf = (float)fP21G; fP21Bf = (float)fP21B;
308 fP31Rf = (float)fP31R; fP31Gf = (float)fP31G; fP31Bf = (float)fP31B;
309
310 dGR = ((dx2 * fP21Rf) + (dx3 * fP31Rf)) * invaera;
311 dGG = ((dx2 * fP21Gf) + (dx3 * fP31Gf)) * invaera;
312 dGB = ((dx2 * fP21Bf) + (dx3 * fP31Bf)) * invaera;
313#endif
314 }
315 else
316 {
317#if TGX_SHADER_GOURAUD_RGB565_FLOAT_INCREMENTAL
318 if constexpr (std::is_same<color_t, RGB565>::value)
319 {
320 const RGBf& cf1 = fP1.color;
321 const RGBf& cf2 = fP2.color;
322 const RGBf& cf3 = fP3.color;
323
324 g565P1R = 31.0f * cf1.R;
325 g565P1G = 63.0f * cf1.G;
326 g565P1B = 31.0f * cf1.B;
327
328 g565P21R = 31.0f * (cf2.R - cf1.R);
329 g565P21G = 63.0f * (cf2.G - cf1.G);
330 g565P21B = 31.0f * (cf2.B - cf1.B);
331
332 g565P31R = 31.0f * (cf3.R - cf1.R);
333 g565P31G = 63.0f * (cf3.G - cf1.G);
334 g565P31B = 31.0f * (cf3.B - cf1.B);
335
336 g565dR = ((dx2 * g565P21R) + (dx3 * g565P31R)) * invaera;
337 g565dG = ((dx2 * g565P21G) + (dx3 * g565P31G)) * invaera;
338 g565dB = ((dx2 * g565P21B) + (dx3 * g565P31B)) * invaera;
339 }
340 else
341#endif
342 {
343 col1_g = (color_t)fP1.color;
344 col2_g = (color_t)fP2.color;
345 col3_g = (color_t)fP3.color;
346 shiftC = (aera > (1 << 22)) ? 10 : 0;
347 aeraShifted = aera >> shiftC;
348 }
349 }
350 }
351 else // Flat or unlit shading
352 {
353 if constexpr (!USE_TEXTURE)
354 {
355 flat_color = (color_t)data.facecolor;
356 }
357 else if constexpr (!USE_UNLIT)
358 {
359 const RGBf& cf = data.facecolor;
360 fPR = (int)(256 * cf.R); fPG = (int)(256 * cf.G); fPB = (int)(256 * cf.B);
361 }
362 }
363
364 if constexpr (USE_TEXTURE)
365 {
366 tex = data.tex->data();
367 const int32_t texsize_x = data.tex->width();
368 const int32_t texsize_y = data.tex->height();
369 texsize_x_mm = texsize_x - 1;
370 texsize_y_mm = texsize_y - 1;
371 texstride = data.tex->stride();
372
373 T1 = fP1.T; T2 = fP2.T; T3 = fP3.T;
374
375 if constexpr (!USE_PERSPECTIVE_TEXTURE)
376 {
377 T1 *= invaera; T2 *= invaera; T3 *= invaera;
378 }
379 else // Perspective-correct texture
380 {
381 invaera_persp = invaera;
382 fP1a_p = fP1.w * invaera_persp;
383 fP2a_p = fP2.w * invaera_persp;
384 fP3a_p = fP3.w * invaera_persp;
385 T1 *= fP1a_p; T2 *= fP2a_p; T3 *= fP3a_p;
386 }
387
388 T1.x *= texsize_x; T2.x *= texsize_x; T3.x *= texsize_x;
389 T1.y *= texsize_y; T2.y *= texsize_y; T3.y *= texsize_y;
390
391 T21x = T2.x - T1.x;
392 T31x = T3.x - T1.x;
393 T21y = T2.y - T1.y;
394 T31y = T3.y - T1.y;
395
396 T1x_aera = T1.x * faera;
397 T1y_aera = T1.y * faera;
398
399 dtx = (T21x * dx2) + (T31x * dx3);
400 dty = (T21y * dx2) + (T31y * dx3);
401
402 if constexpr (USE_PERSPECTIVE_TEXTURE)
403 {
404 fP21a_p = fP2a_p - fP1a_p;
405 fP31a_p = fP3a_p - fP1a_p;
406 fP1a_p_aera = fP1a_p * faera;
407
408 dw_p = (fP21a_p * dx2) + (fP31a_p * dx3);
409 if constexpr (USE_ZBUFFER) { dw_z = dw_p * wa; }
410 }
411 }
412
413 // --- Scanline iteration ---
414 while ((uintptr_t)(buf) < end)
415 {
416 // --- Clipping and finding start x (bx) ---
417 int32_t bx = 0;
418 if (O1 < 0)
419 {
420 bx = (-O1 + dx1 - 1u) / dx1;
421 }
422 if (O2 < 0)
423 {
424 if (dx2 <= 0)
425 {
426 if (dy2 <= 0) return;
427 const int32_t by = (-O2 + dy2 - 1u) / dy2;
428 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
429 buf += by * stride;
430 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
431 continue;
432 }
433 bx = max(bx, (int32_t)((-O2 + dx2 - 1u) / dx2));
434 }
435 if (O3 < 0)
436 {
437 if (dx3 <= 0)
438 {
439 if (dy3 <= 0) return;
440 const int32_t by = (-O3 + dy3 - 1u) / dy3;
441 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
442 buf += by * stride;
443 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
444 continue;
445 }
446 bx = max(bx, (int32_t)((-O3 + dx3 - 1u) / dx3));
447 }
448
449 // --- Per-scanline setup ---
450 int32_t C2 = O2 + (dx2 * bx);
451 int32_t C3 = O3 + (dx3 * bx);
452
453 float cw_z = 0.0f;
454 float cw_p = 0.0f;
455 float tx = 0.0f, ty = 0.0f;
456
457#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
458 float gR = 0.0f, gG = 0.0f, gB = 0.0f;
459
460 if constexpr (USE_GOURAUD && USE_TEXTURE)
461 {
462 gR = (float)fP1R + (((float)C2 * fP21Rf) + ((float)C3 * fP31Rf)) * invaera;
463 gG = (float)fP1G + (((float)C2 * fP21Gf) + ((float)C3 * fP31Gf)) * invaera;
464 gB = (float)fP1B + (((float)C2 * fP21Bf) + ((float)C3 * fP31Bf)) * invaera;
465 }
466#endif
467
468#if TGX_SHADER_GOURAUD_RGB565_FLOAT_INCREMENTAL
469 float g565R = 0.0f, g565G = 0.0f, g565B = 0.0f;
470
471 if constexpr (USE_GOURAUD && !USE_TEXTURE && std::is_same<color_t, RGB565>::value)
472 {
473 g565R = g565P1R + (((float)C2 * g565P21R) + ((float)C3 * g565P31R)) * invaera;
474 g565G = g565P1G + (((float)C2 * g565P21G) + ((float)C3 * g565P31G)) * invaera;
475 g565B = g565P1B + (((float)C2 * g565P21B) + ((float)C3 * g565P31B)) * invaera;
476 }
477#endif
478
479 if constexpr (USE_TEXTURE)
480 {
481 tx = T1x_aera + (T21x * C2) + (T31x * C3);
482 ty = T1y_aera + (T21y * C2) + (T31y * C3);
483
484 if constexpr (USE_PERSPECTIVE_TEXTURE)
485 {
486 cw_p = fP1a_p_aera + (fP21a_p * C2) + (fP31a_p * C3);
487 if constexpr (USE_ZBUFFER)
488 { // Perspective textured path: cw_z = wa * cw_p + wb.
489 cw_z = (cw_p * wa) + wb;
490 }
491 }
492 }
493
494 if constexpr (USE_ZBUFFER)
495 {
496 if constexpr (!USE_PERSPECTIVE_TEXTURE)
497 {
498 cw_z = fP1a_z_aera + (C2 * fP21a_z) + (C3 * fP31a_z);
499 if constexpr (!USE_ORTHO) { cw_z += wb; }
500 }
501 }
502
503 // --- Pixel loop ---
504#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
505 color_t* pix = buf + bx;
506 ZBUFFER_t* zpix = nullptr;
507 if constexpr (USE_ZBUFFER)
508 {
509 zpix = zbuf + bx;
510 }
511#endif
512 while ((bx < lx) && ((C2 | C3) >= 0))
513 {
514 bool z_pass = true;
515 if constexpr (USE_ZBUFFER)
516 {
517#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
518 ZBUFFER_t& W = *zpix;
519#else
520 ZBUFFER_t& W = zbuf[bx];
521#endif
522 ZBUFFER_t current_z;
523
524 if constexpr (std::is_same<ZBUFFER_t, uint16_t>::value)
525 {
526 current_z = (USE_ORTHO) ? ((ZBUFFER_t)(cw_z * wa + wb)) : ((ZBUFFER_t)cw_z);
527 }
528 else
529 {
530 current_z = (ZBUFFER_t)cw_z;
531 }
532
533 if (W < current_z)
534 {
535 W = current_z;
536 }
537 else
538 {
539 z_pass = false;
540 }
541 }
542
543 if (z_pass)
544 {
545 color_t final_color;
546
547 if constexpr (USE_TEXTURE)
548 {
549 float xx, yy;
550 if constexpr (USE_PERSPECTIVE_TEXTURE)
551 {
552 const float icw = fast_inv_approx(cw_p);
553 xx = tx * icw;
554 yy = ty * icw;
555 }
556 else
557 {
558 xx = tx;
559 yy = ty;
560 }
561
562 int modR = 256;
563 int modG = 256;
564 int modB = 256;
565
566 if constexpr (USE_GOURAUD)
567 {
568#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
569 modR = (int)gR;
570 modG = (int)gG;
571 modB = (int)gB;
572#else
573 const int32_t C2s = C2 >> shiftC;
574 const int32_t C3s = C3 >> shiftC;
575 modR = fP1R + ((C2s * fP21R + C3s * fP31R) / aeraShifted);
576 modG = fP1G + ((C2s * fP21G + C3s * fP31G) / aeraShifted);
577 modB = fP1B + ((C2s * fP21B + C3s * fP31B) / aeraShifted);
578#endif
579 }
580 else if constexpr (!USE_UNLIT) // Flat
581 {
582 modR = fPR;
583 modG = fPG;
584 modB = fPB;
585 }
586
587#if TGX_SHADER_RGB565_FAST_TEXTURE_MODULATE
588 if constexpr (std::is_same<color_t, RGB565>::value)
589 {
590 if constexpr (TEXTURE_BILINEAR)
591 {
592 const int ttx = lfloorf(xx);
593 const int tty = lfloorf(yy);
594 const float ax = xx - ttx;
595 const float ay = yy - tty;
596
597 const int minx = TEXTURE_WRAP ? (ttx & texsize_x_mm) : shaderclip(ttx, texsize_x_mm);
598 const int maxx = TEXTURE_WRAP ? ((ttx + 1) & texsize_x_mm) : shaderclip(ttx + 1, texsize_x_mm);
599 const int miny = (TEXTURE_WRAP ? (tty & texsize_y_mm) : shaderclip(tty, texsize_y_mm)) * texstride;
600 const int maxy = (TEXTURE_WRAP ? ((tty + 1) & texsize_y_mm) : shaderclip(tty + 1, texsize_y_mm)) * texstride;
601
602 if constexpr (USE_UNLIT)
603 {
604#if TGX_SHADER_RGB565_FAST_BILINEAR
605 final_color = tgx_rgb565_bilinear_fast(
606 tex[minx + miny],
607 tex[maxx + miny],
608 tex[minx + maxy],
609 tex[maxx + maxy],
610 ax,
611 ay);
612#else
613 final_color = interpolateColorsBilinear(
614 tex[minx + miny],
615 tex[maxx + miny],
616 tex[minx + maxy],
617 tex[maxx + maxy],
618 ax,
619 ay);
620#endif
621 }
622 else
623 {
624 final_color = tgx_rgb565_bilinear_modulate256(
625 tex[minx + miny],
626 tex[maxx + miny],
627 tex[minx + maxy],
628 tex[maxx + maxy],
629 ax,
630 ay,
631 modR,
632 modG,
633 modB);
634 }
635 }
636 else // Nearest neighbor
637 {
638 const int ttx = TEXTURE_WRAP ? ((int)(xx)) & texsize_x_mm : shaderclip((int)(xx), texsize_x_mm);
639 const int tty = TEXTURE_WRAP ? ((int)(yy)) & texsize_y_mm : shaderclip((int)(yy), texsize_y_mm);
640
641 if constexpr (USE_UNLIT)
642 {
643 final_color = tex[ttx + tty * texstride];
644 }
645 else
646 {
647 final_color = tgx_rgb565_modulate256(tex[ttx + tty * texstride], modR, modG, modB);
648 }
649 }
650 }
651 else
652#endif
653 {
654 if constexpr (TEXTURE_BILINEAR)
655 {
656 const int ttx = lfloorf(xx);
657 const int tty = lfloorf(yy);
658 const float ax = xx - ttx;
659 const float ay = yy - tty;
660
661 const int minx = TEXTURE_WRAP ? (ttx & texsize_x_mm) : shaderclip(ttx, texsize_x_mm);
662 const int maxx = TEXTURE_WRAP ? ((ttx + 1) & texsize_x_mm) : shaderclip(ttx + 1, texsize_x_mm);
663 const int miny = (TEXTURE_WRAP ? (tty & texsize_y_mm) : shaderclip(tty, texsize_y_mm)) * texstride;
664 const int maxy = (TEXTURE_WRAP ? ((tty + 1) & texsize_y_mm) : shaderclip(tty + 1, texsize_y_mm)) * texstride;
665
666#if TGX_SHADER_RGB565_FAST_BILINEAR
667 if constexpr (std::is_same<color_t, RGB565>::value)
668 {
669 final_color = tgx_rgb565_bilinear_fast(
670 tex[minx + miny],
671 tex[maxx + miny],
672 tex[minx + maxy],
673 tex[maxx + maxy],
674 ax,
675 ay);
676 }
677 else
678#endif
679 {
680 final_color = interpolateColorsBilinear(
681 tex[minx + miny],
682 tex[maxx + miny],
683 tex[minx + maxy],
684 tex[maxx + maxy],
685 ax,
686 ay);
687 }
688 }
689 else // Nearest neighbor
690 {
691 const int ttx = TEXTURE_WRAP ? ((int)(xx)) & texsize_x_mm : shaderclip((int)(xx), texsize_x_mm);
692 const int tty = TEXTURE_WRAP ? ((int)(yy)) & texsize_y_mm : shaderclip((int)(yy), texsize_y_mm);
693 final_color = tex[ttx + tty * texstride];
694 }
695
696 if constexpr (USE_GOURAUD)
697 {
698 final_color.mult256(modR, modG, modB);
699 }
700 else if constexpr (!USE_UNLIT) // Flat
701 {
702 final_color.mult256(modR, modG, modB);
703 }
704 }
705 }
706 else // No texture
707 {
708 if constexpr (USE_GOURAUD)
709 {
710#if TGX_SHADER_GOURAUD_RGB565_FLOAT_INCREMENTAL
711 if constexpr (std::is_same<color_t, RGB565>::value)
712 {
713 final_color = tgx_make_rgb565_from_raw((int)g565R, (int)g565G, (int)g565B);
714 }
715 else
716#endif
717 {
718 final_color = interpolateColorsTriangle(col2_g, C2 >> shiftC, col3_g, C3 >> shiftC, col1_g, aeraShifted);
719 }
720 }
721 else // Flat
722 {
723 final_color = flat_color;
724 }
725 }
726
727#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
728 *pix = final_color;
729#else
730 buf[bx] = final_color;
731#endif
732 }
733
734 // --- Increment for next pixel ---
735 C2 += dx2;
736 C3 += dx3;
737
738#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
739 if constexpr (USE_GOURAUD && USE_TEXTURE)
740 {
741 gR += dGR;
742 gG += dGG;
743 gB += dGB;
744 }
745#endif
746
747#if TGX_SHADER_GOURAUD_RGB565_FLOAT_INCREMENTAL
748 if constexpr (USE_GOURAUD && !USE_TEXTURE && std::is_same<color_t, RGB565>::value)
749 {
750 g565R += g565dR;
751 g565G += g565dG;
752 g565B += g565dB;
753 }
754#endif
755
756 bx++;
757
758#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
759 pix++;
760#endif
761
762 if constexpr (USE_ZBUFFER) cw_z += dw_z;
763
764#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
765 if constexpr (USE_ZBUFFER) zpix++;
766#endif
767
768 if constexpr (USE_TEXTURE)
769 {
770 tx += dtx;
771 ty += dty;
772 if constexpr (USE_PERSPECTIVE_TEXTURE) cw_p += dw_p;
773 }
774 }
775
776 // --- Increment for next scanline ---
777 O1 += dy1;
778 O2 += dy2;
779 O3 += dy3;
780 buf += stride;
781 if constexpr (USE_ZBUFFER) zbuf += zstride;
782 }
783 }
784
785
786
787
788 /* OLD VERSION
789 template<typename color_t, typename ZBUFFER_t,
790 bool USE_ZBUFFER, bool USE_GOURAUD, bool USE_TEXTURE,
791 bool USE_ORTHO, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP,
792 bool USE_UNLIT>
793 TGX_UBER_SHADER_INLINE inline void uber_shader_inline(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
794 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
795 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
796 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
797 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
798 {
799 static_assert(!(USE_GOURAUD && USE_UNLIT), "UNLIT and GOURAUD shader variants are mutually exclusive.");
800 static_assert((!USE_UNLIT) || USE_TEXTURE, "The dedicated UNLIT shader variant is only useful for textured rendering.");
801
802 // --- Common setup for all shaders ---
803 const int32_t stride = data.im->stride();
804 color_t* buf = data.im->data() + oox + (ooy * stride);
805
806 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
807 const int32_t pa = O1 + O2 + O3;
808 const int32_t E = ((pa == 0) ? 1 : 0);
809 const int32_t aera = pa + E;
810 const float faera = (float)aera;
811
812 // --- Z-Buffer setup ---
813 ZBUFFER_t* zbuf = nullptr;
814 int32_t zstride = 0;
815 float wa = 0.0f, wb = 0.0f;
816 float fP1a_z = 0.0f, fP2a_z = 0.0f, fP3a_z = 0.0f;
817 float fP1a_z_aera = 0.0f;
818 float fP21a_z = 0.0f, fP31a_z = 0.0f;
819 float dw_z = 0.0f;
820
821 float invaera = 0.0f;
822 if constexpr (USE_ZBUFFER || USE_TEXTURE) { invaera = fast_inv((float)aera); }
823
824 if constexpr (USE_ZBUFFER)
825 {
826 zstride = data.im->lx();
827 zbuf = data.zbuf + oox + (ooy * zstride);
828 wa = data.wa;
829 wb = data.wb;
830
831 if constexpr (!(USE_TEXTURE && !USE_ORTHO))
832 {
833 // Normal z path, needed for:
834 // - no texture
835 // - orthographic texture
836 //
837 // Use base+delta form:
838 // cw_z = fP1a_z*aera + C2*(fP2a_z-fP1a_z) + C3*(fP3a_z-fP1a_z)
839 // because C1 + C2 + C3 = aera.
840 const float invaera_wa_factor = USE_ORTHO ? 1.0f : wa;
841
842 fP1a_z = fP1.w * invaera * invaera_wa_factor;
843 fP2a_z = fP2.w * invaera * invaera_wa_factor;
844 fP3a_z = fP3.w * invaera * invaera_wa_factor;
845
846 fP21a_z = fP2a_z - fP1a_z;
847 fP31a_z = fP3a_z - fP1a_z;
848 fP1a_z_aera = fP1a_z * faera;
849
850 dw_z = (dx2 * fP21a_z) + (dx3 * fP31a_z);
851 }
852 }
853
854 // --- Shading & Texturing setup ---
855 color_t flat_color;
856 color_t col1_g, col2_g, col3_g;
857 int shiftC = 0, aeraShifted = 0;
858 int fPR = 0, fPG = 0, fPB = 0; // Flat color components
859 int fP1R = 0, fP1G = 0, fP1B = 0; // Gouraud color components
860 int fP21R = 0, fP21G = 0, fP21B = 0;
861 int fP31R = 0, fP31G = 0, fP31B = 0;
862
863#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
864 float fP21Rf = 0.0f, fP21Gf = 0.0f, fP21Bf = 0.0f;
865 float fP31Rf = 0.0f, fP31Gf = 0.0f, fP31Bf = 0.0f;
866 float dGR = 0.0f, dGG = 0.0f, dGB = 0.0f;
867#endif
868
869 float invaera_persp = 0.0f;
870 float fP1a_p = 0.0f, fP2a_p = 0.0f, fP3a_p = 0.0f;
871 float dw_p = 0.0f;
872
873 const color_t* tex = nullptr;
874 int32_t texsize_x_mm = 0, texsize_y_mm = 0, texstride = 0;
875 float dtx = 0.0f, dty = 0.0f;
876 fVec2 T1, T2, T3;
877
878 float T1x_aera = 0.0f, T1y_aera = 0.0f;
879 float T21x = 0.0f, T31x = 0.0f;
880 float T21y = 0.0f, T31y = 0.0f;
881
882 float fP1a_p_aera = 0.0f;
883 float fP21a_p = 0.0f, fP31a_p = 0.0f;
884
885 if constexpr (USE_GOURAUD)
886 {
887 if constexpr (USE_TEXTURE)
888 {
889 const RGBf& cf1 = fP1.color;
890 const RGBf& cf2 = fP2.color;
891 const RGBf& cf3 = fP3.color;
892
893 fP1R = (int)(256 * cf1.R); fP1G = (int)(256 * cf1.G); fP1B = (int)(256 * cf1.B);
894 fP21R = (int)(256 * (cf2.R - cf1.R)); fP21G = (int)(256 * (cf2.G - cf1.G)); fP21B = (int)(256 * (cf2.B - cf1.B));
895 fP31R = (int)(256 * (cf3.R - cf1.R)); fP31G = (int)(256 * (cf3.G - cf1.G)); fP31B = (int)(256 * (cf3.B - cf1.B));
896
897 shiftC = (aera > (1 << 22)) ? 10 : 0;
898 aeraShifted = aera >> shiftC;
899
900#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
901 fP21Rf = (float)fP21R; fP21Gf = (float)fP21G; fP21Bf = (float)fP21B;
902 fP31Rf = (float)fP31R; fP31Gf = (float)fP31G; fP31Bf = (float)fP31B;
903
904 dGR = ((dx2 * fP21Rf) + (dx3 * fP31Rf)) * invaera;
905 dGG = ((dx2 * fP21Gf) + (dx3 * fP31Gf)) * invaera;
906 dGB = ((dx2 * fP21Bf) + (dx3 * fP31Bf)) * invaera;
907#endif
908 }
909 else
910 {
911 col1_g = (color_t)fP1.color;
912 col2_g = (color_t)fP2.color;
913 col3_g = (color_t)fP3.color;
914 shiftC = (aera > (1 << 22)) ? 10 : 0;
915 aeraShifted = aera >> shiftC;
916 }
917 }
918 else // Flat or unlit shading
919 {
920 flat_color = (color_t)data.facecolor;
921 if constexpr (USE_TEXTURE && !USE_UNLIT)
922 {
923 const RGBf& cf = data.facecolor;
924 fPR = (int)(256 * cf.R); fPG = (int)(256 * cf.G); fPB = (int)(256 * cf.B);
925 }
926 }
927
928 if constexpr (USE_TEXTURE)
929 {
930 tex = data.tex->data();
931 const int32_t texsize_x = data.tex->width();
932 const int32_t texsize_y = data.tex->height();
933 texsize_x_mm = texsize_x - 1;
934 texsize_y_mm = texsize_y - 1;
935 texstride = data.tex->stride();
936
937 T1 = fP1.T; T2 = fP2.T; T3 = fP3.T;
938
939 if constexpr (USE_ORTHO)
940 {
941 T1 *= invaera; T2 *= invaera; T3 *= invaera;
942 }
943 else // Perspective
944 {
945 invaera_persp = invaera;
946 fP1a_p = fP1.w * invaera_persp;
947 fP2a_p = fP2.w * invaera_persp;
948 fP3a_p = fP3.w * invaera_persp;
949 T1 *= fP1a_p; T2 *= fP2a_p; T3 *= fP3a_p;
950 }
951
952 T1.x *= texsize_x; T2.x *= texsize_x; T3.x *= texsize_x;
953 T1.y *= texsize_y; T2.y *= texsize_y; T3.y *= texsize_y;
954
955 T21x = T2.x - T1.x;
956 T31x = T3.x - T1.x;
957 T21y = T2.y - T1.y;
958 T31y = T3.y - T1.y;
959
960 T1x_aera = T1.x * faera;
961 T1y_aera = T1.y * faera;
962
963 dtx = (T21x * dx2) + (T31x * dx3);
964 dty = (T21y * dx2) + (T31y * dx3);
965
966 if constexpr (!USE_ORTHO)
967 {
968 fP21a_p = fP2a_p - fP1a_p;
969 fP31a_p = fP3a_p - fP1a_p;
970 fP1a_p_aera = fP1a_p * faera;
971
972 dw_p = (fP21a_p * dx2) + (fP31a_p * dx3);
973 if constexpr (USE_ZBUFFER) { dw_z = dw_p * wa; }
974 }
975 }
976
977 // --- Scanline iteration ---
978 while ((uintptr_t)(buf) < end)
979 {
980 // --- Clipping and finding start x (bx) ---
981 int32_t bx = 0;
982 if (O1 < 0)
983 {
984 bx = (-O1 + dx1 - 1u) / dx1;
985 }
986 if (O2 < 0)
987 {
988 if (dx2 <= 0)
989 {
990 if (dy2 <= 0) return;
991 const int32_t by = (-O2 + dy2 - 1u) / dy2;
992 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
993 buf += by * stride;
994 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
995 continue;
996 }
997 bx = max(bx, (int32_t)((-O2 + dx2 - 1u) / dx2));
998 }
999 if (O3 < 0)
1000 {
1001 if (dx3 <= 0)
1002 {
1003 if (dy3 <= 0) return;
1004 const int32_t by = (-O3 + dy3 - 1u) / dy3;
1005 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
1006 buf += by * stride;
1007 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
1008 continue;
1009 }
1010 bx = max(bx, (int32_t)((-O3 + dx3 - 1u) / dx3));
1011 }
1012
1013 // --- Per-scanline setup ---
1014 int32_t C1 = O1 + (dx1 * bx) + E;
1015 int32_t C2 = O2 + (dx2 * bx);
1016 int32_t C3 = O3 + (dx3 * bx);
1017
1018 float cw_z = 0.0f;
1019 float cw_p = 0.0f;
1020 float tx = 0.0f, ty = 0.0f;
1021
1022#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
1023 float gR = 0.0f, gG = 0.0f, gB = 0.0f;
1024
1025 if constexpr (USE_GOURAUD && USE_TEXTURE)
1026 {
1027 gR = (float)fP1R + (((float)C2 * fP21Rf) + ((float)C3 * fP31Rf)) * invaera;
1028 gG = (float)fP1G + (((float)C2 * fP21Gf) + ((float)C3 * fP31Gf)) * invaera;
1029 gB = (float)fP1B + (((float)C2 * fP21Bf) + ((float)C3 * fP31Bf)) * invaera;
1030 }
1031#endif
1032
1033 if constexpr (USE_TEXTURE)
1034 {
1035 tx = T1x_aera + (T21x * C2) + (T31x * C3);
1036 ty = T1y_aera + (T21y * C2) + (T31y * C3);
1037
1038 if constexpr (!USE_ORTHO)
1039 {
1040 cw_p = fP1a_p_aera + (fP21a_p * C2) + (fP31a_p * C3);
1041 if constexpr (USE_ZBUFFER)
1042 { // Perspective textured path: cw_z = wa * cw_p + wb.
1043 cw_z = (cw_p * wa) + wb;
1044 }
1045 }
1046 }
1047
1048 if constexpr (USE_ZBUFFER)
1049 {
1050 if constexpr (!(USE_TEXTURE && !USE_ORTHO))
1051 {
1052 cw_z = fP1a_z_aera + (C2 * fP21a_z) + (C3 * fP31a_z);
1053 if constexpr (!USE_ORTHO) { cw_z += wb; }
1054 }
1055 }
1056
1057 // --- Pixel loop ---
1058#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1059 color_t* pix = buf + bx;
1060 ZBUFFER_t* zpix = nullptr;
1061 if constexpr (USE_ZBUFFER)
1062 {
1063 zpix = zbuf + bx;
1064 }
1065#endif
1066 while ((bx < lx) && ((C2 | C3) >= 0))
1067 {
1068 bool z_pass = true;
1069 if constexpr (USE_ZBUFFER)
1070 {
1071#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1072 ZBUFFER_t& W = *zpix;
1073#else
1074 ZBUFFER_t& W = zbuf[bx];
1075#endif
1076 ZBUFFER_t current_z;
1077
1078 if constexpr (std::is_same<ZBUFFER_t, uint16_t>::value)
1079 {
1080 current_z = (USE_ORTHO) ? ((ZBUFFER_t)(cw_z * wa + wb)) : ((ZBUFFER_t)cw_z);
1081 }
1082 else
1083 {
1084 current_z = (ZBUFFER_t)cw_z;
1085 }
1086
1087 if (W < current_z)
1088 {
1089 W = current_z;
1090 }
1091 else
1092 {
1093 z_pass = false;
1094 }
1095 }
1096
1097 if (z_pass)
1098 {
1099 color_t final_color;
1100
1101 if constexpr (USE_TEXTURE)
1102 {
1103 float icw = 1.0f;
1104 if constexpr (!USE_ORTHO)
1105 {
1106 icw = fast_inv(cw_p);
1107 }
1108
1109 float xx = tx * icw;
1110 float yy = ty * icw;
1111
1112 if constexpr (TEXTURE_BILINEAR)
1113 {
1114 const int ttx = lfloorf(xx);
1115 const int tty = lfloorf(yy);
1116 const float ax = xx - ttx;
1117 const float ay = yy - tty;
1118
1119 const int minx = TEXTURE_WRAP ? (ttx & texsize_x_mm) : shaderclip(ttx, texsize_x_mm);
1120 const int maxx = TEXTURE_WRAP ? ((ttx + 1) & texsize_x_mm) : shaderclip(ttx + 1, texsize_x_mm);
1121 const int miny = (TEXTURE_WRAP ? (tty & texsize_y_mm) : shaderclip(tty, texsize_y_mm)) * texstride;
1122 const int maxy = (TEXTURE_WRAP ? ((tty + 1) & texsize_y_mm) : shaderclip(tty + 1, texsize_y_mm)) * texstride;
1123
1124 final_color = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1125 }
1126 else // Nearest neighbor
1127 {
1128 const int ttx = TEXTURE_WRAP ? ((int)(xx)) & texsize_x_mm : shaderclip((int)(xx), texsize_x_mm);
1129 const int tty = TEXTURE_WRAP ? ((int)(yy)) & texsize_y_mm : shaderclip((int)(yy), texsize_y_mm);
1130 final_color = tex[ttx + tty * texstride];
1131 }
1132
1133 if constexpr (USE_GOURAUD)
1134 {
1135#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
1136 const int r = (int)gR;
1137 const int g = (int)gG;
1138 const int b = (int)gB;
1139#else
1140 const int32_t C2s = C2 >> shiftC;
1141 const int32_t C3s = C3 >> shiftC;
1142 const int r = fP1R + ((C2s * fP21R + C3s * fP31R) / aeraShifted);
1143 const int g = fP1G + ((C2s * fP21G + C3s * fP31G) / aeraShifted);
1144 const int b = fP1B + ((C2s * fP21B + C3s * fP31B) / aeraShifted);
1145#endif
1146 final_color.mult256(r, g, b);
1147 }
1148 else if constexpr (!USE_UNLIT) // Flat
1149 {
1150 final_color.mult256(fPR, fPG, fPB);
1151 }
1152 }
1153 else // No texture
1154 {
1155 if constexpr (USE_GOURAUD)
1156 {
1157 final_color = interpolateColorsTriangle(col2_g, C2 >> shiftC, col3_g, C3 >> shiftC, col1_g, aeraShifted);
1158 }
1159 else // Flat
1160 {
1161 final_color = flat_color;
1162 }
1163 }
1164#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1165 *pix = final_color;
1166#else
1167 buf[bx] = final_color;
1168#endif
1169 }
1170
1171 // --- Increment for next pixel ---
1172 C2 += dx2;
1173 C3 += dx3;
1174
1175#if TGX_SHADER_GOURAUD_TEXTURE_FLOAT_INCREMENTAL
1176 if constexpr (USE_GOURAUD && USE_TEXTURE)
1177 {
1178 gR += dGR;
1179 gG += dGG;
1180 gB += dGB;
1181 }
1182#endif
1183
1184 bx++;
1185#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1186 pix++;
1187#endif
1188
1189 if constexpr (USE_ZBUFFER) cw_z += dw_z;
1190#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1191 if constexpr (USE_ZBUFFER) zpix++;
1192#endif
1193
1194 if constexpr (USE_TEXTURE)
1195 {
1196 tx += dtx;
1197 ty += dty;
1198 if constexpr (!USE_ORTHO) cw_p += dw_p;
1199 }
1200 }
1201
1202 // --- Increment for next scanline ---
1203 O1 += dy1;
1204 O2 += dy2;
1205 O3 += dy3;
1206 buf += stride;
1207 if constexpr (USE_ZBUFFER) zbuf += zstride;
1208 }
1209 }
1210*/
1211
1212 /* VERY OLD VERSION
1213 template<typename color_t, typename ZBUFFER_t,
1214 bool USE_ZBUFFER, bool USE_GOURAUD, bool USE_TEXTURE,
1215 bool USE_ORTHO, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP,
1216 bool USE_UNLIT>
1217 TGX_UBER_SHADER_INLINE inline void uber_shader_inline_old(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
1218 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1219 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1220 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1221 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
1222 {
1223 static_assert(!(USE_GOURAUD && USE_UNLIT), "UNLIT and GOURAUD shader variants are mutually exclusive.");
1224 static_assert((!USE_UNLIT) || USE_TEXTURE, "The dedicated UNLIT shader variant is only useful for textured rendering.");
1225
1226 // --- Common setup for all shaders ---
1227 const int32_t stride = data.im->stride();
1228 color_t* buf = data.im->data() + oox + (ooy * stride);
1229
1230 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1231 const int32_t pa = O1 + O2 + O3;
1232 const int32_t E = ((pa == 0) ? 1 : 0);
1233 const int32_t aera = pa + E;
1234
1235 // --- Z-Buffer setup ---
1236 ZBUFFER_t* zbuf = nullptr;
1237 int32_t zstride = 0;
1238 float wa = 0.0f, wb = 0.0f;
1239 float fP1a_z = 0.0f, fP2a_z = 0.0f, fP3a_z = 0.0f;
1240 float dw_z = 0.0f;
1241
1242 float invaera = 0.0f;
1243 if constexpr (USE_ZBUFFER || USE_TEXTURE) { invaera = fast_inv((float)aera); }
1244
1245 if constexpr (USE_ZBUFFER)
1246 {
1247 zstride = data.im->lx();
1248 zbuf = data.zbuf + oox + (ooy * zstride);
1249 wa = data.wa;
1250 wb = data.wb;
1251 if constexpr (!(USE_TEXTURE && !USE_ORTHO))
1252 {
1253 // Normal path, needed for:
1254 // - no texture
1255 // - orthographic texture
1256 const float invaera_wa_factor = USE_ORTHO ? 1.0f : wa;
1257 fP1a_z = fP1.w * invaera * invaera_wa_factor;
1258 fP2a_z = fP2.w * invaera * invaera_wa_factor;
1259 fP3a_z = fP3.w * invaera * invaera_wa_factor;
1260 dw_z = (dx1 * fP1a_z) + (dx2 * fP2a_z) + (dx3 * fP3a_z);
1261 }
1262 }
1263
1264 // --- Shading & Texturing setup ---
1265 color_t flat_color;
1266 color_t col1_g, col2_g, col3_g;
1267 int shiftC = 0, aeraShifted = 0;
1268 int fPR = 0, fPG = 0, fPB = 0; // Flat color components
1269 int fP1R = 0, fP1G = 0, fP1B = 0; // Gouraud color components
1270 int fP21R = 0, fP21G = 0, fP21B = 0;
1271 int fP31R = 0, fP31G = 0, fP31B = 0;
1272
1273 float invaera_persp = 0.0f;
1274 float fP1a_p = 0.0f, fP2a_p = 0.0f, fP3a_p = 0.0f;
1275 float dw_p = 0.0f;
1276
1277 const color_t* tex = nullptr;
1278 int32_t texsize_x_mm = 0, texsize_y_mm = 0, texstride = 0;
1279 float dtx = 0.0f, dty = 0.0f;
1280 fVec2 T1, T2, T3;
1281
1282 if constexpr (USE_GOURAUD)
1283 {
1284 if constexpr (USE_TEXTURE)
1285 {
1286 const RGBf& cf1 = fP1.color;
1287 const RGBf& cf2 = fP2.color;
1288 const RGBf& cf3 = fP3.color;
1289 fP1R = (int)(256 * cf1.R); fP1G = (int)(256 * cf1.G); fP1B = (int)(256 * cf1.B);
1290 fP21R = (int)(256 * (cf2.R - cf1.R)); fP21G = (int)(256 * (cf2.G - cf1.G)); fP21B = (int)(256 * (cf2.B - cf1.B));
1291 fP31R = (int)(256 * (cf3.R - cf1.R)); fP31G = (int)(256 * (cf3.G - cf1.G)); fP31B = (int)(256 * (cf3.B - cf1.B));
1292 shiftC = (aera > (1 << 22)) ? 10 : 0;
1293 aeraShifted = aera >> shiftC;
1294 }
1295 else
1296 {
1297 col1_g = (color_t)fP1.color;
1298 col2_g = (color_t)fP2.color;
1299 col3_g = (color_t)fP3.color;
1300 shiftC = (aera > (1 << 22)) ? 10 : 0;
1301 aeraShifted = aera >> shiftC;
1302 }
1303 }
1304 else // Flat or unlit shading
1305 {
1306 flat_color = (color_t)data.facecolor;
1307 if constexpr (USE_TEXTURE && !USE_UNLIT)
1308 {
1309 const RGBf& cf = data.facecolor;
1310 fPR = (int)(256 * cf.R); fPG = (int)(256 * cf.G); fPB = (int)(256 * cf.B);
1311 }
1312 }
1313
1314 if constexpr (USE_TEXTURE)
1315 {
1316 tex = data.tex->data();
1317 const int32_t texsize_x = data.tex->width();
1318 const int32_t texsize_y = data.tex->height();
1319 texsize_x_mm = texsize_x - 1;
1320 texsize_y_mm = texsize_y - 1;
1321 texstride = data.tex->stride();
1322
1323 T1 = fP1.T; T2 = fP2.T; T3 = fP3.T;
1324
1325 if constexpr (USE_ORTHO)
1326 {
1327 T1 *= invaera; T2 *= invaera; T3 *= invaera;
1328 }
1329 else // Perspective
1330 {
1331 invaera_persp = invaera;
1332 fP1a_p = fP1.w * invaera_persp;
1333 fP2a_p = fP2.w * invaera_persp;
1334 fP3a_p = fP3.w * invaera_persp;
1335 dw_p = (dx1 * fP1a_p) + (dx2 * fP2a_p) + (dx3 * fP3a_p);
1336 if constexpr (USE_ZBUFFER) { dw_z = dw_p * wa; }
1337 T1 *= fP1a_p; T2 *= fP2a_p; T3 *= fP3a_p;
1338 }
1339
1340 T1.x *= texsize_x; T2.x *= texsize_x; T3.x *= texsize_x;
1341 T1.y *= texsize_y; T2.y *= texsize_y; T3.y *= texsize_y;
1342
1343 dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
1344 dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
1345 }
1346
1347 // --- Scanline iteration ---
1348 while ((uintptr_t)(buf) < end)
1349 {
1350 // --- Clipping and finding start x (bx) ---
1351 int32_t bx = 0;
1352 if (O1 < 0)
1353 {
1354 bx = (-O1 + dx1 - 1u) / dx1;
1355 }
1356 if (O2 < 0)
1357 {
1358 if (dx2 <= 0)
1359 {
1360 if (dy2 <= 0) return;
1361 const int32_t by = (-O2 + dy2 - 1u) / dy2;
1362 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
1363 buf += by * stride;
1364 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
1365 continue;
1366 }
1367 bx = max(bx, (int32_t)((-O2 + dx2 - 1u) / dx2));
1368 }
1369 if (O3 < 0)
1370 {
1371 if (dx3 <= 0)
1372 {
1373 if (dy3 <= 0) return;
1374 const int32_t by = (-O3 + dy3 - 1u) / dy3;
1375 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
1376 buf += by * stride;
1377 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
1378 continue;
1379 }
1380 bx = max(bx, (int32_t)((-O3 + dx3 - 1u) / dx3));
1381 }
1382
1383 // --- Per-scanline setup ---
1384 int32_t C1 = O1 + (dx1 * bx) + E;
1385 int32_t C2 = O2 + (dx2 * bx);
1386 int32_t C3 = O3 + (dx3 * bx);
1387
1388 float cw_z = 0.0f;
1389 float cw_p = 0.0f;
1390 float tx = 0.0f, ty = 0.0f;
1391
1392 if constexpr (USE_TEXTURE)
1393 {
1394 tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
1395 ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
1396 if constexpr (!USE_ORTHO)
1397 {
1398 cw_p = ((C1 * fP1a_p) + (C2 * fP2a_p) + (C3 * fP3a_p));
1399 if constexpr (USE_ZBUFFER)
1400 { // Perspective textured path: cw_z = wa * cw_p + wb.
1401 cw_z = (cw_p * wa) + wb;
1402 }
1403 }
1404 }
1405
1406 if constexpr (USE_ZBUFFER)
1407 {
1408 if constexpr (!(USE_TEXTURE && !USE_ORTHO))
1409 {
1410 cw_z = ((C1 * fP1a_z) + (C2 * fP2a_z) + (C3 * fP3a_z));
1411 if constexpr (!USE_ORTHO) { cw_z += wb; }
1412 }
1413 }
1414
1415 // --- Pixel loop ---
1416#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1417 color_t* pix = buf + bx;
1418 ZBUFFER_t* zpix = nullptr;
1419 if constexpr (USE_ZBUFFER)
1420 {
1421 zpix = zbuf + bx;
1422 }
1423#endif
1424 while ((bx < lx) && ((C2 | C3) >= 0))
1425 {
1426 bool z_pass = true;
1427 if constexpr (USE_ZBUFFER)
1428 {
1429#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1430 ZBUFFER_t& W = *zpix;
1431#else
1432 ZBUFFER_t& W = zbuf[bx];
1433#endif
1434 ZBUFFER_t current_z;
1435
1436 if constexpr (std::is_same<ZBUFFER_t, uint16_t>::value)
1437 {
1438 current_z = (USE_ORTHO) ? ((ZBUFFER_t)(cw_z * wa + wb)) : ((ZBUFFER_t)cw_z);
1439 }
1440 else
1441 {
1442 current_z = (ZBUFFER_t)cw_z;
1443 }
1444
1445 if (W < current_z)
1446 {
1447 W = current_z;
1448 }
1449 else
1450 {
1451 z_pass = false;
1452 }
1453 }
1454
1455 if (z_pass)
1456 {
1457 color_t final_color;
1458
1459 if constexpr (USE_TEXTURE)
1460 {
1461 float icw = 1.0f;
1462 if constexpr (!USE_ORTHO)
1463 {
1464 icw = fast_inv(cw_p);
1465 }
1466
1467 float xx = tx * icw;
1468 float yy = ty * icw;
1469
1470 if constexpr (TEXTURE_BILINEAR)
1471 {
1472 const int ttx = lfloorf(xx);
1473 const int tty = lfloorf(yy);
1474 const float ax = xx - ttx;
1475 const float ay = yy - tty;
1476
1477 const int minx = TEXTURE_WRAP ? (ttx & texsize_x_mm) : shaderclip(ttx, texsize_x_mm);
1478 const int maxx = TEXTURE_WRAP ? ((ttx + 1) & texsize_x_mm) : shaderclip(ttx + 1, texsize_x_mm);
1479 const int miny = (TEXTURE_WRAP ? (tty & texsize_y_mm) : shaderclip(tty, texsize_y_mm)) * texstride;
1480 const int maxy = (TEXTURE_WRAP ? ((tty + 1) & texsize_y_mm) : shaderclip(tty + 1, texsize_y_mm)) * texstride;
1481
1482 final_color = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1483 }
1484 else // Nearest neighbor
1485 {
1486 const int ttx = TEXTURE_WRAP ? ((int)(xx)) & texsize_x_mm : shaderclip((int)(xx), texsize_x_mm);
1487 const int tty = TEXTURE_WRAP ? ((int)(yy)) & texsize_y_mm : shaderclip((int)(yy), texsize_y_mm);
1488 final_color = tex[ttx + tty * texstride];
1489 }
1490
1491 if constexpr (USE_GOURAUD)
1492 {
1493 const int32_t C2s = C2 >> shiftC;
1494 const int32_t C3s = C3 >> shiftC;
1495 const int r = fP1R + ((C2s * fP21R + C3s * fP31R) / aeraShifted);
1496 const int g = fP1G + ((C2s * fP21G + C3s * fP31G) / aeraShifted);
1497 const int b = fP1B + ((C2s * fP21B + C3s * fP31B) / aeraShifted);
1498 final_color.mult256(r, g, b);
1499 }
1500 else if constexpr (!USE_UNLIT) // Flat
1501 {
1502 final_color.mult256(fPR, fPG, fPB);
1503 }
1504 }
1505 else // No texture
1506 {
1507 if constexpr (USE_GOURAUD)
1508 {
1509 final_color = interpolateColorsTriangle(col2_g, C2 >> shiftC, col3_g, C3 >> shiftC, col1_g, aeraShifted);
1510 }
1511 else // Flat
1512 {
1513 final_color = flat_color;
1514 }
1515 }
1516#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1517 *pix = final_color;
1518#else
1519 buf[bx] = final_color;
1520#endif
1521 }
1522
1523 // --- Increment for next pixel ---
1524 C2 += dx2;
1525 C3 += dx3;
1526 bx++;
1527#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1528 pix++;
1529#endif
1530
1531 if constexpr (USE_ZBUFFER) cw_z += dw_z;
1532#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
1533 if constexpr (USE_ZBUFFER) zpix++;
1534#endif
1535
1536 if constexpr (USE_TEXTURE)
1537 {
1538 tx += dtx;
1539 ty += dty;
1540 if constexpr (!USE_ORTHO) cw_p += dw_p;
1541 }
1542 }
1543
1544 // --- Increment for next scanline ---
1545 O1 += dy1;
1546 O2 += dy2;
1547 O3 += dy3;
1548 buf += stride;
1549 if constexpr (USE_ZBUFFER) zbuf += zstride;
1550 }
1551 }
1552*/
1553
1554
1555
1560 template<typename color_t, typename ZBUFFER_t,
1561 bool USE_ZBUFFER, bool USE_GOURAUD, bool USE_TEXTURE,
1562 bool USE_ORTHO, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP,
1563 bool USE_UNLIT, bool USE_TEXTURE_AFFINE>
1564 void uber_shader(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
1565 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1566 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1567 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1568 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
1569 {
1570 uber_shader_inline<color_t, ZBUFFER_t, USE_ZBUFFER, USE_GOURAUD, USE_TEXTURE, USE_ORTHO, TEXTURE_BILINEAR, TEXTURE_WRAP, USE_UNLIT, USE_TEXTURE_AFFINE>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1571 }
1572
1573
1574
1578 template<int SHADER_FLAGS_ENABLED, typename color_t, typename ZBUFFER_t>
1579 inline TGX_SHADER_SELECT_INLINE void shader_select(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
1580 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1581 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1582 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1583 const RasterizerParams<color_t, color_t, ZBUFFER_t> & data)
1584 {
1585 int raster_type = data.shader_type;
1586 if ((!TGX_SHADER_HAS_NOZBUFFER(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_ZBUFFER(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_ZBUFFER(raster_type)))
1587 { // USING ZBUFFER
1588 if ((!TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_ORTHO(raster_type)))
1589 { // USING ORTHOGRAPHIC PROJECTION
1590 if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type)))
1591 { // Texture
1592 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1593 { // Gouraud
1594 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1595 { // Bilinear
1596 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1597 uber_shader<color_t, ZBUFFER_t, true, true, true, true, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1598 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1599 uber_shader<color_t, ZBUFFER_t, true, true, true, true, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1600 }
1601 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1602 { // Nearest
1603 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1604 uber_shader<color_t, ZBUFFER_t, true, true, true, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1605 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1606 uber_shader<color_t, ZBUFFER_t, true, true, true, true, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1607 }
1608 }
1609 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
1610 { // Unlit
1611 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1612 { // Bilinear
1613 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1614 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1615 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1616 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1617 }
1618 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1619 { // Nearest
1620 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1621 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1622 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1623 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1624 }
1625 }
1626 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1627 { // Flat
1628 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1629 { // Bilinear
1630 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1631 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1632 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1633 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1634 }
1635 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1636 { // Nearest
1637 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1638 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1639 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1640 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1641 }
1642 }
1643 }
1644 else if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_AFFINE(raster_type)))
1645 { // Texture affine
1646 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1647 { // Gouraud
1648 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1649 { // Bilinear
1650 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1651 uber_shader<color_t, ZBUFFER_t, true, true, true, true, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1652 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1653 uber_shader<color_t, ZBUFFER_t, true, true, true, true, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1654 }
1655 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1656 { // Nearest
1657 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1658 uber_shader<color_t, ZBUFFER_t, true, true, true, true, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1659 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1660 uber_shader<color_t, ZBUFFER_t, true, true, true, true, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1661 }
1662 }
1663 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
1664 { // Unlit
1665 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1666 { // Bilinear
1667 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1668 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1669 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1670 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1671 }
1672 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1673 { // Nearest
1674 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1675 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1676 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1677 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1678 }
1679 }
1680 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1681 { // Flat
1682 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1683 { // Bilinear
1684 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1685 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1686 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1687 uber_shader<color_t, ZBUFFER_t, true, false, true, true, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1688 }
1689 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1690 { // Nearest
1691 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1692 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1693 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1694 uber_shader<color_t, ZBUFFER_t, true, false, true, true, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1695 }
1696 }
1697 }
1698 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
1699 { // No Texture
1700 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1701 uber_shader<color_t, ZBUFFER_t, true, true, false, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1702 else if ((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) || TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
1703 uber_shader<color_t, ZBUFFER_t, true, false, false, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1704 }
1705 }
1706 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
1707 { // USING PERSPECTIVE PROJECTION
1708 if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type)))
1709 { // Texture
1710 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1711 { // Gouraud
1712 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1713 { // Bilinear
1714 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1715 uber_shader<color_t, ZBUFFER_t, true, true, true, false, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1716 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1717 uber_shader<color_t, ZBUFFER_t, true, true, true, false, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1718 }
1719 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1720 { // Nearest
1721 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1722 uber_shader<color_t, ZBUFFER_t, true, true, true, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1723 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1724 uber_shader<color_t, ZBUFFER_t, true, true, true, false, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1725 }
1726 }
1727 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
1728 { // Unlit
1729 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1730 { // Bilinear
1731 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1732 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1733 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1734 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1735 }
1736 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1737 { // Nearest
1738 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1739 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1740 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1741 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1742 }
1743 }
1744 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1745 { // Flat
1746 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1747 { // Bilinear
1748 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1749 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1750 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1751 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1752 }
1753 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1754 { // Nearest
1755 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1756 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1757 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1758 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1759 }
1760 }
1761 }
1762 else if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_AFFINE(raster_type)))
1763 { // Texture affine
1764 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1765 { // Gouraud
1766 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1767 { // Bilinear
1768 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1769 uber_shader<color_t, ZBUFFER_t, true, true, true, false, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1770 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1771 uber_shader<color_t, ZBUFFER_t, true, true, true, false, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1772 }
1773 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1774 { // Nearest
1775 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1776 uber_shader<color_t, ZBUFFER_t, true, true, true, false, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1777 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1778 uber_shader<color_t, ZBUFFER_t, true, true, true, false, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1779 }
1780 }
1781 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
1782 { // Unlit
1783 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1784 { // Bilinear
1785 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1786 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1787 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1788 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1789 }
1790 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1791 { // Nearest
1792 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1793 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1794 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1795 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1796 }
1797 }
1798 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1799 { // Flat
1800 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1801 { // Bilinear
1802 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1803 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1804 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1805 uber_shader<color_t, ZBUFFER_t, true, false, true, false, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1806 }
1807 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1808 { // Nearest
1809 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1810 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1811 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1812 uber_shader<color_t, ZBUFFER_t, true, false, true, false, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1813 }
1814 }
1815 }
1816 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
1817 { // No Texture
1818 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1819 uber_shader<color_t, ZBUFFER_t, true, true, false, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1820 else if ((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) || TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
1821 uber_shader<color_t, ZBUFFER_t, true, false, false, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1822 }
1823 }
1824 }
1825 else if (TGX_SHADER_HAS_NOZBUFFER(SHADER_FLAGS_ENABLED))
1826 { // NOT USING Z-BUFFER
1827 if ((!TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_ORTHO(raster_type)))
1828 { // USING ORTHOGRAPHIC PROJECTION
1829 if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type)))
1830 { // Texture
1831 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1832 { // Gouraud
1833 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1834 { // Bilinear
1835 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1836 uber_shader<color_t, ZBUFFER_t, false, true, true, true, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1837 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1838 uber_shader<color_t, ZBUFFER_t, false, true, true, true, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1839 }
1840 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1841 { // Nearest
1842 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1843 uber_shader<color_t, ZBUFFER_t, false, true, true, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1844 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1845 uber_shader<color_t, ZBUFFER_t, false, true, true, true, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1846 }
1847 }
1848 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
1849 { // Unlit
1850 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1851 { // Bilinear
1852 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1853 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1854 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1855 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1856 }
1857 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1858 { // Nearest
1859 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1860 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1861 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1862 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1863 }
1864 }
1865 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1866 { // Flat
1867 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1868 { // Bilinear
1869 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1870 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1871 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1872 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1873 }
1874 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1875 { // Nearest
1876 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1877 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1878 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1879 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1880 }
1881 }
1882 }
1883 else if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_AFFINE(raster_type)))
1884 { // Texture affine
1885 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1886 { // Gouraud
1887 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1888 { // Bilinear
1889 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1890 uber_shader<color_t, ZBUFFER_t, false, true, true, true, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1891 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1892 uber_shader<color_t, ZBUFFER_t, false, true, true, true, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1893 }
1894 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1895 { // Nearest
1896 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1897 uber_shader<color_t, ZBUFFER_t, false, true, true, true, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1898 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1899 uber_shader<color_t, ZBUFFER_t, false, true, true, true, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1900 }
1901 }
1902 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
1903 { // Unlit
1904 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1905 { // Bilinear
1906 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1907 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1908 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1909 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1910 }
1911 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1912 { // Nearest
1913 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1914 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1915 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1916 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1917 }
1918 }
1919 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1920 { // Flat
1921 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1922 { // Bilinear
1923 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1924 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1925 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1926 uber_shader<color_t, ZBUFFER_t, false, false, true, true, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1927 }
1928 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1929 { // Nearest
1930 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1931 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1932 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1933 uber_shader<color_t, ZBUFFER_t, false, false, true, true, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1934 }
1935 }
1936 }
1937 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
1938 { // No Texture
1939 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1940 uber_shader<color_t, ZBUFFER_t, false, true, false, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1941 else if ((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) || TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
1942 uber_shader<color_t, ZBUFFER_t, false, false, false, true, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1943 }
1944 }
1945 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
1946 { // USING PERSPECTIVE PROJECTION
1947 if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type)))
1948 { // Texture
1949 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
1950 { // Gouraud
1951 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1952 { // Bilinear
1953 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1954 uber_shader<color_t, ZBUFFER_t, false, true, true, false, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1955 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1956 uber_shader<color_t, ZBUFFER_t, false, true, true, false, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1957 }
1958 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1959 { // Nearest
1960 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1961 uber_shader<color_t, ZBUFFER_t, false, true, true, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1962 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1963 uber_shader<color_t, ZBUFFER_t, false, true, true, false, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1964 }
1965 }
1966 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
1967 { // Unlit
1968 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1969 { // Bilinear
1970 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1971 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1972 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1973 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1974 }
1975 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1976 { // Nearest
1977 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1978 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, false, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1979 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1980 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, true, true, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1981 }
1982 }
1983 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1984 { // Flat
1985 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
1986 { // Bilinear
1987 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1988 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1989 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1990 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1991 }
1992 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1993 { // Nearest
1994 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
1995 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1996 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1997 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, true, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1998 }
1999 }
2000 }
2001 else if (((!TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_TEXTURE_AFFINE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_AFFINE(raster_type)))
2002 { // Texture affine
2003 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
2004 { // Gouraud
2005 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
2006 { // Bilinear
2007 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
2008 uber_shader<color_t, ZBUFFER_t, false, true, true, false, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2009 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
2010 uber_shader<color_t, ZBUFFER_t, false, true, true, false, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2011 }
2012 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
2013 { // Nearest
2014 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
2015 uber_shader<color_t, ZBUFFER_t, false, true, true, false, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2016 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
2017 uber_shader<color_t, ZBUFFER_t, false, true, true, false, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2018 }
2019 }
2020 else if (((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type)))
2021 { // Unlit
2022 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
2023 { // Bilinear
2024 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
2025 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2026 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
2027 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2028 }
2029 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
2030 { // Nearest
2031 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
2032 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, false, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2033 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
2034 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, true, true, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2035 }
2036 }
2037 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
2038 { // Flat
2039 if ((!TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type)))
2040 { // Bilinear
2041 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
2042 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2043 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
2044 uber_shader<color_t, ZBUFFER_t, false, false, true, false, true, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2045 }
2046 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
2047 { // Nearest
2048 if ((!TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED)) || (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type)))
2049 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, false, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2050 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
2051 uber_shader<color_t, ZBUFFER_t, false, false, true, false, false, true, false, true>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2052 }
2053 }
2054 }
2055 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
2056 { // No Texture
2057 if (((!TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED)) && (!TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED))) || (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type)))
2058 uber_shader<color_t, ZBUFFER_t, false, true, false, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2059 else if ((!TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED)) || TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
2060 uber_shader<color_t, ZBUFFER_t, false, false, false, false, false, false, false, false>(oox, ooy, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
2061 }
2062 }
2063 }
2064 }
2065
2066
2067
2068
2069
2073 template<bool USE_BLENDING, typename color_t_im>
2074 void shader_2D_gradient(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
2075 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
2076 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
2077 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
2078 const RasterizerParams<color_t_im, color_t_im, float> & data)
2079 {
2080 const int32_t stride = data.im->stride();
2081 color_t_im * buf = data.im->data() + oox + (ooy * stride);
2082
2083 // use RGB32 (could use RGB64 be it would be slower).
2084 const RGB32 col1 = RGB64(fP1.color.R, fP1.color.G, fP1.color.B, fP1.A);
2085 const RGB32 col2 = RGB64(fP2.color.R, fP2.color.G, fP2.color.B, fP2.A);
2086 const RGB32 col3 = RGB64(fP3.color.R, fP3.color.G, fP3.color.B, fP3.A);
2087
2088 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
2089 const int32_t pa = O1 + O2 + O3;
2090 const int32_t E = ((pa == 0) ? 1 : 0);
2091 const int32_t aera = pa + E;
2092 const int shiftC = (aera > (1 << 22)) ? 10 : 0; // prevent overflow during color interpolation
2093
2094 while ((uintptr_t)(buf) < end)
2095 { // iterate over scanlines
2096 int32_t bx = 0; // start offset
2097 if (O1 < 0)
2098 {
2099 // we know that dx1 > 0
2100 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
2101 }
2102 if (O2 < 0)
2103 {
2104 if (dx2 <= 0)
2105 {
2106 if (dy2 <= 0) return;
2107 const int32_t by = (-O2 + dy2 - 1u) / dy2;
2108 O1 += (by * dy1);
2109 O2 += (by * dy2);
2110 O3 += (by * dy3);
2111 const int32_t offs = by * stride;
2112 buf += offs;
2113 continue;
2114 }
2115 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
2116 bx = max(bx, bx2);
2117 }
2118 if (O3 < 0)
2119 {
2120 if (dx3 <= 0)
2121 {
2122 if (dy3 <= 0) return;
2123 const int32_t by = (-O3 + dy3 - 1u) / dy3;
2124 O1 += (by * dy1);
2125 O2 += (by * dy2);
2126 O3 += (by * dy3);
2127 const int32_t offs = by * stride;
2128 buf += offs;
2129 continue;
2130 }
2131 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
2132 bx = max(bx, bx3);
2133 }
2134
2135 int32_t C2 = O2 + (dx2 * bx);
2136 int32_t C3 = O3 + (dx3 * bx);
2137 while ((bx < lx) && ((C2 | C3) >= 0))
2138 {
2139 if (USE_BLENDING)
2140 {
2141 RGB32 c(buf[bx]); // could use RGB64 instead but would be slower
2142 c.blend(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC), data.opacity);
2143 buf[bx] = color_t_im(c);
2144 }
2145 else
2146 {
2147 buf[bx] = color_t_im(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC));
2148 }
2149 C2 += dx2;
2150 C3 += dx3;
2151 bx++;
2152 }
2153
2154 O1 += dy1;
2155 O2 += dy2;
2156 O3 += dy3;
2157 buf += stride;
2158 }
2159 }
2160
2161
2162
2166 template<bool USE_BLENDING, bool USE_MASKING, bool USE_GRADIENT, typename color_t_im, typename color_t_tex>
2167 void shader_2D_texture(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
2168 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
2169 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
2170 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
2171 const RasterizerParams<color_t_im, color_t_tex, float> & data)
2172 {
2173
2174 const int32_t stride = data.im->stride();
2175 color_t_im* buf = data.im->data() + oox + (ooy * stride);
2176
2177 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
2178 const int32_t pa = O1 + O2 + O3;
2179 const int32_t E = ((pa == 0) ? 1 : 0);
2180 const int32_t aera = pa + E;
2181
2182 const float invaera = fast_inv((float)aera);
2183
2184 const color_t_tex mask_color = data.mask_color;
2185
2186 const RGBf& cf1 = fP1.color;
2187 const RGBf& cf2 = fP2.color;
2188 const RGBf& cf3 = fP3.color;
2189
2190 // the texture coord
2191 fVec2 T1 = fP1.T;
2192 fVec2 T2 = fP2.T;
2193 fVec2 T3 = fP3.T;
2194
2195 const color_t_tex * tex = data.tex->data();
2196 const int32_t texsize_x = data.tex->width();
2197 const int32_t texsize_y = data.tex->height();
2198 const int32_t texsize_x_mm = data.tex->width() - 1;
2199 const int32_t texsize_y_mm = data.tex->height() - 1;
2200 const int32_t texstride = data.tex->stride();
2201
2202 // divide the texture coord by aera
2203 T1 *= invaera;
2204 T2 *= invaera;
2205 T3 *= invaera;
2206 T1.x *= texsize_x;
2207 T2.x *= texsize_x;
2208 T3.x *= texsize_x;
2209 T1.y *= texsize_y;
2210 T2.y *= texsize_y;
2211 T3.y *= texsize_y;
2212
2213 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
2214 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
2215
2216 while ((uintptr_t)(buf) < end)
2217 { // iterate over scanlines
2218 int32_t bx = 0; // start offset
2219 if (O1 < 0)
2220 {
2221 // we know that dx1 > 0
2222 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
2223 }
2224 if (O2 < 0)
2225 {
2226 if (dx2 <= 0)
2227 {
2228 if (dy2 <= 0) return;
2229 const int32_t by = (-O2 + dy2 - 1u) / dy2;
2230 O1 += (by * dy1);
2231 O2 += (by * dy2);
2232 O3 += (by * dy3);
2233 const int32_t offs = by * stride;
2234 buf += offs;
2235 continue;
2236 }
2237 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
2238 bx = max(bx, bx2);
2239 }
2240 if (O3 < 0)
2241 {
2242 if (dx3 <= 0)
2243 {
2244 if (dy3 <= 0) return;
2245 const int32_t by = (-O3 + dy3 - 1u) / dy3;
2246 O1 += (by * dy1);
2247 O2 += (by * dy2);
2248 O3 += (by * dy3);
2249 const int32_t offs = by * stride;
2250 buf += offs;
2251 continue;
2252 }
2253 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
2254 bx = max(bx, bx3);
2255 }
2256
2257 int32_t C1 = O1 + (dx1 * bx) + E;
2258 int32_t C2 = O2 + (dx2 * bx);
2259 int32_t C3 = O3 + (dx3 * bx);
2260
2261 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
2262 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
2263
2264 while ((bx < lx) && ((C2 | C3) >= 0))
2265 {
2266 const float xx = tx;
2267 const float yy = ty;
2268 const int ttx = lfloorf(xx);
2269 const int tty = lfloorf(yy);
2270 const float ax = xx - ttx;
2271 const float ay = yy - tty;
2272
2273 const int minx = shaderclip(ttx, texsize_x_mm);
2274 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
2275 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
2276 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
2277
2278 if (USE_MASKING)
2279 { //
2280 auto col00 = tex[minx + miny];
2281 auto col10 = tex[maxx + miny];
2282 auto col01 = tex[minx + maxy];
2283 auto col11 = tex[maxx + maxy];
2284
2285 if ((col00 != mask_color) && (col10 != mask_color) && (col01 != mask_color) && (col11 != mask_color))
2286 {
2287 color_t_tex col = interpolateColorsBilinear(col00, col10, col01, col11, ax, ay);
2288 if (USE_GRADIENT)
2289 {
2290 const int sC2 = C2;
2291 const int sC3 = C3;
2292 const int sC1 = aera - C3 - C2;
2293 const float m = 256.0f / aera;
2294 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
2295 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
2296 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
2297 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
2298 col.mult256(r, g, b, a);
2299 }
2300 if (USE_BLENDING)
2301 {
2302 color_t_tex c = color_t_tex(buf[bx]);
2303 c.blend(col, data.opacity);
2304 buf[bx] = color_t_im(c);
2305 }
2306 else
2307 {
2308 buf[bx] = color_t_im(col);
2309 }
2310 }
2311 else
2312 {
2313 tgx::RGB32 acol00 = (col00 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col00);
2314 tgx::RGB32 acol10 = (col10 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col10);
2315 tgx::RGB32 acol01 = (col01 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col01);
2316 tgx::RGB32 acol11 = (col11 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col11);
2317
2318 tgx::RGB32 col = interpolateColorsBilinear(acol00, acol10, acol01, acol11, ax, ay);
2319
2320 if (USE_GRADIENT)
2321 {
2322 const int sC2 = C2;
2323 const int sC3 = C3;
2324 const int sC1 = aera - C3 - C2;
2325 const float m = 256.0f / aera;
2326 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
2327 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
2328 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
2329 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
2330 col.mult256(r, g, b, a);
2331 }
2332 if (USE_BLENDING)
2333 {
2334 tgx::RGB32 c = tgx::RGB32(buf[bx]);
2335 c.blend(col, data.opacity);
2336 buf[bx] = color_t_im(c);
2337 }
2338 else
2339 {
2340 if (col.A == 255)
2341 {
2342 buf[bx] = color_t_im(col);
2343 }
2344 else if (col.A > 0)
2345 {
2346 tgx::RGB32 c = tgx::RGB32(buf[bx]);
2347 c.blend(col);
2348 buf[bx] = color_t_im(c);
2349 }
2350 }
2351 }
2352 }
2353 else
2354 {
2355 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
2356 if (USE_GRADIENT)
2357 {
2358 const int sC2 = C2;
2359 const int sC3 = C3;
2360 const int sC1 = aera - C3 - C2;
2361 const float m = 256.0f / aera;
2362 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
2363 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
2364 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
2365 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
2366 col.mult256(r, g, b, a);
2367 }
2368 if (USE_BLENDING)
2369 {
2370 color_t_tex c = color_t_tex(buf[bx]);
2371 c.blend(col, data.opacity);
2372 buf[bx] = color_t_im(c);
2373 }
2374 else
2375 {
2376 buf[bx] = color_t_im(col);
2377 }
2378 }
2379
2380 C2 += dx2;
2381 C3 += dx3;
2382
2383 tx += dtx;
2384 ty += dty;
2385
2386 bx++;
2387 }
2388
2389 O1 += dy1;
2390 O2 += dy2;
2391 O3 += dy3;
2392 buf += stride;
2393 }
2394 }
2395
2396
2397
2398
2402 template<typename BLEND_OP, typename color_t_im, typename color_t_tex>
2403 void shader_2D_texture_blend_op(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
2404 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
2405 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
2406 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
2407 const RasterizerParams<color_t_im, color_t_tex, float, BLEND_OP> & data)
2408 {
2409
2410 const int32_t stride = data.im->stride();
2411 color_t_im * buf = data.im->data() + oox + (ooy * stride);
2412
2413 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
2414 const int32_t pa = O1 + O2 + O3;
2415 const int32_t E = ((pa == 0) ? 1 : 0);
2416 const int32_t aera = pa + E;
2417
2418 const float invaera = fast_inv((float)aera);
2419
2420 // the texture coord
2421 fVec2 T1 = fP1.T;
2422 fVec2 T2 = fP2.T;
2423 fVec2 T3 = fP3.T;
2424
2425
2426 const color_t_tex * tex = data.tex->data();
2427 const int32_t texsize_x = data.tex->width();
2428 const int32_t texsize_y = data.tex->height();
2429 const int32_t texsize_x_mm = data.tex->width() - 1;
2430 const int32_t texsize_y_mm = data.tex->height() - 1;
2431 const int32_t texstride = data.tex->stride();
2432
2433 // divide the texture coord by aera
2434 T1 *= invaera;
2435 T2 *= invaera;
2436 T3 *= invaera;
2437 T1.x *= texsize_x;
2438 T2.x *= texsize_x;
2439 T3.x *= texsize_x;
2440 T1.y *= texsize_y;
2441 T2.y *= texsize_y;
2442 T3.y *= texsize_y;
2443
2444 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
2445 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
2446
2447 while ((uintptr_t)(buf) < end)
2448 { // iterate over scanlines
2449 int32_t bx = 0; // start offset
2450 if (O1 < 0)
2451 {
2452 // we know that dx1 > 0
2453 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
2454 }
2455 if (O2 < 0)
2456 {
2457 if (dx2 <= 0)
2458 {
2459 if (dy2 <= 0) return;
2460 const int32_t by = (-O2 + dy2 - 1u) / dy2;
2461 O1 += (by * dy1);
2462 O2 += (by * dy2);
2463 O3 += (by * dy3);
2464 const int32_t offs = by * stride;
2465 buf += offs;
2466 continue;
2467 }
2468 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
2469 bx = max(bx, bx2);
2470 }
2471 if (O3 < 0)
2472 {
2473 if (dx3 <= 0)
2474 {
2475 if (dy3 <= 0) return;
2476 const int32_t by = (-O3 + dy3 - 1u) / dy3;
2477 O1 += (by * dy1);
2478 O2 += (by * dy2);
2479 O3 += (by * dy3);
2480 const int32_t offs = by * stride;
2481 buf += offs;
2482 continue;
2483 }
2484 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
2485 bx = max(bx, bx3);
2486 }
2487
2488 int32_t C1 = O1 + (dx1 * bx) + E;
2489 int32_t C2 = O2 + (dx2 * bx);
2490 int32_t C3 = O3 + (dx3 * bx);
2491
2492 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
2493 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
2494
2495 while ((bx < lx) && ((C2 | C3) >= 0))
2496 {
2497 const float xx = tx;
2498 const float yy = ty;
2499 const int ttx = lfloorf(xx);
2500 const int tty = lfloorf(yy);
2501 const float ax = xx - ttx;
2502 const float ay = yy - tty;
2503
2504 const int minx = shaderclip(ttx, texsize_x_mm);
2505 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
2506 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
2507 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
2508
2509 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
2510
2511 buf[bx] = (color_t_im)((*data.p_blend_op)(col, buf[bx]));
2512
2513 C2 += dx2;
2514 C3 += dx3;
2515
2516 tx += dtx;
2517 ty += dty;
2518
2519 bx++;
2520 }
2521
2522 O1 += dy1;
2523 O2 += dy2;
2524 O3 += dy3;
2525 buf += stride;
2526 }
2527 }
2528
2529
2530}
2531
2532#endif
2533
2534#endif
2535
tgx::interpolateColorsBilinear
TGX_INLINE RGB565 interpolateColorsBilinear(const RGB565 &C00, const RGB565 &C10, const RGB565 &C01, const RGB565 &C11, const float ax, const float ay)
Bilinear interpolation between 4 colors.
Definition: Color.h:621
tgx::RGB32_Red
const RGB32 RGB32_Red
Color red in RGB32 format.
tgx::interpolateColorsTriangle
TGX_INLINE RGB565 interpolateColorsTriangle(const RGB565 &col1, int32_t C1, const RGB565 &col2, int32_t C2, const RGB565 &col3, const int32_t totC)
Interpolate between 3 colors.
Definition: Color.h:591
tgx::lfloorf
TGX_INLINE int32_t lfloorf(float x)
Compute (int32_t)floorf(x).
Definition: Misc.h:441
tgx::max
TGX_INLINE T max(T a, T b)
Don't know why but much faster than fmaxf() for floats.
Definition: Misc.h:153
tgx::fast_inv
TGX_INLINE float fast_inv(float x)
Fast (approximate) computation of 1/x.
Definition: Misc.h:197
tgx::fast_inv_approx
TGX_INLINE float fast_inv_approx(float x)
Fast (very approximate) computation of 1/x.
Definition: Misc.h:243
ShaderParams.h
Triangle shader parameters.
TGX_SHADER_CAN_USE_FLAT_OR_UNLIT
#define TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(enabled_shader_type, shader_type)
True when a shader configuration can use either flat shading or unlit shading.
Definition: ShaderParams.h:113
tgx::uber_shader_inline
TGX_UBER_SHADER_INLINE void uber_shader_inline(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
UBER-SHADER for all 3D rendering variants.
Definition: Shaders.h:181
tgx::shader_2D_texture
void shader_2D_texture(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_tex, float > &data)
2D shader (texture)
Definition: Shaders.h:2167
tgx::shader_2D_gradient
void shader_2D_gradient(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_im, float > &data)
2D shader (gradient)
Definition: Shaders.h:2074
tgx::shader_test
void shader_test(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const tgx::RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const tgx::RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const tgx::RasterizerVec4 &fP3, const tgx::RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
For test purposes...
Definition: Shaders.h:45
tgx::shader_2D_texture_blend_op
void shader_2D_texture_blend_op(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_tex, float, BLEND_OP > &data)
2D shader (texture with custom blending operator)
Definition: Shaders.h:2403
tgx::shader_select
TGX_SHADER_SELECT_INLINE void shader_select(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
META-Shader THAT DISPATCH TO THE CORRECT Shader ABOVE (IF ENABLED).
Definition: Shaders.h:1579
tgx::shaderclip
TGX_INLINE int shaderclip(int v, int maxv)
for texture clamping
Definition: Shaders.h:34
tgx::uber_shader
void uber_shader(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
UBER-SHADER for all 3D rendering variants.
Definition: Shaders.h:1564
tgx::RGB32
Color in R8/G8/B8/A8 format.
Definition: Color.h:1174
tgx::RGB32::mult256
TGX_INLINE void mult256(int mr, int mg, int mb)
Multiply each color component by a given factor m/256 with m in [0,256] except the A component.
Definition: Color.h:1588
tgx::RGB32::A
uint8_t A
Alpha channel (8bits)
Definition: Color.h:1195
tgx::RGB32::opacity
TGX_INLINE float opacity() const
Return the opacity (alpha channel value) of this color in the range [0,1] (0=fully transparent,...
Definition: Color.h:1627
tgx::RGB32::blend
TGX_INLINE void blend(const RGB32 &fg_col, float alpha)
alpha-blend fg_col over this one with a given opacity in the range 0.0f (fully transparent) to 1....
Definition: Color.h:1544
tgx::RGB32::blend256
TGX_INLINE void blend256(const RGB32 &fg_col, uint32_t alpha)
alpha-blend fg_col over this one with a given opacity in the range 0.0f (fully transparent) to 1....
Definition: Color.h:1559
tgx::RGB565::opacity
float opacity() const
Dummy function for compatibility with color types having an alpha channel.
Definition: Color.h:565
tgx::RGB64
Color in R16/G16/B16/A16 format.
Definition: Color.h:1789
tgx::RGBf
Color in R,G,B float format.
Definition: Color.h:2405
tgx::RGBf::R
float R
Red channel.
Definition: Color.h:2418
tgx::RGBf::B
float B
Blue channel.
Definition: Color.h:2420
tgx::RGBf::G
float G
Green channel.
Definition: Color.h:2419
tgx::Vec2< float >
tgx::Vec2::x
T x
'x' coordinate (first dimension)
Definition: Vec2.h:72
tgx::Vec2::y
T y
'y' coordinate (second dimension)
Definition: Vec2.h:73