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.
o3de/Code/Editor/LightmapCompiler/SimpleTriangleRasterizer.cpp

506 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;
}
}