I was developing a program. When I tried to compile to clean up any syntax errors, etc, I got a cryptic error message at a memcpy. I can comment out the call to memcpy and replace it with explicit copying of values, so I have a workaround but I would still like this bug to be fixed.
C:\...\source.c(165): fatal error: Internal error: spill_at_range().
The bug can be reproduced with the code below. Just add it to a 32 bit console application project.
I am using version 7.00.355 (Win64)
/*
Source file for 3D graphics core
Copyright (C) 2015 Kyle Gagner
All rights reserved
*/
#include <string.h>
int GCORE_ClipTriangles(void* buffin, int attributes, int statics, int count, void* buffout, int capacity)
{
// pointer to current triangle in input buffer
double* ctriangle = buffin;
// pointer to location in output buffer for next triangle
double* wtriangle = buffout;
// number of triangles written out
int written = 0;
// offset to statics in triangle
int statoff = 12+3*attributes;
// number of doubles in a triangle
int pitch = statoff+statics;
// loop across all input triangles
for(int n = 0; n < count; n++)
{
// region for each vertex (describes on which side of each clipping plane it lies)
unsigned char regions[3];
// mark the regions of each vertex
for(int i = 0; i < 3; i++)
{
double* cvertex = ctriangle + 4*i;
if(cvertex[0] < -cvertex[3]) regions[i] |= 0x01; // mark regions outside w+x=0 plane
else if(cvertex[0] > cvertex[3]) regions[i] |= 0x02; // mark regions outside w-x=0 plane
if(cvertex[1] < -cvertex[3]) regions[i] |= 0x04; // mark regions outside w+y=0 plane
else if(cvertex[1] > cvertex[3]) regions[i] |= 0x08; // mark regions outside w-y=0 plane
if(cvertex[2] < -cvertex[3]) regions[i] |= 0x10; // mark regions outside w+z=0 plane
else if(cvertex[2] > cvertex[3]) regions[i] |= 0x20; // mark regions outside w-z=0 plane
}
// trivial accept, entire triangle is within the bounding cube
if((regions[0] | regions[1] | regions[2]) == 0)
{
memcpy(wtriangle, ctriangle, pitch*sizeof(double));
written++;
wtriangle+=pitch;
}
// trivial reject, entire triangle is on the wrong side of at least one of the clipping planes
else if((~((regions[0]^regions[1]) | (regions[1]^regions[2]) | (regions[2]^regions[0]))) & regions[0]);
// non-trivial, perform intersections with clipping planes
else
{
// temporary buffer for barycentric coordinates
double barycentric[6][3];
// temporary buffer for conventional coordinates
double coordinates[6][3];
// index into the buffers
int index = 0;
// pointer to current vertex
double* cvertex = ctriangle;
// pointer to next vertex (wraps back around for last vertex)
double* nvertex = ctriangle + 4;
// loop through the edges of the triangle
for(int i = 0; i < 3; i++)
{
unsigned char cregion = regions[i];
unsigned char nregion = regions[(i+1)%3];
// accepting the start vertex is still trivial
if(!cregion)
{
memcpy(coordinates[index], cvertex, 4*sizeof(double));
for(int k = 0; k < 3; k++) barycentric[index][k] = k==i ? 1.0 : 0.0;
index++;
}
// and rejecting an entire edge is also trivial
else if((~(cregion^nregion)) & cregion) continue; // some feel continue is just fancy goto
// t values (interpolation from current to next vertex)
double tvalues[2];
// index into t values
int tindex = 0;
// find planes cut by edge
unsigned char planes = cregion^nregion;
// loop across all clipping planes
for(int j = 0; j < 6; j++)
{
// only consider those planes cut by the edge
if((planes >> j) & 1)
{
// two dimensional barycentric coordinate across edge
double b1, b2;
// x, y, or z cutting plane
int comp = j/2;
if(j%2) // w-comp=0 planes
{
b1=(cvertex[comp]-cvertex[3])/(cvertex[comp]-nvertex[comp]+nvertex[3]-cvertex[3]);
}
else // w+comp=0 planes
{
b1=(cvertex[comp]-cvertex[3])/(cvertex[comp]-nvertex[comp]+nvertex[3]-cvertex[3]);
}
b2 = 1-b1;
// calculate the actual point
double x = cvertex[0]*b1+nvertex[0]*b2;
double y = cvertex[1]*b1+nvertex[1]*b2;
double z = cvertex[2]*b1+nvertex[2]*b2;
double w = cvertex[3]*b1+nvertex[3]*b2;
// test to see if point is clipped (ORs are due to floating point not to be trusted)
if(x < -1 || j==0) continue;
else if(x > w || j==1) continue;
if(y < -1 || j==2) continue;
else if(y > w || j==3) continue;
if(z < -1 || j==4) continue;
else if(z > w || j==5) continue;
// the point is valid, not clipped, to be put in buffer
coordinates[index][0] = x;
coordinates[index][1] = y;
coordinates[index][2] = z;
coordinates[index][3] = w;
barycentric[index][i] = b1;
barycentric[index][(i+1)%3] = b2;
barycentric[index][(i+2)%3] = 0;
index++;
tvalues[tindex] == b1;
tindex++;
// prevent degeneracy from causing tindex out of bounds issue
if(tindex == 2) break;
}
// optimization
else if(!(planes >> j)) break;
}
// it's possible the vertices could have been put in out of order if edge passes through two faces of cube
if(tindex == 2 && tvalues[0] > tvalues[1])
{
double temp[4];
memcpy(temp, coordinates[index-1], 4*sizeof(double));
memcpy(coordinates[index-1], coordinates[index-2], 4*sizeof(double));
memcpy(coordinates[index-2], temp, 4*sizeof(double));
memcpy(temp, barycentric[index-1], 3*sizeof(double));
memcpy(barycentric[index-1], barycentric[index-2], 4*sizeof(double));
memcpy(barycentric[index-2], temp, 4*sizeof(double));
}
cvertex += 4;
nvertex = i==2 ? ctriangle : cvertex+4;
}
// now the buffer has all the information needed to construct the final triangle mesh
// easier to do this by splitting the loop up into a first case then subsequent cases
memcpy(wtriangle, coordinates[0], 12*sizeof(double));
wtriangle += 12;
for(int j = 0; j < attributes; j++)
{
for(int k = 0; k < 3; k++)
{
*wtriangle=
ctriangle[12+3*j+0]*barycentric[k][0]+
ctriangle[12+3*j+1]*barycentric[k][1]+
ctriangle[12+3*j+2]*barycentric[k][2];
wtriangle++;
}
}
memcpy(wtriangle, ctriangle+statoff, statics*sizeof(double));
wtriangle += statics;
written++;
if(written == capacity) return capacity;
for(int i = 1; i < index-2; i++)
{
for(int j = 0; j < 3; j++)
{
memcpy(wtriangle, coordinates[(i+j)%index], 4*sizeof(double));
wtriangle += 4;
}
for(int j = 0; j < attributes; j++)
{
for(int k = 0; k < 3; k++)
{
*wtriangle=
ctriangle[12+3*j+0]*barycentric[(j+k)%index][0]+
ctriangle[12+3*j+1]*barycentric[(j+k)%index][1]+
ctriangle[12+3*j+2]*barycentric[(j+k)%index][2];
wtriangle++;
}
}
memcpy(wtriangle, ctriangle+statoff, statics*sizeof(double));
wtriangle += statics;
written++;
if(written == capacity) return capacity;
}
}
ctriangle+=pitch;
}
return written;
}