2016-03-12 01:20:51 +01:00
/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software ; you can redistribute it and / or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA . */
2016-03-11 14:57:17 +01:00
2016-03-29 03:03:54 +02:00
# include "Engine/StdH.h"
2016-03-11 14:57:17 +01:00
# include <Engine/Math/Object3D.h>
# include <Engine/Templates/BSP_internal.h>
# include <Engine/Templates/DynamicArray.cpp>
/*
* CSG operation table action .
*/
enum CSGAction {
CSGA_WallA1 , // wall of sector A1
CSGA_WallA1_2 , // wall of sector A1 second part
CSGA_PortalA1A2 , // portal between A1 and A2
CSGA_PortalA1A2_2 , // portal between A1 and A2 second part
CSGA_PortalA1B1B1A1 , // two portals: A1-B1 and B1-A1
CSGA_WallB1 , // wall of sector B1
CSGA_PortalB1B2 , // portal between B1 and B2
CSGA_Remove , // this polygon is removed
CSGA_Proceed , // this polygon proceeds with testing
} ;
/*
* CSG operation table .
*/
struct CSGOperationTable {
enum CSGAction cot_WallA1InsideB1 , cot_WallA1OutsideB , cot_WallA1OnB1BorderInside , cot_WallA1OnB1BorderOutside ;
enum CSGAction cot_PortalA1A2InsideB1 , cot_PortalA1A2OutsideB , cot_PortalA1A2OnB1BorderInside , cot_PortalA1A2OnB1BorderOutside ;
} ;
/*
NOTE : In following tables , the operations for object B have A and B sectors reversed .
That is because tables are always interpreted as being for object A , therefore
when using it for B , sector B means ' sector of other object ' that is in fact sector A
and vice versa .
For readable tables see " CSG.doc " .
*/
/*
* CSG operation tables for ' add rooms ' .
*/
static struct CSGOperationTable csgotAddRoomsA = {
CSGA_PortalA1B1B1A1 , CSGA_WallA1 , CSGA_WallA1 , CSGA_PortalA1B1B1A1 ,
CSGA_PortalA1A2 , CSGA_PortalA1A2 , CSGA_PortalA1A2 , CSGA_PortalA1A2 ,
} ;
static struct CSGOperationTable csgotAddRoomsB = {
CSGA_Remove , CSGA_WallA1 , CSGA_Remove , CSGA_Remove ,
CSGA_Remove , CSGA_PortalA1A2 , CSGA_Remove , CSGA_Remove ,
} ;
/*
* CSG operation tables for ' add material ' .
*/
static struct CSGOperationTable csgotAddMaterialA = {
CSGA_WallA1 , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
CSGA_PortalA1A2 , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
} ;
static struct CSGOperationTable csgotAddMaterialB = {
CSGA_WallB1 , CSGA_Remove , CSGA_WallB1 , CSGA_Proceed ,
CSGA_Remove , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
} ;
static struct CSGOperationTable csgotAddMaterialReverseA = {
CSGA_WallA1 , CSGA_Remove , CSGA_WallA1 , CSGA_Remove ,
CSGA_PortalA1A2 , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
} ;
static struct CSGOperationTable csgotAddMaterialReverseB = {
CSGA_WallB1 , CSGA_Remove , CSGA_Remove , CSGA_Proceed ,
CSGA_Remove , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
} ;
/*
* CSG operation tables for ' split sectors ' .
*/
static struct CSGOperationTable csgotSplitSectorsA = {
CSGA_WallB1 , CSGA_WallA1 , CSGA_WallB1 , CSGA_WallA1 ,
CSGA_PortalB1B2 , CSGA_PortalA1A2 , CSGA_PortalB1B2 , CSGA_PortalA1A2 ,
} ;
static struct CSGOperationTable csgotSplitSectorsB = {
CSGA_PortalA1B1B1A1 , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
CSGA_Remove , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
} ;
/*
* CSG operation tables for ' join sectors ' .
*/
static struct CSGOperationTable csgotJoinSectorsA = {
CSGA_Remove , CSGA_WallA1 , CSGA_WallA1 , CSGA_Remove ,
CSGA_Remove , CSGA_PortalA1A2 , CSGA_PortalA1A2 , CSGA_Remove ,
} ;
static struct CSGOperationTable csgotJoinSectorsB = {
CSGA_Remove , CSGA_WallB1 , CSGA_Remove , CSGA_Remove ,
CSGA_Remove , CSGA_PortalB1B2 , CSGA_Remove , CSGA_Remove ,
} ;
/*
* CSG operation tables for ' split polygons ' .
*/
static struct CSGOperationTable csgotSplitPolygonsA = {
CSGA_WallA1_2 , CSGA_WallA1 , CSGA_WallA1_2 , CSGA_WallA1 ,
CSGA_PortalA1A2_2 , CSGA_PortalA1A2 , CSGA_PortalA1A2_2 , CSGA_PortalA1A2 ,
} ;
static struct CSGOperationTable csgotSplitPolygonsB = {
CSGA_Remove , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
CSGA_Remove , CSGA_Remove , CSGA_Remove , CSGA_Remove ,
} ;
/*
* Create a new polygon that will be a piece of some split polygon .
*/
static inline CObjectPolygon * CreatePieceOfPolygon (
CObjectSector * poscSector ,
const CObjectPolygon & opoOriginal ,
BOOL bReversePlane )
{
// create new polygon
CObjectPolygon * popoPiece = poscSector - > osc_aopoPolygons . New ( 1 ) ;
// if the plane should be reversed
if ( bReversePlane ) {
// create a new reversed plane
CObjectPlane * poplNew = poscSector - > osc_aoplPlanes . New ( 1 ) ;
* poplNew = - * opoOriginal . opo_Plane ;
popoPiece - > opo_Plane = poplNew ;
// otherwise
} else {
// create a new plane (not reversed)
CObjectPlane * poplNew = poscSector - > osc_aoplPlanes . New ( 1 ) ;
* poplNew = * opoOriginal . opo_Plane ;
popoPiece - > opo_Plane = poplNew ;
}
// create a new material
CObjectMaterial * pomtNew = poscSector - > osc_aomtMaterials . New ( 1 ) ;
* pomtNew = * opoOriginal . opo_Material ;
popoPiece - > opo_Material = pomtNew ;
// copy other attributes
popoPiece - > opo_colorColor = opoOriginal . opo_colorColor ;
memcpy ( popoPiece - > opo_amdMappings , opoOriginal . opo_amdMappings ,
sizeof ( opoOriginal . opo_amdMappings ) ) ;
popoPiece - > opo_ulFlags = opoOriginal . opo_ulFlags ;
memcpy ( popoPiece - > opo_ubUserData , opoOriginal . opo_ubUserData , OPO_MAXUSERDATA ) ;
return popoPiece ;
}
/*
* A machine for doing CSG operations on an CObject3D object .
*/
class CObjectCSG {
public :
// pointers to sectors and polygons that is currently operating on
CObjectSector * oc_poscSectorA ;
CObjectSector * oc_poscSectorB ;
CObjectPolygon * oc_popoA ;
CObjectPolygon * oc_popoWallA1 ;
CObjectPolygon * oc_popoWallA1_2 ;
CObjectPolygon * oc_popoPortalA1A2 ;
CObjectPolygon * oc_popoPortalA1A2_2 ;
CObjectPolygon * oc_popoPortalA1B1 ;
CObjectPolygon * oc_popoWallB1 ;
CObjectPolygon * oc_popoPortalB1A1 ;
CObjectPolygon * oc_popoPortalB1B2 ;
inline CObjectPolygon * GetWallA1 ( void ) ;
inline CObjectPolygon * GetWallA1_2 ( void ) ;
inline CObjectPolygon * GetPortalA1A2 ( void ) ;
inline CObjectPolygon * GetPortalA1A2_2 ( void ) ;
inline CObjectPolygon * GetPortalA1B1 ( void ) ;
inline CObjectPolygon * GetWallB1 ( void ) ;
inline CObjectPolygon * GetPortalB1A1 ( void ) ;
inline CObjectPolygon * GetPortalB1B2 ( void ) ;
BOOL oc_bCSGIngoringEnabled ;
BOOL oc_bSkipObjectB ;
// array for holding edges that proceed with testing
CDynamicArray < DOUBLEbspedge3D > oc_abedProceeding ;
CObjectCSG ( void ) {
oc_bCSGIngoringEnabled = FALSE ;
oc_bSkipObjectB = FALSE ;
}
/* Add an entire array of BSP edges to some polygon according to action code. */
inline void AddEdgeArrayAccordingToAction (
CDynamicArray < DOUBLEbspedge3D > & abed ,
enum CSGAction csga ) ;
/* Fill array of bsp edges from array of polygon edges. */
void PolygonEdgesToBSPEdges (
CDynamicArray < CObjectPolygonEdge > & aope ,
CDynamicArray < DOUBLEbspedge3D > & abed
) ;
public :
/* Perform CSG splitting of sectors in one operand using other operand. */
void DoCSGSplitting (
CObject3D & obResult ,
CObject3D & obA ,
INDEX iSectorOffsetA ,
struct CSGOperationTable * pcsgotA ,
CObject3D & obB ,
INDEX iSectorOffsetB ) ;
/* Perform CSG operation -- destroys both operands! */
void DoCSGOperation (
CObject3D & obResult ,
CObject3D & obA ,
CObject3D & obB ,
struct CSGOperationTable * pcsgotA ,
struct CSGOperationTable * pcsgotB ) ;
} ;
CObjectPolygon * CObjectCSG : : GetWallA1 ( void )
{
if ( oc_popoWallA1 = = NULL ) {
oc_popoWallA1 = CreatePieceOfPolygon ( oc_poscSectorA , * oc_popoA , FALSE ) ;
oc_popoWallA1 - > opo_ulFlags & = ~ OPOF_PORTAL ;
}
return oc_popoWallA1 ;
}
CObjectPolygon * CObjectCSG : : GetWallA1_2 ( void )
{
if ( oc_popoWallA1_2 = = NULL ) {
oc_popoWallA1_2 = CreatePieceOfPolygon ( oc_poscSectorA , * oc_popoA , FALSE ) ;
oc_popoWallA1_2 - > opo_ulFlags & = ~ OPOF_PORTAL ;
}
return oc_popoWallA1_2 ;
}
CObjectPolygon * CObjectCSG : : GetPortalA1A2 ( void )
{
if ( oc_popoPortalA1A2 = = NULL ) {
oc_popoPortalA1A2 = CreatePieceOfPolygon ( oc_poscSectorA , * oc_popoA , FALSE ) ;
oc_popoPortalA1A2 - > opo_ulFlags | = OPOF_PORTAL ;
}
return oc_popoPortalA1A2 ;
}
CObjectPolygon * CObjectCSG : : GetPortalA1A2_2 ( void )
{
if ( oc_popoPortalA1A2_2 = = NULL ) {
oc_popoPortalA1A2_2 = CreatePieceOfPolygon ( oc_poscSectorA , * oc_popoA , FALSE ) ;
oc_popoPortalA1A2_2 - > opo_ulFlags | = OPOF_PORTAL ;
}
return oc_popoPortalA1A2_2 ;
}
CObjectPolygon * CObjectCSG : : GetPortalA1B1 ( void )
{
if ( oc_popoPortalA1B1 = = NULL ) {
oc_popoPortalA1B1 = CreatePieceOfPolygon ( oc_poscSectorA , * oc_popoA , FALSE ) ;
oc_popoPortalA1B1 - > opo_ulFlags | = OPOF_PORTAL ;
}
return oc_popoPortalA1B1 ;
}
CObjectPolygon * CObjectCSG : : GetWallB1 ( void )
{
if ( oc_popoWallB1 = = NULL ) {
oc_popoWallB1 = CreatePieceOfPolygon ( oc_poscSectorB , * oc_popoA , FALSE ) ;
oc_popoWallB1 - > opo_ulFlags & = ~ OPOF_PORTAL ;
}
return oc_popoWallB1 ;
}
CObjectPolygon * CObjectCSG : : GetPortalB1A1 ( void )
{
if ( oc_popoPortalB1A1 = = NULL ) {
oc_popoPortalB1A1 = CreatePieceOfPolygon ( oc_poscSectorB , * oc_popoA , TRUE ) ; // this one is reversed !
oc_popoPortalB1A1 - > opo_ulFlags | = OPOF_PORTAL ;
}
return oc_popoPortalB1A1 ;
}
CObjectPolygon * CObjectCSG : : GetPortalB1B2 ( void )
{
if ( oc_popoPortalB1B2 = = NULL ) {
oc_popoPortalB1B2 = CreatePieceOfPolygon ( oc_poscSectorB , * oc_popoA , FALSE ) ;
oc_popoPortalB1B2 - > opo_ulFlags | = OPOF_PORTAL ;
}
return oc_popoPortalB1B2 ;
}
/*
* Fill array of bsp edges from array of polygon edges .
*/
void CObjectCSG : : PolygonEdgesToBSPEdges (
CDynamicArray < CObjectPolygonEdge > & aope ,
CDynamicArray < DOUBLEbspedge3D > & abed
)
{
aope . Lock ( ) ;
abed . Lock ( ) ;
// get number of edges in the polygon
INDEX ctEdges = aope . Count ( ) ;
// create that much edges in array of bsp edges
abed . New ( ctEdges ) ;
// for each edge in polygon
for ( INDEX iEdge = 0 ; iEdge < ctEdges ; iEdge + + ) {
const CObjectPolygonEdge & ope = aope [ iEdge ] ;
// if it is reversed
if ( ope . ope_Backward ) {
// add bsp edge with reverse vertices
2016-04-07 05:16:30 +02:00
STUBBED ( " 64-bit issue " ) ; // we're casting ope.ope_Edge to a 32-bit value. Code really only cares if this is zero or !zero, but one could totally have a non-NULL 64-bit pointer that truncates down to zero!
2016-03-11 14:57:17 +01:00
abed [ iEdge ] = DOUBLEbspedge3D ( * ope . ope_Edge - > oed_Vertex1 ,
2016-04-07 05:16:30 +02:00
* ope . ope_Edge - > oed_Vertex0 , ( ULONG ) ( size_t ) ope . ope_Edge ) ;
2016-03-11 14:57:17 +01:00
// if it is not reversed
} else {
// add bsp edge with normal vertices
2016-04-07 05:16:30 +02:00
STUBBED ( " 64-bit issue " ) ; // we're casting ope.ope_Edge to a 32-bit value. Code really only cares if this is zero or !zero, but one could totally have a non-NULL 64-bit pointer that truncates down to zero!
2016-03-11 14:57:17 +01:00
abed [ iEdge ] = DOUBLEbspedge3D ( * ope . ope_Edge - > oed_Vertex0 ,
2016-04-07 05:16:30 +02:00
* ope . ope_Edge - > oed_Vertex1 , ( ULONG ) ( size_t ) ope . ope_Edge ) ;
2016-03-11 14:57:17 +01:00
}
}
aope . Unlock ( ) ;
abed . Unlock ( ) ;
}
/*
* Add an entire array of BSP edges to some polygon according to action code .
*/
inline void CObjectCSG : : AddEdgeArrayAccordingToAction (
CDynamicArray < DOUBLEbspedge3D > & abed ,
enum CSGAction csga )
{
// if there are no edges to process
INDEX ctEdges = abed . Count ( ) ;
if ( ctEdges = = 0 ) {
// do nothing
return ;
}
// if the action is Remove
if ( csga = = CSGA_Remove ) {
// do nothing
return ;
}
// if the action is Proceed
if ( csga = = CSGA_Proceed ) {
// add entire array to array of proceeding edges
oc_abedProceeding . MoveArray ( abed ) ;
return ;
}
// check the action code and find sector(s) and polygon(s) to add edges to
CObjectPolygon * popoNormal = NULL ;
CObjectSector * poscNormal = NULL ;
CObjectPolygon * popoReverse = NULL ;
CObjectSector * poscReverse = NULL ;
switch ( csga ) {
case CSGA_WallA1 :
poscNormal = oc_poscSectorA ;
popoNormal = GetWallA1 ( ) ;
break ;
case CSGA_WallA1_2 :
poscNormal = oc_poscSectorA ;
popoNormal = GetWallA1_2 ( ) ;
break ;
case CSGA_PortalA1A2_2 :
poscNormal = oc_poscSectorA ;
popoNormal = GetPortalA1A2_2 ( ) ;
break ;
case CSGA_PortalA1A2 :
poscNormal = oc_poscSectorA ;
popoNormal = GetPortalA1A2 ( ) ;
break ;
case CSGA_PortalA1B1B1A1 :
poscNormal = oc_poscSectorA ;
popoNormal = GetPortalA1B1 ( ) ;
poscReverse = oc_poscSectorB ;
popoReverse = GetPortalB1A1 ( ) ;
break ;
case CSGA_WallB1 :
poscNormal = oc_poscSectorB ;
popoNormal = GetWallB1 ( ) ;
break ;
case CSGA_PortalB1B2 :
poscNormal = oc_poscSectorB ;
popoNormal = GetPortalB1B2 ( ) ;
break ;
default :
ASSERTALWAYS ( " Unknown CSG action code " ) ;
}
// create needed number of vertices, edges and polygon edges
CObjectVertex * aovxNormal = NULL ;
CObjectEdge * aoedNormal = NULL ;
CObjectPolygonEdge * aopeNormal = NULL ;
CObjectVertex * aovxReverse = NULL ;
CObjectEdge * aoedReverse = NULL ;
CObjectPolygonEdge * aopeReverse = NULL ;
aovxNormal = poscNormal - > osc_aovxVertices . New ( 2 * ctEdges ) ;
aoedNormal = poscNormal - > osc_aoedEdges . New ( ctEdges ) ;
aopeNormal = popoNormal - > opo_PolygonEdges . New ( ctEdges ) ;
if ( poscReverse ! = NULL ) {
aovxReverse = poscReverse - > osc_aovxVertices . New ( 2 * ctEdges ) ;
aoedReverse = poscReverse - > osc_aoedEdges . New ( ctEdges ) ;
aopeReverse = popoReverse - > opo_PolygonEdges . New ( ctEdges ) ;
}
abed . Lock ( ) ;
// add all edges to normal polygon
{ for ( INDEX iEdge = 0 ; iEdge < ctEdges ; iEdge + + ) {
DOUBLEbspedge3D & bed = abed [ iEdge ] ;
aovxNormal [ iEdge * 2 + 0 ] = bed . bed_vVertex0 ;
aovxNormal [ iEdge * 2 + 1 ] = bed . bed_vVertex1 ;
aoedNormal [ iEdge ] . oed_Vertex0 = & aovxNormal [ iEdge * 2 + 0 ] ;
aoedNormal [ iEdge ] . oed_Vertex1 = & aovxNormal [ iEdge * 2 + 1 ] ;
aopeNormal [ iEdge ] . ope_Backward = FALSE ;
aopeNormal [ iEdge ] . ope_Edge = & aoedNormal [ iEdge ] ;
} }
// if there is reverse polygon
if ( poscReverse ! = NULL ) {
// add all edges to reverse polygon
{ for ( INDEX iEdge = 0 ; iEdge < ctEdges ; iEdge + + ) {
DOUBLEbspedge3D & bed = abed [ iEdge ] ;
aovxReverse [ iEdge * 2 + 0 ] = bed . bed_vVertex1 ;
aovxReverse [ iEdge * 2 + 1 ] = bed . bed_vVertex0 ;
aoedReverse [ iEdge ] . oed_Vertex0 = & aovxReverse [ iEdge * 2 + 0 ] ;
aoedReverse [ iEdge ] . oed_Vertex1 = & aovxReverse [ iEdge * 2 + 1 ] ;
aopeReverse [ iEdge ] . ope_Backward = FALSE ;
aopeReverse [ iEdge ] . ope_Edge = & aoedReverse [ iEdge ] ;
} }
}
abed . Unlock ( ) ;
}
/*
* Perform CSG splitting of sectors in one operand using other operand .
*/
void CObjectCSG : : DoCSGSplitting (
CObject3D & obResult ,
CObject3D & obA ,
INDEX iSectorOffsetA ,
struct CSGOperationTable * pcsgotA ,
CObject3D & obB ,
INDEX iSectorOffsetB )
{
obResult . ob_aoscSectors . Lock ( ) ;
// for each sector in A
{ FOREACHINDYNAMICARRAY ( obA . ob_aoscSectors , CObjectSector , itoscA ) {
// make sector reference in result
oc_poscSectorA = & obResult . ob_aoscSectors [ iSectorOffsetA + itoscA - > osc_Index ] ;
// copy sector properties from operand A to result
oc_poscSectorA - > osc_colColor = itoscA - > osc_colColor ;
oc_poscSectorA - > osc_colAmbient = itoscA - > osc_colAmbient ;
oc_poscSectorA - > osc_ulFlags [ 0 ] = itoscA - > osc_ulFlags [ 0 ] ;
oc_poscSectorA - > osc_ulFlags [ 1 ] = itoscA - > osc_ulFlags [ 1 ] ;
oc_poscSectorA - > osc_ulFlags [ 2 ] = itoscA - > osc_ulFlags [ 2 ] ;
oc_poscSectorA - > osc_strName = itoscA - > osc_strName ;
// for each of polygons in that sector
{ FOREACHINDYNAMICARRAY ( itoscA - > osc_aopoPolygons , CObjectPolygon , itopoA ) {
oc_popoA = itopoA ;
// prepare appropriate actions for it
enum CSGAction csgaInside , csgaOutside , csgaBorderInside , csgaBorderOutside , csgaSkip ;
if ( itopoA - > opo_ulFlags & OPOF_PORTAL ) {
csgaInside = pcsgotA - > cot_PortalA1A2InsideB1 ;
csgaOutside = pcsgotA - > cot_PortalA1A2OutsideB ;
csgaBorderInside = pcsgotA - > cot_PortalA1A2OnB1BorderInside ;
csgaBorderOutside = pcsgotA - > cot_PortalA1A2OnB1BorderOutside ;
csgaSkip = CSGA_PortalA1A2 ;
} else {
csgaInside = pcsgotA - > cot_WallA1InsideB1 ;
csgaOutside = pcsgotA - > cot_WallA1OutsideB ;
csgaBorderInside = pcsgotA - > cot_WallA1OnB1BorderInside ;
csgaBorderOutside = pcsgotA - > cot_WallA1OnB1BorderOutside ;
csgaSkip = CSGA_WallA1 ;
}
// create temporary array for holding remaining edges
CDynamicArray < DOUBLEbspedge3D > abedRemaining ;
// fill the array with edges from the polygon
PolygonEdgesToBSPEdges ( itopoA - > opo_PolygonEdges , abedRemaining ) ;
// create wall A1 polygon
oc_popoWallA1 = NULL ;
oc_popoWallA1_2 = NULL ;
// create portal A1-A2 polygon
oc_popoPortalA1A2 = NULL ;
oc_popoPortalA1A2_2 = NULL ;
// if the polygon should be skipped
if ( oc_bCSGIngoringEnabled & & ( itopoA - > opo_ulFlags & OPOF_IGNOREDBYCSG ) ) {
// add entire polygon according to _skip_ action
AddEdgeArrayAccordingToAction ( abedRemaining , csgaSkip ) ;
// skip splitting
continue ;
}
// for each sector in B
{ FOREACHINDYNAMICARRAY ( obB . ob_aoscSectors , CObjectSector , itoscB ) {
// clear array of proceeding edges
oc_abedProceeding . Clear ( ) ;
// make sector references in result
oc_poscSectorB = & obResult . ob_aoscSectors [ iSectorOffsetB + itoscB - > osc_Index ] ;
// copy sector properties from operand B to result
oc_poscSectorB - > osc_colColor = itoscB - > osc_colColor ;
oc_poscSectorB - > osc_colAmbient = itoscB - > osc_colAmbient ;
oc_poscSectorB - > osc_ulFlags [ 0 ] = itoscB - > osc_ulFlags [ 0 ] ;
oc_poscSectorB - > osc_ulFlags [ 1 ] = itoscB - > osc_ulFlags [ 1 ] ;
oc_poscSectorB - > osc_ulFlags [ 2 ] = itoscB - > osc_ulFlags [ 2 ] ;
oc_poscSectorB - > osc_strName = itoscB - > osc_strName ;
// create portal A1-B1 polygon
oc_popoPortalA1B1 = NULL ;
// create portal B1-A1 polygon
oc_popoPortalB1A1 = NULL ;
// create wall B1 polygon
oc_popoWallB1 = NULL ;
// create portal B1-B2 polygon
oc_popoPortalB1B2 = NULL ;
// create a bsp polygon from first temporary array
2016-04-07 05:16:30 +02:00
STUBBED ( " 64-bit issue " ) ;
DOUBLEbsppolygon3D bpoA ( * itopoA - > opo_Plane , abedRemaining , ( ULONG ) ( size_t ) itopoA - > opo_Plane ) ;
2016-03-11 14:57:17 +01:00
// create a BSP cutter for B's sector BSP and A's polygon
DOUBLEbspcutter3D bcCutter ( bpoA , * itoscB - > osc_BSPTree . bt_pbnRoot ) ;
// optimize all parts of the polygon
DOUBLEbspedge3D : : OptimizeBSPEdges ( bcCutter . bc_abedInside ) ;
DOUBLEbspedge3D : : OptimizeBSPEdges ( bcCutter . bc_abedBorderInside ) ;
DOUBLEbspedge3D : : OptimizeBSPEdges ( bcCutter . bc_abedBorderOutside ) ;
DOUBLEbspedge3D : : OptimizeBSPEdges ( bcCutter . bc_abedOutside ) ;
// add all parts that are inside according to _inside_ action
AddEdgeArrayAccordingToAction ( bcCutter . bc_abedInside , csgaInside ) ;
// add all parts that are on border inside according to _on_border_inside_ action
AddEdgeArrayAccordingToAction ( bcCutter . bc_abedBorderInside , csgaBorderInside ) ;
// add all parts that are on border outside according to _on_border_outside_ action
AddEdgeArrayAccordingToAction ( bcCutter . bc_abedBorderOutside , csgaBorderOutside ) ;
// clear the temporary array
abedRemaining . Clear ( ) ;
// move all parts that are outside or proceeding to the temporary array
abedRemaining . MoveArray ( bcCutter . bc_abedOutside ) ;
abedRemaining . MoveArray ( oc_abedProceeding ) ;
} }
// add all parts that are still remaining according to _outside_ action
AddEdgeArrayAccordingToAction ( abedRemaining , csgaOutside ) ;
} }
} }
obResult . ob_aoscSectors . Unlock ( ) ;
}
/*
* Perform CSG operation - - destroys both operands !
*/
void CObjectCSG : : DoCSGOperation (
CObject3D & obResult ,
CObject3D & obA ,
CObject3D & obB ,
struct CSGOperationTable * pcsgotA ,
struct CSGOperationTable * pcsgotB )
{
// remove current contents
obResult . Clear ( ) ;
// create indices in operand sectors
obA . CreateSectorIndices ( ) ;
obB . CreateSectorIndices ( ) ;
// create sector BSP trees in both operands
obA . CreateSectorBSPs ( ) ;
obB . CreateSectorBSPs ( ) ;
// get number of sectors in operands
INDEX ctSectorsA = obA . ob_aoscSectors . Count ( ) ;
INDEX ctSectorsB = obB . ob_aoscSectors . Count ( ) ;
// create as much sectors in result as there is in both operands
obResult . ob_aoscSectors . New ( ctSectorsA + ctSectorsB ) ;
// do splitting of first operand using the second operand BSPs and first table
DoCSGSplitting ( obResult , obA , 0 , pcsgotA , obB , ctSectorsA ) ;
// do splitting of second operand using the first operand BSPs and second table
if ( ! oc_bSkipObjectB ) {
DoCSGSplitting ( obResult , obB , ctSectorsA , pcsgotB , obA , 0 ) ;
}
}
/*
* * * CSG operations - - they all destroy both operands ! * * *
*/
/*
* Add rooms .
*/
void CObject3D : : CSGAddRooms ( CObject3D & obA , CObject3D & obB )
{
// do CSG with 'add rooms' tables
CObjectCSG oc ;
oc . DoCSGOperation ( * this , obA , obB , & csgotAddRoomsA , & csgotAddRoomsB ) ;
}
/*
* Add material from object B to object A . ( B should have only one
* open sector and no closed sectors )
*/
void CObject3D : : CSGAddMaterial ( CObject3D & obA , CObject3D & obB )
{
// do CSG with 'add material' tables
CObjectCSG oc ;
oc . DoCSGOperation ( * this , obA , obB , & csgotAddMaterialA , & csgotAddMaterialB ) ;
}
void CObject3D : : CSGAddMaterialReverse ( CObject3D & obA , CObject3D & obB )
{
// do CSG with 'add material' tables, but with reverse priorities
CObjectCSG oc ;
oc . DoCSGOperation ( * this , obA , obB , & csgotAddMaterialReverseA , & csgotAddMaterialReverseB ) ;
}
/*
* Remove material of object B from object A . ( B should have only one
* open sector and no closed sectors )
*/
void CObject3D : : CSGRemoveMaterial ( CObject3D & obA , CObject3D & obB )
{
// reverse the object B
obB . Inverse ( ) ;
// do CSG with 'add rooms' tables, but with reversed priorities
CObjectCSG oc ;
oc . DoCSGOperation ( * this , obA , obB , & csgotAddRoomsB , & csgotAddRoomsA ) ;
}
/*
* Split sectors of object A using object B . ( B should have only one
* closed sector and no open sectors )
*/
void CObject3D : : CSGSplitSectors ( CObject3D & obA , CObject3D & obB )
{
// do CSG with 'split sectors' tables
CObjectCSG oc ;
oc . DoCSGOperation ( * this , obA , obB , & csgotSplitSectorsA , & csgotSplitSectorsB ) ;
}
/* Join sectors of object A with sectors of object B. (both A and B should
have only one sector ) */
void CObject3D : : CSGJoinSectors ( CObject3D & obA , CObject3D & obB )
{
// do CSG with 'join sectors' tables
CObjectCSG oc ;
oc . DoCSGOperation ( * this , obA , obB , & csgotJoinSectorsA , & csgotJoinSectorsB ) ;
}
/* Split polygons of object A with sectors of object B. (both A and B should
have only one sector ) */
void CObject3D : : CSGSplitPolygons ( CObject3D & obA , CObject3D & obB )
{
// do CSG with 'split polygons' tables
CObjectCSG oc ;
oc . oc_bCSGIngoringEnabled = TRUE ;
oc . oc_bSkipObjectB = TRUE ;
oc . DoCSGOperation ( * this , obA , obB , & csgotSplitPolygonsA , & csgotSplitPolygonsB ) ;
}