#include "StdAfx.h" #include "TerrainMaterial.h" #include "TerrainTextureMgr.h" #include "Terrain.h" #include "SceneDesignerConfig.h" #include #include "utility.h" CTerrainMaterial::CTerrainMaterial(const char *pszL0, const char *pszL1, const char *pszL2, const char *pszL3) : m_iTexIndex( -1 ), m_spSSMaterial( 0 ), m_spShader( 0 ), m_iUsedTexLayer(0) { ZeroMemory(m_pLayerTexture, sizeof(void*)*MAX_LAYER); bool bAddLayer; if ( pszL0 ) SetTexture( string(pszL0), bAddLayer); if ( pszL1 ) SetTexture( string(pszL1), bAddLayer ); if ( pszL2 ) SetTexture( string(pszL2), bAddLayer ); if ( pszL3 ) SetTexture( string(pszL3), bAddLayer ); /*SetTexture( "c:/Shader/Red.BMP" ); SetTexture( "c:/Shader/Green.BMP" ); SetTexture( "c:/Shader/Yello.BMP" ); SetTexture( "c:/Shader/Blue.BMP" );*/ } CTerrainMaterial::~CTerrainMaterial(void) { Destroy(); } bool CTerrainMaterial::Create(const char* pszBlendTexFile, const char* pszPropertyTexFile) { m_spShader = NiShaderFactory::GetInstance()-> RetrieveShader( "TerrainBlender", NiShader::DEFAULT_IMPLEMENTATION, true ); if ( !m_spShader ) return false; m_spSSMaterial = NiSingleShaderMaterial::Create( m_spShader ); if ( !m_spSSMaterial ) return false; #ifndef CODE_INGAME if (!_CreatePropertyTexture(pszPropertyTexFile)) { return false; } #endif if (!CreateBlendTexture(pszBlendTexFile)) { return false; } return true; } bool CTerrainMaterial::Create(const stChunkTextures& pChunkTextueres) { // 创建 shader m_spShader = NiShaderFactory::GetInstance()-> RetrieveShader( "TerrainBlender", NiShader::DEFAULT_IMPLEMENTATION, true ); if ( !m_spShader ) return false; m_spSSMaterial = NiSingleShaderMaterial::Create( m_spShader ); if ( !m_spSSMaterial ) return false; // blend texture m_spBlendTexture = pChunkTextueres.pkBlendTexture; #ifndef CODE_INGAME m_spBlendTexture->LoadPixelDataFromFile(); #endif // 四层纹理 m_iUsedTexLayer = pChunkTextueres.iUsedTextureLayer; for (int i=0; iSetStatic( false ); NiSourceTexture::SetDestroyAppDataFlag( true ); if ( !m_spBlendTexture ) return false; for ( int y = 0; y < BLENDTEX_SIZE; ++y ) { for ( int x = 0; x < BLENDTEX_SIZE; ++x ) { unsigned char *pPtr = ( *pPixelData )(x,y); pPtr[0] = pPtr[1] = pPtr[2] = 0x00; //B,G,R pPtr[3] = 0xFF; //A } } pPixelData->MarkAsChanged(); return true; } else { NiSourceTexture::SetDestroyAppDataFlag( false ); m_spBlendTexture = NiSourceTexture::Create( pszTexFile ); #ifndef CODE_INGAME m_spBlendTexture->LoadPixelDataFromFile(); m_spBlendTexture->SetStatic( false ); #endif NiSourceTexture::SetDestroyAppDataFlag( true ); return (m_spBlendTexture!=NULL); } } /// 设置纹理 int CTerrainMaterial::SetTexture( const string& strTexFile, bool& bAddLayer) { bAddLayer = false; // 如果该纹理已存在,设为当前使用纹理,返回true for (int i=0; i= MAX_LAYER ) return false; // 增加纹理层 NiSourceTexture *pTex = CTerrainTextureMgr::GetInstance()->GetTexture( strTexFile.c_str() ); if ( pTex ) { bAddLayer = true; m_strTexFiles[m_iUsedTexLayer] = strTexFile; m_pLayerTexture[m_iUsedTexLayer] = pTex; m_iTexIndex = m_iUsedTexLayer; m_iUsedTexLayer++; return m_iTexIndex; } else { return -1; } } /************************************************ * 这里是只在编辑器中使用,游戏中不使用的函数 *************************************************/ #ifndef CODE_INGAME bool CTerrainMaterial::_CreatePropertyTexture( const char *pszTexFile) { if (pszTexFile == NULL) { NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiPixelData *pPixelData = NiNew NiPixelData( BLENDTEX_SIZE, BLENDTEX_SIZE, NiPixelFormat::RGBA32 ); NiSourceTexture::SetDestroyAppDataFlag( false ); m_spPropertyTexture = NiSourceTexture::Create( pPixelData ); m_spPropertyTexture->SetStatic( false ); NiSourceTexture::SetDestroyAppDataFlag( true ); if ( !m_spPropertyTexture ) return false; // 有配置表获得空属性的颜色 [7/8/2009 hemeng] NiColor kColor = CSceneDesignerConfig::GetInstance()->GetTerrainSurfacePropertyColor(0); for ( int y = 0; y < BLENDTEX_SIZE; ++y ) { for ( int x = 0; x < BLENDTEX_SIZE; ++x ) { unsigned char *pPtr = ( *pPixelData )(x,y); // 修改原无属性显示黑色为白色 [6/29/2009 hemeng] pPtr[0] = kColor.r * 255; pPtr[1] = kColor.g * 255; pPtr[2] = kColor.b * 255; //B,G,R pPtr[3] = 128; //A } } pPixelData->MarkAsChanged(); return true; } else { NiSourceTexture::SetDestroyAppDataFlag( false ); m_spPropertyTexture = NiSourceTexture::Create( pszTexFile ); m_spPropertyTexture->LoadPixelDataFromFile(); m_spPropertyTexture->SetStatic( false ); NiSourceTexture::SetDestroyAppDataFlag( true ); return (m_spPropertyTexture!=NULL); } } bool CTerrainMaterial::ReplaceTexture(int iLayer, const string& strTexFile) { // 如果该纹理已存在,返回 false for (int i=0; iGetTexture( strTexFile.c_str() ); if ( pTex ) { m_strTexFiles[iLayer] = strTexFile; m_pLayerTexture[iLayer] = pTex; //m_iTexIndex = iLayer; return true; } return false; } // 删除iLayer层纹理 [5/4/2009 hemeng] bool CTerrainMaterial::DeleteTexture(int iLayer) { // 如果层数为第0层或大于最大层则返回 if (iLayer == 0 || iLayer > MAX_LAYER) { return false; } // 删除纹理层文件名及纹理 m_strTexFiles[iLayer] = ""; m_pLayerTexture[iLayer] = NULL; // 逐层替换 for (int iIndex = iLayer; iIndex < (MAX_LAYER - 1); iIndex++) { string strTemp = m_strTexFiles[iIndex]; NiSourceTexture* pTex = m_pLayerTexture[iIndex]; m_strTexFiles[iIndex] = m_strTexFiles[iIndex + 1]; m_pLayerTexture[iIndex] = m_pLayerTexture[iIndex + 1]; m_strTexFiles[iIndex + 1] = strTemp; m_pLayerTexture[iIndex + 1] = pTex; } // 修改当前层信息 if (m_iUsedTexLayer > 1) { m_iUsedTexLayer --; } if (m_iTexIndex > m_iUsedTexLayer) { m_iTexIndex = m_iUsedTexLayer; } // 修改BlendTexture if (iLayer > 0) { m_spBlendTexture->SetStatic(false); NiPixelData* pPixelData = m_spBlendTexture->GetSourcePixelData(); if (pPixelData == NULL) { return false; } for (int y = 0; y < BLENDTEX_SIZE; ++y) { for (int x = 0; x < BLENDTEX_SIZE; ++x) { unsigned char* pPtr = (*pPixelData)(x,y); pPtr[iLayer - 1] = 0x00; for (int i = iLayer - 1; i < 2; i++) { int iTemp = pPtr[i]; pPtr[i] = pPtr[i + 1]; pPtr[i + 1] = iTemp; } } } pPixelData->MarkAsChanged(); } return true; } /// 设置blend纹理数据,R通道 void CTerrainMaterial::_doSetBlendData( int iChannel, const NiPoint2& vPos, float fAlpha, float fr, float fR, bool bAddTo, NiSourceTexture* pkBrushTexture) { if ( !m_spBlendTexture ) return; NiPixelData *pPixelData = m_spBlendTexture->GetSourcePixelData(); NiPixelData *pBrushPixelData = NULL; int iBrushTexWidth = 0; int iBrushTexHeight = 0; if (pkBrushTexture != NULL) { pBrushPixelData = pkBrushTexture->GetSourcePixelData(); iBrushTexWidth = pkBrushTexture->GetWidth(); iBrushTexHeight = pkBrushTexture->GetHeight(); assert( pBrushPixelData ); } assert( pPixelData ); NiPoint2 kTransVector(-(vPos.x-fR), -(vPos.y-fR)); // 从 chunk 坐标变换到 brush texture 坐标的变换向量 for (unsigned int y = 0; y < BLENDTEX_SIZE; y++) { for (unsigned int x = 0; x < BLENDTEX_SIZE; x++) { NiPoint2 vDis = NiPoint2( x - vPos.x, y - vPos.y ); float fLength = vDis.Length(); if ( fLength > fR ) // 外半径之外 { continue; } unsigned char ucVal = ( unsigned char )( fAlpha * 255 ); float fBrushTextureAlpah = 1.0f; if (pkBrushTexture != NULL) { int iBrushTexX = (float)(x+kTransVector.x)/(fR*2)*iBrushTexWidth; int iBrushTexY = (float)(y+kTransVector.y)/(fR*2)*iBrushTexHeight; //int iBrushTexX = (float)(x+kTransVector.x); //int iBrushTexY = (float)(y+kTransVector.y); // 只取 R 通道中的颜色 fBrushTextureAlpah = 1.0f - (*(*pBrushPixelData)(iBrushTexX, iBrushTexY))/255.0f; } float fVal = fAlpha * 255.0f * fBrushTextureAlpah; unsigned char* pPtr = (*pPixelData)( x, y ); // 获取 x, y 位置上 brush texture 的对应像素 /*if ( fLength <= fRadius0 ) { pPtr[2] = ( bAddTo ) ? min((pPtr[2]+ucVal), 255 ): ucVal; } else if ( fLength <= fRadius1 ) { float f = 1-(fLength-fRadius0 )/(fRadius1 - fRadius0); unsigned char ucVal_ = (unsigned char) ( ucVal * NiSin( NI_PI * 0.5f * f ) ); pPtr[2] = ( bAddTo ) ? min( (pPtr[2]+ ucVal_), 255 ) : max( pPtr[2], ucVal_ ); }*/ if ( fLength <= fr ) // 内半径 { float fV = max(0.0f, (pPtr[iChannel]+fVal)); fV = min(fV, 255.0f); pPtr[iChannel] = (bAddTo) ? unsigned char(fV) : (unsigned char)fVal; } else if ( fLength <= fR ) // 外半径 { float f = 1-(fLength-fr )/(fR - fr); if ( bAddTo ) { float fOffset = fVal * f ; float fV = max(0.0f, pPtr[iChannel]+ fOffset); fV = min( fV, 255.0f ); pPtr[iChannel] = unsigned char (fV); } else { if (fVal < 0) return; // 非 add to 模式不支 fVal 小于 0 float fOffset = ( fVal - pPtr[iChannel] ) * f; float fV = pPtr[iChannel]+ fOffset; fV = min( fV, 255.0f ); pPtr[iChannel] = unsigned char( fV ); } } } } pPixelData->MarkAsChanged(); } /// 设置blend纹理数据,R通道 void CTerrainMaterial::SetBlendDataR( const NiPoint2& vPos, float fAlpha, float fr, float fR, bool bAddTo, NiSourceTexture* pkBrushTexture) { _doSetBlendData( 0, vPos, fAlpha, fr, fR, bAddTo, pkBrushTexture); } /// 设置blend纹理数据,G通道 void CTerrainMaterial::SetBlendDataG( const NiPoint2& vPos, float fAlpha, float fr, float fR, bool bAddTo, NiSourceTexture* pkBrushTexture) { _doSetBlendData( 1, vPos, fAlpha, fr, fR, bAddTo, pkBrushTexture); } /// 设置blend纹理数据,B通道 void CTerrainMaterial::SetBlendDataB( const NiPoint2& vPos, float fAlpha, float fr, float fR, bool bAddTo, NiSourceTexture* pkBrushTexture) { _doSetBlendData( 2, vPos, fAlpha, fr, fR, bAddTo, pkBrushTexture); } void CTerrainMaterial::SetTerrainPropertyA( const NiRect &rect, int iProperty ) { if ( !m_spPropertyTexture ) return; NiPixelData *pPixelData = m_spPropertyTexture->GetSourcePixelData(); assert( pPixelData ); NiColor kColor = CSceneDesignerConfig::GetInstance()->GetTerrainSurfacePropertyColor(iProperty); for (unsigned int y = 0; y < BLENDTEX_SIZE; y++) { for (unsigned int x = 0; x < BLENDTEX_SIZE; x++) { if ( x >= rect.m_left && x < rect.m_right && y >= rect.m_bottom && y < rect.m_top ) { unsigned char* pPtr = (*pPixelData)( x, y ); pPtr[0] = kColor.r*255; pPtr[1] = kColor.g*255; pPtr[2] = kColor.b*255; pPtr[3] = 255; } } } pPixelData->MarkAsChanged(); } void CTerrainMaterial::ClearCollisionDataA() { if ( !m_spBlendTexture ) return; NiPixelData *pPixelData = m_spPropertyTexture->GetSourcePixelData(); assert( pPixelData ); for (unsigned int y = 0; y < BLENDTEX_SIZE; y++) { for (unsigned int x = 0; x < BLENDTEX_SIZE; x++) { unsigned char* pPtr = (*pPixelData)( x, y ); pPtr[0] = pPtr[1] = pPtr[2] = 0; } } pPixelData->MarkAsChanged(); } /// 获取4层纹理的最终混合结果纹理 NiSourceTexturePtr CTerrainMaterial::GetTextureBlendResult() { // 创建混合目标纹理 NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiPixelDataPtr pResultPixelData = NiNew NiPixelData( BLENDTEX_SIZE, BLENDTEX_SIZE, NiPixelFormat::RGBA32); unsigned char *pPtrResult = ( *pResultPixelData )(0,0); ZeroMemory(pPtrResult, BLENDTEX_SIZE*BLENDTEX_SIZE*4); //for ( int y = 0; y < BLENDTEX_SIZE; ++y ) //{ // for ( int x = 0; x < BLENDTEX_SIZE; ++x ) // { // // 目标纹理象素 // } //} NiPixelData* pBlendPixelData = m_spBlendTexture->GetSourcePixelData(); // for(int i=0; iLoadPixelDataFromFile(); // 从文件载入的纹理,必须执行这个才能取得 pixel data NiPixelData* pSourcePixelData = m_pLayerTexture[i]->GetSourcePixelData(); unsigned int iSrcTexDimX = m_pLayerTexture[i]->GetWidth(); // 源纹理尺寸 unsigned int iSrcTexDimY = m_pLayerTexture[i]->GetHeight(); // 遍历 blend texture 每个象素 for ( int y = 0; y < BLENDTEX_SIZE; ++y ) { for ( int x = 0; x < BLENDTEX_SIZE; ++x ) { unsigned char *pPtrResult = ( *pResultPixelData )(x,y); // 目标纹理象素 unsigned char *pPtrBlend = ( *pBlendPixelData )(x,y); // 混合文理象素 float fBlendFactor = 0.0f; if (i>0) { //(float)pPtrBlend[i-1]/255.0f; // 混合因子 fBlendFactor = 0.5f; } NiColor kColorResult(pPtrResult[0]/255.0f, pPtrResult[1]/255.0f, pPtrResult[2]/255.0f); // 计算对应源纹理的象素位置 int iSrcX = x % iSrcTexDimX; int iSrcY = y % iSrcTexDimY; unsigned char *pPtrSource = ( *pSourcePixelData )(iSrcX,iSrcY); // 源纹理象素 NiColor kColorSrc(pPtrSource[0]/255.0f, pPtrSource[1]/255.0f, pPtrSource[2]/255.0f); kColorResult = ColorLerp(kColorResult, kColorSrc, fBlendFactor); pPtrResult[0] = (unsigned char)(kColorResult.r*255); pPtrResult[1] = (unsigned char)(kColorResult.g*255); pPtrResult[2] = (unsigned char)(kColorResult.b*255); pPtrResult[3] = (unsigned char)(255); } }// end for 遍历每个象素 } pResultPixelData->MarkAsChanged(); NiSourceTexture::SetDestroyAppDataFlag( false ); NiSourceTexturePtr pkTexBlendResult = NiSourceTexture::Create( pResultPixelData ); pkTexBlendResult->SetStatic( false ); NiSourceTexture::SetDestroyAppDataFlag( true ); if ( !pkTexBlendResult ) return NULL; return pkTexBlendResult; } /// 保存blend纹理数据,仅供测试 bool CTerrainMaterial::SaveBlendTexture( const char *pszFile ) { if ( !m_spBlendTexture ) return false; CImage image; image.Create( BLENDTEX_SIZE, BLENDTEX_SIZE, 32, CImage::createAlphaChannel ); NiPixelData *pPixelData = m_spBlendTexture->GetSourcePixelData(); unsigned char *pPtr = (*pPixelData)( 0, 0 ); unsigned char *pData = ( unsigned char *)image.GetBits(); for ( int y = 0; y < BLENDTEX_SIZE; y++) { memcpy( pData, pPtr, BLENDTEX_SIZE * 4 ); pPtr = (*pPixelData)( 0, y); pData += image.GetPitch(); } HRESULT h = image.Save( pszFile ); return true; } #endif