TGX 1.1.1
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
75 template<typename color_t, typename ZBUFFER_t,
76 bool USE_ZBUFFER, bool USE_GOURAUD, bool USE_TEXTURE,
77 bool USE_ORTHO, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP,
78 bool USE_UNLIT = false>
79 void uber_shader(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
80 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
81 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
82 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
83 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
84 {
85 static_assert(!(USE_GOURAUD && USE_UNLIT), "UNLIT and GOURAUD shader variants are mutually exclusive.");
86 static_assert((!USE_UNLIT) || USE_TEXTURE, "The dedicated UNLIT shader variant is only useful for textured rendering.");
87
88 // --- Common setup for all shaders ---
89 const int32_t stride = data.im->stride();
90 color_t* buf = data.im->data() + oox + (ooy * stride);
91
92 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
93 const int32_t pa = O1 + O2 + O3;
94 const int32_t E = ((pa == 0) ? 1 : 0);
95 const int32_t aera = pa + E;
96
97 // --- Z-Buffer setup ---
98 ZBUFFER_t* zbuf = nullptr;
99 int32_t zstride = 0;
100 float wa = 0.0f, wb = 0.0f;
101 float fP1a_z = 0.0f, fP2a_z = 0.0f, fP3a_z = 0.0f;
102 float dw_z = 0.0f;
103
104 if constexpr (USE_ZBUFFER)
105 {
106 zstride = data.im->lx();
107 zbuf = data.zbuf + oox + (ooy * zstride);
108 wa = data.wa;
109 wb = data.wb;
110
111 const float invaera = fast_inv((float)aera);
112 float invaera_wa_factor = USE_ORTHO ? 1.0f : wa;
113
114 fP1a_z = fP1.w * invaera * invaera_wa_factor;
115 fP2a_z = fP2.w * invaera * invaera_wa_factor;
116 fP3a_z = fP3.w * invaera * invaera_wa_factor;
117
118 dw_z = (dx1 * fP1a_z) + (dx2 * fP2a_z) + (dx3 * fP3a_z);
119 }
120
121 // --- Shading & Texturing setup ---
122 color_t flat_color;
123 color_t col1_g, col2_g, col3_g;
124 int shiftC = 0, aeraShifted = 0;
125 int fPR = 0, fPG = 0, fPB = 0; // Flat color components
126 int fP1R = 0, fP1G = 0, fP1B = 0; // Gouraud color components
127 int fP21R = 0, fP21G = 0, fP21B = 0;
128 int fP31R = 0, fP31G = 0, fP31B = 0;
129
130 float invaera_persp = 0.0f;
131 float fP1a_p = 0.0f, fP2a_p = 0.0f, fP3a_p = 0.0f;
132 float dw_p = 0.0f;
133
134 const color_t* tex = nullptr;
135 int32_t texsize_x_mm = 0, texsize_y_mm = 0, texstride = 0;
136 float dtx = 0.0f, dty = 0.0f;
137 fVec2 T1, T2, T3;
138
139 if constexpr (USE_GOURAUD)
140 {
141 if constexpr (USE_TEXTURE)
142 {
143 const RGBf& cf1 = fP1.color;
144 const RGBf& cf2 = fP2.color;
145 const RGBf& cf3 = fP3.color;
146 fP1R = (int)(256 * cf1.R); fP1G = (int)(256 * cf1.G); fP1B = (int)(256 * cf1.B);
147 fP21R = (int)(256 * (cf2.R - cf1.R)); fP21G = (int)(256 * (cf2.G - cf1.G)); fP21B = (int)(256 * (cf2.B - cf1.B));
148 fP31R = (int)(256 * (cf3.R - cf1.R)); fP31G = (int)(256 * (cf3.G - cf1.G)); fP31B = (int)(256 * (cf3.B - cf1.B));
149 shiftC = (aera > (1 << 22)) ? 10 : 0;
150 aeraShifted = aera >> shiftC;
151 }
152 else
153 {
154 col1_g = (color_t)fP1.color;
155 col2_g = (color_t)fP2.color;
156 col3_g = (color_t)fP3.color;
157 shiftC = (aera > (1 << 22)) ? 10 : 0;
158 aeraShifted = aera >> shiftC;
159 }
160 }
161 else // Flat or unlit shading
162 {
163 flat_color = (color_t)data.facecolor;
164 if constexpr (USE_TEXTURE && !USE_UNLIT)
165 {
166 const RGBf& cf = data.facecolor;
167 fPR = (int)(256 * cf.R); fPG = (int)(256 * cf.G); fPB = (int)(256 * cf.B);
168 }
169 }
170
171 if constexpr (USE_TEXTURE)
172 {
173 tex = data.tex->data();
174 const int32_t texsize_x = data.tex->width();
175 const int32_t texsize_y = data.tex->height();
176 texsize_x_mm = texsize_x - 1;
177 texsize_y_mm = texsize_y - 1;
178 texstride = data.tex->stride();
179
180 T1 = fP1.T; T2 = fP2.T; T3 = fP3.T;
181
182 const float invaera = fast_inv((float)aera);
183
184 if constexpr (USE_ORTHO)
185 {
186 T1 *= invaera; T2 *= invaera; T3 *= invaera;
187 }
188 else // Perspective
189 {
190 invaera_persp = invaera;
191 fP1a_p = fP1.w * invaera_persp;
192 fP2a_p = fP2.w * invaera_persp;
193 fP3a_p = fP3.w * invaera_persp;
194 dw_p = (dx1 * fP1a_p) + (dx2 * fP2a_p) + (dx3 * fP3a_p);
195
196 T1 *= fP1a_p; T2 *= fP2a_p; T3 *= fP3a_p;
197 }
198
199 T1.x *= texsize_x; T2.x *= texsize_x; T3.x *= texsize_x;
200 T1.y *= texsize_y; T2.y *= texsize_y; T3.y *= texsize_y;
201
202 dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
203 dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
204 }
205
206 // --- Scanline iteration ---
207 while ((uintptr_t)(buf) < end)
208 {
209 // --- Clipping and finding start x (bx) ---
210 int32_t bx = 0;
211 if (O1 < 0)
212 {
213 bx = (-O1 + dx1 - 1u) / dx1;
214 }
215 if (O2 < 0)
216 {
217 if (dx2 <= 0)
218 {
219 if (dy2 <= 0) return;
220 const int32_t by = (-O2 + dy2 - 1u) / dy2;
221 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
222 buf += by * stride;
223 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
224 continue;
225 }
226 bx = max(bx, (int32_t)((-O2 + dx2 - 1u) / dx2));
227 }
228 if (O3 < 0)
229 {
230 if (dx3 <= 0)
231 {
232 if (dy3 <= 0) return;
233 const int32_t by = (-O3 + dy3 - 1u) / dy3;
234 O1 += (by * dy1); O2 += (by * dy2); O3 += (by * dy3);
235 buf += by * stride;
236 if constexpr (USE_ZBUFFER) zbuf += by * zstride;
237 continue;
238 }
239 bx = max(bx, (int32_t)((-O3 + dx3 - 1u) / dx3));
240 }
241
242 // --- Per-scanline setup ---
243 int32_t C1 = O1 + (dx1 * bx) + E;
244 int32_t C2 = O2 + (dx2 * bx);
245 int32_t C3 = O3 + (dx3 * bx);
246
247 float cw_z = 0.0f;
248 if constexpr (USE_ZBUFFER)
249 {
250 cw_z = ((C1 * fP1a_z) + (C2 * fP2a_z) + (C3 * fP3a_z));
251 if constexpr (!USE_ORTHO)
252 {
253 cw_z += wb;
254 }
255 }
256
257 float cw_p = 0.0f;
258 float tx = 0.0f, ty = 0.0f;
259 if constexpr (USE_TEXTURE)
260 {
261 tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
262 ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
263 if constexpr (!USE_ORTHO) // Perspective
264 {
265 cw_p = ((C1 * fP1a_p) + (C2 * fP2a_p) + (C3 * fP3a_p));
266 }
267 }
268
269 // --- Pixel loop ---
270#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
271 color_t* pix = buf + bx;
272 ZBUFFER_t* zpix = nullptr;
273 if constexpr (USE_ZBUFFER)
274 {
275 zpix = zbuf + bx;
276 }
277#endif
278 while ((bx < lx) && ((C2 | C3) >= 0))
279 {
280 bool z_pass = true;
281 if constexpr (USE_ZBUFFER)
282 {
283#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
284 ZBUFFER_t& W = *zpix;
285#else
286 ZBUFFER_t& W = zbuf[bx];
287#endif
288 ZBUFFER_t current_z;
289
290 if constexpr (std::is_same<ZBUFFER_t, uint16_t>::value)
291 {
292 current_z = (USE_ORTHO) ? ((ZBUFFER_t)(cw_z * wa + wb)) : ((ZBUFFER_t)cw_z);
293 }
294 else
295 {
296 current_z = (ZBUFFER_t)cw_z;
297 }
298
299 if (W < current_z)
300 {
301 W = current_z;
302 }
303 else
304 {
305 z_pass = false;
306 }
307 }
308
309 if (z_pass)
310 {
311 color_t final_color;
312
313 if constexpr (USE_TEXTURE)
314 {
315 float icw = 1.0f;
316 if constexpr (!USE_ORTHO)
317 {
318 icw = fast_inv(cw_p);
319 }
320
321 float xx = tx * icw;
322 float yy = ty * icw;
323
324 if constexpr (TEXTURE_BILINEAR)
325 {
326 const int ttx = lfloorf(xx);
327 const int tty = lfloorf(yy);
328 const float ax = xx - ttx;
329 const float ay = yy - tty;
330
331 const int minx = TEXTURE_WRAP ? (ttx & texsize_x_mm) : shaderclip(ttx, texsize_x_mm);
332 const int maxx = TEXTURE_WRAP ? ((ttx + 1) & texsize_x_mm) : shaderclip(ttx + 1, texsize_x_mm);
333 const int miny = (TEXTURE_WRAP ? (tty & texsize_y_mm) : shaderclip(tty, texsize_y_mm)) * texstride;
334 const int maxy = (TEXTURE_WRAP ? ((tty + 1) & texsize_y_mm) : shaderclip(tty + 1, texsize_y_mm)) * texstride;
335
336 final_color = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
337 }
338 else // Nearest neighbor
339 {
340 const int ttx = TEXTURE_WRAP ? ((int)(xx)) & texsize_x_mm : shaderclip((int)(xx), texsize_x_mm);
341 const int tty = TEXTURE_WRAP ? ((int)(yy)) & texsize_y_mm : shaderclip((int)(yy), texsize_y_mm);
342 final_color = tex[ttx + tty * texstride];
343 }
344
345 if constexpr (USE_GOURAUD)
346 {
347 const int32_t C2s = C2 >> shiftC;
348 const int32_t C3s = C3 >> shiftC;
349 const int r = fP1R + ((C2s * fP21R + C3s * fP31R) / aeraShifted);
350 const int g = fP1G + ((C2s * fP21G + C3s * fP31G) / aeraShifted);
351 const int b = fP1B + ((C2s * fP21B + C3s * fP31B) / aeraShifted);
352 final_color.mult256(r, g, b);
353 }
354 else if constexpr (!USE_UNLIT) // Flat
355 {
356 final_color.mult256(fPR, fPG, fPB);
357 }
358 }
359 else // No texture
360 {
361 if constexpr (USE_GOURAUD)
362 {
363 final_color = interpolateColorsTriangle(col2_g, C2 >> shiftC, col3_g, C3 >> shiftC, col1_g, aeraShifted);
364 }
365 else // Flat
366 {
367 final_color = flat_color;
368 }
369 }
370#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
371 *pix = final_color;
372#else
373 buf[bx] = final_color;
374#endif
375 }
376
377 // --- Increment for next pixel ---
378 C2 += dx2;
379 C3 += dx3;
380 bx++;
381#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
382 pix++;
383#endif
384
385 if constexpr (USE_ZBUFFER) cw_z += dw_z;
386#if TGX_SHADER_USE_INCREMENTAL_PIXEL_POINTERS
387 if constexpr (USE_ZBUFFER) zpix++;
388#endif
389
390 if constexpr (USE_TEXTURE)
391 {
392 tx += dtx;
393 ty += dty;
394 if constexpr (!USE_ORTHO) cw_p += dw_p;
395 }
396 }
397
398 // --- Increment for next scanline ---
399 O1 += dy1;
400 O2 += dy2;
401 O3 += dy3;
402 buf += stride;
403 if constexpr (USE_ZBUFFER) zbuf += zstride;
404 }
405 }
406
407
411 template<int SHADER_FLAGS_ENABLED, typename color_t, typename ZBUFFER_t> void shader_select(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
412 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
413 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
414 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
415 const RasterizerParams<color_t, color_t, ZBUFFER_t> & data)
416 {
417 int raster_type = data.shader_type;
418 if (TGX_SHADER_HAS_ZBUFFER(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ZBUFFER(raster_type)))
419 { // USING ZBUFFER
420 if (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ORTHO(raster_type)))
421 { // USING ORTHOGRAPHIC PROJECTION
422 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
423 { // Texture
424 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
425 { // Gouraud
426 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
427 { // Bilinear
428 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
429 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);
430 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
431 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);
432 }
433 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
434 { // Nearest
435 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
436 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);
437 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
438 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);
439 }
440 }
441 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
442 { // Unlit
443 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
444 { // Bilinear
445 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
446 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);
447 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
448 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);
449 }
450 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
451 { // Nearest
452 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
453 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);
454 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
455 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);
456 }
457 }
458 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
459 { // Flat
460 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
461 { // Bilinear
462 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
463 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);
464 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
465 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);
466 }
467 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
468 { // Nearest
469 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
470 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);
471 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
472 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);
473 }
474 }
475 }
476 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
477 { // No Texture
478 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
479 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);
480 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
481 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);
482 }
483 }
484 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
485 { // USING PERSPECTIVE PROJECTION
486 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
487 { // Texture
488 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
489 { // Gouraud
490 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
491 { // Bilinear
492 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
493 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);
494 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
495 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);
496 }
497 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
498 { // Nearest
499 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
500 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);
501 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
502 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);
503 }
504 }
505 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
506 { // Unlit
507 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
508 { // Bilinear
509 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
510 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);
511 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
512 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);
513 }
514 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
515 { // Nearest
516 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
517 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);
518 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
519 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);
520 }
521 }
522 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
523 { // Flat
524 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
525 { // Bilinear
526 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
527 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);
528 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
529 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);
530 }
531 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
532 { // Nearest
533 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
534 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);
535 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
536 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);
537 }
538 }
539 }
540 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
541 { // No Texture
542 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
543 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);
544 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
545 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);
546 }
547 }
548 }
549 else if (TGX_SHADER_HAS_NOZBUFFER(SHADER_FLAGS_ENABLED))
550 { // NOT USING Z-BUFFER
551 if (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ORTHO(raster_type)))
552 { // USING ORTHOGRAPHIC PROJECTION
553 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
554 { // Texture
555 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
556 { // Gouraud
557 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
558 { // Bilinear
559 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
560 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);
561 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
562 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);
563 }
564 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
565 { // Nearest
566 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
567 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);
568 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
569 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);
570 }
571 }
572 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
573 { // Unlit
574 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
575 { // Bilinear
576 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
577 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);
578 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
579 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);
580 }
581 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
582 { // Nearest
583 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
584 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);
585 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
586 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);
587 }
588 }
589 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
590 { // Flat
591 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
592 { // Bilinear
593 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
594 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);
595 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
596 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);
597 }
598 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
599 { // Nearest
600 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
601 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);
602 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
603 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);
604 }
605 }
606 }
607 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
608 { // No Texture
609 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
610 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);
611 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
612 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);
613 }
614 }
615 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
616 { // USING PERSPECTIVE PROJECTION
617 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
618 { // Texture
619 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
620 { // Gouraud
621 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
622 { // Bilinear
623 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
624 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);
625 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
626 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);
627 }
628 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
629 { // Nearest
630 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
631 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);
632 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
633 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);
634 }
635 }
636 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
637 { // Unlit
638 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
639 { // Bilinear
640 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
641 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);
642 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
643 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);
644 }
645 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
646 { // Nearest
647 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
648 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);
649 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
650 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);
651 }
652 }
653 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
654 { // Flat
655 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
656 { // Bilinear
657 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
658 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);
659 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
660 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);
661 }
662 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
663 { // Nearest
664 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
665 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);
666 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
667 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);
668 }
669 }
670 }
671 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
672 { // No Texture
673 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
674 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);
675 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
676 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);
677 }
678 }
679 }
680 }
681
682
683
684
685
689 template<bool USE_BLENDING, typename color_t_im>
690 void shader_2D_gradient(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
691 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
692 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
693 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
694 const RasterizerParams<color_t_im, color_t_im, float> & data)
695 {
696 const int32_t stride = data.im->stride();
697 color_t_im * buf = data.im->data() + oox + (ooy * stride);
698
699 // use RGB32 (could use RGB64 be it would be slower).
700 const RGB32 col1 = RGB64(fP1.color.R, fP1.color.G, fP1.color.B, fP1.A);
701 const RGB32 col2 = RGB64(fP2.color.R, fP2.color.G, fP2.color.B, fP2.A);
702 const RGB32 col3 = RGB64(fP3.color.R, fP3.color.G, fP3.color.B, fP3.A);
703
704 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
705 const int32_t pa = O1 + O2 + O3;
706 const int32_t E = ((pa == 0) ? 1 : 0);
707 const int32_t aera = pa + E;
708 const int shiftC = (aera > (1 << 22)) ? 10 : 0; // prevent overflow during color interpolation
709
710 while ((uintptr_t)(buf) < end)
711 { // iterate over scanlines
712 int32_t bx = 0; // start offset
713 if (O1 < 0)
714 {
715 // we know that dx1 > 0
716 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
717 }
718 if (O2 < 0)
719 {
720 if (dx2 <= 0)
721 {
722 if (dy2 <= 0) return;
723 const int32_t by = (-O2 + dy2 - 1u) / dy2;
724 O1 += (by * dy1);
725 O2 += (by * dy2);
726 O3 += (by * dy3);
727 const int32_t offs = by * stride;
728 buf += offs;
729 continue;
730 }
731 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
732 bx = max(bx, bx2);
733 }
734 if (O3 < 0)
735 {
736 if (dx3 <= 0)
737 {
738 if (dy3 <= 0) return;
739 const int32_t by = (-O3 + dy3 - 1u) / dy3;
740 O1 += (by * dy1);
741 O2 += (by * dy2);
742 O3 += (by * dy3);
743 const int32_t offs = by * stride;
744 buf += offs;
745 continue;
746 }
747 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
748 bx = max(bx, bx3);
749 }
750
751 int32_t C2 = O2 + (dx2 * bx);
752 int32_t C3 = O3 + (dx3 * bx);
753 while ((bx < lx) && ((C2 | C3) >= 0))
754 {
755 if (USE_BLENDING)
756 {
757 RGB32 c(buf[bx]); // could use RGB64 instead but would be slower
758 c.blend(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC), data.opacity);
759 buf[bx] = color_t_im(c);
760 }
761 else
762 {
763 buf[bx] = color_t_im(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC));
764 }
765 C2 += dx2;
766 C3 += dx3;
767 bx++;
768 }
769
770 O1 += dy1;
771 O2 += dy2;
772 O3 += dy3;
773 buf += stride;
774 }
775 }
776
777
778
782 template<bool USE_BLENDING, bool USE_MASKING, bool USE_GRADIENT, typename color_t_im, typename color_t_tex>
783 void shader_2D_texture(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
784 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
785 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
786 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
787 const RasterizerParams<color_t_im, color_t_tex, float> & data)
788 {
789
790 const int32_t stride = data.im->stride();
791 color_t_im* buf = data.im->data() + oox + (ooy * stride);
792
793 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
794 const int32_t pa = O1 + O2 + O3;
795 const int32_t E = ((pa == 0) ? 1 : 0);
796 const int32_t aera = pa + E;
797
798 const float invaera = fast_inv((float)aera);
799
800 const color_t_tex mask_color = data.mask_color;
801
802 const RGBf& cf1 = fP1.color;
803 const RGBf& cf2 = fP2.color;
804 const RGBf& cf3 = fP3.color;
805
806 // the texture coord
807 fVec2 T1 = fP1.T;
808 fVec2 T2 = fP2.T;
809 fVec2 T3 = fP3.T;
810
811 const color_t_tex * tex = data.tex->data();
812 const int32_t texsize_x = data.tex->width();
813 const int32_t texsize_y = data.tex->height();
814 const int32_t texsize_x_mm = data.tex->width() - 1;
815 const int32_t texsize_y_mm = data.tex->height() - 1;
816 const int32_t texstride = data.tex->stride();
817
818 // divide the texture coord by aera
819 T1 *= invaera;
820 T2 *= invaera;
821 T3 *= invaera;
822 T1.x *= texsize_x;
823 T2.x *= texsize_x;
824 T3.x *= texsize_x;
825 T1.y *= texsize_y;
826 T2.y *= texsize_y;
827 T3.y *= texsize_y;
828
829 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
830 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
831
832 while ((uintptr_t)(buf) < end)
833 { // iterate over scanlines
834 int32_t bx = 0; // start offset
835 if (O1 < 0)
836 {
837 // we know that dx1 > 0
838 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
839 }
840 if (O2 < 0)
841 {
842 if (dx2 <= 0)
843 {
844 if (dy2 <= 0) return;
845 const int32_t by = (-O2 + dy2 - 1u) / dy2;
846 O1 += (by * dy1);
847 O2 += (by * dy2);
848 O3 += (by * dy3);
849 const int32_t offs = by * stride;
850 buf += offs;
851 continue;
852 }
853 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
854 bx = max(bx, bx2);
855 }
856 if (O3 < 0)
857 {
858 if (dx3 <= 0)
859 {
860 if (dy3 <= 0) return;
861 const int32_t by = (-O3 + dy3 - 1u) / dy3;
862 O1 += (by * dy1);
863 O2 += (by * dy2);
864 O3 += (by * dy3);
865 const int32_t offs = by * stride;
866 buf += offs;
867 continue;
868 }
869 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
870 bx = max(bx, bx3);
871 }
872
873 int32_t C1 = O1 + (dx1 * bx) + E;
874 int32_t C2 = O2 + (dx2 * bx);
875 int32_t C3 = O3 + (dx3 * bx);
876
877 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
878 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
879
880 while ((bx < lx) && ((C2 | C3) >= 0))
881 {
882 const float xx = tx;
883 const float yy = ty;
884 const int ttx = lfloorf(xx);
885 const int tty = lfloorf(yy);
886 const float ax = xx - ttx;
887 const float ay = yy - tty;
888
889 const int minx = shaderclip(ttx, texsize_x_mm);
890 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
891 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
892 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
893
894 if (USE_MASKING)
895 { //
896 auto col00 = tex[minx + miny];
897 auto col10 = tex[maxx + miny];
898 auto col01 = tex[minx + maxy];
899 auto col11 = tex[maxx + maxy];
900
901 if ((col00 != mask_color) && (col10 != mask_color) && (col01 != mask_color) && (col11 != mask_color))
902 {
903 color_t_tex col = interpolateColorsBilinear(col00, col10, col01, col11, ax, ay);
904 if (USE_GRADIENT)
905 {
906 const int sC2 = C2;
907 const int sC3 = C3;
908 const int sC1 = aera - C3 - C2;
909 const float m = 256.0f / aera;
910 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
911 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
912 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
913 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
914 col.mult256(r, g, b, a);
915 }
916 if (USE_BLENDING)
917 {
918 color_t_tex c = color_t_tex(buf[bx]);
919 c.blend(col, data.opacity);
920 buf[bx] = color_t_im(c);
921 }
922 else
923 {
924 buf[bx] = color_t_im(col);
925 }
926 }
927 else
928 {
929 tgx::RGB32 acol00 = (col00 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col00);
930 tgx::RGB32 acol10 = (col10 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col10);
931 tgx::RGB32 acol01 = (col01 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col01);
932 tgx::RGB32 acol11 = (col11 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col11);
933
934 tgx::RGB32 col = interpolateColorsBilinear(acol00, acol10, acol01, acol11, ax, ay);
935
936 if (USE_GRADIENT)
937 {
938 const int sC2 = C2;
939 const int sC3 = C3;
940 const int sC1 = aera - C3 - C2;
941 const float m = 256.0f / aera;
942 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
943 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
944 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
945 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
946 col.mult256(r, g, b, a);
947 }
948 if (USE_BLENDING)
949 {
950 tgx::RGB32 c = tgx::RGB32(buf[bx]);
951 c.blend(col, data.opacity);
952 buf[bx] = color_t_im(c);
953 }
954 else
955 {
956 if (col.A == 255)
957 {
958 buf[bx] = color_t_im(col);
959 }
960 else if (col.A > 0)
961 {
962 tgx::RGB32 c = tgx::RGB32(buf[bx]);
963 c.blend(col);
964 buf[bx] = color_t_im(c);
965 }
966 }
967 }
968 }
969 else
970 {
971 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
972 if (USE_GRADIENT)
973 {
974 const int sC2 = C2;
975 const int sC3 = C3;
976 const int sC1 = aera - C3 - C2;
977 const float m = 256.0f / aera;
978 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
979 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
980 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
981 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
982 col.mult256(r, g, b, a);
983 }
984 if (USE_BLENDING)
985 {
986 color_t_tex c = color_t_tex(buf[bx]);
987 c.blend(col, data.opacity);
988 buf[bx] = color_t_im(c);
989 }
990 else
991 {
992 buf[bx] = color_t_im(col);
993 }
994 }
995
996 C2 += dx2;
997 C3 += dx3;
998
999 tx += dtx;
1000 ty += dty;
1001
1002 bx++;
1003 }
1004
1005 O1 += dy1;
1006 O2 += dy2;
1007 O3 += dy3;
1008 buf += stride;
1009 }
1010 }
1011
1012
1013
1014
1018 template<typename BLEND_OP, typename color_t_im, typename color_t_tex>
1019 void shader_2D_texture_blend_op(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
1020 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1021 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1022 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1023 const RasterizerParams<color_t_im, color_t_tex, float, BLEND_OP> & data)
1024 {
1025
1026 const int32_t stride = data.im->stride();
1027 color_t_im * buf = data.im->data() + oox + (ooy * stride);
1028
1029 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1030 const int32_t pa = O1 + O2 + O3;
1031 const int32_t E = ((pa == 0) ? 1 : 0);
1032 const int32_t aera = pa + E;
1033
1034 const float invaera = fast_inv((float)aera);
1035
1036 // the texture coord
1037 fVec2 T1 = fP1.T;
1038 fVec2 T2 = fP2.T;
1039 fVec2 T3 = fP3.T;
1040
1041
1042 const color_t_tex * tex = data.tex->data();
1043 const int32_t texsize_x = data.tex->width();
1044 const int32_t texsize_y = data.tex->height();
1045 const int32_t texsize_x_mm = data.tex->width() - 1;
1046 const int32_t texsize_y_mm = data.tex->height() - 1;
1047 const int32_t texstride = data.tex->stride();
1048
1049 // divide the texture coord by aera
1050 T1 *= invaera;
1051 T2 *= invaera;
1052 T3 *= invaera;
1053 T1.x *= texsize_x;
1054 T2.x *= texsize_x;
1055 T3.x *= texsize_x;
1056 T1.y *= texsize_y;
1057 T2.y *= texsize_y;
1058 T3.y *= texsize_y;
1059
1060 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
1061 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
1062
1063 while ((uintptr_t)(buf) < end)
1064 { // iterate over scanlines
1065 int32_t bx = 0; // start offset
1066 if (O1 < 0)
1067 {
1068 // we know that dx1 > 0
1069 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
1070 }
1071 if (O2 < 0)
1072 {
1073 if (dx2 <= 0)
1074 {
1075 if (dy2 <= 0) return;
1076 const int32_t by = (-O2 + dy2 - 1u) / dy2;
1077 O1 += (by * dy1);
1078 O2 += (by * dy2);
1079 O3 += (by * dy3);
1080 const int32_t offs = by * stride;
1081 buf += offs;
1082 continue;
1083 }
1084 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
1085 bx = max(bx, bx2);
1086 }
1087 if (O3 < 0)
1088 {
1089 if (dx3 <= 0)
1090 {
1091 if (dy3 <= 0) return;
1092 const int32_t by = (-O3 + dy3 - 1u) / dy3;
1093 O1 += (by * dy1);
1094 O2 += (by * dy2);
1095 O3 += (by * dy3);
1096 const int32_t offs = by * stride;
1097 buf += offs;
1098 continue;
1099 }
1100 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
1101 bx = max(bx, bx3);
1102 }
1103
1104 int32_t C1 = O1 + (dx1 * bx) + E;
1105 int32_t C2 = O2 + (dx2 * bx);
1106 int32_t C3 = O3 + (dx3 * bx);
1107
1108 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
1109 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
1110
1111 while ((bx < lx) && ((C2 | C3) >= 0))
1112 {
1113 const float xx = tx;
1114 const float yy = ty;
1115 const int ttx = lfloorf(xx);
1116 const int tty = lfloorf(yy);
1117 const float ax = xx - ttx;
1118 const float ay = yy - tty;
1119
1120 const int minx = shaderclip(ttx, texsize_x_mm);
1121 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
1122 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
1123 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
1124
1125 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1126
1127 buf[bx] = (color_t_im)((*data.p_blend_op)(col, buf[bx]));
1128
1129 C2 += dx2;
1130 C3 += dx3;
1131
1132 tx += dtx;
1133 ty += dty;
1134
1135 bx++;
1136 }
1137
1138 O1 += dy1;
1139 O2 += dy2;
1140 O3 += dy3;
1141 buf += stride;
1142 }
1143 }
1144
1145
1146}
1147
1148#endif
1149
1150#endif
1151
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:391
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
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:783
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:690
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:1019
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:411
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:79
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