/* 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. */ #include "Engine/StdH.h" #include #include #include #include #include #include #include #include #include #include static const INDEX _iSupportedVersion = 14; static INDEX _ctPolygonsLoaded; #define BPOV_OLD 0 #define BPOV_WITHHYPERTEXTURES 1 #define BPOV_MULTITEXTURING 2 #define BPOV_FAKEPORTALFLAG 3 #define BPOV_TRIANGLES 4 #define BPOV_CURRENT BPOV_TRIANGLES #define BSCV_OLD 0 #define BSCV_WITHNAME 1 #define BSCV_WITHFLAGS2 2 #define BSCV_WITHVISFLAGS 3 #define BSCV_CURRENT BSCV_WITHVISFLAGS /* * Write to stream. */ void CBrush3D::Write_t( CTStream *postrm) // throw char * { ASSERT(GetFPUPrecision()==FPT_53BIT); (*postrm).WriteID_t("BR3D"); // 'brush 3D' // write the brush version (*postrm)<<_iSupportedVersion; // write number of brush mips (*postrm)<Write_t(postrm); } (*postrm).WriteID_t("BREN"); // 'brush 3D end' } /* * Read from stream. */ void CBrush3D::Read_t( CTStream *pistrm) // throw char * { ASSERT(GetFPUPrecision()==FPT_53BIT); (*pistrm).ExpectID_t("BR3D"); // 'brush 3D' // read the version number INDEX iSavedVersion; (*pistrm)>>iSavedVersion; // if the version number is the newest if(iSavedVersion==_iSupportedVersion) { // read current version Read_new_t(pistrm); // if the version number is not the newest } else { // if the version can be converted if (iSavedVersion==_iSupportedVersion-1) { // show warning WarningMessage( TRANS("The brush version was %d.\n" "Auto-converting to version %d."), iSavedVersion, _iSupportedVersion); // read previous version Read_old_t(pistrm); } else { // report error ThrowF_t( TRANS("The brush version on disk is %d.\n" "Current supported version is %d."), iSavedVersion, _iSupportedVersion); } } } /* * Read from stream -- previous version. */ void CBrush3D::Read_old_t( CTStream *pistrm) // throw char * { _ctPolygonsLoaded = 0; // read number of brush mips INDEX ctMips; (*pistrm)>>ctMips; // for each mip for(INDEX iMip=0; iMipbm_lnInBrush); // read it from stream pbmMip->Read_old_t(pistrm); // set back-pointer to the brush pbmMip->bm_pbrBrush = this; } (*pistrm).ExpectID_t("BREN"); // 'brush 3D end' _RPT1(_CRT_WARN, "Polygons in brush: %d\n", _ctPolygonsLoaded); } /* * Read from stream -- current version. */ void CBrush3D::Read_new_t( CTStream *pistrm) // throw char * { _ctPolygonsLoaded = 0; // read number of brush mips INDEX ctMips; (*pistrm)>>ctMips; // for each mip for(INDEX iMip=0; iMipbm_lnInBrush); // set back-pointer to the brush pbmMip->bm_pbrBrush = this; // read it from stream pbmMip->Read_new_t(pistrm); } (*pistrm).ExpectID_t("BREN"); // 'brush 3D end' _RPT1(_CRT_WARN, "Polygons in brush: %d\n", _ctPolygonsLoaded); } /* * Write to stream. */ void CBrushMip::Write_t( CTStream *postrm) // throw char * { // write the mip factor postrm->WriteID_t("BRMP"); (*postrm)<Write_t(postrm); } } /* * Read from stream -- previous version. */ void CBrushMip::Read_old_t( CTStream *pistrm) // throw char * { // read number of sectors INDEX ctSectors; (*pistrm)>>ctSectors; // create that much sectors bm_abscSectors.New(ctSectors); bm_abscSectors.Lock(); // for each sector for(INDEX iSector=0; iSectorPeekID_t()==CChunkID("BRMP")) { pistrm->ExpectID_t("BRMP"); bWithMipDistance = TRUE; } (*pistrm)>>bm_fMaxDistance; // if old mip-factor instead max distance if (!bWithMipDistance) { // convert from factor to distance if (bm_fMaxDistance==100.0f) { bm_fMaxDistance = 1E6f; } else { FLOAT fPerspectiveRatio = 640/(2.0f*Tan(90.0f/2)); bm_fMaxDistance = fPerspectiveRatio*pow(2, bm_fMaxDistance)/1024; } } // read number of sectors INDEX ctSectors; (*pistrm)>>ctSectors; // create that much sectors bm_abscSectors.New(ctSectors); bm_abscSectors.Lock(); // for each sector for(INDEX iSector=0; iSector>fnmTexture; SetTextureWithPossibleReplacing_t(bpt_toTexture, fnmTexture); // gather CRC of that texture if (bpt_toTexture.GetData()!=NULL) { bpt_toTexture.GetData()->AddToCRCTable(); } strm>>bpt_mdMapping; strm>>s.bpt_ubScroll; strm>>s.bpt_ubBlend; strm>>s.bpt_ubFlags; strm>>s.bpt_ubDummy; strm>>s.bpt_colColor; } void CBrushPolygonTexture::Write_t( CTStream &strm) // throw char * { strm<Write_t(&itbvx->bvx_vdPreciseRelative, sizeof(DOUBLE3D)); }} (*postrm).WriteID_t("PLNs"); // 'planes' // write the number of planes in brush (*postrm)<Write_t(&itbpl->bpl_pldPreciseRelative, sizeof(DOUBLEplane3D)); }} (*postrm).WriteID_t("EDGs"); // 'edges' // write the number of edges in brush (*postrm)<bed_pbvxVertex0); (*postrm)<bed_pbvxVertex1); }} (*postrm).WriteID_t("BPOs"); // 'brush polygons' (*postrm)<bpe_pbedEdge); // if it is reverse edge if (itbpe->bpe_bReverse) { // set highest bit in the index iEdge |= 0x80000000; } // write the index (*postrm)<0) { (*postrm).Write_t(&bpo.bpo_aiTriangleElements[0], ctElements*sizeof(INDEX)); } // write the shadow-map (if it exists) bpo.bpo_smShadowMap.Write_t(postrm); // write shadow color (*postrm)<>iBSCVersion; if (iBSCVersion=BSCV_WITHNAME) { (*pistrm)>>bsc_strName; } // read sector color and ambient light (*pistrm)>>bsc_colColor; (*pistrm)>>bsc_colAmbient; // read sector flags (*pistrm)>>bsc_ulFlags; if (iBSCVersion>=BSCV_WITHFLAGS2) { (*pistrm)>>bsc_ulFlags2; } if (iBSCVersion>=BSCV_WITHVISFLAGS) { (*pistrm)>>bsc_ulVisFlags; } // clear sector flags for selection bsc_ulFlags &= ~(BSCF_SELECTED | BSCF_SELECTEDFORCSG); // no temp flags initially bsc_ulTempFlags = 0; (*pistrm).ExpectID_t("VTXs"); // 'vertices' // read the number of vertices in brush INDEX ctVertices; (*pistrm)>>ctVertices; // create that much vertices bsc_abvxVertices.New(ctVertices); bsc_awvxVertices.New(ctVertices); // for each vertex {FOREACHINSTATICARRAY(bsc_abvxVertices, CBrushVertex, itbvx) { // read precise vertex coordinates (*pistrm)>>itbvx->bvx_vdPreciseRelative; // remember sector pointer itbvx->bvx_pbscSector = this; }} (*pistrm).ExpectID_t("PLNs"); // 'planes' // read the number of planes in brush INDEX ctPlanes; (*pistrm)>>ctPlanes; // create that much planes bsc_abplPlanes.New(ctPlanes); bsc_awplPlanes.New(ctPlanes); // for each plane {FOREACHINSTATICARRAY(bsc_abplPlanes, CBrushPlane, itbpl) { // read precise plane coordinates (*pistrm)>>itbpl->bpl_pldPreciseRelative; }} (*pistrm).ExpectID_t("EDGs"); // 'edges' // read the number of edges in brush INDEX ctEdges; (*pistrm)>>ctEdges; // create that much edges bsc_abedEdges.New(ctEdges); bsc_awedEdges.New(ctEdges); // for all edges in object {for(INDEX iEdge=0; iEdge>iVertex0; INDEX iVertex1; (*pistrm)>>iVertex1; // set vertex pointers bed.bed_pbvxVertex0 = &bsc_abvxVertices[iVertex0]; bed.bed_pbvxVertex1 = &bsc_abvxVertices[iVertex1]; // set the working edge bed.bed_pwedWorking = &wed; wed.wed_iwvx0 = iVertex0; wed.wed_iwvx1 = iVertex1; }} INDEX iBPOVersion; (*pistrm).ExpectID_t("BPOs"); // 'brush polygons' (*pistrm)>>iBPOVersion; if (iBPOVersion>ctPolygons; _ctPolygonsLoaded += ctPolygons; // create that much polygons bsc_abpoPolygons.New(ctPolygons); // for each polygon {FOREACHINSTATICARRAY(bsc_abpoPolygons, CBrushPolygon, itbpo) { CBrushPolygon &bpo = *itbpo; // read index of the plane INDEX iPlane; (*pistrm)>>iPlane; // set plane pointer bpo.bpo_pbplPlane = &bsc_abplPlanes[iPlane]; if (iBPOVersion>=BPOV_MULTITEXTURING) { // read polygon color (*pistrm)>>bpo.bpo_colColor; // read polygon flags (*pistrm)>>bpo.bpo_ulFlags; // read all textures bpo.bpo_abptTextures[0].Read_t(*pistrm); bpo.bpo_abptTextures[1].Read_t(*pistrm); bpo.bpo_abptTextures[2].Read_t(*pistrm); // read other polygon properties (*pistrm)>>bpo.bpo_bppProperties; } else { // read textures CTFileName fnmTexture; (*pistrm)>>fnmTexture; SetTextureWithPossibleReplacing_t(bpo.bpo_abptTextures[0].bpt_toTexture, fnmTexture); CTFileName fnmHyperTexture; (*pistrm)>>fnmHyperTexture; SetTextureWithPossibleReplacing_t(bpo.bpo_abptTextures[1].bpt_toTexture, fnmHyperTexture); // read polygon color (*pistrm)>>bpo.bpo_colColor; // read polygon flags (*pistrm)>>bpo.bpo_ulFlags; // read texture mapping bpo.bpo_mdShadow.ReadOld_t(*pistrm); // read other polygon properties (*pistrm)>>bpo.bpo_bppProperties; // adjust polygon and texture properties bpo.bpo_abptTextures[0].bpt_mdMapping = bpo.bpo_mdShadow; bpo.bpo_abptTextures[0].s.bpt_ubBlend = BPT_BLEND_OPAQUE; bpo.bpo_abptTextures[0].s.bpt_colColor = C_WHITE|CT_OPAQUE; bpo.bpo_abptTextures[1].bpt_mdMapping = bpo.bpo_mdShadow; bpo.bpo_abptTextures[1].s.bpt_ubBlend = BPT_BLEND_SHADE; bpo.bpo_abptTextures[1].s.bpt_colColor = C_WHITE|CT_OPAQUE; bpo.bpo_abptTextures[2].bpt_mdMapping = bpo.bpo_mdShadow; bpo.bpo_abptTextures[2].s.bpt_ubBlend = BPT_BLEND_SHADE; bpo.bpo_abptTextures[2].s.bpt_colColor = C_WHITE|CT_OPAQUE; bpo.bpo_bppProperties.bpp_ubShadowBlend = BPT_BLEND_SHADE; if (bpo.bpo_ulFlags&BPOF_PORTAL) { bpo.bpo_abptTextures[0].s.bpt_ubBlend = BPT_BLEND_BLEND; bpo.bpo_abptTextures[1].s.bpt_ubBlend = BPT_BLEND_ADD; bpo.bpo_bppProperties.bpp_ubShadowBlend = BPT_BLEND_ADD; } } // if version before fake protal flag if(iBPOVersion>ctPolygonEdges; // create that much polygons edges bpo.bpo_abpePolygonEdges.New(ctPolygonEdges); // for each polygon edge {FOREACHINSTATICARRAY(bpo.bpo_abpePolygonEdges, CBrushPolygonEdge, itbpe) { // read its edge index INDEX iEdge; (*pistrm)>>iEdge; // if the highest bit is set if (iEdge & 0x80000000) { // mark that it is reverse edge itbpe->bpe_bReverse = TRUE; // clear the highest bit iEdge &= ~0x80000000; } else { // mark that it is not reverse edge itbpe->bpe_bReverse = FALSE; } // set edge pointer itbpe->bpe_pbedEdge = &bsc_abedEdges[iEdge]; }} // if triangles are saved if (iBPOVersion>=BPOV_TRIANGLES) { // read number of triangle vertices INDEX ctVertices; (*pistrm)>>ctVertices; // allocate them bpo.bpo_apbvxTriangleVertices.New(ctVertices); // for each triangle vertex {FOREACHINSTATICARRAY(bpo.bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx) { // read its index INDEX ivx; (*pistrm)>>ivx; *itpbvx = &bsc_abvxVertices[ivx]; }} // read number of triangle elements INDEX ctElements; (*pistrm)>>ctElements; // allocate them bpo.bpo_aiTriangleElements.New(ctElements); // read all element indices if (ctElements>0) { for (INDEX i = 0; i < ctElements; i++) { (*pistrm)>>bpo.bpo_aiTriangleElements[i]; } } } // read the shadow-map (if it exists) bpo.bpo_smShadowMap.Read_t(pistrm); if (iBPOVersion>=BPOV_MULTITEXTURING) { // read shadow color (*pistrm)>>bpo.bpo_colShadow; } else { // read shadow animation object index UBYTE ubDummy; (*pistrm)>>ubDummy; bpo.bpo_colShadow = C_WHITE|CT_OPAQUE; } }} // unlock the brush elements UnlockAll(); // calculate the volume of the sector CalculateVolume(); bsc_ulTempFlags&=~BSCTF_PRELOADEDBSP; // if there is current version of bsp saved if ((*pistrm).PeekID_t()==CChunkID("BSP0")) { _pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_READBSP); (*pistrm).ExpectID_t("BSP0"); // read it bsc_bspBSPTree.Read_t(*pistrm); // if read ok if (bsc_bspBSPTree.bt_abnNodes.Count()>0) { // mark that tree doesn't have to be recalculated bsc_ulTempFlags|=BSCTF_PRELOADEDBSP; } _pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_READBSP); } }