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