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