A better triangle fill algorithm
This commit is contained in:
parent
c93eab9963
commit
7c4c6d5bcb
@ -46,6 +46,8 @@ def update():
|
||||
|
||||
text(scenes[current_scene].title, 2, 15, 63)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from scene import Scene
|
||||
from triangles import draw_line
|
||||
|
||||
from triangles import lineTri
|
||||
import math
|
||||
white = 63
|
||||
fire1 = 6
|
||||
fire2 = 5
|
||||
@ -132,5 +133,24 @@ class Particles(Scene):
|
||||
text("Num Particles: " + str(len(self.fireParts) + len(self.waterParts)), 2, 15, 30)
|
||||
text("FPS: " + str(fps()), 3, 29, 59)
|
||||
text("FPS: " + str(fps()), 2, 28, 29)
|
||||
# triangle(10, 10, 50, 10, mouseX, mouseY, 5)
|
||||
# lineTri(10, 10, 50, 10, mouseX, mouseY, 9)
|
||||
pixel(mouseX, mouseY, 9)
|
||||
cx = width/2
|
||||
cy = height/2
|
||||
ang = math.atan2(mouseY - cy, mouseX - cx)
|
||||
dist = math.sqrt(math.pow(mouseX - cx, 2) + math.pow(mouseY - cy, 2))
|
||||
|
||||
x2 = cx + cos(ang + (math.pi * 2 / 3)) * dist
|
||||
y2 = cy + sin(ang + (math.pi * 2 / 3)) * dist
|
||||
|
||||
x3 = cx + cos(ang + (math.pi * 2 / 3 * 2)) * dist
|
||||
y3 = cy + sin(ang + (math.pi * 2 / 3 * 2)) * dist
|
||||
|
||||
# triangle(mouseX, mouseY, x2, y2, x3, y3, 9)
|
||||
|
||||
# lineTri(mouseX, mouseY, x2, y2, x3, y3, 8)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -363,97 +363,148 @@ int Graphics::GetPixel(int x, int y) {
|
||||
return m_virtualScreenColorBuffer[y * m_screenWidth + x];
|
||||
}
|
||||
|
||||
void Graphics::fillBottomFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex)
|
||||
// https://github.com/OneLoneCoder/olcPixelGameEngine/blob/master/olcPixelGameEngine.h#L2456
|
||||
void Graphics::Triangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, int paletteIndex)
|
||||
{
|
||||
float invslope1 = (x2 - x1) / (y2 - y1);
|
||||
float invslope2 = (x3 - x1) / (y3 - y1);
|
||||
auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Pixel(i, ny, paletteIndex); };
|
||||
|
||||
float curx1 = x1;
|
||||
float curx2 = x1;
|
||||
int t1x, t2x, y, minx, maxx, t1xp, t2xp;
|
||||
bool changed1 = false;
|
||||
bool changed2 = false;
|
||||
int signx1, signx2, dx1, dy1, dx2, dy2;
|
||||
int e1, e2;
|
||||
// Sort vertices
|
||||
if (y1 > y2) { std::swap(y1, y2); std::swap(x1, x2); }
|
||||
if (y1 > y3) { std::swap(y1, y3); std::swap(x1, x3); }
|
||||
if (y2 > y3) { std::swap(y2, y3); std::swap(x2, x3); }
|
||||
|
||||
for (int scanlineY = y1; scanlineY <= y2; scanlineY++)
|
||||
{
|
||||
h_line((int)curx1, scanlineY, (int)curx2, paletteIndex);
|
||||
curx1 += invslope1;
|
||||
curx2 += invslope2;
|
||||
t1x = t2x = x1; y = y1; // Starting points
|
||||
dx1 = (int)(x2 - x1);
|
||||
if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
|
||||
else signx1 = 1;
|
||||
dy1 = (int)(y2 - y1);
|
||||
|
||||
dx2 = (int)(x3 - x1);
|
||||
if (dx2 < 0) { dx2 = -dx2; signx2 = -1; }
|
||||
else signx2 = 1;
|
||||
dy2 = (int)(y3 - y1);
|
||||
|
||||
if (dy1 > dx1) { std::swap(dx1, dy1); changed1 = true; }
|
||||
if (dy2 > dx2) { std::swap(dy2, dx2); changed2 = true; }
|
||||
|
||||
e2 = (int)(dx2 >> 1);
|
||||
// Flat top, just process the second half
|
||||
if (y1 == y2) goto next;
|
||||
e1 = (int)(dx1 >> 1);
|
||||
|
||||
for (int i = 0; i < dx1;) {
|
||||
t1xp = 0; t2xp = 0;
|
||||
if (t1x < t2x) { minx = t1x; maxx = t2x; }
|
||||
else { minx = t2x; maxx = t1x; }
|
||||
// process first line until y value is about to change
|
||||
while (i < dx1) {
|
||||
i++;
|
||||
e1 += dy1;
|
||||
while (e1 >= dx1) {
|
||||
e1 -= dx1;
|
||||
if (changed1) t1xp = signx1;//t1x += signx1;
|
||||
else goto next1;
|
||||
}
|
||||
if (changed1) break;
|
||||
else t1x += signx1;
|
||||
}
|
||||
// Move line
|
||||
next1:
|
||||
// process second line until y value is about to change
|
||||
while (1) {
|
||||
e2 += dy2;
|
||||
while (e2 >= dx2) {
|
||||
e2 -= dx2;
|
||||
if (changed2) t2xp = signx2;//t2x += signx2;
|
||||
else goto next2;
|
||||
}
|
||||
if (changed2) break;
|
||||
else t2x += signx2;
|
||||
}
|
||||
next2:
|
||||
if (minx > t1x) minx = t1x;
|
||||
if (minx > t2x) minx = t2x;
|
||||
if (maxx < t1x) maxx = t1x;
|
||||
if (maxx < t2x) maxx = t2x;
|
||||
drawline(minx, maxx, y); // Draw line from min to max points found on the y
|
||||
// Now increase y
|
||||
if (!changed1) t1x += signx1;
|
||||
t1x += t1xp;
|
||||
if (!changed2) t2x += signx2;
|
||||
t2x += t2xp;
|
||||
y += 1;
|
||||
if (y == y2) break;
|
||||
}
|
||||
next:
|
||||
// Second half
|
||||
dx1 = (int)(x3 - x2); if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
|
||||
else signx1 = 1;
|
||||
dy1 = (int)(y3 - y2);
|
||||
t1x = x2;
|
||||
|
||||
if (dy1 > dx1) { // swap values
|
||||
std::swap(dy1, dx1);
|
||||
changed1 = true;
|
||||
}
|
||||
else changed1 = false;
|
||||
|
||||
e1 = (int)(dx1 >> 1);
|
||||
|
||||
for (int i = 0; i <= dx1; i++) {
|
||||
t1xp = 0; t2xp = 0;
|
||||
if (t1x < t2x) { minx = t1x; maxx = t2x; }
|
||||
else { minx = t2x; maxx = t1x; }
|
||||
// process first line until y value is about to change
|
||||
while (i < dx1) {
|
||||
e1 += dy1;
|
||||
while (e1 >= dx1) {
|
||||
e1 -= dx1;
|
||||
if (changed1) { t1xp = signx1; break; }//t1x += signx1;
|
||||
else goto next3;
|
||||
}
|
||||
if (changed1) break;
|
||||
else t1x += signx1;
|
||||
if (i < dx1) i++;
|
||||
}
|
||||
next3:
|
||||
// process second line until y value is about to change
|
||||
while (t2x != x3) {
|
||||
e2 += dy2;
|
||||
while (e2 >= dx2) {
|
||||
e2 -= dx2;
|
||||
if (changed2) t2xp = signx2;
|
||||
else goto next4;
|
||||
}
|
||||
if (changed2) break;
|
||||
else t2x += signx2;
|
||||
}
|
||||
next4:
|
||||
|
||||
if (minx > t1x) minx = t1x;
|
||||
if (minx > t2x) minx = t2x;
|
||||
if (maxx < t1x) maxx = t1x;
|
||||
if (maxx < t2x) maxx = t2x;
|
||||
drawline(minx, maxx, y);
|
||||
if (!changed1) t1x += signx1;
|
||||
t1x += t1xp;
|
||||
if (!changed2) t2x += signx2;
|
||||
t2x += t2xp;
|
||||
y += 1;
|
||||
if (y > y3) return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Graphics::fillTopFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex)
|
||||
{
|
||||
float invslope1 = (x3 - x1) / (y3 - y1);
|
||||
float invslope2 = (x3 - x2) / (y3 - y2);
|
||||
|
||||
float curx1 = x3;
|
||||
float curx2 = x3;
|
||||
|
||||
for (int scanlineY = y3; scanlineY > y1; scanlineY--)
|
||||
{
|
||||
h_line((int)curx1, scanlineY, (int)curx2, paletteIndex);
|
||||
curx1 -= invslope1;
|
||||
curx2 -= invslope2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Graphics::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, int paletteIndex)
|
||||
{
|
||||
int aX = x1;
|
||||
int aY = y1;
|
||||
int bX = x2;
|
||||
int bY = y2;
|
||||
int cX = x3;
|
||||
int cY = y3;
|
||||
|
||||
if(bY < aY){
|
||||
int t = bY;
|
||||
bY = aY;
|
||||
aY = t;
|
||||
t = bX;
|
||||
bX = aX;
|
||||
aX = t;
|
||||
}
|
||||
|
||||
if(cY < aY){
|
||||
int t = cY;
|
||||
cY = aY;
|
||||
aY = t;
|
||||
t = cX;
|
||||
cX = aX;
|
||||
aX = t;
|
||||
}
|
||||
|
||||
if(cY < bY){
|
||||
int t = cY;
|
||||
cY = bY;
|
||||
bY = t;
|
||||
t = cX;
|
||||
cX = bX;
|
||||
bX = t;
|
||||
}
|
||||
|
||||
//std::cout << aX << " " << aY << " " << bX << " " << bY << " " << cX << " " << cY << "\n";
|
||||
|
||||
/* here we know that v1.y <= v2.y <= v3.y */
|
||||
/* check for trivial case of bottom-flat triangle */
|
||||
if (bY == cY)
|
||||
{
|
||||
fillBottomFlatTriangle(aX, aY, bX, bY, cX, cY, paletteIndex);
|
||||
}
|
||||
/* check for trivial case of top-flat triangle */
|
||||
else if (aY == bY)
|
||||
{
|
||||
fillTopFlatTriangle(aX, aY, bX, bY, cX, cY, paletteIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* general case - split the triangle in a topflat and bottom-flat one */
|
||||
int dX = aX + ((float)(bY - aY) / (float)(cY - aY)) * (cX - aX);
|
||||
int dY = bY;
|
||||
|
||||
fillBottomFlatTriangle(aX, aY, bX, bY, dX, dY, paletteIndex);
|
||||
fillTopFlatTriangle(bX, bY, dX, dY, cX, cY, paletteIndex);
|
||||
}
|
||||
void Graphics::swap(float &a, float &b) {
|
||||
float temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -26,6 +26,8 @@ private:
|
||||
std::vector<uint8_t> m_virtualScreenColorBuffer;
|
||||
Image m_virtualScreenImageBuffer;
|
||||
|
||||
static void swap(float &a, float &b);
|
||||
|
||||
|
||||
private:
|
||||
void renderVirtualScreen();
|
||||
@ -72,7 +74,7 @@ public:
|
||||
void Rect(int x, int y, int width, int height, int paletteIndex);
|
||||
void RectBorder(int x, int y, int width, int height, int paletteIndex);
|
||||
void Text(std::string s, int x, int y, int paletteIndex);
|
||||
void Triangle(int x1, int y1, int x2, int y2, int x3, int y3, int paletteIndex);
|
||||
void Triangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, int paletteIndex);
|
||||
|
||||
int GetPixel(int x, int y);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user