| 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
30 namespace tgx
31{
32
34 inline TGX_INLINE int shaderclip(int v, int maxv)
35 {
36 return ((v < 0) ? 0 : ((v > maxv) ? maxv : v));
37 }
38
39
40
44 template<typename color_t, typename ZBUFFER_t>
45 void shader_test(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
46 const int32_t dx1, const int32_t dy1, int32_t O1, const tgx::RasterizerVec4& fP1,
47 const int32_t dx2, const int32_t dy2, int32_t O2, const tgx::RasterizerVec4& fP2,
48 const int32_t dx3, const int32_t dy3, int32_t O3, const tgx::RasterizerVec4& fP3,
49 const tgx::RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
50 {
51 color_t col = (color_t)tgx::RGB32_Red; //data.facecolor;
52 const int32_t stride = data.im->stride();
53 color_t* buf = data.im->data() + oox + (ooy * stride);
54
55 for (int y = 0; y < ly; y++)
56 {
57 for (int x = 0; x < lx; x++)
58 {
59 const int32_t o1 = O1 + dx1 * x + dy1 * y;
60 const int32_t o2 = O2 + dx2 * x + dy2 * y;
61 const int32_t o3 = O3 + dx3 * x + dy3 * y;
62 if ((o1 >= 0) && (o2 >= 0) && (o3 >= 0))
63 {
64 buf[x + stride * y].blend256(col, 128);
65 }
66 }
67 }
68 }
69
70
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 = (RGBf)fP1.color;
144 const RGBf& cf2 = (RGBf)fP2.color;
145 const RGBf& cf3 = (RGBf)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 = (RGBf)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 while ((bx < lx) && ((C2 | C3) >= 0))
271 {
272 bool z_pass = true;
273 if constexpr (USE_ZBUFFER)
274 {
275 ZBUFFER_t& W = zbuf[bx];
276 ZBUFFER_t current_z;
277
278 if constexpr (std::is_same<ZBUFFER_t, uint16_t>::value)
279 {
280 current_z = (USE_ORTHO) ? ((ZBUFFER_t)(cw_z * wa + wb)) : ((ZBUFFER_t)cw_z);
281 }
282 else
283 {
284 current_z = (ZBUFFER_t)cw_z;
285 }
286
287 if (W < current_z)
288 {
289 W = current_z;
290 }
291 else
292 {
293 z_pass = false;
294 }
295 }
296
297 if (z_pass)
298 {
299 color_t final_color;
300
301 if constexpr (USE_TEXTURE)
302 {
303 float icw = 1.0f;
304 if constexpr (!USE_ORTHO)
305 {
306 icw = fast_inv(cw_p);
307 }
308
309 float xx = tx * icw;
310 float yy = ty * icw;
311
312 if constexpr (TEXTURE_BILINEAR)
313 {
314 const int ttx = lfloorf(xx);
315 const int tty = lfloorf(yy);
316 const float ax = xx - ttx;
317 const float ay = yy - tty;
318
319 const int minx = TEXTURE_WRAP ? (ttx & texsize_x_mm) : shaderclip(ttx, texsize_x_mm);
320 const int maxx = TEXTURE_WRAP ? ((ttx + 1) & texsize_x_mm) : shaderclip(ttx + 1, texsize_x_mm);
321 const int miny = (TEXTURE_WRAP ? (tty & texsize_y_mm) : shaderclip(tty, texsize_y_mm)) * texstride;
322 const int maxy = (TEXTURE_WRAP ? ((tty + 1) & texsize_y_mm) : shaderclip(tty + 1, texsize_y_mm)) * texstride;
323
324 final_color = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
325 }
326 else // Nearest neighbor
327 {
328 const int ttx = TEXTURE_WRAP ? ((int)(xx)) & texsize_x_mm : shaderclip((int)(xx), texsize_x_mm);
329 const int tty = TEXTURE_WRAP ? ((int)(yy)) & texsize_y_mm : shaderclip((int)(yy), texsize_y_mm);
330 final_color = tex[ttx + tty * texstride];
331 }
332
333 if constexpr (USE_GOURAUD)
334 {
335 const int32_t C2s = C2 >> shiftC;
336 const int32_t C3s = C3 >> shiftC;
337 const int r = fP1R + ((C2s * fP21R + C3s * fP31R) / aeraShifted);
338 const int g = fP1G + ((C2s * fP21G + C3s * fP31G) / aeraShifted);
339 const int b = fP1B + ((C2s * fP21B + C3s * fP31B) / aeraShifted);
340 final_color.mult256(r, g, b);
341 }
342 else if constexpr (!USE_UNLIT) // Flat
343 {
344 final_color.mult256(fPR, fPG, fPB);
345 }
346 }
347 else // No texture
348 {
349 if constexpr (USE_GOURAUD)
350 {
351 final_color = interpolateColorsTriangle(col2_g, C2 >> shiftC, col3_g, C3 >> shiftC, col1_g, aeraShifted);
352 }
353 else // Flat
354 {
355 final_color = flat_color;
356 }
357 }
358 buf[bx] = final_color;
359 }
360
361 // --- Increment for next pixel ---
362 C2 += dx2;
363 C3 += dx3;
364 bx++;
365
366 if constexpr (USE_ZBUFFER) cw_z += dw_z;
367
368 if constexpr (USE_TEXTURE)
369 {
370 tx += dtx;
371 ty += dty;
372 if constexpr (!USE_ORTHO) cw_p += dw_p;
373 }
374 }
375
376 // --- Increment for next scanline ---
377 O1 += dy1;
378 O2 += dy2;
379 O3 += dy3;
380 buf += stride;
381 if constexpr (USE_ZBUFFER) zbuf += zstride;
382 }
383 }
384
385
389 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,
390 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
391 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
392 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
393 const RasterizerParams<color_t, color_t, ZBUFFER_t> & data)
394 {
395 int raster_type = data.shader_type;
396 if (TGX_SHADER_HAS_ZBUFFER(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ZBUFFER(raster_type)))
397 { // USING ZBUFFER
398 if (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ORTHO(raster_type)))
399 { // USING ORTHOGRAPHIC PROJECTION
400 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
401 { // Texture
402 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
403 { // Gouraud
404 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
405 { // Bilinear
406 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
407 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);
408 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
409 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);
410 }
411 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
412 { // Nearest
413 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
414 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);
415 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
416 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);
417 }
418 }
419 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
420 { // Unlit
421 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
422 { // Bilinear
423 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
424 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);
425 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
426 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);
427 }
428 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
429 { // Nearest
430 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
431 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);
432 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
433 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);
434 }
435 }
436 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
437 { // Flat
438 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
439 { // Bilinear
440 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
441 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);
442 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
443 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);
444 }
445 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
446 { // Nearest
447 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
448 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);
449 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
450 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);
451 }
452 }
453 }
454 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
455 { // No Texture
456 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
457 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);
458 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
459 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);
460 }
461 }
462 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
463 { // USING PERSPECTIVE PROJECTION
464 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
465 { // Texture
466 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
467 { // Gouraud
468 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
469 { // Bilinear
470 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
471 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);
472 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
473 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);
474 }
475 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
476 { // Nearest
477 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
478 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);
479 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
480 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);
481 }
482 }
483 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
484 { // Unlit
485 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
486 { // Bilinear
487 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
488 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);
489 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
490 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);
491 }
492 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
493 { // Nearest
494 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
495 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);
496 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
497 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);
498 }
499 }
500 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
501 { // Flat
502 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
503 { // Bilinear
504 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
505 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);
506 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
507 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);
508 }
509 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
510 { // Nearest
511 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
512 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);
513 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
514 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);
515 }
516 }
517 }
518 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
519 { // No Texture
520 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
521 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);
522 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
523 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);
524 }
525 }
526 }
527 else if (TGX_SHADER_HAS_NOZBUFFER(SHADER_FLAGS_ENABLED))
528 { // NOT USING Z-BUFFER
529 if (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ORTHO(raster_type)))
530 { // USING ORTHOGRAPHIC PROJECTION
531 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
532 { // Texture
533 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
534 { // Gouraud
535 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
536 { // Bilinear
537 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
538 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);
539 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
540 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);
541 }
542 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
543 { // Nearest
544 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
545 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);
546 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
547 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);
548 }
549 }
550 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
551 { // Unlit
552 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
553 { // Bilinear
554 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
555 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);
556 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
557 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);
558 }
559 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
560 { // Nearest
561 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
562 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);
563 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
564 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);
565 }
566 }
567 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
568 { // Flat
569 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
570 { // Bilinear
571 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
572 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);
573 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
574 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);
575 }
576 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
577 { // Nearest
578 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
579 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);
580 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
581 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);
582 }
583 }
584 }
585 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
586 { // No Texture
587 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
588 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);
589 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
590 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);
591 }
592 }
593 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
594 { // USING PERSPECTIVE PROJECTION
595 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
596 { // Texture
597 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
598 { // Gouraud
599 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
600 { // Bilinear
601 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
602 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);
603 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
604 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);
605 }
606 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
607 { // Nearest
608 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
609 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);
610 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
611 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);
612 }
613 }
614 else if (TGX_SHADER_HAS_UNLIT(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_UNLIT(raster_type))
615 { // Unlit
616 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
617 { // Bilinear
618 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
619 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);
620 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
621 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);
622 }
623 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
624 { // Nearest
625 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
626 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);
627 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
628 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);
629 }
630 }
631 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
632 { // Flat
633 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
634 { // Bilinear
635 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
636 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);
637 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
638 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);
639 }
640 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
641 { // Nearest
642 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
643 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);
644 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
645 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);
646 }
647 }
648 }
649 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
650 { // No Texture
651 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
652 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);
653 else if (TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(SHADER_FLAGS_ENABLED, raster_type))
654 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);
655 }
656 }
657 }
658 }
659
660
661
662
663
667 template<bool USE_BLENDING, typename color_t_im>
668 void shader_2D_gradient(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
669 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
670 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
671 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
672 const RasterizerParams<color_t_im, color_t_im, float> & data)
673 {
674 const int32_t stride = data.im->stride();
675 color_t_im * buf = data.im->data() + oox + (ooy * stride);
676
677 // use RGB32 (could use RGB64 be it would be slower).
678 const RGB32 col1 = RGB64(fP1.color.R, fP1.color.G, fP1.color.B, fP1.A);
679 const RGB32 col2 = RGB64(fP2.color.R, fP2.color.G, fP2.color.B, fP2.A);
680 const RGB32 col3 = RGB64(fP3.color.R, fP3.color.G, fP3.color.B, fP3.A);
681
682 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
683 const int32_t pa = O1 + O2 + O3;
684 const int32_t E = ((pa == 0) ? 1 : 0);
685 const int32_t aera = pa + E;
686 const int shiftC = (aera > (1 << 22)) ? 10 : 0; // prevent overflow during color interpolation
687
688 while ((uintptr_t)(buf) < end)
689 { // iterate over scanlines
690 int32_t bx = 0; // start offset
691 if (O1 < 0)
692 {
693 // we know that dx1 > 0
694 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
695 }
696 if (O2 < 0)
697 {
698 if (dx2 <= 0)
699 {
700 if (dy2 <= 0) return;
701 const int32_t by = (-O2 + dy2 - 1u) / dy2;
702 O1 += (by * dy1);
703 O2 += (by * dy2);
704 O3 += (by * dy3);
705 const int32_t offs = by * stride;
706 buf += offs;
707 continue;
708 }
709 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
710 bx = max(bx, bx2);
711 }
712 if (O3 < 0)
713 {
714 if (dx3 <= 0)
715 {
716 if (dy3 <= 0) return;
717 const int32_t by = (-O3 + dy3 - 1u) / dy3;
718 O1 += (by * dy1);
719 O2 += (by * dy2);
720 O3 += (by * dy3);
721 const int32_t offs = by * stride;
722 buf += offs;
723 continue;
724 }
725 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
726 bx = max(bx, bx3);
727 }
728
729 int32_t C2 = O2 + (dx2 * bx);
730 int32_t C3 = O3 + (dx3 * bx);
731 while ((bx < lx) && ((C2 | C3) >= 0))
732 {
733 if (USE_BLENDING)
734 {
735 RGB32 c(buf[bx]); // could use RGB64 instead but would be slower
736 c.blend(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC), data.opacity);
737 buf[bx] = color_t_im(c);
738 }
739 else
740 {
741 buf[bx] = color_t_im(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC));
742 }
743 C2 += dx2;
744 C3 += dx3;
745 bx++;
746 }
747
748 O1 += dy1;
749 O2 += dy2;
750 O3 += dy3;
751 buf += stride;
752 }
753 }
754
755
756
760 template<bool USE_BLENDING, bool USE_MASKING, bool USE_GRADIENT, typename color_t_im, typename color_t_tex>
761 void shader_2D_texture(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
762 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
763 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
764 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
765 const RasterizerParams<color_t_im, color_t_tex, float> & data)
766 {
767
768 const int32_t stride = data.im->stride();
769 color_t_im* buf = data.im->data() + oox + (ooy * stride);
770
771 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
772 const int32_t pa = O1 + O2 + O3;
773 const int32_t E = ((pa == 0) ? 1 : 0);
774 const int32_t aera = pa + E;
775
776 const float invaera = fast_inv((float)aera);
777
778 const color_t_tex mask_color = data.mask_color;
779
780 const RGBf& cf1 = (RGBf)fP1.color;
781 const RGBf& cf2 = (RGBf)fP2.color;
782 const RGBf& cf3 = (RGBf)fP3.color;
783
784 // the texture coord
785 fVec2 T1 = fP1.T;
786 fVec2 T2 = fP2.T;
787 fVec2 T3 = fP3.T;
788
789 const color_t_tex * tex = data.tex->data();
790 const int32_t texsize_x = data.tex->width();
791 const int32_t texsize_y = data.tex->height();
792 const int32_t texsize_x_mm = data.tex->width() - 1;
793 const int32_t texsize_y_mm = data.tex->height() - 1;
794 const int32_t texstride = data.tex->stride();
795
796 // divide the texture coord by aera
797 T1 *= invaera;
798 T2 *= invaera;
799 T3 *= invaera;
800 T1.x *= texsize_x;
801 T2.x *= texsize_x;
802 T3.x *= texsize_x;
803 T1.y *= texsize_y;
804 T2.y *= texsize_y;
805 T3.y *= texsize_y;
806
807 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
808 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
809
810 while ((uintptr_t)(buf) < end)
811 { // iterate over scanlines
812 int32_t bx = 0; // start offset
813 if (O1 < 0)
814 {
815 // we know that dx1 > 0
816 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
817 }
818 if (O2 < 0)
819 {
820 if (dx2 <= 0)
821 {
822 if (dy2 <= 0) return;
823 const int32_t by = (-O2 + dy2 - 1u) / dy2;
824 O1 += (by * dy1);
825 O2 += (by * dy2);
826 O3 += (by * dy3);
827 const int32_t offs = by * stride;
828 buf += offs;
829 continue;
830 }
831 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
832 bx = max(bx, bx2);
833 }
834 if (O3 < 0)
835 {
836 if (dx3 <= 0)
837 {
838 if (dy3 <= 0) return;
839 const int32_t by = (-O3 + dy3 - 1u) / dy3;
840 O1 += (by * dy1);
841 O2 += (by * dy2);
842 O3 += (by * dy3);
843 const int32_t offs = by * stride;
844 buf += offs;
845 continue;
846 }
847 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
848 bx = max(bx, bx3);
849 }
850
851 int32_t C1 = O1 + (dx1 * bx) + E;
852 int32_t C2 = O2 + (dx2 * bx);
853 int32_t C3 = O3 + (dx3 * bx);
854
855 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
856 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
857
858 while ((bx < lx) && ((C2 | C3) >= 0))
859 {
860 const float xx = tx;
861 const float yy = ty;
862 const int ttx = lfloorf(xx);
863 const int tty = lfloorf(yy);
864 const float ax = xx - ttx;
865 const float ay = yy - tty;
866
867 const int minx = shaderclip(ttx, texsize_x_mm);
868 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
869 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
870 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
871
872 if (USE_MASKING)
873 { //
874 auto col00 = tex[minx + miny];
875 auto col10 = tex[maxx + miny];
876 auto col01 = tex[minx + maxy];
877 auto col11 = tex[maxx + maxy];
878
879 if ((col00 != mask_color) && (col10 != mask_color) && (col01 != mask_color) && (col11 != mask_color))
880 {
881 color_t_tex col = interpolateColorsBilinear(col00, col10, col01, col11, ax, ay);
882 if (USE_GRADIENT)
883 {
884 const int sC2 = C2;
885 const int sC3 = C3;
886 const int sC1 = aera - C3 - C2;
887 const float m = 256.0f / aera;
888 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
889 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
890 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
891 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
892 col.mult256(r, g, b, a);
893 }
894 if (USE_BLENDING)
895 {
896 color_t_tex c = color_t_tex(buf[bx]);
897 c.blend(col, data.opacity);
898 buf[bx] = color_t_im(c);
899 }
900 else
901 {
902 buf[bx] = color_t_im(col);
903 }
904 }
905 else
906 {
907 tgx::RGB32 acol00 = (col00 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col00);
908 tgx::RGB32 acol10 = (col10 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col10);
909 tgx::RGB32 acol01 = (col01 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col01);
910 tgx::RGB32 acol11 = (col11 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col11);
911
912 tgx::RGB32 col = interpolateColorsBilinear(acol00, acol10, acol01, acol11, ax, ay);
913
914 if (USE_GRADIENT)
915 {
916 const int sC2 = C2;
917 const int sC3 = C3;
918 const int sC1 = aera - C3 - C2;
919 const float m = 256.0f / aera;
920 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
921 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
922 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
923 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
924 col.mult256(r, g, b, a);
925 }
926 if (USE_BLENDING)
927 {
928 tgx::RGB32 c = tgx::RGB32(buf[bx]);
929 c.blend(col, data.opacity);
930 buf[bx] = color_t_im(c);
931 }
932 else
933 {
934 if (col.A == 255)
935 {
936 buf[bx] = color_t_im(col);
937 }
938 else if (col.A > 0)
939 {
940 tgx::RGB32 c = tgx::RGB32(buf[bx]);
941 c.blend(col);
942 buf[bx] = color_t_im(c);
943 }
944 }
945 }
946 }
947 else
948 {
949 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
950 if (USE_GRADIENT)
951 {
952 const int sC2 = C2;
953 const int sC3 = C3;
954 const int sC1 = aera - C3 - C2;
955 const float m = 256.0f / aera;
956 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
957 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
958 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
959 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
960 col.mult256(r, g, b, a);
961 }
962 if (USE_BLENDING)
963 {
964 color_t_tex c = color_t_tex(buf[bx]);
965 c.blend(col, data.opacity);
966 buf[bx] = color_t_im(c);
967 }
968 else
969 {
970 buf[bx] = color_t_im(col);
971 }
972 }
973
974 C2 += dx2;
975 C3 += dx3;
976
977 tx += dtx;
978 ty += dty;
979
980 bx++;
981 }
982
983 O1 += dy1;
984 O2 += dy2;
985 O3 += dy3;
986 buf += stride;
987 }
988 }
989
990
991
992
996 template<typename BLEND_OP, typename color_t_im, typename color_t_tex>
997 void shader_2D_texture_blend_op(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly,
998 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
999 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1000 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1001 const RasterizerParams<color_t_im, color_t_tex, float, BLEND_OP> & data)
1002 {
1003
1004 const int32_t stride = data.im->stride();
1005 color_t_im * buf = data.im->data() + oox + (ooy * stride);
1006
1007 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1008 const int32_t pa = O1 + O2 + O3;
1009 const int32_t E = ((pa == 0) ? 1 : 0);
1010 const int32_t aera = pa + E;
1011
1012 const float invaera = fast_inv((float)aera);
1013
1014 // the texture coord
1015 fVec2 T1 = fP1.T;
1016 fVec2 T2 = fP2.T;
1017 fVec2 T3 = fP3.T;
1018
1019
1020 const color_t_tex * tex = data.tex->data();
1021 const int32_t texsize_x = data.tex->width();
1022 const int32_t texsize_y = data.tex->height();
1023 const int32_t texsize_x_mm = data.tex->width() - 1;
1024 const int32_t texsize_y_mm = data.tex->height() - 1;
1025 const int32_t texstride = data.tex->stride();
1026
1027 // divide the texture coord by aera
1028 T1 *= invaera;
1029 T2 *= invaera;
1030 T3 *= invaera;
1031 T1.x *= texsize_x;
1032 T2.x *= texsize_x;
1033 T3.x *= texsize_x;
1034 T1.y *= texsize_y;
1035 T2.y *= texsize_y;
1036 T3.y *= texsize_y;
1037
1038 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
1039 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
1040
1041 while ((uintptr_t)(buf) < end)
1042 { // iterate over scanlines
1043 int32_t bx = 0; // start offset
1044 if (O1 < 0)
1045 {
1046 // we know that dx1 > 0
1047 bx = (-O1 + dx1 - 1u) / dx1; // first index where it becomes positive
1048 }
1049 if (O2 < 0)
1050 {
1051 if (dx2 <= 0)
1052 {
1053 if (dy2 <= 0) return;
1054 const int32_t by = (-O2 + dy2 - 1u) / dy2;
1055 O1 += (by * dy1);
1056 O2 += (by * dy2);
1057 O3 += (by * dy3);
1058 const int32_t offs = by * stride;
1059 buf += offs;
1060 continue;
1061 }
1062 const int32_t bx2 = (-O2 + dx2 - 1u) / dx2;
1063 bx = max(bx, bx2);
1064 }
1065 if (O3 < 0)
1066 {
1067 if (dx3 <= 0)
1068 {
1069 if (dy3 <= 0) return;
1070 const int32_t by = (-O3 + dy3 - 1u) / dy3;
1071 O1 += (by * dy1);
1072 O2 += (by * dy2);
1073 O3 += (by * dy3);
1074 const int32_t offs = by * stride;
1075 buf += offs;
1076 continue;
1077 }
1078 const int32_t bx3 = (-O3 + dx3 - 1u) / dx3;
1079 bx = max(bx, bx3);
1080 }
1081
1082 int32_t C1 = O1 + (dx1 * bx) + E;
1083 int32_t C2 = O2 + (dx2 * bx);
1084 int32_t C3 = O3 + (dx3 * bx);
1085
1086 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
1087 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
1088
1089 while ((bx < lx) && ((C2 | C3) >= 0))
1090 {
1091 const float xx = tx;
1092 const float yy = ty;
1093 const int ttx = lfloorf(xx);
1094 const int tty = lfloorf(yy);
1095 const float ax = xx - ttx;
1096 const float ay = yy - tty;
1097
1098 const int minx = shaderclip(ttx, texsize_x_mm);
1099 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
1100 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
1101 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
1102
1103 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1104
1105 buf[bx] = (color_t_im)((*data.p_blend_op)(col, buf[bx]));
1106
1107 C2 += dx2;
1108 C3 += dx3;
1109
1110 tx += dtx;
1111 ty += dty;
1112
1113 bx++;
1114 }
1115
1116 O1 += dy1;
1117 O2 += dy2;
1118 O3 += dy3;
1119 buf += stride;
1120 }
1121 }
1122
1123
1124}
1125
1126#endif
1127
1128#endif
1129
tgx::RGB32_Red
const RGB32 RGB32_Red
Color red in RGB32 format.
tgx::interpolateColorsBilinear
RGB565 interpolateColorsBilinear(const RGB565 &C00, const RGB565 &C10, const RGB565 &C01, const RGB565 &C11, const float ax, const float ay)
Bilinear interpolation between 4 colors.
Definition: Color.h:621
tgx::interpolateColorsTriangle
RGB565 interpolateColorsTriangle(const RGB565 &col1, int32_t C1, const RGB565 &col2, int32_t C2, const RGB565 &col3, const int32_t totC)
Interpolate between 3 colors.
Definition: Color.h:591
tgx::lfloorf
TGX_INLINE int32_t lfloorf(float x)
Compute (int32_t)floorf(x).
Definition: Misc.h:391
tgx::max
TGX_INLINE T max(const T &a, const T &b)
Don't know why but much faster than fmaxf() for floats.
Definition: Misc.h:153
tgx::fast_inv
TGX_INLINE float fast_inv(float x)
Fast (approximate) computation of 1/x.
Definition: Misc.h:197
ShaderParams.h
Triangle shader parameters.
TGX_SHADER_CAN_USE_FLAT_OR_UNLIT
#define TGX_SHADER_CAN_USE_FLAT_OR_UNLIT(enabled_shader_type, shader_type)
True when a shader configuration can use either flat shading or unlit shading.
Definition: ShaderParams.h:112
tgx::shader_2D_texture
void shader_2D_texture(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_tex, float > &data)
2D shader (texture)
Definition: Shaders.h:761
tgx::shader_2D_gradient
void shader_2D_gradient(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_im, float > &data)
2D shader (gradient)
Definition: Shaders.h:668
tgx::shader_test
void shader_test(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const tgx::RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const tgx::RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const tgx::RasterizerVec4 &fP3, const tgx::RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
For test purposes...
Definition: Shaders.h:45
tgx::shader_2D_texture_blend_op
void shader_2D_texture_blend_op(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_tex, float, BLEND_OP > &data)
2D shader (texture with custom blending operator)
Definition: Shaders.h:997
tgx::shader_select
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:389
tgx::uber_shader
void uber_shader(const int32_t oox, const int32_t ooy, const int32_t lx, const int32_t ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
UBER-SHADER for all 3D rendering variants.
Definition: Shaders.h:79
tgx::shaderclip
TGX_INLINE int shaderclip(int v, int maxv)
for texture clamping
Definition: Shaders.h:34
tgx::RGB32
Color in R8/G8/B8/A8 format.
Definition: Color.h:1176
tgx::RGB32::mult256
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:1590
tgx::RGB32::A
uint8_t A
Alpha channel (8bits)
Definition: Color.h:1197
tgx::RGB32::blend256
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:1561
tgx::RGB32::blend
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:1546
tgx::RGB32::opacity
float opacity() const
Return the opacity (alpha channel value) of this color in the range [0,1] (0=fully transparent,...
Definition: Color.h:1629
tgx::RGB565::opacity
float opacity() const
Dummy function for compatibility with color types having an alpha channel.
Definition: Color.h:565
tgx::RGB64
Color in R16/G16/B16/A16 format.
Definition: Color.h:1791
tgx::RGBf
Color in R,G,B float format.
Definition: Color.h:2407
tgx::RGBf::R
float R
Red channel.
Definition: Color.h:2420
tgx::RGBf::B
float B
Blue channel.
Definition: Color.h:2422
tgx::RGBf::G
float G
Green channel.
Definition: Color.h:2421
tgx::Vec2< float >
tgx::Vec2::x
T x
'x' coordinate (first dimension)
Definition: Vec2.h:72
tgx::Vec2::y
T y
'y' coordinate (second dimension)
Definition: Vec2.h:73