#include "stdafx.h" #include "KRenderDeviceDX.h" #include "KResourceDX.h" #include #include "SDebug_Util.h" int g_TexRef = 0; static inline D3DFORMAT GetD3DFormat( K3DFORMAT fmt ) { return D3DFORMAT( fmt ); //switch ( fmt ) //{ // default: // case K3DFMT_UNKNOWN : return D3DFMT_UNKNOWN ; // // case K3DFMT_R8G8B8 : return K3DFMT_R8G8B8 ; // case K3DFMT_A8R8G8B8 : return K3DFMT_A8R8G8B8 ; // case K3DFMT_X8R8G8B8 : return K3DFMT_X8R8G8B8 ; // case K3DFMT_R5G6B5 : return K3DFMT_R5G6B5 ; // case K3DFMT_X1R5G5B5 : return K3DFMT_X1R5G5B5 ; // case K3DFMT_A1R5G5B5 : return K3DFMT_A1R5G5B5 ; // case K3DFMT_A4R4G4B4 : return K3DFMT_A4R4G4B4 ; // case K3DFMT_R3G3B2 : return K3DFMT_R3G3B2 ; // case K3DFMT_A8 : return K3DFMT_A8 ; // case K3DFMT_A8R3G3B2 : return K3DFMT_A8R3G3B2 ; // case K3DFMT_X4R4G4B4 : return K3DFMT_X4R4G4B4 ; // case K3DFMT_A2B10G10R10 : return K3DFMT_A2B10G10R10 ; // case K3DFMT_G16R16 : return K3DFMT_G16R16 ; // // case K3DFMT_A8P8 : return K3DFMT_A8P8 ; // case K3DFMT_P8 : return K3DFMT_P8 ; // // case K3DFMT_L8 : return K3DFMT_L8 ; // case K3DFMT_A8L8 : return K3DFMT_A8L8 ; // case K3DFMT_A4L4 : return K3DFMT_A4L4 ; // // case K3DFMT_V8U8 : return K3DFMT_V8U8 ; // case K3DFMT_L6V5U5 : return K3DFMT_L6V5U5 ; // case K3DFMT_X8L8V8U8 : return K3DFMT_X8L8V8U8 ; // case K3DFMT_Q8W8V8U8 : return K3DFMT_Q8W8V8U8 ; // case K3DFMT_V16U16 : return K3DFMT_V16U16 ; // case K3DFMT_W11V11U10 : return K3DFMT_W11V11U10 ; // case K3DFMT_A2W10V10U10 : return K3DFMT_A2W10V10U10 ; // // case K3DFMT_UYVY : return K3DFMT_UYVY ; // case K3DFMT_YUY2 : return K3DFMT_YUY2 ; // case K3DFMT_DXT1 : return K3DFMT_DXT1 ; // case K3DFMT_DXT2 : return K3DFMT_DXT2 ; // case K3DFMT_DXT3 : return K3DFMT_DXT3 ; // case K3DFMT_DXT4 : return K3DFMT_DXT4 ; // case K3DFMT_DXT5 : return K3DFMT_DXT5 ; // // case K3DFMT_D16_LOCKABLE : return K3DFMT_D16_LOCKABLE ; // case K3DFMT_D32 : return K3DFMT_D32 ; // case K3DFMT_D15S1 : return K3DFMT_D15S1 ; // case K3DFMT_D24S8 : return K3DFMT_D24S8 ; // case K3DFMT_D16 : return K3DFMT_D16 ; // case K3DFMT_D24X8 : return K3DFMT_D24X8 ; // case K3DFMT_D24X4S4 : return K3DFMT_D24X4S4 ; // // case K3DFMT_VERTEXDATA : return K3DFMT_VERTEXDATA ; // case K3DFMT_INDEX16 : return K3DFMT_INDEX16 ; // case K3DFMT_INDEX32 : return K3DFMT_INDEX32 ; // // case K3DFMT_R32F : return K3DFMT_R32F ; //} } K3DTextureDX::K3DTextureDX( K3DRenderDeviceDX *dev ) { m_bLocked = false; m_dev = dev; m_d3dtex = NULL; m_usage = 0; m_pool = D3DPOOL_MANAGED; // _oprint( "TC:(%08X)\n", this ); } K3DTextureDX::~K3DTextureDX() { //if( m_strName.length() ) // _oprint( "TD:(%08X : %s)\n", this, m_strName.c_str() ); //else // _oprint( "TD:(%08X)\n", this ); if ( m_d3dtex) g_TexRef--; SAFE_RELEASE(m_d3dtex); } template< typename T > static inline T _max( const T& a, const T& b ) { return a > b ? a : b; } template< typename T > static inline T _min( const T& a, const T& b ) { return a < b ? a : b; } bool K3DTextureDX::Initialize( KStream &stream, int nQuality, D3DPOOL pool/* = D3DPOOL_MANAGED*/, K3DFORMAT fmt/* = K3DFMT_UNKNOWN*/ ) { //if( pool == D3DPOOL_DEFAULT ) // _oprint( "K3DTextureDX::Initialize : (0x%08X)\n", this ); void *pSrc = stream.GetMappedPtr( KStream::MAPPED_READ ); if ( pSrc == NULL ) return false; bool original = false; if(nQuality >= 10000 || nQuality < 0) { nQuality = 0; original = true; } HRESULT res; m_nQuality = nQuality; D3DXIMAGE_INFO infoImg; D3DXGetImageInfoFromFileInMemory( pSrc, static_cast(stream.GetLength()), &infoImg ); m_origin_size.width = infoImg.Width; m_origin_size.height = infoImg.Height; if ( m_nQuality != 0 ) { // 너무 작은 텍스쳐는 뭉게지는것 같아서.. 임시로 추가해봄 -.- infoImg.Width = _max( infoImg.Width / (1 << m_nQuality), _min( infoImg.Width, 32U ) ); infoImg.Height = _max( infoImg.Height / (1 << m_nQuality), _min( infoImg.Height, 32U ) ); infoImg.MipLevels = _max( (int) (infoImg.MipLevels - m_nQuality), 1 ); res = D3DXCreateTextureFromFileInMemoryEx( m_dev->GetD3DDevice(), pSrc, static_cast(stream.GetLength()), infoImg.Width, infoImg.Height, infoImg.MipLevels, 0, GetD3DFormat( fmt ), pool, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &m_d3dtex ); } else { res = D3DXCreateTextureFromFileInMemoryEx( m_dev->GetD3DDevice(), pSrc, static_cast(stream.GetLength()), infoImg.Width, infoImg.Height, infoImg.MipLevels, 0, GetD3DFormat( fmt ), pool, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &m_d3dtex ); // infoImg.MipLevels, 0, D3DFMT_UNKNOWN, original ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &m_d3dtex ); // infoImg.MipLevels, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_POINT, D3DX_FILTER_POINT, 0, NULL, NULL, &m_d3dtex ); } stream.FreeMappedPtr( pSrc ); if ( res != D3D_OK ) { /// 2011.05.12 - prodongi std::string errStr; if( res == D3DERR_NOTAVAILABLE ) errStr = "D3DERR_NOTAVAILABLE"; else if( res == D3DERR_OUTOFVIDEOMEMORY ) errStr = "D3DERR_OUTOFVIDEOMEMORY"; else if( res == D3DERR_INVALIDCALL ) errStr = "D3DERR_INVALIDCALL"; else if( res == E_OUTOFMEMORY ) errStr = "E_OUTOFMEMORY"; else errStr = ""; _oprint("***DEVICE ERROR : %s[%d]\n", errStr.c_str(), res); #ifdef _DEV MessageBox(HWND_DESKTOP, errStr.c_str(), "Failed D3DXCreateTextureFromFileInMemoryEx", MB_OK); #endif /* if( res == D3DERR_NOTAVAILABLE ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_NOTAVAILABLE" ); } else if( res == D3DERR_OUTOFVIDEOMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_OUTOFVIDEOMEMORY" ); } else if( res == D3DERR_INVALIDCALL ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_INVALIDCALL" ); } else if( res == E_OUTOFMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "E_OUTOFMEMORY" ); } */ m_d3dtex = NULL; m_pSurface = NULL; return false; } g_TexRef++; m_fmt = fmt; m_pool = pool; m_pSurface = m_d3dtex; m_size.width = infoImg.Width ; m_size.height = infoImg.Height; m_nMipsLevels = infoImg.MipLevels; m_format = static_cast(infoImg.Format); return true; } bool K3DTextureDX::CreateNew( DWORD width, DWORD height, DWORD usage, K3DFORMAT format, D3DPOOL pool/* = D3DPOOL_DEFAULT*/ ) { //if( pool == D3DPOOL_DEFAULT ) // _oprint( "DeviceLost : K3DTextureDX::CreateNew : (0x%08X)\n", this ); HRESULT res = m_dev->GetD3DDevice()->CreateTexture( width, height, 1, usage, GetD3DFormat(format), pool, &m_d3dtex, NULL ); if ( res != D3D_OK ) { if( res == D3DERR_NOTAVAILABLE ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_NOTAVAILABLE" ); } else if( res == D3DERR_OUTOFVIDEOMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_OUTOFVIDEOMEMORY" ); } else if( res == D3DERR_INVALIDCALL ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_INVALIDCALL" ); } else if( res == E_OUTOFMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "E_OUTOFMEMORY" ); } m_d3dtex = NULL; m_pSurface = NULL; return false; } m_pool = pool; m_usage = usage; m_pSurface = m_d3dtex; D3DSURFACE_DESC desc; m_d3dtex->GetLevelDesc( 0, &desc ); m_size.width = desc.Width; m_size.height = desc.Height; g_TexRef++; m_nMipsLevels = 1; m_fmt = format; m_format = static_cast(desc.Format); return true; } bool K3DTextureDX::CreateNew( DWORD width, DWORD height, K3DFORMAT format, D3DPOOL pool/* = D3DPOOL_MANAGED*/, int nLevel /*= 1*/ ) { //if( pool == D3DPOOL_DEFAULT ) // _oprint( "DeviceLost : K3DTextureDX::CreateNew : (0x%08X)\n", this ); HRESULT res = D3DXCreateTexture( m_dev->GetD3DDevice(), width, height, nLevel, 0, GetD3DFormat(format), pool, &m_d3dtex ); if ( res != D3D_OK ) { if( res == D3DERR_NOTAVAILABLE ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_NOTAVAILABLE" ); } else if( res == D3DERR_OUTOFVIDEOMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_OUTOFVIDEOMEMORY" ); } else if( res == D3DERR_INVALIDCALL ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_INVALIDCALL" ); } else if( res == E_OUTOFMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "E_OUTOFMEMORY" ); } m_d3dtex = NULL; m_pSurface = NULL; return false; } g_TexRef++; m_pSurface = m_d3dtex; D3DSURFACE_DESC desc; m_d3dtex->GetLevelDesc( 0, &desc ); m_size.width = desc.Width; m_size.height = desc.Height; m_format = static_cast(desc.Format); return true; } bool K3DTextureDX::IsValid() const { return m_d3dtex ? true : false; } void K3DTextureDX::Refresh( KStream &stream, int nQuality ) { if ( m_d3dtex) g_TexRef--; SAFE_RELEASE(m_d3dtex); Initialize( stream, nQuality ); } void K3DTextureDX::LockRect( KRect *rect, void** ppBuf, int& stride ) { if ( !m_bLocked && m_d3dtex != NULL ) { D3DLOCKED_RECT rt; HRESULT hr = m_d3dtex->LockRect( 0, &rt, (const RECT*)rect, 0/*D3DLOCK_NOSYSLOCK*/ ); if ( hr == D3D_OK ) { *ppBuf = rt.pBits; stride = rt.Pitch; m_bLocked = true; } } else { *ppBuf = NULL; stride = 0; } } void K3DTextureDX::Unlock() { if ( m_bLocked ) { m_d3dtex->UnlockRect(0); m_bLocked = false; } } bool K3DTextureDX::PreReload() { if (m_d3dtex) g_TexRef--; SAFE_RELEASE(m_d3dtex); return true; } bool K3DTextureDX::Reload() { //Device Lost 처리 if( m_pool == D3DPOOL_DEFAULT ) { if (m_d3dtex) g_TexRef--; SAFE_RELEASE(m_d3dtex); CreateNew( m_size.width, m_size.height, m_usage, m_format, m_pool ); } return true; } bool K3DTextureDX::SaveToFile( const std::string& strFile ) { if( D3DXSaveTextureToFile( strFile.c_str(), D3DXIFF_DDS, m_d3dtex, NULL ) == D3D_OK ) return true; return false; } // 추가. bintitle. #include bool K3DTextureDX::LoadFromFile( const std::string& strFile ) { HRESULT hr; if( !FAILED( hr = D3DXCreateTextureFromFile( m_dev->GetD3DDevice(), strFile.c_str(), &m_d3dtex ) ) ) { m_origin_size.width = 20; // 테스트 강제 적용. m_origin_size.height = 20; return true; } else { const TCHAR* szError = DXGetErrorString9(hr); ::MessageBox( NULL, szError, "Load Fail", MB_OK ); } return false; } struct Color_RGB { // 2010.04.23 순서를 수정했습니다. - prodongi double red,green,blue; //doubles used for best accuracy //double red,blue, green; //doubles used for best accuracy }; struct Color_HSV { double hue, sat, val; }; struct Color_HSV RGBtoHSV(struct Color_RGB RGB) { struct Color_HSV HSV; //structure to return double vals[3]; //thue = temporary var (linked to hue) unsigned char maxc=0, minc=0; //red=0, green=1, blue=2 vals[0]=RGB.red; vals[1]=RGB.green; vals[2]=RGB.blue; //red is set as maximum and minimum if(vals[1]>vals[maxc]) maxc=1; //if green is greater, make green the max. if(vals[2]>vals[maxc]) maxc=2; //if blue is greater, make blue the max if(vals[1] 0, to fit help the group seperation */ if(HSV.hue>300) HSV.hue-=360; /* we now determine the maximum component (maxc) by the hue groups */ if(HSV.hue<60) //if it is below 60, then it is red (maxc 0) maxc=0; //The range is -60 -> 60, and there is never anything below -60 else if(HSV.hue>=180) //if it is above 180, then it is blue (maxc 2) maxc=2; //The range is 180 -> 300, and there is never anything above 300, or it would have been modified earlier else //otherwise, it must be between 60 and 180, which is green (maxc 1) maxc=1; //The range is 60 -> 180 vals[maxc]=HSV.val; //vals holds the r, g, and b values temporarialy, so set the maximum one to HSV.val (the value of the maximim component is HSV.val) /* the first of these formulae calculates the minimum * value. it has been "shrink-wrapped", so dont try to make sense of it * * I dont understand it anymore, and i'm not sure if i even did when i wrote it */ min = (HSV.val*(255-HSV.sat)) / 255; /* the second of these formulae calculates a value 'thue'. * the formaula results in a value between -1 and 1, representing * the position of the hue in it's group * this may help: (green "hue group" used as an example.) * * lwr bound ## green ## upr bound * 60 120 180 -----> Hue * |-----|-----|-----------| * hue= 90 * * lwr bound ## green ## upr bound * -1 0 1 -----> tHue * |-----|-----|-----------| * hue= -0.5 * * this part is done in the first half of the equation ((HSV.hue/60)-(2*maxc)) * * the second part multiplies it by the difference between * the maximum and minimum to get a value that is * the difference between the minimum component and the middle component. * i dont really understand why, but it works. * (HSV.val-min) */ thue=(((HSV.hue/60)-(2*maxc)) * (HSV.val-min)); if(thue>0) //if the hue is more like the color group above it, { //i.e. a green that is more 'bluey' than 'reddy' vals[(maxc+2)%3] = min; //then the minimum component is the one it is less like, the group below vals[(maxc+1)%3] = min+thue; //and the middle component is the one it is more like, the group above } else //otherwise, it must be more like the colour group below it { //i.e. a green that is more 'reddy' than 'bluey' vals[(maxc+1)%3] = min; //then the minimum component is the one it is less like, the group above vals[(maxc+2)%3] = min+thue; //and the middle component is the one it is more like, the group below } RGB.red=vals[0]; // now stuff the aray values into the return structure RGB.green=vals[1]; RGB.blue=vals[2]; return RGB; } HRESULT K3DTextureDX::LoadSurfaceFromSurface( K3DTexture* pDestTexture, DWORD c1, DWORD c2, DWORD c3, DWORD c4, short nMode ) { if( !IsValid() ) return S_FALSE; if( pDestTexture == NULL || !pDestTexture->IsValid() ) return S_FALSE; K3DTextureDX* pDestTextureDX = (K3DTextureDX*)pDestTexture; int nMipCount = GetMipsLevels(); D3DSURFACE_DESC sd; HRESULT hr; LPDIRECT3DSURFACE9 psurfSrc = NULL; LPDIRECT3DSURFACE9 psurfDest = NULL; KColor cols[4]; int i, fr[4], fg[4], fb[4]; cols[0].color = c1; cols[1].color = c2; cols[2].color = c3; cols[3].color = c4; for ( i=0 ; i<4 ; ++i ) { if ( cols[i].color == 0 ) fr[i] = fg[i] = fb[i] = 0; else { fr[i] = int(cols[i].r) - 128; fg[i] = int(cols[i].g) - 128; fb[i] = int(cols[i].b) - 128; } } int r,g,b; KColor *colbuf, *newcolbuf; for( int i(0); nMipCount>i; i++ ) { m_d3dtex->GetLevelDesc(i, &sd); hr = m_d3dtex->GetSurfaceLevel(i, &psurfSrc); hr = pDestTextureDX->GetD3DTexture()->GetSurfaceLevel(i, &psurfDest); if( psurfSrc && psurfDest ) { hr = D3DXLoadSurfaceFromSurface(psurfDest, NULL, NULL, psurfSrc, NULL, NULL, D3DX_FILTER_LINEAR/*D3DX_FILTER_TRIANGLE*/, 0); //Colorized if( (c1 != 0 || c2 != 0 || c3 != 0 || c4 != 0) && hr== S_OK ) { D3DLOCKED_RECT lr; hr = psurfDest->LockRect(&lr, NULL, 0); DWORD xp; DWORD yp; DWORD* pdwRow = (DWORD*)lr.pBits; LONG dataBytesPerRow = 4 * sd.Width; colbuf = NULL; newcolbuf= NULL; if( nMode == COLORIZED_DEF ) { Color_RGB rgb = {cols[1].r, cols[1].g, cols[1].b}; Color_HSV hsv = RGBtoHSV(rgb); for (yp = 0; yp < sd.Height; yp++) { colbuf = (KColor*)pdwRow; newcolbuf = (KColor*)pdwRow; for (xp = 0; xp < sd.Width; xp++) { switch( (int)(colbuf->a >> 5) ) { case 0: newcolbuf->color = colbuf->color; break; case 1: case 2: r = int(colbuf->r) + fr[0]; g = int(colbuf->g) + fg[0]; b = int(colbuf->b) + fb[0]; newcolbuf->r = unsigned char((r > 255) ? (255) : ( (r<0) ? (0) : r )); newcolbuf->g = unsigned char((g > 255) ? (255) : ( (g<0) ? (0) : g )); newcolbuf->b = unsigned char((b > 255) ? (255) : ( (b<0) ? (0) : b )); break; case 3: case 4: r = int(colbuf->r) + fr[1]; g = int(colbuf->g) + fg[1]; b = int(colbuf->b) + fb[1]; newcolbuf->r = unsigned char((r > 255) ? (255) : ( (r<0) ? (0) : r )); newcolbuf->g = unsigned char((g > 255) ? (255) : ( (g<0) ? (0) : g )); newcolbuf->b = unsigned char((b > 255) ? (255) : ( (b<0) ? (0) : b )); break; case 5: case 6: r = int(colbuf->r) + fr[2]; g = int(colbuf->g) + fg[2]; b = int(colbuf->b) + fb[2]; newcolbuf->r = unsigned char((r > 255) ? (255) : ( (r<0) ? (0) : r )); newcolbuf->g = unsigned char((g > 255) ? (255) : ( (g<0) ? (0) : g )); newcolbuf->b = unsigned char((b > 255) ? (255) : ( (b<0) ? (0) : b )); break; case 7: r = int(colbuf->r) + fr[3]; g = int(colbuf->g) + fg[3]; b = int(colbuf->b) + fb[3]; newcolbuf->r = unsigned char((r > 255) ? (255) : ( (r<0) ? (0) : r )); newcolbuf->g = unsigned char((g > 255) ? (255) : ( (g<0) ? (0) : g )); newcolbuf->b = unsigned char((b > 255) ? (255) : ( (b<0) ? (0) : b )); break; } //0~127 사이의 알파값은 유지 if( colbuf->a >= 128 ) newcolbuf->a = 255; colbuf++; newcolbuf++; } pdwRow += lr.Pitch / 4; }//for } else if( nMode == COLORIZED_KEEP_ALPHA ) { for (yp = 0; yp < sd.Height; yp++) { colbuf = (KColor*)pdwRow; newcolbuf = (KColor*)pdwRow; for (xp = 0; xp < sd.Width; xp++) { if( colbuf->a != 0 ) { r = int(colbuf->r) + fr[0]; g = int(colbuf->g) + fg[0]; b = int(colbuf->b) + fb[0]; newcolbuf->r = unsigned char((r > 255) ? (255) : ( (r<0) ? (0) : r )); newcolbuf->g = unsigned char((g > 255) ? (255) : ( (g<0) ? (0) : g )); newcolbuf->b = unsigned char((b > 255) ? (255) : ( (b<0) ? (0) : b )); } colbuf++; newcolbuf++; } pdwRow += lr.Pitch / 4; }//for } else if( nMode == COLORIZED_USEALPHA ) { for (yp = 0; yp < sd.Height; yp++) { colbuf = (KColor*)pdwRow; newcolbuf = (KColor*)pdwRow; for (xp = 0; xp < sd.Width; xp++) { if( colbuf->a != 0 ) { newcolbuf->r = cols[0].r; newcolbuf->g = cols[0].g; newcolbuf->b = cols[0].b; } colbuf++; newcolbuf++; } pdwRow += lr.Pitch / 4; }//for } else if( nMode == COLORIZED_GRAY ) { Color_RGB rgb = {cols[1].r, cols[1].g, cols[1].b}; Color_HSV hsv = RGBtoHSV(rgb); for (yp = 0; yp < sd.Height; yp++) { colbuf = (KColor*)pdwRow; newcolbuf = (KColor*)pdwRow; for (xp = 0; xp < sd.Width; xp++) { //if (colbuf->a == 172) // _oprint( "alpha : %d\n", colbuf->a ); switch ((int)(colbuf->a >> 5)) { case 3: case 4: { // 2010.04.27 nrgb값이 -가 나올때가 있어서, 적용 방식을 수정했습니다. - prodongi /* Color_RGB irgb = { colbuf->r, colbuf->g, colbuf->b }; Color_HSV ohsv = RGBtoHSV(irgb); hsv.val = ohsv.val; Color_RGB nrgb = HSVtoRGB(hsv); // 2010.04.23 형변환 워닝 수정 - prodongi newcolbuf->r = (unsigned char)nrgb.red; newcolbuf->g = (unsigned char)nrgb.green; newcolbuf->b = (unsigned char)nrgb.blue; */ float ratio = (float)(colbuf->r)/255.0f; float inv_ratio = 1.0f - ratio; newcolbuf->r = (unsigned char)((float)colbuf->r * inv_ratio + (float)rgb.red * ratio); newcolbuf->g = (unsigned char)((float)colbuf->g * inv_ratio + (float)rgb.green * ratio); newcolbuf->b = (unsigned char)((float)colbuf->b * inv_ratio + (float)rgb.blue * ratio); } break; default: newcolbuf->r = colbuf->r; newcolbuf->g = colbuf->g; newcolbuf->b = colbuf->b; } //0~127 사이의 알파값은 유지 if( colbuf->a >= 128 ) newcolbuf->a = 255; colbuf++; newcolbuf++; } pdwRow += lr.Pitch / 4; }//for } psurfDest->UnlockRect(); } SAFE_RELEASE(psurfSrc ); SAFE_RELEASE(psurfDest); } } return hr; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // K3DRenderTargetDX::K3DRenderTargetDX( K3DRenderDeviceDX *dev ) { m_bLocked = false; m_dev = dev; m_d3dtex = NULL; m_pD3DDepth = NULL; //m_pD3DDepthTex = NULL; } K3DRenderTargetDX::~K3DRenderTargetDX() { Clear(); } void K3DRenderTargetDX::Clear() { SAFE_RELEASE(m_d3dtex); SAFE_RELEASE(m_pD3DDepth); //SAFE_RELEASE(m_pD3DDepthTex); m_pSurface = NULL; } bool K3DRenderTargetDX::CreateNew( DWORD width, DWORD height, UINT nLevels, K3DFORMAT format, DWORD dwDepthUsage, bool bDepth16Bit /*=false*/ ) { Clear(); m_nLevels = nLevels; HRESULT res = D3DXCreateTexture( m_dev->GetD3DDevice(), width, height, m_nLevels, D3DUSAGE_RENDERTARGET, GetD3DFormat(format), D3DPOOL_DEFAULT, &m_d3dtex ); if ( res != D3D_OK ) { if( res == D3DERR_NOTAVAILABLE ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_NOTAVAILABLE" ); } else if( res == D3DERR_OUTOFVIDEOMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_OUTOFVIDEOMEMORY" ); } else if( res == D3DERR_INVALIDCALL ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_INVALIDCALL" ); } else if( res == E_OUTOFMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "E_OUTOFMEMORY" ); } //m_d3dtex = NULL; //m_pSurface = NULL; Clear(); return false; } //m_bUseDepth = bUseDepth; m_dwDepthUsage = dwDepthUsage; #ifdef _KUI_INVALIDATION m_bDepth16Bit = bDepth16Bit; #endif D3DSURFACE_DESC desc; m_d3dtex->GetLevelDesc( 0, &desc ); m_size.width = desc.Width; m_size.height = desc.Height; m_format = static_cast(desc.Format); if( dwDepthUsage == DEPTH_ENABLE ) { if( bDepth16Bit ) { res = m_dev->GetD3DDevice()->CreateDepthStencilSurface( m_size.width, m_size.height, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, TRUE, &m_pD3DDepth, NULL ); } else { res = m_dev->GetD3DDevice()->CreateDepthStencilSurface( m_size.width, m_size.height, D3DFMT_D24X8, D3DMULTISAMPLE_NONE, 0, TRUE, &m_pD3DDepth, NULL ); } if ( res != D3D_OK ) { Clear(); return false; } } // if( dwDepthUsage == DEPTH_ENABLE || dwDepthUsage == DEPTH_USEASTEXTURE) // { // //ATI 계열은 D3DFMT_D24X8, D3DFMT_D24S8 만들 수 없다. // res = m_dev->GetD3DDevice()->CreateTexture( width, height, 1, D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24X8, D3DPOOL_DEFAULT, &m_pD3DDepth, NULL ); //// res = m_dev->GetD3DDevice()->CreateTexture( width, height, 1, D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24S8, D3DPOOL_DEFAULT, &m_pD3DDepth, NULL ); // if ( res != D3D_OK ) // { // Clear(); // return false; // } // } //if( dwDepthUsage == DEPTH_USEASTEXTURE ) //{ // m_pSurface = m_pD3DDepth; //} //else //{ m_pSurface = m_d3dtex; //} return true; } bool K3DRenderTargetDX::IsValid() const { return m_d3dtex ? true : false; } void K3DRenderTargetDX::LockRect( KRect *rect, void** ppBuf, int& stride ) { *ppBuf = NULL; stride = 0; } void K3DRenderTargetDX::Unlock() { } void K3DRenderTargetDX::CopyTo( K3DTexture *pTex ) { LPDIRECT3DDEVICE9 d3ddev = m_dev->GetD3DDevice(); LPDIRECT3DSURFACE9 src, dst; m_d3dtex->GetSurfaceLevel( 0, &src ); K3DTextureDX *pDXTex = reinterpret_cast(pTex); pDXTex->GetD3DTexture()->GetSurfaceLevel( 0, &dst ); HRESULT hr; hr = d3ddev->StretchRect( src, NULL, dst, NULL, D3DTEXF_NONE ); assert( hr == S_OK ); SAFE_RELEASE(src); SAFE_RELEASE(dst); } K3DTexture *K3DRenderTargetDX::CreateCloneTexture() { K3DTexture *pTex = m_dev->CreateTexture( GetWidth(), GetHeight(), GetFormat() ); CopyTo( pTex ); return pTex; } bool K3DRenderTargetDX::PreReload() { Clear(); return true; } bool K3DRenderTargetDX::Reload() { #ifdef _KUI_INVALIDATION CreateNew( m_size.width, m_size.height, m_nLevels, m_format, m_dwDepthUsage, m_bDepth16Bit ); #else CreateNew( m_size.width, m_size.height, m_nLevels, m_format, m_dwDepthUsage ); #endif return true; } bool K3DRenderTargetDX::SaveToFile( const std::string& strFile ) { if( D3DXSaveTextureToFile( strFile.c_str(), D3DXIFF_DDS, m_d3dtex, NULL ) == D3D_OK ) return true; return false; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ///CubeTexture K3DRenderTargetCubeDX::K3DRenderTargetCubeDX( K3DRenderDeviceDX* dev ) : m_dev( dev ), m_d3dcubetex( NULL ), m_pD3DDepth( NULL ), m_bLocked( false ) { } K3DRenderTargetCubeDX::~K3DRenderTargetCubeDX() { Clear(); } void K3DRenderTargetCubeDX::Clear() { SAFE_RELEASE(m_d3dcubetex); SAFE_RELEASE(m_pD3DDepth); m_pSurface = NULL; } bool K3DRenderTargetCubeDX::CreateNew( DWORD size, UINT nLevels, K3DFORMAT format, DWORD dwDepthUsage ) { Clear(); m_nLevels = nLevels; HRESULT res = D3DXCreateCubeTexture( m_dev->GetD3DDevice(), size, m_nLevels, D3DUSAGE_RENDERTARGET, GetD3DFormat(format), D3DPOOL_DEFAULT, &m_d3dcubetex ); if ( res != D3D_OK ) { if( res == D3DERR_NOTAVAILABLE ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_NOTAVAILABLE" ); } else if( res == D3DERR_OUTOFVIDEOMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_OUTOFVIDEOMEMORY" ); } else if( res == D3DERR_INVALIDCALL ) { _oprint( "***DEVICE ERROR : %s\n", "D3DERR_INVALIDCALL" ); } else if( res == E_OUTOFMEMORY ) { _oprint( "***DEVICE ERROR : %s\n", "E_OUTOFMEMORY" ); } Clear(); return false; } m_dwDepthUsage = dwDepthUsage; D3DSURFACE_DESC desc; m_d3dcubetex->GetLevelDesc( 0, &desc ); m_size.width = desc.Width; m_size.height = desc.Height; m_format = static_cast(desc.Format); if( dwDepthUsage == DEPTH_ENABLE ) { res = m_dev->GetD3DDevice()->CreateDepthStencilSurface( m_size.width, m_size.height, D3DFMT_D24X8, D3DMULTISAMPLE_NONE, 0, TRUE, &m_pD3DDepth, NULL ); if ( res != D3D_OK ) { Clear(); return false; } } m_pSurface = m_d3dcubetex; return true; } bool K3DRenderTargetCubeDX::IsValid() const { return m_d3dcubetex ? true : false; } void K3DRenderTargetCubeDX::LockRect( KRect *rect, void** ppBuf, int& stride ) { *ppBuf = NULL; stride = 0; } void K3DRenderTargetCubeDX::Unlock() { } void K3DRenderTargetCubeDX::CopyTo( K3DTexture *pTex ) { K3DRenderTargetCubeDX *pDXCubeTex = reinterpret_cast(pTex); for( int nCubeface = 0; nCubeface < 6; ++nCubeface ) GetCubeMapSurface( pDXCubeTex, (D3DCUBEMAP_FACES)nCubeface ); } void K3DRenderTargetCubeDX::GetCubeMapSurface( K3DRenderTargetCubeDX* pCubeTexture, D3DCUBEMAP_FACES cubeFace ) { LPDIRECT3DDEVICE9 d3ddev = m_dev->GetD3DDevice(); LPDIRECT3DSURFACE9 src, dst; m_d3dcubetex->GetCubeMapSurface( cubeFace, 0, &src ); pCubeTexture->GetD3DCubeTexture()->GetCubeMapSurface( cubeFace, 0, &dst ); HRESULT hr; hr = d3ddev->StretchRect( src, NULL, dst, NULL, D3DTEXF_NONE ); assert( hr == S_OK ); SAFE_RELEASE(src); SAFE_RELEASE(dst); } K3DTexture *K3DRenderTargetCubeDX::CreateCloneTexture() { K3DTexture *pTex = m_dev->CreateTexture( GetWidth(), GetHeight(), GetFormat() ); CopyTo( pTex ); return pTex; } bool K3DRenderTargetCubeDX::PreReload() { Clear(); return true; } bool K3DRenderTargetCubeDX::Reload() { CreateNew( m_size.width, m_nLevels, m_format, m_dwDepthUsage ); return true; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // //IndexBufferDX K3DIndexBufferDX::K3DIndexBufferDX( K3DRenderDeviceDX *dev ) { m_dev = dev; m_bLocked = false; m_d3dib = NULL; } K3DIndexBufferDX::~K3DIndexBufferDX() { if ( m_bLocked ) Unlock(); SAFE_RELEASE(m_d3dib); } bool K3DIndexBufferDX::Initialize( KStream &stream, int count, bool use32bit ) { int formatsize; int fmt; if ( use32bit ) { formatsize = 4; fmt = D3DFMT_INDEX32; } else { formatsize = 2; fmt = D3DFMT_INDEX16; } HRESULT hr = m_dev->GetD3DDevice()->CreateIndexBuffer( count * formatsize, D3DUSAGE_WRITEONLY, static_cast(fmt), D3DPOOL_MANAGED, &m_d3dib, NULL ); unsigned char *pBuf; if( hr == D3D_OK ) { m_d3dib->Lock( 0, count * formatsize, (void**)&pBuf, 0 ); assert(pBuf && "m_d3dib->Lock( 0, count * formatsize, (void**)&pBuf, 0 );"); stream.Read( pBuf, count * formatsize ); m_d3dib->Unlock(); SetValidVtx( true ); m_format = static_cast(fmt); m_idxCount = count; return true; } return false; } bool K3DIndexBufferDX::CreateNew( int count, bool use32bit ) { int formatsize; int fmt; if ( use32bit ) { formatsize = 4; fmt = D3DFMT_INDEX32; } else { formatsize = 2; fmt = D3DFMT_INDEX16; } m_format = static_cast(fmt); m_idxCount = count; HRESULT hr = m_dev->GetD3DDevice()->CreateIndexBuffer( count * formatsize, D3DUSAGE_WRITEONLY, static_cast(fmt), D3DPOOL_MANAGED, &m_d3dib, NULL ); if( hr == D3D_OK ) { SetValidVtx( true ); return true; } return false; } void K3DIndexBufferDX::Lock( void** ppBuf, int& size, DWORD flags ) { if ( m_bLocked == false && m_d3dib != NULL ) { //int formatsize = (m_format == K3DFMT_INDEX16) ? 2 : 4; if ( m_d3dib->Lock( 0, 0, ppBuf, flags ) == D3D_OK ) { m_bLocked = true; } } else { ppBuf = NULL; } } void K3DIndexBufferDX::Unlock() { if ( m_bLocked == true ) { m_d3dib->Unlock(); m_bLocked = false; } } bool K3DIndexBufferDX::PreReload() { return true; } bool K3DIndexBufferDX::Reload() { return true; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // //#define _VB_DEBUG_ #ifdef _VB_DEBUG_ volatile int g_nVB_RefCount = 0; #endif K3DVertexBufferDX::K3DVertexBufferDX() { #ifdef _VB_DEBUG_ InterlockedIncrement( (volatile LONG *)&g_nVB_RefCount ); // _performance_print( "K3DVertexBufferDX 01 : %d\n", g_nVB_RefCount ); #endif m_usage = D3DUSAGE_WRITEONLY; m_type = RESTYPE_VERTEXBUFFER; m_dev = NULL; m_bLocked = false; m_d3dvb = NULL; //Device Lost 처리 m_pBackUpBuf = NULL; m_bIsDeviceLost = false; } K3DVertexBufferDX::K3DVertexBufferDX( K3DRenderDeviceDX *dev ) { #ifdef _VB_DEBUG_ InterlockedIncrement( (volatile LONG *)&g_nVB_RefCount ); // _performance_print( "K3DVertexBufferDX 02 : %d\n", g_nVB_RefCount ); #endif m_usage = D3DUSAGE_WRITEONLY; m_type = RESTYPE_VERTEXBUFFER; m_dev = dev; m_bLocked = false; m_d3dvb = NULL; //Device Lost 처리 m_pBackUpBuf = NULL; m_bIsDeviceLost = false; } K3DVertexBufferDX::~K3DVertexBufferDX() { #ifdef _VB_DEBUG_ InterlockedDecrement( (volatile LONG *)&g_nVB_RefCount ); _performance_print( "K3DVertexBufferDX ~ : %d\tStride:%d\tvtxCount:%d\tFVF:%d\tUsage:%d\n", g_nVB_RefCount, m_vtxStride, m_vtxCount, m_format, m_usage ); #endif //백업 버퍼 삭제 SAFE_DELETE_ARRAY( m_pBackUpBuf ); SAFE_RELEASE(m_d3dvb); if( m_bIsDeviceLost && GetRefCount() <= 1 ) m_dev->DelReloadVertexList(this); } void K3DVertexBufferDX::Recycle() // 재사용 { // KResource::Recycle(); //삭제 됨 // return; if( m_bUseRecycle ) m_dev->AddRecycleVertexBuffer( this, m_format, m_usage, m_vtxStride, m_vtxCount ); else KResource::Recycle(); //삭제 됨 } bool K3DVertexBufferDX::Initialize( KStream &stream, int vertexformat, int count ) { m_format = vertexformat; m_vtxCount = count; m_vtxStride = K3DVertexBuffer::CalcVertexStride( vertexformat ); HRESULT hr = m_dev->GetD3DDevice()->CreateVertexBuffer( m_vtxStride * m_vtxCount, D3DUSAGE_WRITEONLY, vertexformat, D3DPOOL_MANAGED, &m_d3dvb, NULL ); if( hr == D3D_OK ) { unsigned char *pBuf; m_d3dvb->Lock( 0, m_vtxStride * m_vtxCount, (void**)&pBuf, 0 ); assert(pBuf && "m_d3dvb->Lock( 0, m_vtxStride * m_vtxCount, (void**)&pBuf, 0 );"); stream.Read( pBuf, m_vtxStride * m_vtxCount ); m_d3dvb->Unlock(); SetValidVtx( true ); } return true; } bool K3DVertexBufferDX::CreateNewSpeedTree( unsigned int nStride, DWORD Usage, int count, int vertexformat ) { m_bIsDeviceLost = true; m_usage = Usage; m_format = vertexformat; m_vtxCount = count; m_vtxStride = nStride; m_type = RESTYPE_VERTEXBUFFERSPEEDTREE; HRESULT hr; if(m_usage & D3DUSAGE_DYNAMIC) m_Pool = D3DPOOL_DEFAULT; else m_Pool = D3DPOOL_MANAGED; hr = m_dev->GetD3DDevice()->CreateVertexBuffer( nStride * m_vtxCount, m_usage, vertexformat, m_Pool, &m_d3dvb, NULL ); if( hr == D3D_OK ) SetValidVtx( true ); return true; } bool K3DVertexBufferDX::CreateNewSpeedGrass( unsigned int nStride, DWORD Usage, int count, int vertexformat ) { m_bIsDeviceLost = true; m_usage = Usage; m_format = vertexformat; m_vtxCount = count; m_vtxStride = nStride; m_type = RESTYPE_VERTEXBUFFERSPEEDGRASS; HRESULT hr; if(m_usage & D3DUSAGE_DYNAMIC) m_Pool = D3DPOOL_DEFAULT; else m_Pool = D3DPOOL_MANAGED; hr = m_dev->GetD3DDevice()->CreateVertexBuffer( nStride * m_vtxCount, m_usage, vertexformat, m_Pool, &m_d3dvb, NULL ); if( hr == D3D_OK ) SetValidVtx( true ); return true; } //Blend 용 버텍스~ bool K3DVertexBufferDX::CreateNewBlend( unsigned int nStride, int count, int vertexformat ) { m_format = vertexformat; m_vtxCount = count; m_vtxStride = nStride; m_Pool = D3DPOOL_MANAGED; HRESULT hr = m_dev->GetD3DDevice()->CreateVertexBuffer( nStride * m_vtxCount, m_usage, vertexformat, D3DPOOL_MANAGED, &m_d3dvb, NULL ); m_type = RESTYPE_VERTEXBUFFERBLEND; if( hr == D3D_OK ) SetValidVtx( true ); return true; } bool K3DVertexBufferDX::CreateNewPoolDefault( unsigned int nStride, int count, int vertexformat, DWORD Usage ) { m_format = vertexformat; m_vtxCount = count; m_vtxStride = nStride; m_usage = Usage; m_Pool = D3DPOOL_DEFAULT; HRESULT hr = m_dev->GetD3DDevice()->CreateVertexBuffer( nStride * m_vtxCount, m_usage, vertexformat, D3DPOOL_DEFAULT, &m_d3dvb, NULL ); m_type = RESTYPE_VERTEXBUFFERPOOLDEFAULT; if( hr == D3D_OK ) SetValidVtx( true ); return true; } bool K3DVertexBufferDX::CreateNew( int vertexformat, int count ) { m_format = vertexformat; m_vtxCount = count; m_vtxStride = K3DVertexBuffer::CalcVertexStride( vertexformat ); m_Pool = D3DPOOL_MANAGED; HRESULT hr = m_dev->GetD3DDevice()->CreateVertexBuffer( m_vtxStride * m_vtxCount, D3DUSAGE_WRITEONLY, vertexformat, D3DPOOL_MANAGED, &m_d3dvb, NULL ); if( hr == D3D_OK ) SetValidVtx( true ); return true; } void K3DVertexBufferDX::Lock( void** pBuf, int& size, DWORD flags ) { if ( m_bLocked == false && m_d3dvb != NULL ) { if ( m_d3dvb->Lock( 0, 0, pBuf, flags ) == D3D_OK ) m_bLocked = true; } else { *pBuf = NULL; } } void K3DVertexBufferDX::Unlock() { if ( m_bLocked == true && m_d3dvb ) { m_d3dvb->Unlock(); m_bLocked = false; } } bool K3DVertexBufferDX::Backup() { //버퍼에 백업.. int nSize = m_vtxCount*m_vtxStride; SAFE_DELETE_ARRAY( m_pBackUpBuf ); m_pBackUpBuf = new char[nSize]; memset( m_pBackUpBuf, 0, sizeof(char)*nSize ); void *pTempBuf = NULL; if(m_usage & D3DUSAGE_DYNAMIC) Lock( (void**)&pTempBuf, nSize, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD ); else Lock( (void**)&pTempBuf, nSize ); if( pTempBuf ) { memcpy( m_pBackUpBuf, pTempBuf, sizeof(char)*nSize ); Unlock(); } return true; } bool K3DVertexBufferDX::PreReload() { SAFE_RELEASE(m_d3dvb); return true; } bool K3DVertexBufferDX::Reload() { //백업 버퍼로 복구 int nSize = m_vtxCount*m_vtxStride; void *pTempBuf = NULL; if( m_type == RESTYPE_VERTEXBUFFERSPEEDGRASS || m_type == RESTYPE_VERTEXBUFFERSPEEDTREE ) { CreateNewSpeedTree( m_vtxStride, m_usage, m_vtxCount, m_format ); Lock( (void**)&pTempBuf, nSize ); } else if ( m_type == RESTYPE_VERTEXBUFFERPOOLDEFAULT ) { CreateNewPoolDefault( m_vtxStride, m_vtxCount, m_format, m_usage ); Lock( (void**)&pTempBuf, nSize, D3DLOCK_NOOVERWRITE ); if( pTempBuf == NULL ) Lock( (void**)&pTempBuf, nSize, D3DLOCK_DISCARD ); } if( pTempBuf && m_pBackUpBuf ) { memcpy( pTempBuf, m_pBackUpBuf, sizeof(char)*nSize ); } Unlock(); return true; }