Commit 7cf9e12a authored by David Llewellyn-Jones's avatar David Llewellyn-Jones

Added triangle, quadrilateral and cuboid rasterisation to support curve output to SVX.

parent 9db3fe2b
......@@ -28,6 +28,7 @@
#define FUNCTION0 "1"
#define INFLECTION_ZEROCHECK (0.00001f)
#define RADIUSSTEP_MIN (0.0001)
#define EDGE_CHECKS (12)
///////////////////////////////////////////////////////////////////
// Structures and enumerations
......@@ -92,6 +93,10 @@ void CurvePopulateVerticesNoColour (FuncPersist * psFuncData);
void CurveResetVertices (FuncPersist * psFuncData);
void CurveRecalculateCentre (CurvePersist * psCurveData);
void CurveVertex (Vector3 * pvVertex, Vector3 * pvNormal, double fStep, double fTheta, bool boScreenCoords, double fMultiplier, double fScale, FuncPersist const * psFuncData);
void CurveRasteriseTriangle (unsigned char * pcData, int nResolution, int nChannels, Vector3 const * pvV1, Vector3 const * pvV2, Vector3 const * pvV3);
void CurveFilledCuboidSlice (unsigned char * pcData, int nResolution, int nChannels, Vector3 * avCorners, float fZSlice);
void CurveRasteriseTriangle (unsigned char * pcData, int nResolution, int nChannels, Vector3 const * pvV1, Vector3 const * pvV2, Vector3 const * pvV3);
void CurveReorderQuadVertices (Vector3 * avBounds, int nVertices);
///////////////////////////////////////////////////////////////////
// Function definitions
......@@ -1793,6 +1798,25 @@ void CurveOutputVoxelSlice (unsigned char * pcData, int nResolution, int nChanne
fYStep = psFuncData->fYWidth / ((double)nResolution);
fZStep = psFuncData->fZWidth / ((double)nResolution);
// // Test rendering of a triangle
// Vector3 vVector[3];
// SetVector3 (vVector[0], 0.0f, 0.0f, 0.0f);
// SetVector3 (vVector[1], 128.0f, 0.0f, 0.0f);
// SetVector3 (vVector[2], 64.0f, 128.0f, 0.0f);
// CurveRasteriseTriangle (pcData, nResolution, nChannels, & vVector[0], & vVector[1], & vVector[2]);
// // Test rendering of a cuboid
// Vector3 vVector[8];
// SetVector3 (vVector[0], 40.0f, 40.0f, 40.0f);
// SetVector3 (vVector[1], 80.0f, 40.0f, 40.0f);
// SetVector3 (vVector[2], 80.0f, 80.0f, 40.0f);
// SetVector3 (vVector[3], 40.0f, 80.0f, 40.0f);
// SetVector3 (vVector[4], 40.0f, 40.0f, 80.0f);
// SetVector3 (vVector[5], 80.0f, 40.0f, 80.0f);
// SetVector3 (vVector[6], 80.0f, 80.0f, 90.0f);
// SetVector3 (vVector[7], 40.0f, 80.0f, 90.0f);
// CurveFilledCuboidSlice (pcData, nResolution, nChannels, vVector, (float)nSlice);
nPieces = floor (((16.0 * nResolution / 256.0) / psFuncData->fAccuracy)) + 1;
nSegments = floor (((16.0 * nResolution / 256.0) / psCurveData->fAccuracyRadius)) + 1;
......@@ -1889,3 +1913,185 @@ void CurveOutputVoxelSlice (unsigned char * pcData, int nResolution, int nChanne
}
}
// Inetersecs a plane with a cuboid to create a quadrilateral
// Use pixel coordinates for this call
// avCorners should be of size 8
void CurveFilledCuboidSlice (unsigned char * pcData, int nResolution, int nChannels, Vector3 * avCorners, float fZSlice) {
Vector3 avBounds[EDGE_CHECKS];
static const int nStart[EDGE_CHECKS] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3};
static const int nEnd[EDGE_CHECKS] = {1, 2, 3, 0, 5, 6, 7, 4, 4, 5, 6, 7};
int nCheck;
int nFound;
Vector3 vDirection;
float fCross;
// Cycle through the edges to establish whetheer and where they cross the plane
nFound = 0;
for (nCheck = 0; nCheck < EDGE_CHECKS; nCheck++) {
// Calculate whether the edge crosses the x-y plane at height fZSlide
if (((avCorners[nStart[nCheck]].fZ < fZSlice) && (avCorners[nEnd[nCheck]].fZ >= fZSlice)) || ((avCorners[nStart[nCheck]].fZ >= fZSlice) && (avCorners[nEnd[nCheck]].fZ < fZSlice))) {
// Calculate where they cross
vDirection = SubtractVectors (& avCorners[nEnd[nCheck]], & avCorners[nStart[nCheck]]);
fCross = (fZSlice - avCorners[nStart[nCheck]].fZ) / (avCorners[nEnd[nCheck]].fZ - avCorners[nStart[nCheck]].fZ);
ScaleVectorDirect (& vDirection, fCross);
// Store the result
avBounds[nFound] = AddVectors (& vDirection, & avCorners[nStart[nCheck]]);
nFound++;
}
}
// We may need to reorder the vertices to ensure we render a simple rather than a complex (intersecting) quadrilateral
CurveReorderQuadVertices (avBounds, nFound);
// Check whether we ended up with a quadrilateral or a triangle
if (nFound > 4) {
// Something else
printf ("Too many crossing points found (%d)\n", nFound);
}
if (nFound == 4) {
// Render the quadrialteral as two triangles
CurveRasteriseTriangle (pcData, nResolution, nChannels, & avBounds[0], & avBounds[1], & avBounds[2]);
CurveRasteriseTriangle (pcData, nResolution, nChannels, & avBounds[0], & avBounds[2], & avBounds[3]);
}
if (nFound == 3) {
// Render the trinble
printf ("Triangle\n");
CurveRasteriseTriangle (pcData, nResolution, nChannels, & avBounds[0], & avBounds[1], & avBounds[2]);
}
}
// Orders the vertices to create a simple rather than a complex quadrilateral
void CurveReorderQuadVertices (Vector3 * avBounds, int nVertices) {
int nVertex;
Matrix2 mCoefficients;
Vector2 vConstants;
bool boInverted;
Vector2 vResult;
Vector3 vSwitch;
// First check for doubles
if (nVertices > 4) {
printf ("There are %d vertices:\n", nVertices);
for (nVertex = 0; nVertex < nVertices; nVertex++) {
PrintVector (& avBounds[nVertex]);
}
printf ("\n");
}
if (nVertices == 4) {
// Calculate the directions between corners
mCoefficients.fA1 = avBounds[3].fX - avBounds[0].fX;
mCoefficients.fA2 = avBounds[3].fY - avBounds[0].fY;
mCoefficients.fB1 = avBounds[1].fX - avBounds[2].fX;
mCoefficients.fB2 = avBounds[1].fY - avBounds[2].fY;
// Calculate the difference in starting points
vConstants.fX = avBounds[1].fX - avBounds[0].fX;
vConstants.fY = avBounds[1].fY - avBounds[0].fY;
// Solve the simultaneous equations if they can be
boInverted = MatrixInvert2x2 (& mCoefficients, & mCoefficients);
if (boInverted) {
MultMatrix2x2Vector2 (& vResult, & mCoefficients, & vConstants);
// Check whether the lines cross
if ((vResult.fX > 0.0) && (vResult.fX < 1.0) && (vResult.fY > 0.0) && (vResult.fY < 1.0)) {
// The lines cross, so we need to reorder the vertices
printf ("Reordering vertices\n");
vSwitch = avBounds[0];
avBounds[0] = avBounds[1];
avBounds[1] = vSwitch;
}
}
}
}
// Use pixel coordinates for this call
void CurveRasteriseTriangle (unsigned char * pcData, int nResolution, int nChannels, Vector3 const * pvV1, Vector3 const * pvV2, Vector3 const * pvV3) {
Vector3 vDir1;
Vector3 vDir2;
Vector3 vDir3;
float fXSteps;
float fYSteps;
float fXEnd;
float fXStep;
float fYStep;
static const float fDX = 1.0f;
static const float fDY = 1.0f;
Vector3 vXGrad;
Vector3 vYGrad;
Vector3 vXPoint;
Vector3 vYPoint;
Vector3 vPoint;
int nChannel;
int nX;
int nY;
float fXEndFull;
float fXEndStep;
// Calculate direcdtions between vertices
vDir1 = SubtractVectors (pvV2, pvV1);
vDir2 = SubtractVectors (pvV3, pvV1);
vDir3 = SubtractVectors (pvV3, pvV2);
// Calculate gradient steps
fXSteps = abs (pvV2->fX - pvV1->fX) / fDX;
fYSteps = abs (pvV3->fY - pvV1->fY) / fDY;
if ((fXSteps == 0.0f) || (fYSteps == 0.0f)) {
// One or other of the gradients is infinite, so we need to switch the x and y axes
fXSteps = abs (pvV2->fY - pvV1->fY) / fDY;
fYSteps = abs (pvV3->fX - pvV1->fX) / fDX;
if (fXSteps == 0.0f) {
// There's still a problem; probably vertices are identical
fXSteps = 1.0f;
printf ("Infinite x gradient\n");
}
if (fYSteps == 0.0f) {
// There's still a problem; probably vertices are identical
fYSteps = 1.0f;
printf ("Infinite y gradient\n");
}
// Calculate the gradients
vXGrad = ScaleVector (& vDir1, (1.0f / fXSteps));
vYGrad = ScaleVector (& vDir2, (1.0f / fYSteps));
// Calculate some utility variables used to figure out how long we need to draw each line
fXEndFull = (pvV2->fY - pvV1->fY);
fXEndStep = (vYGrad.fY - (vDir3.fY / fYSteps));
}
else {
// Calculate the gradients
vXGrad = ScaleVector (& vDir1, (1.0f / fXSteps));
vYGrad = ScaleVector (& vDir2, (1.0f / fYSteps));
// Calculate some utility variables used to figure out how long we need to draw each line
fXEndFull = (pvV2->fX - pvV1->fX);
fXEndStep = (vYGrad.fX - (vDir3.fX / fYSteps));
}
// Draw the triangle
for (fYStep = 0.0f; fYStep < fYSteps; fYStep += fDY) {
// The length of the line we need to draw
fXEnd = abs (fXEndFull - (fYStep * fXEndStep));
// Draw a line of the triangle
for (fXStep = 0.0f; fXStep < fXEnd; fXStep += fDX) {
// Calculate the position of the point
// TODO: Calculate this incrementally
vYPoint = ScaleVector (& vYGrad, fYStep);
vXPoint = ScaleVector (& vXGrad, fXStep);
vPoint = AddVectors (& vXPoint, & vYPoint);
vPoint = AddVectors (& vPoint, pvV1);
nX = vPoint.fX;
nY = vPoint.fY;
// Plot the point to the bitmap
for (nChannel = 0; nChannel < nChannels; nChannel++) {
pcData[(((nX + ((nResolution - nY - 1) * nResolution)) * nChannels) + nChannel)] = 255;
}
}
}
}
......@@ -23,6 +23,8 @@
///////////////////////////////////////////////////////////////////
// Defines
#define TIMESTRING_LEN (32)
///////////////////////////////////////////////////////////////////
// Structures and enumerations
......@@ -212,6 +214,8 @@ bool ExportManifestSVX (Recall * hFile, int nResolution, VisPersist * psVisData)
float fMinWidth;
struct tm * pTm;
time_t ulTime;
char szTime[TIMESTRING_LEN];
int nLength;
GetVisRange (afRange, psVisData);
fMinWidth = MIN (afRange[3], MIN (afRange[4], afRange[5]));
......@@ -236,8 +240,11 @@ bool ExportManifestSVX (Recall * hFile, int nResolution, VisPersist * psVisData)
ulTime = (unsigned long)GetCurrentTime (psVisData);
pTm = gmtime (& ulTime);
nLength = strftime (szTime, TIMESTRING_LEN, "%c", pTm);
if (nLength > 0) {
recprintf (hFile, "\t\t<entry key=\"creationDate\" value=\"%s\" />\n", szTime);
}
recprintf (hFile, "\t\t<entry key=\"creationDate\" value=\"%s\" />\n", asctime (pTm));
recprintf (hFile, "\t</metadata>\n");
recprintf (hFile, "</grid>\n");
......
......@@ -436,3 +436,53 @@ void MultMatrixScalar4 (Matrix4 * pm1, float fScale) {
}
}
bool MatrixInvert2x2 (Matrix2 * pmOut1, Matrix2 const * pmIn1) {
bool boSuccess;
float fDeterminant;
float fA1Out;
float fB2Out;
boSuccess = TRUE;
fDeterminant = (pmIn1->fA1 * pmIn1->fB2) - (pmIn1->fA2 * pmIn1->fB1);
if (fDeterminant != 0.0f) {
if (pmOut1 != pmIn1) {
pmOut1->fA1 = pmIn1->fB2 / fDeterminant;
pmOut1->fB2 = pmIn1->fA1 / fDeterminant;
pmOut1->fB1 = - pmIn1->fB1 / fDeterminant;
pmOut1->fA2 = - pmIn1->fA2 / fDeterminant;
}
else {
fA1Out = pmIn1->fB2 / fDeterminant;
fB2Out = pmIn1->fA1 / fDeterminant;
pmOut1->fA1 = fA1Out;
pmOut1->fB2 = fB2Out;
pmOut1->fB1 = - pmIn1->fB1 / fDeterminant;
pmOut1->fA2 = - pmIn1->fA2 / fDeterminant;
}
}
else {
boSuccess = FALSE;
}
return boSuccess;
}
// Useful for calculating the result of simultaneous equations
// [ a1 b1 ] [ v1 ] = [ r1 ] = [ (a1*v1) + (b1*v2) ]
// [ a2 b2 ] [ v2 ] [ r2 ] [ (a2*v1) + (b2*v2) ]
void MultMatrix2x2Vector2 (Vector2 * pvOut1, Matrix2 const * pmIn1, Vector2 const * pvIn1) {
Vector2 vOut;
if (pvOut1 != pvIn1) {
pvOut1->fX = (pmIn1->fA1 * pvIn1->fX) + (pmIn1->fB1 * pvIn1->fY);
pvOut1->fY = (pmIn1->fA2 * pvIn1->fX) + (pmIn1->fB2 * pvIn1->fY);
}
else {
vOut.fX = (pmIn1->fA1 * pvIn1->fX) + (pmIn1->fB1 * pvIn1->fY);
vOut.fY = (pmIn1->fA2 * pvIn1->fX) + (pmIn1->fB2 * pvIn1->fY);
pvOut1->fX = vOut.fX;
pvOut1->fY = vOut.fY;
}
}
......@@ -33,11 +33,22 @@
///////////////////////////////////////////////////////////////////
// Defines
#define SetVector2(SET, X, Y) (SET).fX = (X); (SET).fY = (Y);
#define SetVector3(SET, X, Y, Z) (SET).fX = (X); (SET).fY = (Y); (SET).fZ = (Z);
///////////////////////////////////////////////////////////////////
// Structures and enumerations
typedef struct _Vector2 {
union {
struct {
GLfloat fX;
GLfloat fY;
};
GLfloat afV[2];
};
} Vector2;
typedef struct _Vector3 {
union {
struct {
......@@ -49,6 +60,19 @@ typedef struct _Vector3 {
};
} Vector3;
typedef struct _Matrix2 {
union {
struct {
GLfloat fA1;
GLfloat fA2;
GLfloat fB1;
GLfloat fB2;
};
GLfloat afM[4];
GLfloat aafM[2][2];
};
} Matrix2;
typedef struct _Matrix3 {
union {
struct {
......@@ -136,6 +160,10 @@ void MatrixScale4 (Matrix4 * pm1, Vector3 const * pvScale);
void MatrixRotate4 (Matrix4 * pm1, float fAngle, Vector3 const * pvAxis);
void MultMatrixScalar4 (Matrix4 * pm1, float fScale);
bool MatrixInvert2x2 (Matrix2 * pmOut1, Matrix2 const * pmIn1);
void MultMatrix2x2Vector2 (Vector2 * pvOut1, Matrix2 const * pmIn1, Vector2 const * pvIn1);
///////////////////////////////////////////////////////////////////
// Function definitions
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment