You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
507 lines
12 KiB
C++
507 lines
12 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#include "EditorDefs.h"
|
|
|
|
#include "SimpleTriangleRasterizer.h"
|
|
|
|
#include <math.h>
|
|
|
|
#if !defined FLT_MAX
|
|
#define FLT_MAX 3.402823466e+38F
|
|
#endif
|
|
|
|
void CSimpleTriangleRasterizer::lambertHorizlineConservative(float fx1, float fx2, int yy, IRasterizeSink* inpSink)
|
|
{
|
|
int x1 = (int)floorf(fx1 + 0.25f), x2 = (int)floorf(fx2 + .75f);
|
|
|
|
if (x1 < m_iMinX)
|
|
{
|
|
x1 = m_iMinX;
|
|
}
|
|
if (x2 > m_iMaxX + 1)
|
|
{
|
|
x2 = m_iMaxX + 1;
|
|
}
|
|
if (x1 > m_iMaxX + 1)
|
|
{
|
|
x1 = m_iMaxX + 1;
|
|
}
|
|
if (x2 < m_iMinX)
|
|
{
|
|
x2 = m_iMinX;
|
|
}
|
|
|
|
|
|
inpSink->Line(fx1, fx2, x1, x2, yy);
|
|
}
|
|
|
|
void CSimpleTriangleRasterizer::lambertHorizlineSubpixelCorrect(float fx1, float fx2, int yy, IRasterizeSink* inpSink)
|
|
{
|
|
int x1 = (int)floorf(fx1 + 0.5f), x2 = (int)floorf(fx2 + 0.5f);
|
|
// int x1=(int)floorf(fx1*1023.f/1024.f+1.f),x2=(int)floorf(fx2*1023.f/1024.f+1.f);
|
|
|
|
if (x1 < m_iMinX)
|
|
{
|
|
x1 = m_iMinX;
|
|
}
|
|
if (x2 > m_iMaxX)
|
|
{
|
|
x2 = m_iMaxX;
|
|
}
|
|
if (x1 > m_iMaxX)
|
|
{
|
|
x1 = m_iMaxX;
|
|
}
|
|
if (x2 < m_iMinX)
|
|
{
|
|
x2 = m_iMinX;
|
|
}
|
|
|
|
inpSink->Line(fx1, fx2, x1, x2, yy);
|
|
}
|
|
|
|
// optimizable
|
|
void CSimpleTriangleRasterizer::CopyAndSortY(const float infX[3], const float infY[3], float outfX[3], float outfY[3])
|
|
{
|
|
outfX[0] = infX[0];
|
|
outfY[0] = infY[0];
|
|
outfX[1] = infX[1];
|
|
outfY[1] = infY[1];
|
|
outfX[2] = infX[2];
|
|
outfY[2] = infY[2];
|
|
|
|
// Sort the coordinates, so that (x[1], y[1]) becomes the highest coord
|
|
float tmp;
|
|
|
|
if (outfY[0] > outfY[1])
|
|
{
|
|
if (outfY[1] > outfY[2])
|
|
{
|
|
tmp = outfY[0];
|
|
outfY[0] = outfY[1];
|
|
outfY[1] = tmp;
|
|
tmp = outfX[0];
|
|
outfX[0] = outfX[1];
|
|
outfX[1] = tmp;
|
|
tmp = outfY[1];
|
|
outfY[1] = outfY[2];
|
|
outfY[2] = tmp;
|
|
tmp = outfX[1];
|
|
outfX[1] = outfX[2];
|
|
outfX[2] = tmp;
|
|
|
|
if (outfY[0] > outfY[1])
|
|
{
|
|
tmp = outfY[0];
|
|
outfY[0] = outfY[1];
|
|
outfY[1] = tmp;
|
|
tmp = outfX[0];
|
|
outfX[0] = outfX[1];
|
|
outfX[1] = tmp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tmp = outfY[0];
|
|
outfY[0] = outfY[1];
|
|
outfY[1] = tmp;
|
|
tmp = outfX[0];
|
|
outfX[0] = outfX[1];
|
|
outfX[1] = tmp;
|
|
|
|
if (outfY[1] > outfY[2])
|
|
{
|
|
tmp = outfY[1];
|
|
outfY[1] = outfY[2];
|
|
outfY[2] = tmp;
|
|
tmp = outfX[1];
|
|
outfX[1] = outfX[2];
|
|
outfX[2] = tmp;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (outfY[1] > outfY[2])
|
|
{
|
|
tmp = outfY[1];
|
|
outfY[1] = outfY[2];
|
|
outfY[2] = tmp;
|
|
tmp = outfX[1];
|
|
outfX[1] = outfX[2];
|
|
outfX[2] = tmp;
|
|
|
|
if (outfY[0] > outfY[1])
|
|
{
|
|
tmp = outfY[0];
|
|
outfY[0] = outfY[1];
|
|
outfY[1] = tmp;
|
|
tmp = outfX[0];
|
|
outfX[0] = outfX[1];
|
|
outfX[1] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSimpleTriangleRasterizer::CallbackFillRectConservative(float _x[3], float _y[3], IRasterizeSink* inpSink)
|
|
{
|
|
inpSink->Triangle(m_iMinY);
|
|
|
|
float fMinX = (std::min)(_x[0], (std::min)(_x[1], _x[2]));
|
|
float fMaxX = (std::max)(_x[0], (std::max)(_x[1], _x[2]));
|
|
float fMinY = (std::min)(_y[0], (std::min)(_y[1], _y[2]));
|
|
float fMaxY = (std::max)(_y[0], (std::max)(_y[1], _y[2]));
|
|
|
|
int iMinX = (std::max)(m_iMinX, (int)floorf(fMinX));
|
|
int iMaxX = (std::min)(m_iMaxX + 1, (int)ceilf(fMaxX));
|
|
int iMinY = (std::max)(m_iMinY, (int)floorf(fMinY));
|
|
int iMaxY = (std::min)(m_iMaxY + 1, (int)ceilf(fMaxY));
|
|
|
|
for (int y = iMinY; y < iMaxY; y++)
|
|
{
|
|
inpSink->Line(fMinX, fMaxX, iMinX, iMaxX, y);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CSimpleTriangleRasterizer::CallbackFillConservative(float _x[3], float _y[3], IRasterizeSink* inpSink)
|
|
{
|
|
float x[3], y[3];
|
|
|
|
CopyAndSortY(_x, _y, x, y);
|
|
|
|
// Calculate interpolation steps
|
|
float fX1toX2step = 0.0f;
|
|
float fX1toX3step = 0.0f;
|
|
float fX2toX3step = 0.0f;
|
|
if (fabsf(y[1] - y[0]) > FLT_EPSILON)
|
|
{
|
|
fX1toX2step = (x[1] - x[0]) / (float)(y[1] - y[0]);
|
|
}
|
|
if (fabsf(y[2] - y[0]) > FLT_EPSILON)
|
|
{
|
|
fX1toX3step = (x[2] - x[0]) / (float)(y[2] - y[0]);
|
|
}
|
|
if (fabsf(y[2] - y[1]) > FLT_EPSILON)
|
|
{
|
|
fX2toX3step = (x[2] - x[1]) / (float)(y[2] - y[1]);
|
|
}
|
|
|
|
float fX1toX2 = x[0], fX1toX3 = x[0], fX2toX3 = x[1];
|
|
bool bFirstLine = true;
|
|
bool bTriangleCallDone = false;
|
|
|
|
// Go through the scanlines of the triangle
|
|
int yy = (int)floorf(y[0]); // was floor
|
|
|
|
for (; yy <= (int)floorf(y[2]); yy++)
|
|
// for(yy=m_iMinY; yy<=m_iMaxY; yy++) // juhu
|
|
{
|
|
float fSubPixelYStart = 0.0f, fSubPixelYEnd = 1.0f;
|
|
float start, end;
|
|
|
|
// first line
|
|
if (bFirstLine)
|
|
{
|
|
fSubPixelYStart = y[0] - floorf(y[0]);
|
|
start = x[0];
|
|
end = x[0];
|
|
bFirstLine = false;
|
|
}
|
|
else
|
|
{
|
|
// top part without middle corner line
|
|
if (yy <= (int)floorf(y[1]))
|
|
{
|
|
start = (std::min)(fX1toX2, fX1toX3);
|
|
end = (std::max)(fX1toX2, fX1toX3);
|
|
}
|
|
else
|
|
{
|
|
start = (std::min)(fX2toX3, fX1toX3);
|
|
end = (std::max)(fX2toX3, fX1toX3);
|
|
}
|
|
}
|
|
|
|
// middle corner line
|
|
if (yy == (int)floorf(y[1]))
|
|
{
|
|
fSubPixelYEnd = y[1] - floorf(y[1]);
|
|
|
|
fX1toX3 += fX1toX3step * (fSubPixelYEnd - fSubPixelYStart);
|
|
start = (std::min)(start, fX1toX3);
|
|
end = (std::max)(end, fX1toX3);
|
|
start = (std::min)(start, x[1]);
|
|
end = (std::max)(end, x[1]);
|
|
|
|
fSubPixelYStart = fSubPixelYEnd;
|
|
fSubPixelYEnd = 1.0f;
|
|
}
|
|
|
|
// last line
|
|
if (yy == (int)floorf(y[2]))
|
|
{
|
|
start = (std::min)(start, x[2]);
|
|
end = (std::max)(end, x[2]);
|
|
}
|
|
else
|
|
{
|
|
// top part without middle corner line
|
|
if (yy < (int)floorf(y[1]))
|
|
{
|
|
fX1toX2 += fX1toX2step * (fSubPixelYEnd - fSubPixelYStart);
|
|
start = (std::min)(start, fX1toX2);
|
|
end = (std::max)(end, fX1toX2);
|
|
}
|
|
else
|
|
{
|
|
fX2toX3 += fX2toX3step * (fSubPixelYEnd - fSubPixelYStart);
|
|
start = (std::min)(start, fX2toX3);
|
|
end = (std::max)(end, fX2toX3);
|
|
}
|
|
|
|
fX1toX3 += fX1toX3step * (fSubPixelYEnd - fSubPixelYStart);
|
|
start = (std::min)(start, fX1toX3);
|
|
end = (std::max)(end, fX1toX3);
|
|
}
|
|
|
|
if (yy >= m_iMinY && yy <= m_iMaxY)
|
|
{
|
|
if (!bTriangleCallDone)
|
|
{
|
|
inpSink->Triangle(yy);
|
|
bTriangleCallDone = true;
|
|
}
|
|
|
|
lambertHorizlineConservative(start, end, yy, inpSink);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CSimpleTriangleRasterizer::CallbackFillSubpixelCorrect(float _x[3], float _y[3], IRasterizeSink* inpSink)
|
|
{
|
|
float x[3], y[3];
|
|
|
|
CopyAndSortY(_x, _y, x, y);
|
|
|
|
if (fabs(y[0] - floorf(y[0])) < FLT_EPSILON)
|
|
{
|
|
y[0] -= FLT_EPSILON;
|
|
}
|
|
|
|
// Calculate interpolation steps
|
|
float fX1toX2step = 0.0f;
|
|
float fX1toX3step = 0.0f;
|
|
float fX2toX3step = 0.0f;
|
|
if (fabsf(y[1] - y[0]) > FLT_EPSILON)
|
|
{
|
|
fX1toX2step = (x[1] - x[0]) / (y[1] - y[0]);
|
|
}
|
|
if (fabsf(y[2] - y[0]) > FLT_EPSILON)
|
|
{
|
|
fX1toX3step = (x[2] - x[0]) / (y[2] - y[0]);
|
|
}
|
|
if (fabsf(y[2] - y[1]) > FLT_EPSILON)
|
|
{
|
|
fX2toX3step = (x[2] - x[1]) / (y[2] - y[1]);
|
|
}
|
|
|
|
float fX1toX2 = x[0], fX1toX3 = x[0], fX2toX3 = x[1];
|
|
bool bFirstLine = true;
|
|
bool bTriangleCallDone = false;
|
|
|
|
y[0] -= 0.5f;
|
|
y[1] -= 0.5f;
|
|
y[2] -= 0.5f;
|
|
// y[0]=y[0]*1023.f/1024.f+1.f;
|
|
// y[1]=y[1]*1023.f/1024.f+1.f;
|
|
// y[2]=y[2]*1023.f/1024.f+1.f;
|
|
|
|
for (int yy = (int)floorf(y[0]); yy <= (int)floorf(y[2]); yy++)
|
|
{
|
|
float fSubPixelYStart = 0.0f, fSubPixelYEnd = 1.0f;
|
|
float start, end;
|
|
|
|
// first line
|
|
if (bFirstLine)
|
|
{
|
|
fSubPixelYStart = y[0] - floorf(y[0]);
|
|
start = x[0];
|
|
end = x[0];
|
|
bFirstLine = false;
|
|
}
|
|
else
|
|
{
|
|
// top part without middle corner line
|
|
if (yy <= (int)floorf(y[1]))
|
|
{
|
|
start = (std::min)(fX1toX2, fX1toX3);
|
|
end = (std::max)(fX1toX2, fX1toX3);
|
|
}
|
|
else
|
|
{
|
|
start = (std::min)(fX2toX3, fX1toX3);
|
|
end = (std::max)(fX2toX3, fX1toX3);
|
|
}
|
|
}
|
|
|
|
// middle corner line
|
|
if (yy == (int)floorf(y[1]))
|
|
{
|
|
fSubPixelYEnd = y[1] - floorf(y[1]);
|
|
|
|
fX1toX3 += fX1toX3step * (fSubPixelYEnd - fSubPixelYStart);
|
|
|
|
fSubPixelYStart = fSubPixelYEnd;
|
|
fSubPixelYEnd = 1.0f;
|
|
}
|
|
|
|
// last line
|
|
if (yy != (int)floorf(y[2]))
|
|
{
|
|
// top part without middle corner line
|
|
if (yy < (int)floorf(y[1]))
|
|
{
|
|
fX1toX2 += fX1toX2step * (fSubPixelYEnd - fSubPixelYStart);
|
|
}
|
|
else
|
|
{
|
|
fX2toX3 += fX2toX3step * (fSubPixelYEnd - fSubPixelYStart);
|
|
}
|
|
|
|
fX1toX3 += fX1toX3step * (fSubPixelYEnd - fSubPixelYStart);
|
|
}
|
|
|
|
if (start != end)
|
|
{
|
|
if (yy >= m_iMinY && yy <= m_iMaxY)
|
|
{
|
|
if (!bTriangleCallDone)
|
|
{
|
|
inpSink->Triangle(yy);
|
|
bTriangleCallDone = true;
|
|
}
|
|
|
|
lambertHorizlineSubpixelCorrect(start, end, yy, inpSink);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// shrink triangle by n pixel, optimizable
|
|
void CSimpleTriangleRasterizer::ShrinkTriangle(float inoutfX[3], float inoutfY[3], float infAmount)
|
|
{
|
|
float fX[3] = { inoutfX[0], inoutfX[1], inoutfX[2] };
|
|
float fY[3] = { inoutfY[0], inoutfY[1], inoutfY[2] };
|
|
|
|
/*
|
|
// move edge to opposing vertex
|
|
float dx,dy,fLength;
|
|
|
|
for(int a=0;a<3;a++)
|
|
{
|
|
int b=a+1;if(b>=3)b=0;
|
|
int c=b+1;if(c>=3)c=0;
|
|
|
|
dx=fX[a]-(fX[b]+fX[c])*0.5f;
|
|
dy=fY[a]-(fY[b]+fY[c])*0.5f;
|
|
fLength=(float)sqrt(dx*dx+dy*dy);
|
|
if(fLength>1.0f)
|
|
{
|
|
dx/=fLength;dy/=fLength;
|
|
inoutfX[b]+=dx;inoutfY[b]+=dy;
|
|
inoutfX[c]+=dx;inoutfY[c]+=dy;
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
// move vertex to opposing edge
|
|
float dx,dy,fLength;
|
|
|
|
for(int a=0;a<3;a++)
|
|
{
|
|
int b=a+1;if(b>=3)b=0;
|
|
int c=b+1;if(c>=3)c=0;
|
|
|
|
dx=fX[a]-(fX[b]+fX[c])*0.5f;
|
|
dy=fY[a]-(fY[b]+fY[c])*0.5f;
|
|
fLength=(float)sqrt(dx*dx+dy*dy);
|
|
if(fLength>1.0f)
|
|
{
|
|
dx/=fLength;dy/=fLength;
|
|
inoutfX[a]-=dx;inoutfY[a]-=dy;
|
|
}
|
|
}
|
|
*/
|
|
|
|
// move vertex to get edges shifted perpendicular for 1 unit
|
|
for (int a = 0; a < 3; a++)
|
|
{
|
|
float dx1, dy1, dx2, dy2, fLength;
|
|
|
|
int b = a + 1;
|
|
if (b >= 3)
|
|
{
|
|
b = 0;
|
|
}
|
|
int c = b + 1;
|
|
if (c >= 3)
|
|
{
|
|
c = 0;
|
|
}
|
|
|
|
dx1 = fX[b] - fX[a];
|
|
dy1 = fY[b] - fY[a];
|
|
fLength = (float)sqrt(dx1 * dx1 + dy1 * dy1);
|
|
if (infAmount > 0)
|
|
{
|
|
if (fLength < infAmount)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if (fLength == 0.0f)
|
|
{
|
|
continue;
|
|
}
|
|
dx1 /= fLength;
|
|
dy1 /= fLength;
|
|
|
|
dx2 = fX[c] - fX[a];
|
|
dy2 = fY[c] - fY[a];
|
|
fLength = (float)sqrt(dx2 * dx2 + dy2 * dy2);
|
|
if (infAmount > 0)
|
|
{
|
|
if (fLength < infAmount)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if (fLength == 0.0f)
|
|
{
|
|
continue;
|
|
}
|
|
dx2 /= fLength;
|
|
dy2 /= fLength;
|
|
|
|
inoutfX[a] += (dx1 + dx2) * infAmount;
|
|
inoutfY[a] += (dy1 + dy2) * infAmount;
|
|
}
|
|
}
|