i only implemented csg it may lack some face buliding code, i mean maybe not all faces are created, i did this more than year ago i think and left is as it is:
and a supreme goal not realated to antyhing
header
csg.h
#ifndef csgH
#define csgH
#include "DxcMath.h"
#include "modelloading/TachoGLModelSRC.h"
#include "logme.h"
/*
bool * used = new bool[ imaginary_poly.Count ];
float * angles = new float[ imaginary_poly.Count ];
for (int imo=0; imo < imaginary_poly.Count; imo++) used[imo] = false;
used[0] = true;
CSGOut->imaginary_poly.AddVertex(imaginary_poly.V[0]);
//CSGOut->imaginary_poly = imaginary_poly;
t3dpoint<float> center_point;
for (int imo=0; imo < imaginary_poly.Count; imo++)
center_point = center_point + imaginary_poly.V[imo];
center_point = center_point / float(imaginary_poly.Count);
TPolygon<float> CLOCKWISE_POLY;
t3dpoint<float> plane_normal = Normal(imaginary_poly.V[0],imaginary_poly.V[1],imaginary_poly.V[2],true);
float plane_distance = getplaneD(plane_normal, imaginary_poly.V[0]);
CLOCKWISE_POLY.AddVertex(center_point);
CLOCKWISE_POLY.AddVertex(imaginary_poly.V[0] );
TPolygon<float> origin_poly = CreatePoly(plane_normal, imaginary_poly.V[0], 100.0f);
t3dpoint<float> Xvec = vectorAB(origin_poly.V[0], origin_poly.V[1]);
t3dpoint<float> Yvec = vectorAB(origin_poly.V[0], origin_poly.V[3]);
int next_vertex = 0;
while (!nothing_to_check(used, imaginary_poly.Count))
{
float angle = 5555555.0;
int anglei;
for (int imo=0; imo < imaginary_poly.Count; imo++)
if (imo != next_vertex)
{
t3dpoint<float> vector = vectorAB(imaginary_poly.V[ next_vertex ], imaginary_poly.V[ imo ]);
t3dpoint<float> x_coord = VectorProjectionBDIR(vector, Xvec, false);
t3dpoint<float> y_coord = VectorProjectionBDIR(vector, Yvec, false);
angles[ imo ] = GetAngle( t3dpoint<float>(VectorLength(x_coord), VectorLength(y_coord), 0.0f) );
if ( angles[ imo ] < angle)
{
angle = angles[ imo ];
anglei = imo;
}
}
used[anglei] = true;
next_vertex = anglei;
CLOCKWISE_POLY.AddVertex( imaginary_poly.V[ anglei ] );
}*/
//==========================================================================================
//==========================================================================================
//==========================================================================================
/*
*
*
* if (CSGSPH == true)
{
ican = false;
CSGSPH = false;
t3dpoint<float> normal = t3dpoint<float>(-1.0, 0.0, 0.0);
float dist = -Dot(normal, t3dpoint<float>(0.0, 0.0, -1.0));
box_model->CalcFaceCenterPoint(); //this funciton is needed for face area calculation (only convex polys)
box_model->CalculateFaceAreas();
CAN_LOG =true;
ALOG("INIT VOL: "+FloatToStr(box_model->CalculateVolume()));
CAN_LOG= false;
sphere = CSG.CutModelWithPlane(normal, dist, box_model, true);//CSG.CSG_SUBTRACT(1, box_model, cylinder_model, true);
// sphere = CSG.CSG_SUBTRACT(1,box_model, cylinder_model, true);
// if (sphere != NULL)
// {
// dist = -Dot(t3dpoint<float>(0.0, 0.0, 1.0), t3dpoint<float>(3.0, 0.0, 0.0));
// normal = t3dpoint<float>(0.0, 0.0, 1.0);
// TachoGLModel<float> * sphere2 = CSG.CutModelWithPlane(normal, dist, sphere, false);
//
// sphere = sphere2;
CAN_LOG =true;
sphere->MoveToGeometricCenter();
sphere->CalcFaceNormals();
sphere->PointFaceN(t3dpoint<float>(0.0, 0.0, 0.0));
sphere->ReverseNormals();
sphere->CalcFaceCenterPoint();
sphere->CalculateFaceAreas();
ALOG("output VOL: "+FloatToStr(sphere->CalculateVolume()));
CAN_LOG= false;
if (sphere != NULL)
{
sphere->ForceCalculateNormals();
sphere->SendToGPU();
}
// }
CSG_READY = true;
ican = true;
}
*
*
*/
struct TCSGInfo
{
bool blank;
TCSGInfo * n;
TPolygon<float> OUTpoly;
int index; //for easier debugging
TCSGInfo()
{
index = -1;
n = NULL;
blank = true;
}
};
struct TCSGOperationResult
{
TPolygon<float> ImaginaryPoly;
TPolygon<float> LeavePoly;
TPolygon<float> ToBeCutPoly;
};
struct TCSGOperation
{
TCSGInfo * InverseSlicerChubu(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model);
TPolygon<float> InverseSplitPolyByPlane(t3dpoint<float> n, float d, TPolygon<float> CuttedPoly, int leave_side);
TachoGLModel<float> * CutModelWithPlane(t3dpoint<float> n, float d, TachoGLModel<float> * model, bool create_volume);
TCSGOperationResult SplitPolyByPlane(t3dpoint<float> n, float d, TPolygon<float> CuttedPoly, int leave_side)
{
TCSGOperationResult result;
t3dpoint<float> A; t3dpoint<float> B;
int next;
int i;
int cutperformed = 0;
for(i=0; i < CuttedPoly.Count; i++)
{
A = CuttedPoly.V[i];
if (i != CuttedPoly.Count-1) next = i + 1; else next = 0;
B = CuttedPoly.V[next];
int Aside = classifyapointagainstaplane(A, n, d);
int Bside = classifyapointagainstaplane(B, n, d);
t3dpoint<float> output;
bool cut = SegmentPlaneIntersection(n, d, A, B, output);
if (cut)
{
if (Aside == leave_side)
result.LeavePoly.AddVertex(A);
else
result.ToBeCutPoly.AddVertex(A);
result.ImaginaryPoly.AddVertex(output);
result.LeavePoly.AddVertex(output);
result.ToBeCutPoly.AddVertex(output);
} else
{ //here there is no cut atm
if (Aside == leave_side)
result.LeavePoly.AddVertex(A);
else
result.ToBeCutPoly.AddVertex(A);
}
}
// ShowMessage("Initial Face vcnt: "+IntToStr(CuttedPoly.Count)+" leave vcnt: "+IntToStr(result.LeavePoly.Count)
// +" To cut vcnt: "+IntToStr(result.ToBeCutPoly.Count));
return result;
}
TCSGOperation()
{
}
TCSGInfo* GetLastCSG(TCSGInfo * first)
{
TCSGInfo * p = first;
while (p->n != NULL) p = p->n;
return p;
}
TCSGInfo * SlicerChubu(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model) //returns first csg poly that points onto next csg poly from that shape
{
int csg_index = 0;
TCSGInfo * CSGOut = new TCSGInfo();
int vertlen = model->header.LENGTH;
int i; int F;
/*
* How does that function work? FOR EACH FACE IN MODEL TO BE CUT
* Loop through slicing planes and slice that FACE
*/
for (F=0; F < model->FaceLength; F++) //for all model faces that to be cut
{
int face_vindex = model->VBO_BE[F].INDEX_START;
TPolygon<float> poly;
TPolygon<float> imaginary_poly;
for(i=0; i < model->VBO_BE[F].length; i++) poly.V[i] = model->AOS[face_vindex+i].v;
poly.Count = model->VBO_BE[F].length;
int CSG_F;
for (CSG_F=0; CSG_F < CUTTING_model->FaceLength; CSG_F++) //loop through cutting shape (model) faces to cut with its planes the corresponding model
{
TCSGOperationResult csg_res = SplitPolyByPlane(CUTTING_model->FACE_N[ CSG_F ], CUTTING_model->FACE_DISTANCE[ CSG_F ], poly, Leave_side);
poly = csg_res.ToBeCutPoly;
if (csg_res.LeavePoly.Count < 3) continue;
csg_index = csg_index + 1;
if (CSGOut->blank) //we ski
{
if (csg_res.LeavePoly.Count > 0)
{
CSGOut->OUTpoly = csg_res.LeavePoly;
CSGOut->blank = false;
CSGOut->index = csg_index;
}
} else
if (csg_res.LeavePoly.Count > 0)
{
TCSGInfo* lCSG = GetLastCSG(CSGOut);
TCSGInfo* nCSG = new TCSGInfo();
lCSG->n = nCSG;
nCSG->index = csg_index;
nCSG->blank = false;
nCSG->OUTpoly = csg_res.LeavePoly;
}
// if (poly.Count < 3) break; //nothing to cut
}
}
return CSGOut;
}
TachoGLModel<float> * CSG_SUBTRACT(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model, bool recreate_depth)
{
TachoGLModel<float> * result = new TachoGLModel<float>();
TCSGInfo * FirstCSG = NULL;
TCSGInfo * FirstInverseCSG = NULL;
int cut_side;
switch (Leave_side)
{
default:
cut_side = -1;
break;
case 1:
cut_side = -1;
break;
case -1:
cut_side = 1;
break;
}
FirstCSG = SlicerChubu(Leave_side, model, CUTTING_model);
if ( recreate_depth )
FirstInverseCSG = InverseSlicerChubu(Leave_side, model, CUTTING_model);
else
FirstInverseCSG = NULL;
int face_cnt = 0;
int vert_cnt = 0;
TCSGInfo * p;
//****************************************************************************
p = FirstCSG;
if (p != NULL)
{
while (p->n != NULL)
{
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
p = p->n;
}
if (p->n == NULL)
{
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
}
}
//****************************************************************************
//****************************************************************************
p = FirstInverseCSG;
if (p != NULL)
{
while (p->n != NULL)
{
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
p = p->n;
}
if (p->n == NULL)
{
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
}
}
//****************************************************************************
result->AOS = new TTGLVertex<float,float,float>[ vert_cnt ];
result->VBO_BE = new tvbofacenfo[ face_cnt ];
result->Matrixarr = new tmatrixtype[ face_cnt ];
result->header.LENGTH = vert_cnt;
result->header.version = 32;
result->header.addon = 0;
result->FaceLength = face_cnt;
for (int i=0; i < face_cnt; i++)
result->Matrixarr[i] = mtTriangleFan;
/*
* After creating required arrays we need to feed data to it
*/
face_cnt = 0;
vert_cnt = 0;
//****************************************************************************
p = FirstCSG;
if (p != NULL)
{
while (p->n != NULL)
{
for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
result->VBO_BE[face_cnt].INDEX_START = vert_cnt;
result->VBO_BE[face_cnt].length = p->OUTpoly.Count;
result->Matrixarr[face_cnt] = mtTriangleFan;
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
p = p->n;
}
if (p->n == NULL)
{
for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
result->VBO_BE[face_cnt].INDEX_START = vert_cnt;
result->VBO_BE[face_cnt].length = p->OUTpoly.Count;
result->Matrixarr[face_cnt] = mtTriangleFan;
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
}
}
//****************************************************************************
//****************************************************************************
//****************************************************************************
//****************************************************************************
//CAN_LOG = true;
p = FirstInverseCSG;ALOG("INVERSE CSG");
if (p != NULL)
{
while (p->n != NULL)
{
ALOG("outpoly: "+IntToStr(p->OUTpoly.Count));
for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
result->VBO_BE[face_cnt].INDEX_START = vert_cnt;
result->VBO_BE[face_cnt].length = p->OUTpoly.Count;
result->Matrixarr[face_cnt] = mtTriangleFan;
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
p = p->n;
}
if (p->n == NULL)
{
ALOG("outpoly: "+IntToStr(p->OUTpoly.Count));
for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
result->VBO_BE[face_cnt].INDEX_START = vert_cnt;
result->VBO_BE[face_cnt].length = p->OUTpoly.Count;
result->Matrixarr[face_cnt] = mtTriangleFan;
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
}
}
//****************************************************************************
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALOG("done INVERSE CSG");
ClearSlicerChubu(FirstCSG);
ClearSlicerChubu(FirstInverseCSG);
if (vert_cnt == 0)
return NULL;
else
{
// result->SaveToBGLCMD("E:\\csg.bglcmd",false);
return result;
}
}
void ClearSlicerChubu(TCSGInfo * first)
{
TCSGInfo * p = first;
TCSGInfo * pn;
if (p != NULL)
while (p->n != NULL)
{
pn = p->n;
delete p;
p = pn;
}
if ( (p != NULL) && (p->n == NULL) ) delete p;
}
};
#endif
source
#include "csg.h"
/*
* This returns vertices when theres a cut
*/
TPolygon<float> TCSGOperation::InverseSplitPolyByPlane(t3dpoint<float> n, float d, TPolygon<float> CuttedPoly, int leave_side)
{
TPolygon<float> result;
t3dpoint<float> A; t3dpoint<float> B; t3dpoint<float> output;
int next;
int i;
int cutperformed = 0;
for(i=0; i < CuttedPoly.Count; i++)
{
A = CuttedPoly.V[i];
if (i != CuttedPoly.Count-1)
next = i + 1;
else
next = 0;
B = CuttedPoly.V[next];
// int Aside = classifyapointagainstaplane(A, n, d);
bool cut = SegmentPlaneIntersection(n, d, A, B, output);
if (cut)
// if (Aside == leave_side)
result.AddVertex(output);
}
return result;
}
TCSGInfo * TCSGOperation::InverseSlicerChubu(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model) //returns first csg poly that points onto next csg poly from that shape
{
int csg_index = 0;
TCSGInfo * CSGOut = new TCSGInfo();
int vertlen = model->header.LENGTH;
int i; int F;
/*
* How does that function work? FOR EACH FACE IN MODEL TO BE CUT
* Loop through slicing planes and slice that FACE
*/
//CAN_LOG = true;
int face_vindex;
ALOG("INV SLIVER CHUBU");
//imaginary_poly.Count = 0;
int CSG_F;
for (CSG_F=0; CSG_F < CUTTING_model->FaceLength; CSG_F++) //loop through cutting shape (model) faces to cut with its planes the corresponding model
{
TPolygon<float> imaginary_poly;
TPolygon<float> poly;
for (F=0; F < model->FaceLength; F++) //for all model faces that to be cut
{
face_vindex = model->VBO_BE[F].INDEX_START;
for(i=0; i < model->VBO_BE[F].length; i++) poly.V[i] = model->AOS[face_vindex+i].v;
poly.Count = model->VBO_BE[F].length;
TPolygon<float> csg_res = InverseSplitPolyByPlane(CUTTING_model->FACE_N[ CSG_F ], CUTTING_model->FACE_DISTANCE[ CSG_F ], poly, Leave_side);
csg_index = csg_index + 1;
if (csg_res.Count == 0) continue;
for (i=0; i < csg_res.Count; i++) imaginary_poly.AddVertex(csg_res.V[i]);
}
ALOG("ADD TO output poly "+IntToStr(imaginary_poly.Count));
/*
bool used[ imaginary_poly.Count ];
for (int h = 0; h < imaginary_poly.Count; h++)
used[h] = false;
TPolygon<float> convex_poly;
for (int h = 0; h < imaginary_poly.Count; h++)
{
int n = h+1;
if (n > imaginary_poly.Count-1) n = 0;
if (used[h] == false)
if (used[n] == false)
{
float dst = n3ddistance(imaginary_poly.V[h],imaginary_poly.V[n]);
ALOG("testing against: "+FloatToStr(dst));
if (dst < 0.002) //same verts
{
ALOG("FOUND");
convex_poly.AddVertex(imaginary_poly.V[h]);
used[h] = true;
used[n] = true;
}
}
}
imaginary_poly = convex_poly;
*/
ALOG("KK");
ALOG("test if to add");
if (imaginary_poly.Count == 0) continue;
ALOG("KK forward");
if (CSGOut->blank) //we ski
{
ALOG("here");
ALOG("out poly");
CSGOut->OUTpoly = imaginary_poly;
CSGOut->blank = false;
CSGOut->index = csg_index;
} else
{
ALOG("here2");
TCSGInfo* lCSG = GetLastCSG(CSGOut);
TCSGInfo* nCSG = new TCSGInfo();
lCSG->n = nCSG;
ALOG("out poly");
nCSG->OUTpoly = imaginary_poly;
nCSG->blank = false;
nCSG->index = csg_index;
}
}
ALOG("RETURN RESULT");
return CSGOut;
}
TachoGLModel<float> * TCSGOperation::CutModelWithPlane(t3dpoint<float> n, float d, TachoGLModel<float> * model, bool create_volume)
{
// CAN_LOG=true;
//malloc(sizeof(TachoGLModel<double>)* model->header.LENGTH * 10);
ALOG("CUT MODEL WITH PLANE");
TachoGLModel<float> * face_model = new TachoGLModel<float>();
face_model->FACE_N = new t3dpoint<float>[1];
face_model->FACE_DISTANCE = new float[1];
face_model->AOS = new TTGLVertex<float,float,float>[ 1 ];
face_model->VBO_BE = new tvbofacenfo[ 1 ];
face_model->Matrixarr = new tmatrixtype[ 1 ];
face_model->header.LENGTH = 0;
face_model->header.version = 32;
face_model->header.addon = 0;
face_model->FaceLength = 1;
face_model->Matrixarr[0] = mtTriangleFan;
face_model->FACE_N[0] = n;
face_model->FACE_DISTANCE[0] = d;
TachoGLModel<float> * new_model = new TachoGLModel<float>();
ALOG("DO CSG");
new_model = CSG_SUBTRACT(1, model, face_model,create_volume);
ALOG("RETURN RESULT");
return new_model;
}
VBO_BE is face information face first vertex is the index in the vertex array it stores only index and length
however its been a long time i even used this code so i cant guraantee that it produces same results as shown in pictures above. I recommend that you implement your own csg on the go
i just can't understand how i become a miner with such knowledge, dudes, life is shit
the ides is to cut the 'model' with a low poly sphere that procudes imapct on mesh (and hole), then you draw the 'AND' result in shader with time parameter but thats only my delusion