TGX 1.0.3
A tiny 2D/3D graphics library optimized for 32 bits microcontrollers.
Loading...
Searching...
No Matches
Rasterizer.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_RASTERIZER_H_
21#define _TGX_RASTERIZER_H_
22
23
24// only C++, no plain C
25#ifdef __cplusplus
26
27
28#include "ShaderParams.h"
29
30namespace tgx
31{
32
46#define TGX_RASTERIZE_SUBPIXEL_BITS (6)
47
48#define TGX_RASTERIZE_SUBPIXEL256 (1 << TGX_RASTERIZE_SUBPIXEL_BITS)
49#define TGX_RASTERIZE_SUBPIXEL128 (1 << (TGX_RASTERIZE_SUBPIXEL_BITS -1))
50#define TGX_RASTERIZE_MULT256(X) ((X) << (TGX_RASTERIZE_SUBPIXEL_BITS))
51#define TGX_RASTERIZE_MULT128(X) ((X) << (TGX_RASTERIZE_SUBPIXEL_BITS -1))
52#define TGX_RASTERIZE_DIV256(X) ((X) >> (TGX_RASTERIZE_SUBPIXEL_BITS))
53
54
107 template<typename SHADER_FUNCTION, typename RASTERIZER_PARAMS>
108 void rasterizeTriangle(const int LX, const int LY, const RasterizerVec4 & V0, const RasterizerVec4 & V1, const RasterizerVec4 & V2, const int32_t offset_x, const int32_t offset_y, const RASTERIZER_PARAMS & data, SHADER_FUNCTION shader_fun)
109 {
110
111 // assuming that clipping was already perfomed and that V0, V1, V2 are in a reasonable "range" so no overflow will occur.
112 const float mx = (float)(TGX_RASTERIZE_MULT128(LX));
113 const float my = (float)(TGX_RASTERIZE_MULT128(LY));
114 const iVec2 P0((int32_t)floorf(V0.x * mx), (int32_t)floorf(V0.y * my));
115 const iVec2 sP1((int32_t)floorf(V1.x * mx), (int32_t)floorf(V1.y * my));
116 const iVec2 sP2((int32_t)floorf(V2.x * mx), (int32_t)floorf(V2.y * my));
117
118 const int32_t umx = min(min(P0.x, sP1.x), sP2.x);
119 const int32_t uMx = max(max(P0.x, sP1.x), sP2.x);
120 const int32_t umy = min(min(P0.y, sP1.y), sP2.y);
121 const int32_t uMy = max(max(P0.y, sP1.y), sP2.y);
122
123 const bool c32 = ((uMx - umx < 32768) && (uMy - umy < 32768));
124 int32_t a;
125 if (c32)
126 { // 32 bits computation
127 a = (((sP2.x - P0.x) * (sP1.y - P0.y)) - ((sP2.y - P0.y) * (sP1.x - P0.x))); // aera
128 if (a == 0) return; // do not draw flat triangles
129 }
130 else
131 { // 64 bits computations
132 int64_t a64 = (((int64_t)(sP2.x - P0.x)) * ((int64_t)(sP1.y - P0.y))) - (((int64_t)(sP2.y - P0.y)) * ((int64_t)(sP1.x - P0.x))); // aera
133 if (a64 == 0) return; // do not draw flat triangles
134 a = (a64 > 0) ? 1 : -1; // real aera value does not matter, onlythe sign
135 }
136
137 int32_t xmin = (umx + TGX_RASTERIZE_MULT128(LX)) / TGX_RASTERIZE_SUBPIXEL256; // use division and not bitshift
138 int32_t xmax = (uMx + TGX_RASTERIZE_MULT128(LX)) / TGX_RASTERIZE_SUBPIXEL256; // in case values are negative.
139 int32_t ymin = (umy + TGX_RASTERIZE_MULT128(LY)) / TGX_RASTERIZE_SUBPIXEL256; //
140 int32_t ymax = (uMy + TGX_RASTERIZE_MULT128(LY)) / TGX_RASTERIZE_SUBPIXEL256; //
141
142 // intersect the sub-image with the triangle bounding box.
143 int32_t sx = data.im->lx();
144 int32_t sy = data.im->ly();
145 int32_t ox = offset_x;
146 int32_t oy = offset_y;
147 if (ox < xmin) { sx -= (xmin - ox); ox = xmin; }
148 if (ox + sx > xmax) { sx = xmax - ox + 1; }
149 if (sx <= 0) return;
150 if (oy < ymin) { sy -= (ymin - oy); oy = ymin; }
151 if (oy + sy > ymax) { sy = ymax - oy + 1; }
152 if (sy <= 0) return;
153
154 const RasterizerVec4& fP1 = (a > 0) ? V1 : V2;
155 const RasterizerVec4& fP2 = (a > 0) ? V2 : V1;
156 const iVec2& P1 = (a > 0) ? sP1 : sP2;
157 const iVec2& P2 = (a > 0) ? sP2 : sP1;
158
159 const int32_t us = TGX_RASTERIZE_MULT256(ox) - TGX_RASTERIZE_MULT128(LX) + TGX_RASTERIZE_SUBPIXEL128; // start pixel position
160 const int32_t vs = TGX_RASTERIZE_MULT256(oy) - TGX_RASTERIZE_MULT128(LY) + TGX_RASTERIZE_SUBPIXEL128; //
161
162 ox -= offset_x;
163 oy -= offset_y;
164
165 int32_t dx1 = P1.y - P0.y;
166 int32_t dy1 = P0.x - P1.x;
167 int32_t dx2 = P2.y - P1.y;
168 int32_t dy2 = P1.x - P2.x;
169 int32_t dx3 = P0.y - P2.y;
170 int32_t dy3 = P2.x - P0.x;
171
172 int32_t O1, O2, O3;
173
174 if (c32)
175 { // 32 bits computation
176 O1 = ((us - P0.x) * dx1) + ((vs - P0.y) * dy1);
177 if ((dx1 < 0) || ((dx1 == 0) && (dy1 < 0))) O1--; // top left rule (beware, changes total aera).
178
179 O2 = ((us - P1.x) * dx2) + ((vs - P1.y) * dy2);
180 if ((dx2 < 0) || ((dx2 == 0) && (dy2 < 0))) O2--; // top left rule (beware, changes total aera).
181
182 O3 = ((us - P2.x) * dx3) + ((vs - P2.y) * dy3);
183 if ((dx3 < 0) || ((dx3 == 0) && (dy3 < 0))) O3--; // top left rule (beware, changes total aera).
184
185 dx1 *= (TGX_RASTERIZE_SUBPIXEL256);
186 dy1 *= (TGX_RASTERIZE_SUBPIXEL256);
187 dx2 *= (TGX_RASTERIZE_SUBPIXEL256);
188 dy2 *= (TGX_RASTERIZE_SUBPIXEL256);
189 dx3 *= (TGX_RASTERIZE_SUBPIXEL256);
190 dy3 *= (TGX_RASTERIZE_SUBPIXEL256);
191 }
192 else
193 { // 64 bits computation
194 int64_t dO1 = (((int64_t)(us - P0.x)) * ((int64_t)dx1)) + (((int64_t)(vs - P0.y)) * ((int64_t)dy1));
195 if ((dx1 < 0) || ((dx1 == 0) && (dy1 < 0))) dO1--; // top left rule (beware, changes total aera).
196 O1 = (dO1 >= 0) ? ((int32_t)TGX_RASTERIZE_DIV256(dO1)) : -((int32_t)TGX_RASTERIZE_DIV256(-dO1 + (TGX_RASTERIZE_SUBPIXEL256 - 1)));
197
198 int64_t dO2 = (((int64_t)(us - P1.x)) * ((int64_t)dx2)) + (((int64_t)(vs - P1.y)) * ((int64_t)dy2));
199 if ((dx2 < 0) || ((dx2 == 0) && (dy2 < 0))) dO2--; // top left rule (beware, changes total aera).
200 O2 = (dO2 >= 0) ? ((int32_t)TGX_RASTERIZE_DIV256(dO2)) : -((int32_t)TGX_RASTERIZE_DIV256(-dO2 + (TGX_RASTERIZE_SUBPIXEL256 - 1)));
201
202 int64_t dO3 = (((int64_t)(us - P2.x)) * ((int64_t)dx3)) + (((int64_t)(vs - P2.y)) * ((int64_t)dy3));
203 if ((dx3 < 0) || ((dx3 == 0) && (dy3 < 0))) dO3--; // top left rule (beware, changes total aera).
204 O3 = (dO3 >= 0) ? ((int32_t)TGX_RASTERIZE_DIV256(dO3)) : -((int32_t)TGX_RASTERIZE_DIV256(-dO3 + (TGX_RASTERIZE_SUBPIXEL256 - 1)));
205 }
206
207 // beware that O1 + O2 + O3 = 0 is possible now but still we should not discard the triangle:
208 // this case must be dealt with inside the shader...
209
210 if (sx == 1)
211 {
212 while (((O1 | O2 | O3) < 0) && (sy > 0))
213 {
214 sy--;
215 oy++;
216 O1 += dy1;
217 O2 += dy2;
218 O3 += dy3;
219 }
220 if (sy == 0) return;
221 }
222 else if (sy == 1)
223 {
224 while (((O1 | O2 | O3) < 0) && (sx > 0))
225 {
226 sx--;
227 ox++;
228 O1 += dx1;
229 O2 += dx2;
230 O3 += dx3;
231 }
232 if (sx == 0) return;
233 }
234
235
236 if (dx1 > 0)
237 {
238 shader_fun(ox + (data.im->stride() * oy), sx, sy,
239 dx1, dy1, O1, fP2,
240 dx2, dy2, O2, V0,
241 dx3, dy3, O3, fP1,
242 data);
243 }
244 else if (dx2 > 0)
245 {
246 shader_fun(ox + (data.im->stride() * oy), sx, sy,
247 dx2, dy2, O2, V0,
248 dx3, dy3, O3, fP1,
249 dx1, dy1, O1, fP2,
250 data);
251 }
252 else
253 {
254 shader_fun(ox + (data.im->stride() * oy), sx, sy,
255 dx3, dy3, O3, fP1,
256 dx1, dy1, O1, fP2,
257 dx2, dy2, O2, V0,
258 data);
259 }
260 return;
261 }
262
263
264
265}
266
267#endif
268
269#endif
270
TGX_INLINE T min(const T &a, const T &b)
Don't know why but faster than fminf() for floats.
Definition: Misc.h:180
TGX_INLINE T max(const T &a, const T &b)
Don't know why but much faster than fmaxf() for floats.
Definition: Misc.h:184
void rasterizeTriangle(const int LX, const int LY, const RasterizerVec4 &V0, const RasterizerVec4 &V1, const RasterizerVec4 &V2, const int32_t offset_x, const int32_t offset_y, const RASTERIZER_PARAMS &data, SHADER_FUNCTION shader_fun)
Fast triangle rasterizer for 3D graphics:
Definition: Rasterizer.h:108
Triangle shader parameters.
Generic 2D vector [specializations iVec2, fVec2, dVec2].
Definition: Vec2.h:64
T x
'x' coordinate (first dimension)
Definition: Vec2.h:72
T y
'y' coordinate (second dimension)
Definition: Vec2.h:73