#include "SceneDesignerFrameworkPCH.h" #include "MFramework.h" #include "MTextureCombination.h" #include "Utility.h" #include "TextureSearchPath.h" #include using namespace Emergent::Gamebryo::SceneDesigner::Framework; MTextureCombination::MTextureCombination(System::Windows::Forms::Control* topLevelWnd, System::Windows::Forms::Control* renderWnd) : m_pkRenderer(NULL) { m_mapTexture2Model = new map*>; // 纹理名称-使用该纹理的模型 影射 m_mapModel2Texture = new map*>; m_mapTexture2Size = new map; m_mapTextureRectes = new map; m_pkStream = NiNew NiStream; bool bResult = _CreateRenderer(topLevelWnd->Handle, renderWnd->Handle); } //--------------------------------------------------------------------------- void MTextureCombination::Init(System::Windows::Forms::Control* topLevelWnd, System::Windows::Forms::Control* renderWnd) { #if _MSC_VER == 1310 __crt_dll_initialize(); #endif if (ms_pmThis == NULL) { ms_pmThis = new MTextureCombination(topLevelWnd, renderWnd); } } //--------------------------------------------------------------------------- void MTextureCombination::Shutdown() { if (ms_pmThis != NULL) { ms_pmThis->_Dispose(); ms_pmThis = NULL; } #if _MSC_VER == 1310 __crt_dll_terminate(); #endif } //--------------------------------------------------------------------------- void MTextureCombination::_Dispose() { if (m_mapTexture2Model != NULL) { map*>::iterator iter = m_mapTexture2Model->begin(); while (iter != m_mapTexture2Model->end()) { iter->second->clear(); delete iter->second; } m_mapTexture2Model->clear(); delete m_mapTexture2Model; m_mapTexture2Model = NULL; } if (m_mapModel2Texture != NULL) { map*>::iterator iter = m_mapModel2Texture->begin(); while (iter != m_mapModel2Texture->end()) { iter->second->clear(); delete iter->second; } m_mapModel2Texture->clear(); delete m_mapModel2Texture; m_mapModel2Texture = NULL; } if (m_mapTexture2Size != NULL) { m_mapTexture2Size->clear(); delete m_mapTexture2Size; m_mapTexture2Size = NULL; } if (m_mapTextureRectes != NULL) { m_mapTextureRectes->clear(); delete m_mapTextureRectes; m_mapTextureRectes = NULL; } if (m_pkStream != NULL) { NiDelete m_pkStream; m_pkStream = NULL; } } //--------------------------------------------------------------------------- bool MTextureCombination::InstanceIsValid() { return (ms_pmThis != NULL); } //--------------------------------------------------------------------------- MTextureCombination* MTextureCombination::get_Instance() { //if (NULL == ms_pmThis) //{ // Init(); //} return ms_pmThis; } //--------------------------------------------------------------------------- bool MTextureCombination::_CreateRenderer(IntPtr hTopLevelWndPtr, IntPtr hRendererWndPtr) { HWND hTopLevelWnd = (HWND) hTopLevelWndPtr.ToInt32(); HWND hRendererWnd = (HWND) hRendererWndPtr.ToInt32(); RECT rect; NIVERIFY(::GetClientRect(hRendererWnd, &rect)); if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0) { return false; } m_pkRenderer = NiDX9Renderer::Create(0, 0, NiDX9Renderer::USE_STENCIL | NiDX9Renderer::USE_MANUALDEPTHSTENCIL, hTopLevelWnd, hTopLevelWnd); if (m_pkRenderer) { MInitRefObject(m_pkRenderer); // Create swap chain render target group for render window. NiDX9Renderer* pkDX9Renderer = (NiDX9Renderer*) m_pkRenderer; if (pkDX9Renderer->CreateSwapChainRenderTargetGroup( NiDX9Renderer::USE_STENCIL, hRendererWnd)) { m_pkMainRenderTarget = pkDX9Renderer->GetSwapChainRenderTargetGroup( hRendererWnd); MAssert(m_pkMainRenderTarget != NULL, "Swap chain render " "target group not found!"); } else { MDisposeRefObject(m_pkRenderer); m_pkRenderer = NULL; } } else { return false; } return true; } //--------------------------------------------------------------------------- void MTextureCombination::GetModelByTexture(String* textureName, String* modelArray[]) { if (NULL == m_mapTexture2Model || NULL == textureName) { return; } const char* pcTextureName = MStringToCharPointer(textureName); vector* pModelList = (*m_mapTexture2Model)[string(pcTextureName)]; if (pModelList != NULL) { for (unsigned int i=0; isize(); i++) { modelArray[i] = new String((*pModelList)[i].c_str()); } } MFreeCharPointer(pcTextureName); } //--------------------------------------------------------------------------- // 根据纹理尺寸获取纹理名称 void MTextureCombination::GetTextureFileNamesBySize(int iSize, String* textureArray[]) { map::iterator iter = m_mapTexture2Size->begin(); int iIdx = 0; while (iter != m_mapTexture2Size->end()) { if (iter->second==iSize || iSize==0) { textureArray[iIdx++] = new String(iter->first.c_str()); } iter++; } } //--------------------------------------------------------------------------- // 设置目标纹理目录 void MTextureCombination::SetTextureFolder(System::String* strTextureFolder) { if (System::IO::Directory::Exists(strTextureFolder)) { m_strTextureFolder = strTextureFolder; } } //--------------------------------------------------------------------------- // 设置目标模型目录 void MTextureCombination::SetModelFolder(System::String* strModelfolder) { if (System::IO::Directory::Exists(strModelfolder)) { m_strModelFolder = strModelfolder; } } //--------------------------------------------------------------------------- void MTextureCombination::RelodeTextureModelInfo() { /* * 1. 初始化. 包括 MFramework 初始化, 为 NiStream 设置纹理的搜索路径, 清空原影射信息 */ if (MFramework::Instance == NULL) { MFramework::Init(); } if (m_strTextureFolder==NULL) { return; } CTextureSearchPath* pTexSearchPath = NiNew CTextureSearchPath; const char* pcSearchPath = MStringToCharPointer(m_strTextureFolder); pTexSearchPath->AddSearchPath(pcSearchPath, strlen(pcSearchPath)); MFreeCharPointer(pcSearchPath); m_pkStream->SetSearchPath(pTexSearchPath); // 清空所有旧影射信息 _Clear(); /* * 2. 搜集纹理信息,填充 纹理名称-纹理尺寸 map */ // 获取模型所在路径下所有文件 vector modelFileList; vector textureFileList; // 将所有 dds 文件名放如 textureFileList 中 String* textureFiles[] = System::IO::Directory::GetFileSystemEntries(m_strTextureFolder); for (int i=0; iLength; i++) { String* fileName = System::IO::Path::GetFileName(textureFiles[i]); String* fileExtension = System::IO::Path::GetExtension(textureFiles[i]); if (fileExtension->ToLower()->Equals(new String(".dds"))) { const char* pcFileName = MStringToCharPointer(fileName); const char* pcFullPath = MStringToCharPointer(textureFiles[i]); textureFileList.push_back(string(pcFileName)); // 载入该纹理,填充 纹理-尺寸 列表 NiSourceTexture::SetDestroyAppDataFlag( false ); NiSourceTexturePtr pkTexture = NiSourceTexture::Create(pcFullPath); pkTexture->LoadPixelDataFromFile(); NiSourceTexture::SetDestroyAppDataFlag(true); if (pkTexture) { (*m_mapTexture2Size)[pcFileName] = max(pkTexture->GetWidth(), pkTexture->GetHeight()); } MFreeCharPointer(pcFullPath); MFreeCharPointer(pcFileName); } } /* * 3. 搜集模型信息, 填充 纹理-模型 和 模型-纹理 map */ if (m_strModelFolder != NULL) { String* modelFiles[] = System::IO::Directory::GetFileSystemEntries(m_strModelFolder); for (int i=0; iLength; i++) { String* fileName = System::IO::Path::GetFileName(modelFiles[i]); String* fileExtension = System::IO::Path::GetExtension(modelFiles[i]); if (fileExtension->ToLower()->Equals(new String(".nif"))) { const char* pcFileFullPath = MStringToCharPointer(modelFiles[i]); // 载入该模型,找出模型所用的所有纹理 m_pkStream->RemoveAllObjects(); bool bResult = m_pkStream->Load(pcFileFullPath); MFreeCharPointer(pcFileFullPath); if (!bResult) { continue; } NiAVObject* pkAVObj = (NiAVObject*)(m_pkStream->GetObjectAt(0)); vector* textureList = new vector; // 从 AVObj 中搜索所有所使用的纹理名称 _GetUseTextures(pkAVObj, *textureList); if (textureList->size()>0) { const char* pcModelFileName = MStringToCharPointer(fileName); string strModelFileName(pcModelFileName); // 填充 Model - Texture map (*m_mapModel2Texture)[strModelFileName] = textureList; MFreeCharPointer(pcModelFileName); // 填充 Texture - Model map for (unsigned int j=0; jsize(); j++) { map*>::iterator iter = m_mapTexture2Model->find((*textureList)[j]); if (iter != m_mapTexture2Model->end())// 找到了 { vector* pModelList = iter->second; bool bFound = false; for (unsigned int k=0; ksize(); k++) { if ((*pModelList)[k] == strModelFileName) { bFound = true; break; } } if (!bFound) { pModelList->push_back(strModelFileName); } } else { vector* pModelList = new vector; pModelList->push_back(strModelFileName); string strTexName = (*textureList)[j]; (*m_mapTexture2Model)[strTexName] = pModelList; } } } } } } } //--------------------------------------------------------------------------- void MTextureCombination::_GetUseTextures(NiAVObject* pkAVObj, vector& textureList) { NiTexturingProperty* pkTexProp = (NiTexturingProperty*)pkAVObj->GetProperty(NiTexturingProperty::GetType()); if (pkTexProp) { const NiTPrimitiveArray& mapArray = pkTexProp->GetMaps(); for (unsigned int i=0; iGetTexture(); if (NiIsKindOf(NiSourceTexture, pkTexture)) { string strTexFileName = ((NiSourceTexture*)pkTexture)->GetFilename(); bool bFound = false; for (unsigned int j=0; jGetChildCount(); i++) { NiAVObject* pkChild = pkNode->GetAt(i); _GetUseTextures(pkChild, textureList); } } } //--------------------------------------------------------------------------- // 合并纹理并且修改对应模型 bool MTextureCombination::CombineTexturesAndChangeModelUV(String* strSourceTextures[], int iTargetSize, String* strCompressType, String* strCombinedTextureFullPath, bool bBackupOldModel) { /* * 1. 检查待合并纹理对应的模型的 UV 是否可修改. */ // 遍历源纹理,找到纹理对应的模型. for (int i=0; iLength; i++) { const char* pcTextureName = MStringToCharPointer(strSourceTextures[i]); string strTextureName(pcTextureName); MFreeCharPointer(pcTextureName); vector* modelList = (*m_mapTexture2Model)[strTextureName]; if (modelList == NULL) { continue; } // 遍历 modelList, 载入每个模型,判断其是否可以重新影射 UV for (unsigned int j=0; jsize(); j++) { string strModelName = (*modelList)[j]; const char* pcModelFolder = MStringToCharPointer(m_strModelFolder); string strModelFolder(pcModelFolder); MFreeCharPointer(pcModelFolder); string strModelFullPath = strModelFolder+strModelName; // 模型文件全路径 m_pkStream->RemoveAllObjects(); bool bResult = m_pkStream->Load(strModelFullPath.c_str()); if (!bResult) { char tmp[256]; sprintf_s(tmp, "文件装载失败:%s\n", strModelFullPath.c_str()); ::MessageBox(NULL, tmp,"警告", MB_OK); return false; } NiAVObject* pkSceneRoot = (NiAVObject*)m_pkStream->GetObjectAt(0); if (pkSceneRoot != NULL) { if (!_CanResetUV(pkSceneRoot, strTextureName)) { char tmp[256]; sprintf_s(tmp, "不能重新设置 UV 的模型:%s. 该模型有两张纹理共用一套 UV. \n", strModelFullPath.c_str()); ::MessageBox(NULL, tmp,"警告", MB_OK); return false; } } } } /* * 2. 合并纹理 */ NiSourceTexturePtr pkTargetTexture = _CombineTextures(strSourceTextures, iTargetSize); if (pkTargetTexture == NULL) { return false; } /* * 3. 检查 Over Board UV */ map::iterator iter = m_mapTextureRectes->begin(); // 检查需要修改的模型是否有超界 UV while (iter != m_mapTextureRectes->end()) { // 遍历该纹理对应的模型 string strOldTextureName = iter->first; vector* modelList = (*m_mapTexture2Model)[strOldTextureName]; if (modelList == NULL) { iter++; continue; } for (unsigned int j=0; jsize(); j++) { string strModelName = (*modelList)[j]; // 载入该模型,现备份。然后修改 UV const char* pcModelFolder = MStringToCharPointer(m_strModelFolder); string strModelFolder(pcModelFolder); MFreeCharPointer(pcModelFolder); string strModelFullPath = strModelFolder+strModelName; m_pkStream->RemoveAllObjects(); bool bResult = m_pkStream->Load(strModelFullPath.c_str()); if (!bResult) { char tmp[256]; sprintf_s(tmp, "文件装载失败:%s\n", strModelFullPath.c_str()); ::MessageBox(NULL, tmp,"警告", MB_OK); continue; } NiAVObject* pkSceneRoot = (NiAVObject*)m_pkStream->GetObjectAt(0); if (_CheckOverBoardUV(pkSceneRoot, NULL, strOldTextureName)) { char tmp[256]; sprintf_s(tmp, "%s 对应纹理 %s 的UV 有不在0~1之间的,不适合合并纹理.\n", strModelName.c_str(), strOldTextureName.c_str()); ::MessageBox(NULL, tmp,"警告", MB_OK); return false; } } iter++; } /* * 4. 保存纹理 */ const char* pcTargetTextureFullPath = MStringToCharPointer(strCombinedTextureFullPath); SaveTextureToDDS(pkTargetTexture, pcTargetTextureFullPath); char szTargetTextureName[256]; ExtractFileNameFromPath(pcTargetTextureFullPath, szTargetTextureName); MFreeCharPointer(pcTargetTextureFullPath); /* * 5. 修改纹理对应的模型 */ if (!_ResetModelUV(szTargetTextureName, bBackupOldModel)) { return false; } return true; } //--------------------------------------------------------------------------- // 预览纹理合并 bool MTextureCombination::PreviewCombineTextures(String* strSourceTextures[], int iTargetSize, String* strCompressType) { // 合并纹理保存到临时文件 NiSourceTexturePtr pkTargetTexture = _CombineTextures(strSourceTextures, iTargetSize); if (pkTargetTexture == NULL) { return false; } SaveTextureToDDS(pkTargetTexture, "_tmpTex.dds"); // 打开保存的临时纹理 system("dxtex _tmpTex.dds"); return true; } //--------------------------------------------------------------------------- NiSourceTexturePtr MTextureCombination::_CombineTextures(String* strSourceTextures[], int iTargetSize) { // 总体思路: 将纹理按照从大到小排序, 然后按行放到目标纹理中 m_iTargetWidth = m_iTargetHeight = iTargetSize; list openRectList; // 待使用的 rect 列表 RECT rectTarget; rectTarget.left = rectTarget.top = 0; rectTarget.right = rectTarget.bottom = iTargetSize-1; openRectList.push_back(rectTarget); // 1. 将所有纹理都先载入 const char* pcTextureFolder = MStringToCharPointer(m_strTextureFolder); string strTextureFolder(pcTextureFolder); // convert .net String to stl string MFreeCharPointer(pcTextureFolder); map mapSourceTextures; for (int i=0; iLength; i++) { const char* pcTextureFile = MStringToCharPointer(strSourceTextures[i]); string strTextureFile(pcTextureFile); // 纹理的文件名 string strTextureFullPath = strTextureFolder + strTextureFile; // 纹理的全路径名 MFreeCharPointer(pcTextureFile); NiSourceTexture::SetDestroyAppDataFlag(false); NiSourceTexturePtr pkTexture = NiSourceTexture::Create(strTextureFullPath.c_str()); pkTexture->LoadPixelDataFromFile(); NiSourceTexture::SetDestroyAppDataFlag(true); mapSourceTextures[strTextureFile] = pkTexture; } // 2. 从 1024 遍历到 32. 为该纹理分配 rect m_mapTextureRectes->clear(); for (int i=1024; i>=32; i=i>>1) { // 遍历所有纹理,如果纹理尺寸为i, 为该纹理分配 rect map::iterator iter = mapSourceTextures.begin(); while (iter != mapSourceTextures.end()) { NiSourceTexture* pkTexture = iter->second; string strTexName = iter->first; // 在 m_mapTExtureRectes 中搜索 pkTexture.看是否已经为该纹理分配了空间. map::iterator iter2 = m_mapTextureRectes->find(strTexName); if (iter2 != m_mapTextureRectes->end()) { // 找到了,已经分配过了 iter++; continue; } if (pkTexture->GetWidth()==i || pkTexture->GetHeight()==i) { // 为 pkTexture 分配 rect RECT rectTex; if (!_ArrangeRectForTexture(openRectList, pkTexture, rectTex)) { // 没有能容纳该纹理的空间 ::MessageBox(NULL, "目标纹理尺寸太小,无法容纳所有需合并的纹理.", "警告", MB_OK); return NULL; } (*m_mapTextureRectes)[iter->first] = rectTex; } iter++; } } // 3. 创建目标纹理, 将 source texture 拷贝到对应 rect NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiPixelData *pPixelData = NiNew NiPixelData( iTargetSize, iTargetSize, NiPixelFormat::RGBA32 ); NiSourceTexture::SetDestroyAppDataFlag( false ); NiSourceTexturePtr pkTargetTexture = NiSourceTexture::Create( pPixelData ); pkTargetTexture->SetStatic( false ); NiSourceTexture::SetDestroyAppDataFlag( true ); map::iterator iter = m_mapTextureRectes->begin(); while (iter != m_mapTextureRectes->end()) { NiSourceTexture* pkSource = mapSourceTextures[iter->first]; RECT rectTarget = iter->second; if (!_CopyTextureToTexture(pkSource, rectTarget, pkTargetTexture)) { iter++; continue; } iter++; } return pkTargetTexture; } //--------------------------------------------------------------------------- bool MTextureCombination::_ArrangeRectForTexture(list& openRect, NiSourceTexture* pkTexture, RECT& rectTexture) { // 思路: // 1. 遍历 openRect, 找到的第一个能容纳 pkTexture 的 RECT // 2. 从找到的 RECT 的左上角切割出一个 textureRect 分配给 pkTexture. // 3. 从 openRect 中删除被切割的 RECT, 将切割后剩余的两块 rect(右上及下方的)插入到原RECT 的位置. list::iterator iter = openRect.begin(); while (iter != openRect.end()) { RECT rectSource = *iter; unsigned int iWidth = (unsigned int)(rectSource.right - rectSource.left)+1; unsigned int iHeight = (unsigned int) (rectSource.bottom - rectSource.top)+1; if (iWidth>=pkTexture->GetWidth() && iHeight>=pkTexture->GetHeight()) { // 找到了第一个能容纳目标纹理的 rect // 为目标纹理分配 rect rectTexture.left = rectSource.left, rectTexture.right = rectSource.left + pkTexture->GetWidth()-1; rectTexture.top = rectSource.top, rectTexture.bottom = rectSource.top + pkTexture->GetHeight()-1; // 从 openRect 中删除 找到的 RECT iter = openRect.erase(iter); // 分配右上的 rect if (iWidth != pkTexture->GetWidth()) { RECT rectRT; rectRT.left = rectTexture.right + 1; rectRT.right = rectSource.right; rectRT.top = rectSource.top; rectRT.bottom = rectTexture.bottom; openRect.insert(iter, rectRT); } // 分配下方的 rect if (iHeight != pkTexture->GetHeight()) { RECT rectBottom; rectBottom = rectSource; rectBottom.top = rectTexture.bottom+1; openRect.insert(iter, rectBottom); } return true; } iter++; } // 没有找到能容纳 目标纹理 的 RECT return false; } //--------------------------------------------------------------------------- bool MTextureCombination::_CopyTextureToTexture(NiSourceTexture* pkSource, RECT rectTarget, NiSourceTexture* pkTarget) { if (pkSource==NULL || pkTarget ==NULL) { return false; } int iWidth = rectTarget.right-rectTarget.left+1; int iHeight = rectTarget.bottom-rectTarget.top+1; if (pkSource->GetWidth()!=iWidth || pkSource->GetHeight()!=iHeight) { System::Windows::Forms::MessageBox::Show("源纹理尺寸与目标 RECT 不符."); return false; } NiPixelData* pSourcePixelData = pkSource->GetSourcePixelData(); NiPixelData* pTargetPixelData = pkTarget->GetSourcePixelData(); if (NULL==pSourcePixelData || NULL==pTargetPixelData ) { System::Windows::Forms::MessageBox::Show("获取纹理像素数据失败."); return false; } const NiPixelFormat& pkSourceFormat = pSourcePixelData->GetPixelFormat(); const NiPixelFormat& pkTargetFormat = pTargetPixelData->GetPixelFormat(); if (pkSourceFormat!=pkTargetFormat) { // 如果 source texture 的 像素格式与 target texture 的像素格式不符, // 使用 NiImageConverter 转换 source texture 的像素后再拷贝 NiDevImageConverter kImgConverter; if (!kImgConverter.CanConvertPixelData(pkSourceFormat, pkTargetFormat)) { System::Windows::Forms::MessageBox::Show("源纹理像素无法转换到 RGBA32 格式,合并失败."); return false; } NiPixelData* pkNewSourcePixelData = NiNew NiPixelData(pkSource->GetWidth(), pkSource->GetHeight(), NiPixelFormat::RGBA32 ); if (NULL == pkNewSourcePixelData) { return false; } kImgConverter.ConvertPixelData(*pSourcePixelData, pkTargetFormat, pkNewSourcePixelData, false); pSourcePixelData = pkNewSourcePixelData; } int iOffsetX = rectTarget.left; int iOffsetY = rectTarget.top; // for (int m=0; mMarkAsChanged(); return true; } //--------------------------------------------------------------------------- bool MTextureCombination::_CanResetUV(NiAVObject* pkAVObj, string strTexName) { // 判断一个 AVObj 的 UV 是否可以重新影射. NiTexturingProperty* pkTexProp = (NiTexturingProperty*)pkAVObj->GetProperty(NiTexturingProperty::GetType()); if (pkTexProp != NULL) { const NiTPrimitiveArray& mapArray = pkTexProp->GetMaps(); vector texIdxList; // 除了 strTexName 外其他 texture 用的 uv coordinate id unsigned int uiTargetIndex = -1; // strTexName 对应的 uv coordinate id for (unsigned int i=0; iGetTexture(); if (NiIsKindOf(NiSourceTexture, pkTexture)) { string strTexFileName = ((NiSourceTexture*)pkTexture)->GetFilename(); if (strTexFileName == strTexName) { int uiTargetIndex = pkMap->GetTextureIndex(); } else { texIdxList.push_back(pkMap->GetTextureIndex()); } } } for (unsigned int i=0; iGetChildCount(); i++) { NiAVObject* pkChild = pkNode->GetAt(i); if (pkChild!=NULL && !_CanResetUV(pkChild, strTexName)) { return false; } } } return true; } //--------------------------------------------------------------------------- bool MTextureCombination::_CheckOverBoardUV(NiAVObject* pkAVObj, NiTexturingProperty* pkParentTexProp, string strTargetTexName) { // 检查 pkAVObj 中 strTargetTexName 对应的 UV 是否有超过 0~1 范围的. NiTexturingProperty* pkTexProp = (NiTexturingProperty*)pkAVObj->GetProperty(NiTexturingProperty::GetType()); if (pkTexProp != NULL) { pkParentTexProp = pkTexProp; } if (NiIsKindOf(NiGeometry, pkAVObj)) { // 找到 strTargetTexName 使用哪一层 UV if (pkParentTexProp != NULL) { int iUVIndex = -1; const NiTPrimitiveArray& mapArray = pkTexProp->GetMaps(); for (unsigned int i=0; iGetTexture(); if (NiIsKindOf(NiSourceTexture, pkTexture)) { string strTexFileName = ((NiSourceTexture*)pkTexture)->GetFilename(); if (strTexFileName == strTargetTexName) { iUVIndex = pkMap->GetTextureIndex(); break; } } } if (iUVIndex >= 0) { NiGeometry* pkGeom = (NiGeometry*)pkAVObj; NiPoint2* pkUV = pkGeom->GetTextureSet(iUVIndex); unsigned int uiNumVerts = pkGeom->GetVertexCount(); for (unsigned int i=0; i1.0f||pkUV[i].y<0.0f || pkUV[i].y>1.0f) { // 有超界的 uv return true; } } // 没有 return false; } } else { return false; } } else if(NiIsKindOf(NiNode, pkAVObj)) { // 检查所有子结点 NiNode* pkNode = (NiNode*)pkAVObj; for (int i=0; iGetChildCount(); i++) { NiAVObject* pkChild = pkNode->GetAt(i); if (_CheckOverBoardUV(pkChild, pkParentTexProp, strTargetTexName)) { return true; } } } return false; } //--------------------------------------------------------------------------- void MTextureCombination::_CollectAllTexProp(NiAVObject* pkAVObj, NiTexturingProperty* pkParentTexProp, map*>& mapTexProp2Geom) { // 参数合法性检查 if (NULL == pkAVObj) { return; } // 获取 pkAVObj 的 纹理信息 NiTexturingProperty* pkThisTexProp = (NiTexturingProperty*)pkAVObj->GetProperty(NiTexturingProperty::GetType()); if (pkThisTexProp == NULL) { pkThisTexProp = pkParentTexProp; } if (NiIsKindOf(NiNode, pkAVObj)) { // 如果 pkAVObj 是一个 group, 遍历所有子节点 NiNode* pkNode = (NiNode*)pkAVObj; for (unsigned int i=0; iGetChildCount(); i++) { _CollectAllTexProp(pkNode->GetAt(i), pkThisTexProp, mapTexProp2Geom); } } else { if (pkThisTexProp != NULL) { if (NiIsKindOf(NiGeometry, pkAVObj)) { map*>::iterator iter = mapTexProp2Geom.find(pkThisTexProp); if (iter == mapTexProp2Geom.end()) { // mapTexProp2Geom 中还没有该 texProp, 新建一个 vector 添加到 map 中 vector* geomList = new vector; mapTexProp2Geom[pkThisTexProp] = geomList; geomList->push_back((NiGeometry*)pkAVObj); } else { // mapTexProp2Geom 中已经有该 texProp, 将其对应的 geomList 找出,将当前 pkAVOjb 添加到里边. vector* geomList = iter->second; // 查看 pkAVObj 是否已经在 geomList中.如果不在,添加到 geomList 中. bool bFound = false; for (unsigned int i=0; isize(); i++) { if ((*geomList)[i] == pkAVObj) { bFound = true; break; } } if (!bFound) { geomList->push_back((NiGeometry*)pkAVObj); } } } } else { return; } } } //--------------------------------------------------------------------------- // 重设模型 uv bool MTextureCombination::_ResetModelUV(const char* pszCombinedTextureFileName, bool bBackUPOldModel) { // 遍历 纹理-矩形 影射中的每一张纹理 map::iterator iter = m_mapTextureRectes->begin(); while (iter != m_mapTextureRectes->end()) { // 遍历该纹理对应的模型 string strOldTextureName = iter->first; // 计算目标 UV RECT rectTarget = iter->second; NiPoint2 kUTarget((float)rectTarget.left/m_iTargetWidth, (float)(rectTarget.right+1)/m_iTargetWidth); NiPoint2 kVTarget((float)rectTarget.top/m_iTargetHeight, (float)(rectTarget.bottom+1)/m_iTargetHeight); vector* modelList = (*m_mapTexture2Model)[strOldTextureName]; if (modelList == NULL) { iter++; continue; } for (unsigned int j=0; jsize(); j++) { string strModelName = (*modelList)[j]; // 载入该模型,现备份。然后修改 UV const char* pcModelFolder = MStringToCharPointer(m_strModelFolder); string strModelFolder(pcModelFolder); MFreeCharPointer(pcModelFolder); string strModelFullPath = strModelFolder+strModelName; m_pkStream->RemoveAllObjects(); bool bResult = m_pkStream->Load(strModelFullPath.c_str()); if (!bResult) { char tmp[256]; sprintf_s(tmp, "文件装载失败:%s\n", strModelFullPath.c_str()); ::MessageBox(NULL, tmp,"警告", MB_OK); continue; } if (bBackUPOldModel) { // 备份该模型 DWORD dwTime = GetTickCount(); //int uiNow = System::DateTime::Now::get_Millisecond(); char _tmp[256]; string strBackUpPath = strModelFullPath + "." + itoa(dwTime, _tmp, 10); m_pkStream->Save(strBackUpPath.c_str()); } NiAVObject* pkAVObj = (NiAVObject*)(m_pkStream->GetObjectAt(0)); if (NULL != pkAVObj) { // 搜集该 pkAVObj 的所有 NiTexturingProperty 及其对应的 NiGeometry map*> mapTexProp2Geom; _CollectAllTexProp(pkAVObj, NULL, mapTexProp2Geom); // 遍历 mapTexProp2Geom.找到使用 strTextureName 这个纹理的 所有 Geometry. // 修改 strTextureName 这个纹理所在层的 uv 值 // 将 geometry 对应的 texture name 改为 pszCombinedTextureFullPath 的文件部分. map*>::iterator iter2 = mapTexProp2Geom.begin(); while (iter2 != mapTexProp2Geom.end()) { NiTexturingProperty* pkTexProp = iter2->first; const NiTPrimitiveArray& mapArray = pkTexProp->GetMaps(); for (unsigned int i=0; iGetTexture(); if (NiIsKindOf(NiSourceTexture, pkTexture)) { string strTexFileName = ((NiSourceTexture*)pkTexture)->GetFilename(); if (strTexFileName == strOldTextureName) { ((NiSourceTexture*)pkTexture)->SetFilename(pszCombinedTextureFileName); // 需要修改 pkTexProp 对应所有 geometry 的 UV 值 vector* pGeomList = iter2->second; for (unsigned int k=0; ksize(); k++) { NiGeometry* pkGeom = (*pGeomList)[k]; _ResetModelUV(pkGeom, pkMap->GetTextureIndex(), kUTarget, kVTarget); } } } } iter2++; } pkAVObj->Update(0.0f); // 修改一个 nif 的 UV 完成.保存该 nif //m_pkStream->RemoveAllObjects(); //m_pkStream->InsertObject(pkAVObj); NiStream kStream; kStream.InsertObject(pkAVObj); kStream.Save(strModelFullPath.c_str()); //m_pkStream->Save("saved.nif"); } } // End of 遍历使用该纹理的所有模型 iter++; } // End of 遍历 纹理-矩形 影射中的每一张纹理 return true; } //--------------------------------------------------------------------------- // 重设UV bool MTextureCombination::_ResetModelUV(NiGeometry* pkGeom, unsigned int iUVCoordID, NiPoint2 kUTarget, NiPoint2 kVTarget) { if (iUVCoordID > pkGeom->GetTextureSets()) { return false; } NiGeometryData::Consistency oldConsistency = pkGeom->GetConsistency(); pkGeom->SetConsistency(NiGeometryData::MUTABLE); NiPoint2* pkTargetUV = pkGeom->GetTextureSet(iUVCoordID); unsigned int iNumVerts = pkGeom->GetVertexCount(); for (unsigned int i=0; i1.0 || pkTargetUV[i].x<-1.0 || pkTargetUV[i].y>1.0 || pkTargetUV[i].y<-1.0) { return false; } } for (unsigned int i=0; iMarkAsChanged(NiGeometryData::VERTEX_MASK | NiGeometryData::NORMAL_MASK | NiGeometryData::COLOR_MASK); pkGeom->GetModelData()->MarkAsChanged(NiGeometryData::TEXTURE_MASK); pkGeom->Update(0.0f); pkGeom->SetConsistency(oldConsistency); return true; } //--------------------------------------------------------------------------- void MTextureCombination::_Clear() { m_mapTexture2Model->clear(); // 纹理名称-使用该纹理的模型 影射 m_mapModel2Texture->clear(); // 模型-模型使用的纹理 影射 m_mapTexture2Size->clear(); // 纹理名称 - 纹理尺寸 影射 m_mapTextureRectes->clear(); // 纹理名称 - 分配的 RECT 影射 }