/*========================================================================= * * Merge.c - merge functions * * Version 1.0 * Revision date * *=======================================================================*/ #include "Merge.h" #include "print.h" #include "ModLib.h" #include "ModLoad.h" //--- Macros --------------------------------------------------------- #define MLT_M_xEpsilon 1e-3 #define MLT_M_bVectorEqualWithEpsilon( _p_stVect1_, _p_stVect2_)\ (\ ( MTH_M_bEqualWithEpsilon((_p_stVect1_)->xX, (_p_stVect2_)->xX, MLT_M_xEpsilon ))\ && ( MTH_M_bEqualWithEpsilon((_p_stVect1_)->xY, (_p_stVect2_)->xY, MLT_M_xEpsilon ))\ && ( MTH_M_bEqualWithEpsilon((_p_stVect1_)->xZ, (_p_stVect2_)->xZ, MLT_M_xEpsilon ))\ ) //--- Global statics --------------------------------------------------------- static char gs_szMergedName[ SCR_CV_ui_Cfg_MaxLenName ]; //-------------------------------------------------------------------- /**************************************************************************** * Description: merge super object child if needed (recursive function) * * Parameters: _hSO : SuperObject to treat *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ void MLT_vMergeObjectsInHierarchy ( MLT_tdxHandleToSuperObject _hSO ) { MLT_tdxHandleToSuperObject *hCurrentChild, *hLastChild, *hSecondChild, *hThirdChild; long lGroupIndex; tdstMergeData *p_stMergeData; // init pointers hCurrentChild = _hSO->d_hChild; hLastChild = hCurrentChild + _hSO->lNbChild; for (; hCurrentChild < hLastChild; hCurrentChild++) { // check if this is an element lGroupIndex = MLT_lMergeGetIndexAndName( (*hCurrentChild)->sName, gs_szMergedName); if ( lGroupIndex != -1 ) { // create data and search for all item in group p_stMergeData = MLT_pstMergeDataCreate( gs_szMergedName, _hSO->lNbChild ); MLT_vMergeDataAddSO( p_stMergeData, *hCurrentChild, lGroupIndex ); for( hSecondChild = hCurrentChild + 1; hSecondChild < hLastChild; hSecondChild++) { lGroupIndex = MLT_lMergeGetIndexAndName( (*hSecondChild)->sName, gs_szMergedName); if ( (lGroupIndex != -1) && (stricmp( gs_szMergedName, p_stMergeData->szSOName) == 0) ) MLT_vMergeDataAddSO( p_stMergeData, *hSecondChild, lGroupIndex ); } // Merge geometric object MLT_vComputeNewGeometric( p_stMergeData ); // update super object (flags and SPOFlags must not be erased !) strcpy(_hSO->sName, p_stMergeData->szSOName); lGroupIndex = MLT_lMergeGetIndexAndName( (*hCurrentChild)->p_stMatrix->sName, gs_szMergedName); strcpy(_hSO->p_stMatrix->sName, gs_szMergedName); strcpy(_hSO->sGeometric, p_stMergeData->szObjName); // update hierarchy hSecondChild = hThirdChild = hCurrentChild; for( ; hSecondChild < hLastChild; hSecondChild++) { lGroupIndex = MLT_lMergeDataGetSOIndex( p_stMergeData, *hSecondChild ); if (lGroupIndex == -1) *hThirdChild++ = *hSecondChild; } // update children of super-object _hSO->lNbChild -= p_stMergeData->lNumberOfSO; hLastChild -= p_stMergeData->lNumberOfSO; //free merge data MLT_vMergeDataFree( p_stMergeData ); } // test next level else MLT_vMergeObjectsInHierarchy(*hCurrentChild); } } /**************************************************************************** * Description: merge geometric object associated with the SO to be merged * * Parameters: _p_stMergeData : merge data initialized with list of SO to merge *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ void MLT_vComputeNewGeometric ( tdstMergeData *_p_stMergeData ) { long lIndex; long lGroupIndex; MLT_tdstGeometricObject *p_stObj; // allocate memory to store geometric pointer _p_stMergeData->d_p_stObject = (MLT_tdstGeometricObject **) malloc( sizeof(MLT_tdstGeometricObject *) * _p_stMergeData->lNumberOfSO); // get all geometric object to store for ( lIndex = 0; lIndex < _p_stMergeData->lNumberOfSO; lIndex++ ) { _p_stMergeData->d_p_stObject[lIndex] = p_stObj = MLT_pFindInLib( _p_stMergeData->d_hSO[lIndex]->sGeometric ); if(p_stObj == NULL) { MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", _p_stMergeData->d_hSO[lIndex]->sGeometric); return; } if (lIndex == 0) lGroupIndex = MLT_lMergeGetIndexAndName( p_stObj->sName, _p_stMergeData->szObjName ); else p_stObj->bNotForSave = TRUE; } // merge all elements _p_stMergeData->p_stMergedObject = p_stObj = (MLT_tdstGeometricObject *) malloc( sizeof(MLT_tdstGeometricObject) ); memset( p_stObj, 0, sizeof(MLT_tdstGeometricObject) ); strcpy( p_stObj->sName, _p_stMergeData->szObjName ); // count number of point, element, vertex, ... for (lIndex = 0; lIndex < _p_stMergeData->lNumberOfSO; lIndex++ ) { p_stObj->lNbLod = _p_stMergeData->d_p_stObject[lIndex]->lNbLod; p_stObj->xNbPoints += _p_stMergeData->d_p_stObject[lIndex]->xNbPoints; p_stObj->xNbElements += _p_stMergeData->d_p_stObject[lIndex]->xNbElements; p_stObj->xNbEdges += _p_stMergeData->d_p_stObject[lIndex]->xNbEdges; } // allocate new object MLT_xAllocateGeometric( p_stObj ); // merge geometric data MLT_vMergeGeometric( _p_stMergeData ); // put new object in lib, in place of old one memcpy( _p_stMergeData->d_p_stObject[0], _p_stMergeData->p_stMergedObject, sizeof(MLT_tdstGeometricObject) ); } /**************************************************************************** * Description: merge geometric element into result geometric object * * Parameters: _p_stMergeData : merge data initialized with list of SO Object and allocated result object *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ void MLT_vMergeGeometric ( tdstMergeData *_p_stMergeData ) { long lIndex; MLT_tdstGeometricObject *p_stObj; MLT_tdstGeometricObject *p_stCurObj; long *d_lIndex, *p_stCurIndex; long **d_p_lObjFirstVert; MTH3D_tdstVector stTranslation; MTH3D_tdstVector *p_stCurrentVertex, *p_stVertex, *p_stLastVertex; MTH3D_tdstVector *p_stSearchVertex, *p_stLastSearchVertex; long *p_lCurElementType; void **pp_vCurElement, **pp_vLastElem, **pp_vSearchElement; MLT_tdstElementIndexedTriangles *p_stETIT; MLT_tdstElementSprite *p_stESt; MLT_tdstTripledIndex *p_stFace, *p_stLastFace; MLT_tdstIndexedSprite *p_stSprite, *p_stLastSprite; // allocate array for vertices index correspondance p_stObj = _p_stMergeData->p_stMergedObject; d_lIndex = (long *) calloc( p_stObj->xNbPoints, sizeof(long) ); d_p_lObjFirstVert = (long **) malloc (_p_stMergeData->lNumberOfSO * sizeof(long *) ); // copy all points of first object p_stCurObj = _p_stMergeData->d_p_stObject[0]; memcpy( p_stObj->d_stListOfPoints, p_stCurObj->d_stListOfPoints, p_stCurObj->xNbPoints * sizeof( MTH3D_tdstVector ) ); memcpy( p_stObj->d_stListOfPointsNormals, p_stCurObj->d_stListOfPointsNormals, p_stCurObj->xNbPoints * sizeof( MTH3D_tdstVector ) ); memcpy( p_stObj->d_stListOfPointsReceivedLightIntensity, p_stCurObj->d_stListOfPointsReceivedLightIntensity, p_stCurObj->xNbPoints * sizeof( MLT_tdstColor ) ); d_p_lObjFirstVert[0] = d_lIndex; p_stCurrentVertex = p_stObj->d_stListOfPoints + p_stCurObj->xNbPoints; // now copy all points of others object for ( lIndex = 1; lIndex < _p_stMergeData->lNumberOfSO; lIndex++) { MTH3D_M_vSubVector( &stTranslation, &_p_stMergeData->d_hSO[lIndex]->p_stMatrix->stTranslation, &_p_stMergeData->stOrigin ); d_p_lObjFirstVert[ lIndex ] = d_p_lObjFirstVert[ lIndex - 1 ] + p_stCurObj->xNbPoints; p_stCurObj = _p_stMergeData->d_p_stObject[ lIndex ]; p_stVertex = p_stCurObj->d_stListOfPoints; p_stLastVertex = p_stVertex + p_stCurObj->xNbPoints; p_stCurIndex = d_p_lObjFirstVert[ lIndex ]; p_stLastSearchVertex = p_stCurrentVertex; for ( ; p_stVertex < p_stLastVertex; p_stVertex++, p_stCurIndex++) { MTH3D_M_vAddVector( p_stVertex, p_stVertex, &stTranslation ); // search in all previous point for a equal point for (p_stSearchVertex = p_stObj->d_stListOfPoints; p_stSearchVertex < p_stLastSearchVertex; p_stSearchVertex++) { if( MLT_M_bVectorEqualWithEpsilon( p_stVertex, p_stSearchVertex ) ) { *p_stCurIndex = p_stSearchVertex - p_stObj->d_stListOfPoints; break; } } if (p_stSearchVertex == p_stLastSearchVertex) { MTH3D_M_vCopyVector( p_stCurrentVertex, p_stVertex ); *p_stCurIndex = p_stCurrentVertex++ - p_stObj->d_stListOfPoints; } } } // recompute number of points p_stObj->xNbPoints = p_stCurrentVertex - p_stObj->d_stListOfPoints; // copy first object element without change p_stCurObj = _p_stMergeData->d_p_stObject[0]; p_lCurElementType = p_stObj->d_xListOfElementsTypes; pp_vCurElement = p_stObj->d_stListOfElements; memcpy( p_lCurElementType, p_stCurObj->d_xListOfElementsTypes, p_stCurObj->xNbElements * sizeof( long) ); memcpy( pp_vCurElement, p_stCurObj->d_stListOfElements, p_stCurObj->xNbElements * sizeof( long) ); p_lCurElementType += p_stCurObj->xNbElements; pp_vCurElement += p_stCurObj->xNbElements; // add others element with change to vertices point for (lIndex = 1; lIndex < _p_stMergeData->lNumberOfSO; lIndex++) { p_stCurObj = _p_stMergeData->d_p_stObject[ lIndex ]; memcpy( p_lCurElementType, p_stCurObj->d_xListOfElementsTypes, p_stCurObj->xNbElements * sizeof( long) ); memcpy( pp_vCurElement, p_stCurObj->d_stListOfElements, p_stCurObj->xNbElements * sizeof( long) ); pp_vLastElem = pp_vCurElement + p_stCurObj->xNbElements; for (; pp_vCurElement < pp_vLastElem; pp_vCurElement++, p_lCurElementType++) { switch( *p_lCurElementType ) { case 1: p_stETIT = (MLT_tdstElementIndexedTriangles *) *pp_vCurElement; p_stFace = p_stETIT->d_stListOfFacesTripled; p_stLastFace = p_stFace + p_stETIT->xNbFaces; for ( ; p_stFace < p_stLastFace ; p_stFace++ ) { p_stFace->a3_xIndex[0] = d_p_lObjFirstVert[lIndex][ p_stFace->a3_xIndex[0] ]; p_stFace->a3_xIndex[1] = d_p_lObjFirstVert[lIndex][ p_stFace->a3_xIndex[1] ]; p_stFace->a3_xIndex[2] = d_p_lObjFirstVert[lIndex][ p_stFace->a3_xIndex[2] ]; } break; case 3: p_stESt = (MLT_tdstElementSprite *) pp_vCurElement; p_stSprite = p_stESt->d_stListOfSprites; p_stLastSprite = p_stSprite + p_stESt->xNbSprites; for ( ; p_stSprite < p_stLastSprite ; p_stSprite++ ) { p_stSprite->xCenterPoint = d_p_lObjFirstVert[lIndex][ p_stSprite->xCenterPoint ]; } break; } } } // compute all element bounding box index and name pp_vCurElement = p_stObj->d_stListOfElements; pp_vLastElem = pp_vCurElement + p_stObj->xNbElements; p_lCurElementType = p_stObj->d_xListOfElementsTypes; for ( ; pp_vCurElement < pp_vLastElem; pp_vCurElement++, p_lCurElementType++ ) { p_stETIT = (MLT_tdstElementIndexedTriangles *) *pp_vCurElement; p_stETIT->xIndexOfParallelBox = (ACP_tdxIndex) MLT_lMergeGetIndexAndName( p_stETIT->sName, gs_szMergedName); // look if element name is duplicate pp_vSearchElement = p_stObj->d_stListOfElements; for ( ; pp_vSearchElement < pp_vCurElement; pp_vSearchElement++ ) { if (stricmp( gs_szMergedName, ((MLT_tdstElementIndexedTriangles *) (*pp_vSearchElement))->sName) == 0) break; } if (pp_vSearchElement != pp_vCurElement) sprintf( p_stETIT->sName, "%s%d", gs_szMergedName, p_stETIT->xIndexOfParallelBox ); else strcpy( p_stETIT->sName, gs_szMergedName ); } } /**************************************************************************** * Description: create a merge data structure and allocate memory to store information * * Parameters: _szName : name of merged group * _lNumberMax : number max of element in group *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ tdstMergeData *MLT_pstMergeDataCreate ( char *_szName, long _lNumberMax ) { tdstMergeData *p_stMergeData; p_stMergeData = (tdstMergeData *) malloc (sizeof( tdstMergeData ) ); strcpy( p_stMergeData->szSOName, _szName ); p_stMergeData->d_hSO = (MLT_tdxHandleToSuperObject *) malloc ( sizeof(MLT_tdxHandleToSuperObject) * _lNumberMax ); p_stMergeData->d_lIndex = (long *) malloc ( sizeof(long) * _lNumberMax ); p_stMergeData->lNumberOfSO = 0; p_stMergeData->d_p_stObject = NULL; return p_stMergeData; } /**************************************************************************** * Description: free merge data. (no parameters validity check ) * * Parameters: p_stMergeData : merge data to deallocate *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ void MLT_vMergeDataFree ( tdstMergeData *_p_stMergeData ) { free( _p_stMergeData->d_hSO ); free( _p_stMergeData->d_lIndex ); free( _p_stMergeData->d_p_stObject ); free( _p_stMergeData ); } /**************************************************************************** * Description: add a super-object to the list of data to merge * * Parameters: _p_stMergeData : merge data to update * _hSO : super-object to add * _lGroupIndex : index of the element *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ void MLT_vMergeDataAddSO( tdstMergeData *_p_stMergeData, MLT_tdxHandleToSuperObject _hSO, long _lGroupIndex ) { // if first element of group get merged object origin and move element at start of list if (_lGroupIndex == 0) { MTH3D_M_vCopyVector( &_p_stMergeData->stOrigin, &_hSO->p_stMatrix->stTranslation ); if (_p_stMergeData->lNumberOfSO != 0) { _p_stMergeData->d_hSO[ _p_stMergeData->lNumberOfSO ] = _p_stMergeData->d_hSO[0]; _p_stMergeData->d_lIndex[ _p_stMergeData->lNumberOfSO ] = _p_stMergeData->d_lIndex[0]; } _p_stMergeData->d_hSO[0] = _hSO; _p_stMergeData->d_lIndex[0] = 0; } else { _p_stMergeData->d_hSO[ _p_stMergeData->lNumberOfSO ] = _hSO; _p_stMergeData->d_lIndex[ _p_stMergeData->lNumberOfSO ] = _lGroupIndex; } _p_stMergeData->lNumberOfSO++; } /**************************************************************************** * Description: get index in group of a SO * * Parameters: _p_stMergeData : merge data to search * _hSO : super-object to search *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ long MLT_lMergeDataGetSOIndex ( tdstMergeData *_p_stMergeData, MLT_tdxHandleToSuperObject _hSO ) { long lIndex; for (lIndex = 0; lIndex < _p_stMergeData->lNumberOfSO; lIndex++) { if ( _p_stMergeData->d_hSO[lIndex] == _hSO ) return _p_stMergeData->d_lIndex[lIndex]; } return -1; } /**************************************************************************** * Description: get group index and name from a spo or object name * * Parameters: _szName : name to parse * _szResultName : result name *--------------------------------------------------------------------------- * Revision date: Author: *****************************************************************************/ long MLT_lMergeGetIndexAndName ( char *_szName, char *_szResultName ) { char *szGroupChar, *szEndGroup; long lGroupIndex; long lLength; if ( (szGroupChar = strchr( _szName, '&')) == NULL ) return -1; // it's a super object to be grouped szEndGroup = szGroupChar + 1; lGroupIndex = 0; while ( 1 ) { if (!isdigit(*szEndGroup)) break; lGroupIndex = lGroupIndex*10 + *szEndGroup++ - '0'; } // compute transformed name lLength = szGroupChar - _szName; memcpy( _szResultName, _szName, lLength ); strcpy( _szResultName + lLength, szEndGroup ); return lGroupIndex; }