/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ // If you happen to have the Exploration 3D library (in Engine/exploration3d/), you can enable its features here. #define USE_E3D 0 #include "Engine/StdH.h" #include #include #include #include #include #include #include #include #include #if USE_E3D #include #include #endif #undef W #undef NONE void FillConversionArrays_t(const FLOATmatrix3D &mTransform); void ClearConversionArrays( void); void RemapVertices(BOOL bAsOpened); /* * Intermediate structures used for converting from Exploration 3D data format into O3D */ struct ConversionTriangle { INDEX ct_iVtx[3]; // indices of vertices INDEX ct_iTVtx[3]; // indices of texture vertices INDEX ct_iMaterial; // index of material }; struct ConversionMaterial { ULONG cm_ulTag; // for recognition of material CTString cm_strName; // material's name COLOR cm_colColor; // material's color CDynamicContainer ms_Polygons; // indices of polygons in this material }; // conversion arrays CDynamicContainer acmMaterials; CStaticArray actTriangles; CStaticArray avVertices; CStaticStackArray avDst; CStaticArray avTextureVertices; CStaticArray aiRemap; ///////////////////////////////////////////////////////////////////////////// // Helper functions //-------------------------------------------------------------------------------------------- class CObjectSectorLock { private: CObjectSector *oscl_posc; // ptr to object sector that will do lock/unlock public: CObjectSectorLock( CObjectSector *posc); // lock all object sector arrays ~CObjectSectorLock(); // unlock all object sector arrays }; //-------------------------------------------------------------------------------------------- /* * To lock all object 3D dyna arrays one must create an instance of CObject3DLock. * Locking job is done inside class constructor */ CObjectSectorLock::CObjectSectorLock( CObjectSector *posc) { ASSERT( posc != NULL); oscl_posc = posc; posc->LockAll(); } //-------------------------------------------------------------------------------------------- /* * Unlocking of all object 3D dynamic arrays will occur automatically when exiting * current scope (routine). This is done in class destructor */ CObjectSectorLock::~CObjectSectorLock() { oscl_posc->UnlockAll(); } //-------------------------------------------------------------------------------------------- // function makes Little-Big indian conversion of 4 bytes and returns valid SLONG inline SLONG ConvertLong( SBYTE *pfm) { UBYTE i; UBYTE ret_long[ 4]; for( i=0; i<4; i++) ret_long[ i] = *((UBYTE *) pfm + 3 - i); return( *((SLONG *) ret_long) ); }; //-------------------------------------------------------------------------------------------- // function makes Little-Big indian conversion of 2 bytes and returns valid WORD inline INDEX ConvertWord( SBYTE *pfm) { char aret_word[ 2]; aret_word[ 0] = *(pfm+1); aret_word[ 1] = *(pfm+0); INDEX ret_word = (INDEX) *((SWORD *) aret_word); return( ret_word); }; //-------------------------------------------------------------------------------------------- // function makes Little-Big indian conversion of 4 bytes representing float and returns valid float inline float ConvertFloat( SBYTE *pfm) { UBYTE i; char float_no[ 4]; for( i=0; i<4; i++) float_no[ i] = *( pfm + 3 - i); return( *((float *) float_no) ); }; //-------------------------------------------------------------------------------------------- // function recognizes and loads many 3D file formats, throws char* errors #if USE_E3D HINSTANCE _h3dExploration = NULL; TInitExploration3D _Init3d; e3_API*_api; e3_SCENE*_pe3Scene; e3_OBJECT *_pe3Object; HWND _hwnd; BOOL _bBatchLoading = FALSE; #endif // start/end batch loading of 3d objects void CObject3D::BatchLoading_t(BOOL bOn) { #if USE_E3D // check for dummy calls if (!_bBatchLoading==!bOn) { return; } // if turning on if (bOn) { // if exploration library not yet loaded if( _h3dExploration == NULL) { // prepare registry REG_SetString("HKEY_LOCAL_MACHINE\\SOFTWARE\\X Dimension\\SeriousEngine\\Plugins\\LWO\\BreakObject", "0"); REG_SetString("HKEY_LOCAL_MACHINE\\SOFTWARE\\X Dimension\\SeriousEngine\\Plugins\\LWO\\textures", "1"); REG_SetString("HKEY_LOCAL_MACHINE\\SOFTWARE\\X Dimension\\SeriousEngine\\Plugins\\LWO\\chkwrap", "1"); REG_SetString("HKEY_LOCAL_MACHINE\\SOFTWARE\\X Dimension\\SeriousEngine\\Plugins\\LWO\\readUView", "1"); // load the dll _h3dExploration = LoadLibrary(EXPLORATION_LIBRRAY); // if library not opened if(_h3dExploration == NULL) { throw("3D Exploration dll not found !"); } _Init3d=(TInitExploration3D)GetProcAddress(_h3dExploration,"InitExploration3D"); CTString strPlugins = _fnmApplicationPath+"Bin\\3DExplorationPlugins"; e3_INIT init; memset(&init,0,sizeof(init)); init.e_size = sizeof(init); init.e_registry = "Software\\X Dimension\\SeriousEngine"; init.e_plugins = (char*)(const char*)strPlugins; if(_Init3d) { _api=_Init3d(&init); } else { throw("Unable to initialize 3D object library"); } } // if 3dexp window not open yet if (_hwnd==NULL) { // obtain window needed for 3D exploration library to work _hwnd=CreateWindow(EXPLORATION_WINDOW,"Object Loader",0,100,100,100,50,NULL,0,(HINSTANCE) GetModuleHandle( NULL),0); //ShowWindow(_hwnd, SW_HIDE); } // if turning off } else { // if 3dexp window is open if (_hwnd!=NULL) { // close it DestroyWindow(_hwnd); _hwnd = NULL; } } _bBatchLoading = bOn; #else throw("3D Exploration is disabled in this build."); #endif } void CObject3D::LoadAny3DFormat_t( const CTFileName &fnmFileName, const FLOATmatrix3D &mTransform, enum LoadType ltLoadType/*= LT_NORMAL*/) { #if USE_E3D BOOL bWasOn = _bBatchLoading; try { if (!_bBatchLoading) { BatchLoading_t(TRUE); } // call file load with file's full path name CTString strFile = _fnmApplicationPath+fnmFileName; char acFile[MAX_PATH]; wsprintf(acFile,"%s",strFile); e3_LoadFile(_hwnd, acFile); _pe3Scene=e3_GetScene(_hwnd); // if scene is successefuly loaded if(_pe3Scene != NULL) { _pe3Object = _pe3Scene->GetObject3d( 0); // use different methods to convert into Object3D switch( ltLoadType) { case LT_NORMAL: FillConversionArrays_t(mTransform); ConvertArraysToO3D(); break; case LT_OPENED: FillConversionArrays_t(mTransform); RemapVertices(TRUE); ConvertArraysToO3D(); break; case LT_UNWRAPPED: FLOATmatrix3D mOne; mOne.Diagonal(1.0f); FillConversionArrays_t(mOne); if( avTextureVertices.Count() == 0) { ThrowF_t("Unable to import mapping from 3D object because it doesn't contain mapping coordinates."); } RemapVertices(FALSE); ConvertArraysToO3D(); break; } ClearConversionArrays(); } else { ThrowF_t("Unable to load 3D object: %s", (const char *)fnmFileName); } if (!bWasOn) { BatchLoading_t(FALSE); } } catch (char *) { if (!bWasOn) { BatchLoading_t(FALSE); } throw; } #endif } /* * Converts data from Exploration3D format into arrays used for conversion to O3D */ void FillConversionArrays_t(const FLOATmatrix3D &mTransform) { #if USE_E3D // all polygons must be triangles if(_pe3Object->_facecount != 0) { throw("Error: Not all polygons are triangles!"); } // check if we need flipping (if matrix is flipping, polygons need to be flipped) const FLOATmatrix3D &m = mTransform; FLOAT fDet = m(1,1)*(m(2,2)*m(3,3)-m(2,3)*m(3,2))+ m(1,2)*(m(2,3)*m(3,1)-m(2,1)*m(3,3))+ m(1,3)*(m(2,1)*m(3,2)-m(2,2)*m(3,1)); FLOAT bFlipped = fDet<0; // ------------ Convert object vertices (coordinates) INDEX ctVertices = _pe3Object->pointcount; avVertices.New(ctVertices); // copy vertices for( INDEX iVtx=0; iVtxpoints[iVtx])*mTransform; avVertices[iVtx](1) = -avVertices[iVtx](1); avVertices[iVtx](3) = -avVertices[iVtx](3); } // ------------ Convert object's mapping vertices (texture vertices) INDEX ctTextureVertices = _pe3Object->txtcount; avTextureVertices.New(ctTextureVertices); // copy texture vertices for( INDEX iTVtx=0; iTVtxtxtpoints[iTVtx]; } // ------------ Organize triangles as list of surfaces // allocate triangles INDEX ctTriangles = _pe3Object->facecount; actTriangles.New(ctTriangles); acmMaterials.Lock(); // sort triangles per surfaces for( INDEX iTriangle=0; iTriangleGetFace( iTriangle); // copy vertex indices if (bFlipped) { ctTriangle.ct_iVtx[0] = pe3Triangle->v[2]; ctTriangle.ct_iVtx[1] = pe3Triangle->v[1]; ctTriangle.ct_iVtx[2] = pe3Triangle->v[0]; } else { ctTriangle.ct_iVtx[0] = pe3Triangle->v[0]; ctTriangle.ct_iVtx[1] = pe3Triangle->v[1]; ctTriangle.ct_iVtx[2] = pe3Triangle->v[2]; } // copy texture vertex indices if (bFlipped) { ctTriangle.ct_iTVtx[0] = pe3Triangle->t[2]; ctTriangle.ct_iTVtx[1] = pe3Triangle->t[1]; ctTriangle.ct_iTVtx[2] = pe3Triangle->t[0]; } else { ctTriangle.ct_iTVtx[0] = pe3Triangle->t[0]; ctTriangle.ct_iTVtx[1] = pe3Triangle->t[1]; ctTriangle.ct_iTVtx[2] = pe3Triangle->t[2]; } // obtain material e3_MATERIAL *pe3Mat = pe3Triangle->material; BOOL bNewMaterial = TRUE; // attach triangle into one material for( INDEX iMat=0; iMatcm_ulTag = (ULONG) pe3Mat; // ---------- Set material's name // if not default material if( pe3Mat != NULL && pe3Mat->name != NULL) { acmMaterials[iNewMaterial].cm_strName = CTString(pe3Mat->name); // get color COLOR colColor = CLR_CLRF( pe3Mat->GetDiffuse().rgb()); acmMaterials[iNewMaterial].cm_colColor = colColor; } else { acmMaterials[iNewMaterial].cm_strName = "Default"; acmMaterials[iNewMaterial].cm_colColor = C_GRAY; } } } acmMaterials.Unlock(); #endif } void ClearConversionArrays( void) { acmMaterials.Clear(); actTriangles.Clear(); avVertices.Clear(); avTextureVertices.Clear(); aiRemap.Clear(); } void RemapVertices(BOOL bAsOpened) { {INDEX ctSurf = 0; // fill remap array with indices of vertices in order how they appear per polygons {FOREACHINDYNAMICCONTAINER(acmMaterials, ConversionMaterial, itcm) { _RPT1(_CRT_WARN, "Indices of polygons in surface %d:", ctSurf); // for each polygon in surface {FOREACHINDYNAMICCONTAINER(itcm->ms_Polygons, INDEX, itipol) { _RPT1(_CRT_WARN, " %d,", *itipol); }} _RPT0(_CRT_WARN, "\n"); ctSurf++; }} _RPT0(_CRT_WARN, "Polygons and their vertex indices:\n"); for( INDEX ipol=0; ipolms_Polygons, INDEX, itipol) { INDEX idxPol = *itipol; // for each vertex in polygon for(INDEX iVtx=0; iVtx<3; iVtx++) { // get vertex's index INDEX idxVtx = actTriangles[idxPol].ct_iVtx[iVtx]; if( aiRemap[idxVtx] == -1) { aiRemap[idxVtx] = ctvx; ctvx++; } } }} INDEX ctOld = avDst.Count(); // allocate new block of vertices used in this surface FLOAT3D *pavDst = avDst.Push( ctvx); // for each polygon in surface {FOREACHINDYNAMICCONTAINER(itcm->ms_Polygons, INDEX, itipol) { INDEX iPol=*itipol; // for each vertex in polygon for(INDEX iVtx=0; iVtx<3; iVtx++) { // get vertex's index INDEX idxVtx = actTriangles[iPol].ct_iVtx[iVtx]; // get remapped index INDEX iRemap = aiRemap[idxVtx]; // if cutting object if( bAsOpened) { // copy vertex coordinate pavDst[ iRemap] = avVertices[idxVtx]; } // if creating unwrapped mapping else { // copy texture coordinate FLOAT3D vMap; vMap(1) = avTextureVertices[actTriangles[iPol].ct_iTVtx[iVtx]](1); vMap(2) = -avTextureVertices[actTriangles[iPol].ct_iTVtx[iVtx]](2); vMap(3) = 0; pavDst[ iRemap] = vMap; } // remap index of polygon vertex actTriangles[iPol].ct_iVtx[iVtx] = iRemap+ctOld; } }} } aiRemap.Clear(); // replace remapped array of vertices over original one avVertices.Clear(); avVertices.New(avDst.Count()); for( INDEX iVtxNew=0; iVtxNewms_Polygons, INDEX, itipol) { _RPT1(_CRT_WARN, " %d,", *itipol); }} _RPT0(_CRT_WARN, "\n"); ctSurf++; }} _RPT0(_CRT_WARN, "Polygons and their vertex indices:\n"); for( INDEX ipol=0; ipolomt_Color; // create and set plane popl[iTri] = DOUBLEplane3D( *pVtx0, *pVtx1, *pVtx2); popo[iTri].opo_Plane = &popl[iTri]; } acmMaterials.Unlock(); }