mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2024-12-23 12:26:59 +01:00
Rework PaintPolygon2D's triangle rasterizer so both color and uv interpolation works properly.
This commit is contained in:
parent
43a2b7d6f3
commit
94f412a352
@ -434,10 +434,9 @@ Ref<Image> PaintPolygon2D::_get_rendered_image() {
|
|||||||
texture_image->lock();
|
texture_image->lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 cpoints[3];
|
Vector2i cpoints[3];
|
||||||
Vector2 cuvs[3];
|
Vector2 cuvs[3];
|
||||||
Color ccolors[3];
|
Color ccolors[3];
|
||||||
int cinds[3];
|
|
||||||
|
|
||||||
if (colors.size() == 1) {
|
if (colors.size() == 1) {
|
||||||
for (int j = 0; j < 3; ++j) {
|
for (int j = 0; j < 3; ++j) {
|
||||||
@ -449,113 +448,172 @@ Ref<Image> PaintPolygon2D::_get_rendered_image() {
|
|||||||
|
|
||||||
for (int index = 0; index < indices.size(); index += 3) {
|
for (int index = 0; index < indices.size(); index += 3) {
|
||||||
// Rasterize triangle
|
// Rasterize triangle
|
||||||
|
// Based on https://www.youtube.com/watch?v=PahbNFypubE
|
||||||
|
|
||||||
for (int j = 0; j < 3; ++j) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
cinds[j] = indices[index + j];
|
int cind = indices[index + i];
|
||||||
|
|
||||||
cpoints[j] = points[cinds[j]];
|
cpoints[i] = points[cind].round();
|
||||||
|
|
||||||
if (colors.size() > 1) {
|
if (colors.size() > 1) {
|
||||||
ccolors[j] = colors[cinds[j]];
|
ccolors[i] = colors[cind];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_uvs) {
|
if (use_uvs) {
|
||||||
cuvs[j] = uvs[cinds[j]];
|
cuvs[i] = uvs[cind];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Super simple scanline rasterizer
|
//Sort them
|
||||||
// Same idea as presented here: https://www.youtube.com/watch?v=PahbNFypubE
|
|
||||||
|
|
||||||
Vector2i min_coords = Vector2i(INT_MAX, INT_MAX);
|
if (cpoints[1].y < cpoints[0].y || (cpoints[1].y == cpoints[0].y && cpoints[1].x < cpoints[0].x)) {
|
||||||
Vector2i max_coords = Vector2i(INT_MIN, INT_MIN);
|
SWAP(cpoints[0], cpoints[1]);
|
||||||
|
SWAP(ccolors[0], ccolors[1]);
|
||||||
for (int j = 0; j < 3; ++j) {
|
SWAP(cuvs[0], cuvs[1]);
|
||||||
min_coords.x = MIN(cpoints[j].x, min_coords.x);
|
|
||||||
min_coords.y = MIN(cpoints[j].y, min_coords.y);
|
|
||||||
max_coords.x = MAX(cpoints[j].x, max_coords.x);
|
|
||||||
max_coords.y = MAX(cpoints[j].y, max_coords.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Point2i> brenzenham_line_points = Geometry::brenzenham_line(cpoints[0].x, cpoints[1].x, cpoints[0].y, cpoints[1].y);
|
if (cpoints[2].y < cpoints[0].y || (cpoints[2].y == cpoints[0].y && cpoints[2].x < cpoints[0].x)) {
|
||||||
brenzenham_line_points.append_array(Geometry::brenzenham_line(cpoints[1].x, cpoints[2].x, cpoints[1].y, cpoints[2].y));
|
SWAP(cpoints[0], cpoints[2]);
|
||||||
brenzenham_line_points.append_array(Geometry::brenzenham_line(cpoints[2].x, cpoints[0].x, cpoints[2].y, cpoints[0].y));
|
SWAP(ccolors[0], ccolors[2]);
|
||||||
|
SWAP(cuvs[0], cuvs[2]);
|
||||||
|
}
|
||||||
|
|
||||||
//Rect2i tri_rect = Rect2i(min_coords, max_coords - min_coords);
|
if (cpoints[2].y < cpoints[1].y || (cpoints[2].y == cpoints[1].y && cpoints[2].x < cpoints[1].x)) {
|
||||||
|
SWAP(cpoints[1], cpoints[2]);
|
||||||
|
SWAP(ccolors[1], ccolors[2]);
|
||||||
|
SWAP(cuvs[1], cuvs[2]);
|
||||||
|
}
|
||||||
|
|
||||||
const int blp_size = brenzenham_line_points.size();
|
if (cpoints[0].y == cpoints[2].y) {
|
||||||
const Point2i *blp_ptr = brenzenham_line_points.ptr();
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int fys = MAX(0, min_coords.y);
|
bool shortside = (cpoints[1].y - cpoints[0].y) * (cpoints[2].x - cpoints[0].x) < (cpoints[1].x - cpoints[0].x) * (cpoints[2].y - cpoints[0].y);
|
||||||
int fye = MIN(_size.y, max_coords.y);
|
|
||||||
|
|
||||||
for (int y = fys; y < fye; ++y) {
|
Slope sides[2];
|
||||||
// Current scanline:
|
|
||||||
// . . . . psx X X X X X pse . . . .
|
|
||||||
|
|
||||||
int psx = INT_MAX;
|
sides[!shortside].setup_position(cpoints[0], cpoints[2], cpoints[2].y - cpoints[0].y);
|
||||||
int pex = INT_MIN;
|
sides[!shortside].setup_color(ccolors[0], ccolors[2], cpoints[2].y - cpoints[0].y);
|
||||||
|
|
||||||
for (int i = 0; i < blp_size; ++i) {
|
if (use_uvs) {
|
||||||
Point2i p = blp_ptr[i];
|
sides[!shortside].setup_uv(cuvs[0], cuvs[2], cpoints[2].y - cpoints[0].y);
|
||||||
|
}
|
||||||
|
|
||||||
if (p.y != y) {
|
if (cpoints[0].y < cpoints[1].y) {
|
||||||
continue;
|
sides[shortside].setup_position(cpoints[0], cpoints[1], cpoints[1].y - cpoints[0].y);
|
||||||
}
|
sides[shortside].setup_color(ccolors[0], ccolors[1], cpoints[1].y - cpoints[0].y);
|
||||||
|
|
||||||
if (p.x < psx) {
|
|
||||||
psx = p.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p.x > pex) {
|
|
||||||
pex = p.x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (psx == INT_MIN || pex == INT_MAX) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// maybe?
|
|
||||||
// pse -= 1;
|
|
||||||
|
|
||||||
float interpy = (y - min_coords.y) / (float)(max_coords.y - min_coords.y);
|
|
||||||
|
|
||||||
Vector2 uvsy;
|
|
||||||
Vector2 uvey;
|
|
||||||
|
|
||||||
if (use_uvs) {
|
if (use_uvs) {
|
||||||
uvsy = cuvs[0].linear_interpolate(cuvs[1], interpy);
|
sides[shortside].setup_uv(cuvs[0], cuvs[1], cpoints[1].y - cpoints[0].y);
|
||||||
uvey = cuvs[0].linear_interpolate(cuvs[2], interpy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Color colorsy = ccolors[0].linear_interpolate(ccolors[1], interpy);
|
int starty = MAX(0, cpoints[0].y);
|
||||||
Color colorey = ccolors[0].linear_interpolate(ccolors[2], interpy);
|
int endy = MIN(cpoints[1].y, _size.y);
|
||||||
|
|
||||||
int fxs = MAX(0, psx);
|
for (int y = starty; y < endy; ++y) {
|
||||||
int fxe = MIN(_size.x, pex);
|
Slope s;
|
||||||
|
s.setup_color(sides[0].color_current, sides[1].color_current, sides[1].position_current.x - sides[0].position_current.x);
|
||||||
|
if (use_uvs) {
|
||||||
|
s.setup_uv(sides[0].uv_current, sides[1].uv_current, sides[1].position_current.x - sides[0].position_current.x);
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = fxs; x < fxe; ++x) {
|
int startx = MAX(0, sides[0].position_current.x);
|
||||||
//Vector2 point = Vector2(x, y);
|
int endx = MIN(sides[1].position_current.x, _size.x);
|
||||||
|
|
||||||
float interpx = (x - psx) / (float)(pex - psx);
|
for (int x = startx; x < endx; ++x) {
|
||||||
|
Color color = s.color_current;
|
||||||
|
|
||||||
Color color = colorsy.linear_interpolate(colorey, interpx);
|
if (use_uvs) {
|
||||||
|
Vector2 uv = s.uv_current;
|
||||||
|
|
||||||
|
uv.x = CLAMP(uv.x, 0, 1);
|
||||||
|
uv.y = CLAMP(uv.y, 0, 1);
|
||||||
|
|
||||||
|
Vector2 imgcoord = uv * texture_image_size;
|
||||||
|
|
||||||
|
imgcoord.x = CLAMP(imgcoord.x, 0, texture_image_size.x - 1);
|
||||||
|
imgcoord.y = CLAMP(imgcoord.y, 0, texture_image_size.y - 1);
|
||||||
|
|
||||||
|
Color img_color = texture_image->get_pixelv(imgcoord);
|
||||||
|
|
||||||
|
color *= img_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rendered_image->set_pixelv(Vector2(x, y), color);
|
||||||
|
|
||||||
|
s.advance_color();
|
||||||
|
|
||||||
|
if (use_uvs) {
|
||||||
|
s.advance_uv();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sides[0].advance();
|
||||||
|
sides[1].advance();
|
||||||
|
|
||||||
if (use_uvs) {
|
if (use_uvs) {
|
||||||
Vector2 uv = uvsy.linear_interpolate(uvey, interpx);
|
sides[0].advance_uv();
|
||||||
|
sides[1].advance_uv();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vector2 imgcoord = uv * texture_image_size;
|
if (cpoints[1].y < cpoints[2].y) {
|
||||||
|
sides[shortside].setup_position(cpoints[1], cpoints[2], cpoints[2].y - cpoints[1].y);
|
||||||
|
sides[shortside].setup_color(ccolors[1], ccolors[2], cpoints[2].y - cpoints[1].y);
|
||||||
|
|
||||||
imgcoord.x = CLAMP(imgcoord.x, 0, texture_image_size.x - 1);
|
if (use_uvs) {
|
||||||
imgcoord.y = CLAMP(imgcoord.y, 0, texture_image_size.y - 1);
|
sides[shortside].setup_uv(cuvs[1], cuvs[2], cpoints[2].y - cpoints[1].y);
|
||||||
|
}
|
||||||
|
|
||||||
Color img_color = texture_image->get_pixelv(imgcoord);
|
int starty = MAX(0, cpoints[1].y);
|
||||||
|
int endy = MIN(cpoints[2].y, _size.y);
|
||||||
|
|
||||||
color *= img_color;
|
for (int y = starty; y < endy; ++y) {
|
||||||
|
Slope s;
|
||||||
|
s.setup_color(sides[0].color_current, sides[1].color_current, sides[1].position_current.x - sides[0].position_current.x);
|
||||||
|
if (use_uvs) {
|
||||||
|
s.setup_uv(sides[0].uv_current, sides[1].uv_current, sides[1].position_current.x - sides[0].position_current.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rendered_image->set_pixelv(Vector2(x, y), color);
|
int startx = MAX(0, sides[0].position_current.x);
|
||||||
|
int endx = MIN(sides[1].position_current.x, _size.x);
|
||||||
|
|
||||||
|
for (int x = startx; x < endx; ++x) {
|
||||||
|
Color color = s.color_current;
|
||||||
|
|
||||||
|
if (use_uvs) {
|
||||||
|
Vector2 uv = s.uv_current;
|
||||||
|
|
||||||
|
uv.x = CLAMP(uv.x, 0, 1);
|
||||||
|
uv.y = CLAMP(uv.y, 0, 1);
|
||||||
|
|
||||||
|
Vector2 imgcoord = uv * texture_image_size;
|
||||||
|
|
||||||
|
imgcoord.x = CLAMP(imgcoord.x, 0, texture_image_size.x - 1);
|
||||||
|
imgcoord.y = CLAMP(imgcoord.y, 0, texture_image_size.y - 1);
|
||||||
|
|
||||||
|
Color img_color = texture_image->get_pixelv(imgcoord);
|
||||||
|
|
||||||
|
color *= img_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rendered_image->set_pixelv(Vector2(x, y), color);
|
||||||
|
|
||||||
|
s.advance_color();
|
||||||
|
|
||||||
|
if (use_uvs) {
|
||||||
|
s.advance_uv();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sides[0].advance();
|
||||||
|
sides[1].advance();
|
||||||
|
|
||||||
|
if (use_uvs) {
|
||||||
|
sides[0].advance_uv();
|
||||||
|
sides[1].advance_uv();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,49 @@ public:
|
|||||||
|
|
||||||
PaintPolygon2D();
|
PaintPolygon2D();
|
||||||
virtual ~PaintPolygon2D();
|
virtual ~PaintPolygon2D();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct Slope {
|
||||||
|
Vector2 position_current;
|
||||||
|
Vector2 position_step;
|
||||||
|
|
||||||
|
Vector2 uv_current;
|
||||||
|
Vector2 uv_step;
|
||||||
|
|
||||||
|
Color color_current;
|
||||||
|
Color color_step;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void setup_position(Vector2 begin, Vector2 end, float num_steps) {
|
||||||
|
float inv_step = 1.0 / num_steps;
|
||||||
|
position_step = (end - begin) * Vector2(inv_step, inv_step);
|
||||||
|
position_current = begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void setup_color(Color begin, Color end, float num_steps) {
|
||||||
|
float inv_step = 1.0 / num_steps;
|
||||||
|
color_step = (end - begin) * Color(inv_step, inv_step, inv_step);
|
||||||
|
color_current = begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void setup_uv(Vector2 begin, Vector2 end, float num_steps) {
|
||||||
|
float inv_step = 1.0 / num_steps;
|
||||||
|
uv_step = (end - begin) * Vector2(inv_step, inv_step);
|
||||||
|
uv_current = begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void advance() {
|
||||||
|
position_current += position_step;
|
||||||
|
color_current += color_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void advance_color() {
|
||||||
|
color_current += color_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void advance_uv() {
|
||||||
|
uv_current += uv_step;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // POLYGON_2D_H
|
#endif // POLYGON_2D_H
|
||||||
|
Loading…
Reference in New Issue
Block a user