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
|
|
|
|
|
|
|
#include "stdh.h"
|
|
|
|
|
|
|
|
#include <Engine/Brushes/Brush.h>
|
|
|
|
#include <Engine/Math/Float.h>
|
|
|
|
#include <Engine/Math/Object3D.h>
|
|
|
|
#include <Engine/Templates/StaticArray.cpp>
|
|
|
|
#include <Engine/Templates/DynamicContainer.cpp>
|
|
|
|
#include <Engine/Templates/DynamicArray.cpp>
|
|
|
|
#include <Engine/World/WorldEditingProfile.h>
|
|
|
|
#include <Engine/Brushes/BrushTransformed.h>
|
|
|
|
#include <Engine/Graphics/Color.h>
|
|
|
|
#include <Engine/Math/Projection_DOUBLE.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add 3d object as new mip brush.
|
|
|
|
*/
|
|
|
|
void CBrush3D::AddMipBrushFromObject3D_t(CObject3D &ob, FLOAT fSwitchDistance) // throw char *
|
|
|
|
{
|
|
|
|
ASSERT(GetFPUPrecision()==FPT_53BIT);
|
|
|
|
// create one brush mip
|
|
|
|
CBrushMip *pbmBrushMip = new CBrushMip;
|
|
|
|
// add it to the brush
|
|
|
|
br_lhBrushMips.AddTail(pbmBrushMip->bm_lnInBrush);
|
|
|
|
pbmBrushMip->bm_pbrBrush = this;
|
|
|
|
pbmBrushMip->bm_fMaxDistance = fSwitchDistance;
|
|
|
|
|
|
|
|
// add the object to the brush mip
|
|
|
|
pbmBrushMip->AddFromObject3D_t(ob);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill a brush from 3d object.
|
|
|
|
*/
|
|
|
|
void CBrush3D::FromObject3D_t(CObject3D &ob) // throw char *
|
|
|
|
{
|
|
|
|
ASSERT(GetFPUPrecision()==FPT_53BIT);
|
|
|
|
// clear this brush in case there is something in it
|
|
|
|
Clear();
|
|
|
|
|
|
|
|
// create one brush mip
|
|
|
|
CBrushMip *pbmBrushMip = new CBrushMip;
|
|
|
|
// add it to the brush
|
|
|
|
br_lhBrushMips.AddTail(pbmBrushMip->bm_lnInBrush);
|
|
|
|
pbmBrushMip->bm_pbrBrush = this;
|
|
|
|
|
|
|
|
// add the object to the brush mip
|
|
|
|
pbmBrushMip->AddFromObject3D_t(ob);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an object3d to brush. (returns pointer to the first created sector)
|
|
|
|
*/
|
|
|
|
CBrushSector *CBrushMip::AddFromObject3D_t(CObject3D &ob) // throw char *
|
|
|
|
{
|
|
|
|
CSetFPUPrecision sfp(FPT_53BIT);
|
|
|
|
_pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_ADDFROMOBJECT3D);
|
|
|
|
// optimize the object, to remove replicated and unused elements and find edge inverses
|
|
|
|
CBrush3D::OptimizeObject3D(ob);
|
|
|
|
|
|
|
|
// turn this on to dump result of all CSG operations
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// ob.DebugDump();
|
|
|
|
#endif //NDEBUG
|
|
|
|
|
|
|
|
// create as much new sectors in brush mip as there are sectors in object
|
|
|
|
CBrushSector *pbscSectors = bm_abscSectors.New(ob.ob_aoscSectors.Count());
|
|
|
|
CBrushSector *pbscFirstSector = pbscSectors;
|
|
|
|
// for each sector in the object
|
|
|
|
FOREACHINDYNAMICARRAY(ob.ob_aoscSectors, CObjectSector, itosc) {
|
|
|
|
// set brush sector's pointer to the brush
|
|
|
|
pbscSectors->bsc_pbmBrushMip = this;
|
|
|
|
// fill one brush sector from it
|
|
|
|
pbscSectors->FromObjectSector_t(*itosc);
|
|
|
|
|
|
|
|
pbscSectors++;
|
|
|
|
}
|
|
|
|
|
|
|
|
_pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_ADDFROMOBJECT3D);
|
|
|
|
// return pointer to first created sector
|
|
|
|
return pbscFirstSector;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill a brush sector from a sector in object3d.
|
|
|
|
*/
|
|
|
|
void CBrushSector::FromObjectSector_t(CObjectSector &osc) // throw char *
|
|
|
|
{
|
|
|
|
// copy sector color
|
|
|
|
bsc_colColor = osc.osc_colColor;
|
|
|
|
bsc_colAmbient = osc.osc_colAmbient;
|
|
|
|
bsc_ulFlags = osc.osc_ulFlags[0] & ~(BSCF_SELECTED|BSCF_SELECTEDFORCSG);
|
|
|
|
bsc_ulFlags2 = osc.osc_ulFlags[1];
|
|
|
|
bsc_ulVisFlags = osc.osc_ulFlags[2];
|
|
|
|
bsc_strName = osc.osc_strName;
|
|
|
|
|
|
|
|
// lock the object elements
|
|
|
|
osc.LockAll();
|
|
|
|
// lock the brush elements
|
|
|
|
LockAll();
|
|
|
|
|
|
|
|
/* Copy vertices. */
|
|
|
|
|
|
|
|
// get the number of vertices in object
|
|
|
|
INDEX ctVertices = osc.osc_aovxVertices.Count();
|
|
|
|
// create that much vertices in brush
|
|
|
|
bsc_abvxVertices.New(ctVertices);
|
|
|
|
bsc_awvxVertices.New(ctVertices);
|
|
|
|
// copy all vertices and set their indices
|
|
|
|
for(INDEX iVertex=0; iVertex<ctVertices; iVertex++) {
|
|
|
|
bsc_abvxVertices[iVertex].bvx_vdPreciseRelative = osc.osc_aovxVertices[iVertex];
|
|
|
|
bsc_abvxVertices[iVertex].bvx_pbscSector = this;
|
|
|
|
osc.osc_aovxVertices[iVertex].ovx_Index = iVertex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy planes. */
|
|
|
|
|
|
|
|
// get the number of planes in object
|
|
|
|
INDEX ctPlanes = osc.osc_aoplPlanes.Count();
|
|
|
|
// create that much planes in brush
|
|
|
|
bsc_abplPlanes.New(ctPlanes);
|
|
|
|
bsc_awplPlanes.New(ctPlanes);
|
|
|
|
// copy all planes and set their indices
|
|
|
|
for(INDEX iPlane=0; iPlane<ctPlanes; iPlane++) {
|
|
|
|
bsc_abplPlanes[iPlane].bpl_pldPreciseRelative = osc.osc_aoplPlanes[iPlane];
|
|
|
|
osc.osc_aoplPlanes[iPlane].opl_Index = iPlane;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy edges. */
|
|
|
|
|
|
|
|
// get the number of edges in object
|
|
|
|
INDEX ctEdges = osc.osc_aoedEdges.Count();
|
|
|
|
// create that much edges in brush
|
|
|
|
bsc_abedEdges.New(ctEdges);
|
|
|
|
bsc_awedEdges.New(ctEdges);
|
|
|
|
// for all edges in object
|
|
|
|
for(INDEX iEdge=0; iEdge<ctEdges; iEdge++) {
|
|
|
|
CObjectEdge &oed = osc.osc_aoedEdges[iEdge]; // object edge alias
|
|
|
|
CBrushEdge &bed = bsc_abedEdges[iEdge]; // brush edge alias
|
|
|
|
CWorkingEdge &wed = bsc_awedEdges[iEdge];
|
|
|
|
// set the brush edge
|
|
|
|
bed.bed_pbvxVertex0 = &bsc_abvxVertices[oed.oed_Vertex0->ovx_Index];
|
|
|
|
bed.bed_pbvxVertex1 = &bsc_abvxVertices[oed.oed_Vertex1->ovx_Index];
|
|
|
|
// set the working edge
|
|
|
|
bed.bed_pwedWorking = &wed;
|
|
|
|
wed.wed_iwvx0 = oed.oed_Vertex0->ovx_Index;
|
|
|
|
wed.wed_iwvx1 = oed.oed_Vertex1->ovx_Index;
|
|
|
|
// set object edge index
|
|
|
|
oed.oed_Index = iEdge;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy polygons. */
|
|
|
|
|
|
|
|
// get the number of polygons in object
|
|
|
|
INDEX ctPolygons = osc.osc_aopoPolygons.Count();
|
|
|
|
// create that much polygons in brush
|
|
|
|
bsc_abpoPolygons.New(ctPolygons);
|
|
|
|
|
|
|
|
// copy all polygons and set their indices
|
|
|
|
for(INDEX iPolygon=0; iPolygon<ctPolygons; iPolygon++) {
|
|
|
|
CBrushPolygon &bpo = bsc_abpoPolygons[iPolygon]; // brush polygon alias
|
|
|
|
CObjectPolygon &opo = osc.osc_aopoPolygons[iPolygon]; // object polygon alias
|
|
|
|
|
|
|
|
// get plane
|
|
|
|
bpo.bpo_pbplPlane = &bsc_abplPlanes[opo.opo_Plane->opl_Index];
|
|
|
|
// get texture from object material
|
|
|
|
bpo.bpo_abptTextures[0].bpt_toTexture.SetData_t(opo.opo_Material->omt_Name);
|
|
|
|
bpo.bpo_abptTextures[1].bpt_toTexture.SetData_t(opo.opo_Material->omt_strName2);
|
|
|
|
bpo.bpo_abptTextures[2].bpt_toTexture.SetData_t(opo.opo_Material->omt_strName3);
|
|
|
|
// set polygon index
|
|
|
|
opo.opo_Index = iPolygon;
|
|
|
|
// set polygon color
|
|
|
|
bpo.bpo_colColor = opo.opo_colorColor;
|
|
|
|
// set polygon mapping
|
|
|
|
bpo.bpo_abptTextures[0].bpt_mdMapping = opo.opo_amdMappings[0];
|
|
|
|
bpo.bpo_abptTextures[1].bpt_mdMapping = opo.opo_amdMappings[1];
|
|
|
|
bpo.bpo_abptTextures[2].bpt_mdMapping = opo.opo_amdMappings[2];
|
|
|
|
bpo.bpo_mdShadow = opo.opo_amdMappings[3];
|
|
|
|
// set sector pointer
|
|
|
|
bpo.bpo_pbscSector = this;
|
|
|
|
|
|
|
|
// copy polygon properties
|
|
|
|
const int sizeTextureProperties = sizeof(bpo.bpo_abptTextures[0].bpt_auProperties);
|
|
|
|
const int sizePolygonProperties = sizeof(CBrushPolygonProperties);
|
|
|
|
ASSERT(sizeof(opo.opo_ubUserData)>=sizePolygonProperties+3*sizeTextureProperties);
|
|
|
|
UBYTE *pubUserData = (UBYTE*)&opo.opo_ubUserData;
|
|
|
|
memcpy(&bpo.bpo_bppProperties, pubUserData, sizePolygonProperties);
|
|
|
|
memcpy(&bpo.bpo_abptTextures[0].bpt_auProperties,
|
|
|
|
pubUserData+sizePolygonProperties+0*sizeTextureProperties,
|
|
|
|
sizeTextureProperties);
|
|
|
|
memcpy(&bpo.bpo_abptTextures[1].bpt_auProperties,
|
|
|
|
pubUserData+sizePolygonProperties+1*sizeTextureProperties,
|
|
|
|
sizeTextureProperties);
|
|
|
|
memcpy(&bpo.bpo_abptTextures[2].bpt_auProperties,
|
|
|
|
pubUserData+sizePolygonProperties+2*sizeTextureProperties,
|
|
|
|
sizeTextureProperties);
|
|
|
|
bpo.bpo_colShadow = *(ULONG*)(pubUserData+sizePolygonProperties+3*sizeTextureProperties),
|
|
|
|
|
|
|
|
// set polygon flags
|
|
|
|
bpo.bpo_ulFlags = opo.opo_ulFlags & ~(OPOF_IGNOREDBYCSG|BPOF_SELECTED);
|
|
|
|
|
|
|
|
// if the polygon was just created
|
|
|
|
if(!(bpo.bpo_ulFlags&BPOF_WASBRUSHPOLYGON)) {
|
|
|
|
// initialize its textures and properties properly
|
|
|
|
bpo.bpo_bppProperties.bpp_ubShadowBlend = 1;
|
|
|
|
bpo.bpo_colShadow = C_WHITE|CT_OPAQUE;
|
|
|
|
|
|
|
|
bpo.bpo_abptTextures[0].s.bpt_colColor = C_WHITE|CT_OPAQUE;
|
|
|
|
bpo.bpo_abptTextures[0].s.bpt_ubFlags = BPTF_DISCARDABLE;
|
|
|
|
bpo.bpo_abptTextures[0].s.bpt_ubScroll = 0;
|
|
|
|
bpo.bpo_abptTextures[0].s.bpt_ubBlend = BPT_BLEND_OPAQUE;
|
|
|
|
|
|
|
|
bpo.bpo_abptTextures[1].s.bpt_colColor = C_WHITE|CT_OPAQUE;
|
|
|
|
bpo.bpo_abptTextures[1].s.bpt_ubFlags = BPTF_DISCARDABLE;
|
|
|
|
bpo.bpo_abptTextures[1].s.bpt_ubScroll = 0;
|
|
|
|
bpo.bpo_abptTextures[1].s.bpt_ubBlend = BPT_BLEND_SHADE;
|
|
|
|
|
|
|
|
bpo.bpo_abptTextures[2].s.bpt_colColor = C_WHITE|CT_OPAQUE;
|
|
|
|
bpo.bpo_abptTextures[2].s.bpt_ubFlags = BPTF_DISCARDABLE;
|
|
|
|
bpo.bpo_abptTextures[2].s.bpt_ubScroll = 0;
|
|
|
|
bpo.bpo_abptTextures[2].s.bpt_ubBlend = BPT_BLEND_SHADE;
|
|
|
|
|
|
|
|
bpo.bpo_ulFlags|=BPOF_WASBRUSHPOLYGON;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if it was a wall, but it became a portal now
|
|
|
|
if (!(bpo.bpo_ulFlags&BPOF_WASPORTAL) && (bpo.bpo_ulFlags&OPOF_PORTAL)) {
|
|
|
|
// turn on usual portal flags
|
|
|
|
bpo.bpo_ulFlags |= (BPOF_PASSABLE|BPOF_PORTAL);
|
|
|
|
// make its first texture translucent
|
|
|
|
bpo.bpo_abptTextures[0].s.bpt_ubBlend = BPT_BLEND_BLEND;
|
|
|
|
// make its shadow additive
|
|
|
|
bpo.bpo_bppProperties.bpp_ubShadowBlend = BPT_BLEND_ADD;
|
|
|
|
|
|
|
|
// if it was a portal, but it became a wall now
|
|
|
|
} else if ((bpo.bpo_ulFlags&BPOF_WASPORTAL) && !(bpo.bpo_ulFlags&OPOF_PORTAL)) {
|
|
|
|
// turn off usual portal flags
|
|
|
|
bpo.bpo_ulFlags &= ~(BPOF_PASSABLE|BPOF_PORTAL);
|
|
|
|
// make its first texture opaque
|
|
|
|
bpo.bpo_abptTextures[0].s.bpt_ubBlend = BPT_BLEND_OPAQUE;
|
|
|
|
// make its shadow shading
|
|
|
|
bpo.bpo_bppProperties.bpp_ubShadowBlend = BPT_BLEND_SHADE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the brush of this sector
|
|
|
|
CBrush3D *pbr = bsc_pbmBrushMip->bm_pbrBrush;
|
|
|
|
ASSERT(pbr!=NULL);
|
|
|
|
// if the brush is field
|
|
|
|
if (pbr->br_pfsFieldSettings!=NULL) {
|
|
|
|
// set polygon flags for fields
|
|
|
|
bpo.bpo_ulFlags|=BPOF_PORTAL|BPOF_PASSABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the number of edges in object polygon
|
|
|
|
INDEX ctPolygonEdges = opo.opo_PolygonEdges.Count();
|
|
|
|
// create that much edges in brush polygon
|
|
|
|
bpo.bpo_abpePolygonEdges.New(ctPolygonEdges);
|
|
|
|
|
|
|
|
// for all edges in object polygon
|
|
|
|
INDEX iPolygonEdge=0;
|
|
|
|
FOREACHINDYNAMICARRAY(opo.opo_PolygonEdges, CObjectPolygonEdge, itope) {
|
|
|
|
// get corresponding polygon edge in brush polygon
|
|
|
|
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[iPolygonEdge];
|
|
|
|
// set edge reference
|
|
|
|
bpe.bpe_pbedEdge = &bsc_abedEdges[itope->ope_Edge->oed_Index];
|
|
|
|
// set backward flag
|
|
|
|
bpe.bpe_bReverse = itope->ope_Backward;
|
|
|
|
|
|
|
|
iPolygonEdge++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// unlock the object elements
|
|
|
|
osc.UnlockAll();
|
|
|
|
// unlock the brush elements
|
|
|
|
UnlockAll();
|
|
|
|
|
|
|
|
// update changed sector's data after dragging vertices or importing
|
|
|
|
UpdateSector();
|
|
|
|
}
|