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)
|
text(scenes[current_scene].title, 2, 15, 63)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from scene import Scene
|
from scene import Scene
|
||||||
from triangles import draw_line
|
from triangles import draw_line
|
||||||
|
from triangles import lineTri
|
||||||
|
import math
|
||||||
white = 63
|
white = 63
|
||||||
fire1 = 6
|
fire1 = 6
|
||||||
fire2 = 5
|
fire2 = 5
|
||||||
@ -132,5 +133,24 @@ class Particles(Scene):
|
|||||||
text("Num Particles: " + str(len(self.fireParts) + len(self.waterParts)), 2, 15, 30)
|
text("Num Particles: " + str(len(self.fireParts) + len(self.waterParts)), 2, 15, 30)
|
||||||
text("FPS: " + str(fps()), 3, 29, 59)
|
text("FPS: " + str(fps()), 3, 29, 59)
|
||||||
text("FPS: " + str(fps()), 2, 28, 29)
|
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];
|
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);
|
auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Pixel(i, ny, paletteIndex); };
|
||||||
float invslope2 = (x3 - x1) / (y3 - y1);
|
|
||||||
|
|
||||||
float curx1 = x1;
|
int t1x, t2x, y, minx, maxx, t1xp, t2xp;
|
||||||
float curx2 = x1;
|
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++)
|
t1x = t2x = x1; y = y1; // Starting points
|
||||||
{
|
dx1 = (int)(x2 - x1);
|
||||||
h_line((int)curx1, scanlineY, (int)curx2, paletteIndex);
|
if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
|
||||||
curx1 += invslope1;
|
else signx1 = 1;
|
||||||
curx2 += invslope2;
|
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)
|
void Graphics::swap(float &a, float &b) {
|
||||||
{
|
float temp = a;
|
||||||
float invslope1 = (x3 - x1) / (y3 - y1);
|
a = b;
|
||||||
float invslope2 = (x3 - x2) / (y3 - y2);
|
b = temp;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,8 @@ private:
|
|||||||
std::vector<uint8_t> m_virtualScreenColorBuffer;
|
std::vector<uint8_t> m_virtualScreenColorBuffer;
|
||||||
Image m_virtualScreenImageBuffer;
|
Image m_virtualScreenImageBuffer;
|
||||||
|
|
||||||
|
static void swap(float &a, float &b);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void renderVirtualScreen();
|
void renderVirtualScreen();
|
||||||
@ -72,7 +74,7 @@ public:
|
|||||||
void Rect(int x, int y, int width, int height, int paletteIndex);
|
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 RectBorder(int x, int y, int width, int height, int paletteIndex);
|
||||||
void Text(std::string s, int x, int y, 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);
|
int GetPixel(int x, int y);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user