diff --git a/panda/src/dxgsg8/dxIndexBufferContext8.cxx b/panda/src/dxgsg8/dxIndexBufferContext8.cxx index 022461511a..3f2e2cf0c1 100644 --- a/panda/src/dxgsg8/dxIndexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxIndexBufferContext8.cxx @@ -70,12 +70,14 @@ create_ibuffer(DXScreenData &scrn) { PStatTimer timer(GraphicsStateGuardian::_create_index_buffer_pcollector); - D3DFORMAT index_type = + D3DFORMAT index_type = DXGraphicsStateGuardian8::get_index_type(get_data()->get_index_type()); HRESULT hr = scrn._d3d_device->CreateIndexBuffer - (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY, - index_type, D3DPOOL_MANAGED, &_ibuffer); +// (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY, +// index_type, D3DPOOL_MANAGED, &_ibuffer); + (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, + index_type, D3DPOOL_DEFAULT, &_ibuffer); if (FAILED(hr)) { dxgsg8_cat.warning() << "CreateIndexBuffer failed" << D3DERRORSTRING(hr); @@ -84,7 +86,7 @@ create_ibuffer(DXScreenData &scrn) { if (dxgsg8_cat.is_debug()) { dxgsg8_cat.debug() << "creating index buffer " << _ibuffer << ": " - << get_data()->get_num_vertices() << " indices (" + << get_data()->get_num_vertices() << " indices (" << get_data()->get_vertices()->get_array_format()->get_column(0)->get_numeric_type() << ")\n"; } @@ -103,7 +105,7 @@ upload_data() { PStatTimer timer(GraphicsStateGuardian::_load_index_buffer_pcollector); int data_size = get_data()->get_data_size_bytes(); - + if (dxgsg8_cat.is_spam()) { dxgsg8_cat.spam() << "copying " << data_size @@ -111,7 +113,8 @@ upload_data() { } BYTE *local_pointer; - HRESULT hr = _ibuffer->Lock(0, data_size, &local_pointer, 0); +// HRESULT hr = _ibuffer->Lock(0, data_size, &local_pointer, 0); + HRESULT hr = _ibuffer->Lock(0, data_size, &local_pointer, D3DLOCK_DISCARD); if (FAILED(hr)) { dxgsg8_cat.error() << "IndexBuffer::Lock failed" << D3DERRORSTRING(hr); diff --git a/panda/src/dxgsg8/dxVertexBufferContext8.cxx b/panda/src/dxgsg8/dxVertexBufferContext8.cxx index 3c7472a331..b6d04d3c93 100644 --- a/panda/src/dxgsg8/dxVertexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxVertexBufferContext8.cxx @@ -46,8 +46,8 @@ DXVertexBufferContext8(GeomVertexArrayData *data) : int num_columns = array_format->get_num_columns(); _fvf = 0; - - if (n < num_columns && + + if (n < num_columns && array_format->get_column(n)->get_name() == InternalName::get_vertex()) { ++n; @@ -59,7 +59,7 @@ DXVertexBufferContext8(GeomVertexArrayData *data) : num_blend_values = array_format->get_column(n)->get_num_values(); ++n; } - + if (n < num_columns && array_format->get_column(n)->get_name() == InternalName::get_transform_index()) { // Furthermore, it's indexed vertex animation. @@ -95,12 +95,12 @@ DXVertexBufferContext8(GeomVertexArrayData *data) : } } - if (n < num_columns && + if (n < num_columns && array_format->get_column(n)->get_name() == InternalName::get_normal()) { _fvf |= D3DFVF_NORMAL; ++n; } - if (n < num_columns && + if (n < num_columns && array_format->get_column(n)->get_name() == InternalName::get_color()) { _fvf |= D3DFVF_DIFFUSE; ++n; @@ -109,7 +109,7 @@ DXVertexBufferContext8(GeomVertexArrayData *data) : // Now look for all of the texcoord names and enable them in the // same order they appear in the array. int texcoord_index = 0; - while (n < num_columns && + while (n < num_columns && array_format->get_column(n)->get_contents() == Geom::C_texcoord) { const GeomVertexColumn *column = array_format->get_column(n); switch (column->get_num_values()) { @@ -197,8 +197,10 @@ create_vbuffer(DXScreenData &scrn) { PStatTimer timer(GraphicsStateGuardian::_create_vertex_buffer_pcollector); HRESULT hr = scrn._d3d_device->CreateVertexBuffer - (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY, - _fvf, D3DPOOL_MANAGED, &_vbuffer); +// (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY, +// _fvf, D3DPOOL_MANAGED, &_vbuffer); + (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, + _fvf, D3DPOOL_DEFAULT, &_vbuffer); if (FAILED(hr)) { dxgsg8_cat.warning() << "CreateVertexBuffer failed" << D3DERRORSTRING(hr); @@ -207,7 +209,7 @@ create_vbuffer(DXScreenData &scrn) { if (dxgsg8_cat.is_debug()) { dxgsg8_cat.debug() << "created vertex buffer " << _vbuffer << ": " - << get_data()->get_num_rows() << " vertices " + << get_data()->get_num_rows() << " vertices " << *get_data()->get_array_format() << "\n"; } } @@ -225,7 +227,7 @@ upload_data() { PStatTimer timer(GraphicsStateGuardian::_load_vertex_buffer_pcollector); int data_size = get_data()->get_data_size_bytes(); - + if (dxgsg8_cat.is_spam()) { dxgsg8_cat.spam() << "copying " << data_size @@ -233,7 +235,8 @@ upload_data() { } BYTE *local_pointer; - HRESULT hr = _vbuffer->Lock(0, data_size, &local_pointer, 0); +// HRESULT hr = _vbuffer->Lock(0, data_size, &local_pointer, 0); + HRESULT hr = _vbuffer->Lock(0, data_size, &local_pointer, D3DLOCK_DISCARD); if (FAILED(hr)) { dxgsg8_cat.error() << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr); diff --git a/panda/src/dxgsg9/Sources.pp b/panda/src/dxgsg9/Sources.pp index b98d19d973..7118d1c293 100755 --- a/panda/src/dxgsg9/Sources.pp +++ b/panda/src/dxgsg9/Sources.pp @@ -1,14 +1,13 @@ -// DX9 build is temporarily disabled until we bring it up-to-date with -// the new Geom rewrite. -#define BUILD_DIRECTORY -//#define BUILD_DIRECTORY $[HAVE_DX] +#define BUILD_DIRECTORY $[HAVE_DX] -#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ - dtoolutil:c dtoolbase:c dtool:m -#define USE_PACKAGES dx +#define OTHER_LIBS \ + interrogatedb:c dconfig:c dtoolconfig:m \ + dtoolutil:c dtoolbase:c dtool:m #define WIN_SYS_LIBS \ d3d9.lib d3dx9.lib dxerr9.lib + +#define USE_PACKAGES dx #begin lib_target #define TARGET dxgsg9 @@ -18,12 +17,6 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx - // need to install these due to external projects that link directly with libpandadx (bartop) - #define INSTALL_HEADERS \ - dxgsg9base.h config_dxgsg9.h dxGraphicsStateGuardian9.I dxGraphicsStateGuardian9.h \ - dxTextureContext9.h d3dfont9.h \ - dxGraphicsDevice9.h - // build dxGraphicsStateGuardian separately since its so big #define SOURCES \ @@ -31,12 +24,19 @@ dxGraphicsDevice9.h \ wdxGraphicsPipe9.I wdxGraphicsPipe9.h \ wdxGraphicsWindow9.I wdxGraphicsWindow9.h \ - $[INSTALL_HEADERS] + dxgsg9base.h config_dxgsg9.h dxGraphicsStateGuardian9.I dxGraphicsStateGuardian9.h \ + dxVertexBufferContext9.h dxVertexbufferContext9.I \ + dxIndexBufferContext9.h dxIndexBufferContext9.I \ + dxTextureContext9.h dxTextureContext9.I \ + dxGeomMunger9.h dxGeomMunger9.I \ + dxGraphicsDevice9.h #define INCLUDED_SOURCES \ config_dxgsg9.cxx \ + dxVertexBufferContext9.cxx \ + dxIndexBufferContext9.cxx \ dxTextureContext9.cxx \ - d3dfont9.cxx \ + dxGeomMunger9.cxx \ dxGraphicsDevice9.cxx \ wdxGraphicsPipe9.cxx wdxGraphicsWindow9.cxx diff --git a/panda/src/dxgsg9/config_dxgsg9.cxx b/panda/src/dxgsg9/config_dxgsg9.cxx index b049d85ac4..e5635abac9 100755 --- a/panda/src/dxgsg9/config_dxgsg9.cxx +++ b/panda/src/dxgsg9/config_dxgsg9.cxx @@ -1,10 +1,10 @@ -// Filename: config_dxgsg8.cxx -// Created by: masad (02Jan04) +// Filename: config_dxgsg9.cxx +// Created by: drose (06Oct99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -19,6 +19,9 @@ #include "config_dxgsg9.h" #include "dxGraphicsStateGuardian9.h" #include "dxTextureContext9.h" +#include "dxVertexBufferContext9.h" +#include "dxIndexBufferContext9.h" +#include "dxGeomMunger9.h" #include "graphicsPipeSelection.h" #include "wdxGraphicsWindow9.h" #include "wdxGraphicsPipe9.h" @@ -27,9 +30,8 @@ #include "dconfig.h" Configure(config_dxgsg9); -//NotifyCategoryDef(dxgsg9, ":display:gsg"); dont want to merge this with the regular parent class dbg output -NotifyCategoryDef(dxgsg9, "dxgsg"); -NotifyCategoryDef(wdxdisplay9, "windisplay"); +NotifyCategoryDef(dxgsg9, ":display:gsg"); +NotifyCategoryDef(wdxdisplay9, "display"); // Configure this variable true to cause the DXGSG to show each // transform space it renders by drawing a little unit axis. This @@ -45,9 +47,9 @@ ConfigVariableInt dx_multisample_antialiasing_level ConfigVariableBool dx_no_vertex_fog ("dx-no-vertex-fog", false); -// if true, overwrite cursor bitmap tip with "D3D" to distinguish it from GDI cursor +// if true, overwrite cursor bitmap tip with "D3D" to distinguish it from GDI cursor ConfigVariableBool dx_show_cursor_watermark -("dx-show-cursor-watermark", +("dx-show-cursor-watermark", #ifdef _DEBUG true #else @@ -59,6 +61,18 @@ ConfigVariableBool dx_show_cursor_watermark ConfigVariableBool dx_use_triangle_mipgen_filter ("dx-use-triangle-mipgen-filter", false); +ConfigVariableBool dx_broken_max_index +("dx-broken-max-index", false, + PRC_DESC("Configure this true if you have a buggy graphics driver that " + "doesn't correctly implement the third parameter, NumVertices, " + "of DrawIndexedPrimitive(). In particular, the NVIDIA Quadro " + "driver version 6.14.10.7184 seems to treat this as a maximum " + "vertex index, rather than a delta between the maximum and " + "minimum vertex index. Turn this on if you are seeing stray " + "triangles, or you are not seeing all of your triangles. Enabling " + "this should work around this bug, at the cost of some additional " + "rendering overhead on the GPU.")); + #ifndef NDEBUG // debugging flag // values are same as D3DCULL enumtype, 0 - no force, 1 - force none, 2 - force CW, 3 - force CCW @@ -110,7 +124,7 @@ ConfigVariableBool dx_debug_view_mipmaps ConfigVariableBool dx_force_anisotropic_filtering ("dx-force-anisotropic-filtering", false); -// set 'retained-mode #t' and this to have prepare_geom concatenate all tristrips within a geom +// set 'retained-mode #t' and this to have prepare_geom concatenate all tristrips within a geom // together using degenerate tris ConfigVariableBool link_tristrips ("link-tristrips", false); @@ -137,6 +151,9 @@ init_libdxgsg9() { DXGraphicsStateGuardian9::init_type(); DXTextureContext9::init_type(); + DXVertexBufferContext9::init_type(); + DXIndexBufferContext9::init_type(); + DXGeomMunger9::init_type(); wdxGraphicsPipe9::init_type(); wdxGraphicsWindow9::init_type(); diff --git a/panda/src/dxgsg9/config_dxgsg9.h b/panda/src/dxgsg9/config_dxgsg9.h index a31441a522..b6b7363643 100755 --- a/panda/src/dxgsg9/config_dxgsg9.h +++ b/panda/src/dxgsg9/config_dxgsg9.h @@ -1,10 +1,10 @@ // Filename: config_dxgsg.h -// Created by: masad (02Jan04) +// Created by: drose (06Oct99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -36,6 +36,7 @@ extern ConfigVariableBool dx_use_rangebased_fog; extern ConfigVariableBool link_tristrips; extern ConfigVariableInt dx_multisample_antialiasing_level; extern ConfigVariableBool dx_use_triangle_mipgen_filter; +extern ConfigVariableBool dx_broken_max_index; // debug flags we might want to use in full optimized build diff --git a/panda/src/dxgsg9/d3dfont9.cxx b/panda/src/dxgsg9/d3dfont9.cxx deleted file mode 100755 index 585a853f70..0000000000 --- a/panda/src/dxgsg9/d3dfont9.cxx +++ /dev/null @@ -1,946 +0,0 @@ -//----------------------------------------------------------------------------- -// File: D3DFont.cpp -// -// Desc: Texture-based font class -// modified from a modified version of DXSDK CD3DFont from http://www.lafaqmfc.com/directx.htm -// Note that this is faster than ID3DXFont, which calls GDI in Draw() -//----------------------------------------------------------------------------- -#ifndef STRICT -#define STRICT -#endif - -#include "dxgsg9base.h" -#include -#include -#include -#include "d3dfont9.h" - -//----------------------------------------------------------------------------- -// Custom vertex types for rendering text -//----------------------------------------------------------------------------- - -struct FONT2DVERTEX { - D3DXVECTOR4 p; DWORD color; FLOAT tu, tv; -}; -struct FONT3DVERTEX { - D3DXVECTOR3 p; D3DXVECTOR3 n; FLOAT tu, tv; -}; - -inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color, - FLOAT tu, FLOAT tv ) { - FONT2DVERTEX v; v.p = p; v.color = color; v.tu = tu; v.tv = tv; - return v; -} - -inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n, - FLOAT tu, FLOAT tv ) { - FONT3DVERTEX v; v.p = p; v.n = n; v.tu = tu; v.tv = tv; - return v; -} - -//----------------------------------------------------------------------------- -// Name: CD3DFont() -// Desc: Font class constructor -//----------------------------------------------------------------------------- -CD3DFont::CD3DFont( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags ) { - _tcscpy( m_strFontName, strFontName ); - m_dwFontHeight = dwHeight; - m_dwFontFlags = dwFlags; - - m_pd3dDevice = NULL; - m_pTexture = NULL; - m_pVB = NULL; - - m_pSBSavedStateBlock = NULL; - m_pSBDrawTextStateBlock = NULL; - - ClearBeginEndData ( ) ; - m_bBeginText = false ; -} - -//----------------------------------------------------------------------------- -// Name: ~CD3DFont() -// Desc: Font class destructor -//----------------------------------------------------------------------------- -CD3DFont::~CD3DFont() { - DeleteDeviceObjects(); -} - -//----------------------------------------------------------------------------- -// Name: InitDeviceObjects() -// Desc: Initializes device-dependent objects, including the vertex buffer used -// for rendering text and the texture map which stores the font image. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice ) { - HRESULT hr; - - // Keep a local copy of the device - m_pd3dDevice = pd3dDevice; - - // Establish the font and texture size - m_fTextScale = 1.0f; // Draw fonts into texture without scaling - - // Large fonts need larger textures - // We can be generous at this step, this is an estimate - if(m_dwFontHeight > 40) - m_dwTexWidth = m_dwTexHeight = 2048; - else if(m_dwFontHeight > 32) - m_dwTexWidth = m_dwTexHeight = 1024; - else if(m_dwFontHeight > 16) - m_dwTexWidth = m_dwTexHeight = 512; - else - m_dwTexWidth = m_dwTexHeight = 256; - - // Prepare to create a bitmap - DWORD* pBitmapBits; - BITMAPINFO bmi; - ZeroMemory( &bmi.bmiHeader, sizeof(BITMAPINFOHEADER) ); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // Create a DC and a bitmap for the font - HDC hDC = CreateCompatibleDC( NULL ); - HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS, - (VOID**)&pBitmapBits, NULL, 0 ); - SetMapMode( hDC, MM_TEXT ); - - // Create a font. By specifying ANTIALIASED_QUALITY, we might get an - // antialiased font, but this is not guaranteed. - INT nHeight = -MulDiv( m_dwFontHeight, - (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 ); - DWORD dwBold = (m_dwFontFlags&D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL; - DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE : FALSE; - HFONT hFont = CreateFont( nHeight, 0, 0, 0, dwBold, - - FALSE , // dwItalic, // NO! We should not do that... - // See below comment about GetTextExtentPoint32 - - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, - VARIABLE_PITCH, m_strFontName ); - if(NULL==hFont) { - dxgsg9_cat.error() << "CD3DFont InitDeviceObjects(): initial CreateFont failed! GetLastError=" << GetLastError() << endl; - return E_FAIL; - } - - HBITMAP hbmOld = ( HBITMAP ) SelectObject ( hDC, hbmBitmap ); - HFONT hfOld = ( HFONT ) SelectObject ( hDC, hFont ); - - // Set text properties - SetTextColor( hDC, RGB(255,255,255) ); - SetBkColor( hDC, 0x00000000 ); - SetTextAlign( hDC, TA_TOP ); - - // First Loop through all printable characters - // in order to determine the smallest necessary texture - DWORD x = 0; - DWORD y = 0; - TCHAR str[2] = _T("x"); - SIZE size; - SIZE sizes [ 127 - 32 ] ; - - TCHAR c; - for(c=32; c<127; c++) { - str[0] = c; - // GetTextExtentPoint32 does not care that the font is Italic or not, it will - // return the same value. However, if we specify an Italic font, the output - // on the bitmap will use more pixels. - // If the font is Italic we have to output the standard character - // and bend our vertices. - GetTextExtentPoint32 ( hDC, str, 1, & sizes [ c - 32 ] ); - } ; - - static DWORD TexturesSizes [ 5 ] = { 128 , 256 , 512 , 1024 , 2048} ; - DWORD dwTexSize = 0 ; - for(DWORD iTex = 0 ; iTex < 5 ; ++ iTex) { - // fake the tex coord loop calculation - x = 0 ; - y = 0 ; - for(TCHAR c=32; c<127; c++) { - if((DWORD)( x + sizes[ c - 32 ].cx+1) > TexturesSizes [ iTex ]) { - x = 0; - y += sizes[ c - 32 ].cy+1; - // new y size - if((DWORD) ( y + sizes[ 0 ].cy + 1 ) >= TexturesSizes [ iTex ]) { - // does not fit, let's try a larger one - break ; - }; - }; - x += sizes[ c - 32 ].cx + 2 ; - } ; - - if((DWORD) ( y + sizes[ 0 ].cy + 1 ) < TexturesSizes [ iTex ]) { - // Yahoo! it fits! - dwTexSize = TexturesSizes [ iTex ] ; - break ; - }; - } ; - - m_dwTexWidth = m_dwTexHeight = dwTexSize ; - - // Select old objects ( added ) - // Is this needed for compatible DCs? - // The old handles are not not NULL, so it is done "by the book" - SelectObject ( hDC, hbmOld ); - SelectObject ( hDC, hfOld ); - - // delete our gdi objects - DeleteObject( hbmBitmap ); - DeleteObject( hFont ); - DeleteDC( hDC ); - - // moved here to allow deletion of GDI objects - if(dwTexSize == 0) { - dxgsg9_cat.error() << "CD3DFont InitDeviceObjects() error: Texture didnt fit, creation failed!\n"; - return E_FAIL; - } - - // Re-Create new GDI stuff with the optimal size - // - // Prepare to create a bitmap - ZeroMemory( &bmi.bmiHeader, sizeof(BITMAPINFOHEADER) ); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // Create a DC and a bitmap for the font - hDC = CreateCompatibleDC( NULL ); - hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS, - (VOID**)&pBitmapBits, NULL, 0 ); - SetMapMode( hDC, MM_TEXT ); - - // Create a font. By specifying ANTIALIASED_QUALITY, we might get an - // antialiased font, but this is not guaranteed. - nHeight = -MulDiv( m_dwFontHeight, - (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 ); - dwBold = (m_dwFontFlags&D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL; - dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE : FALSE; - hFont = CreateFont( nHeight, 0, 0, 0, dwBold, - FALSE , // was dwItalic, // see above - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, - VARIABLE_PITCH, m_strFontName ); - - if(NULL==hFont) { - dxgsg9_cat.error() << "CD3DFont InitDeviceObjects(): optimal CreateFont failed! GetLastError=" << GetLastError() << endl; - return E_FAIL; - } - - hbmOld = ( HBITMAP ) SelectObject ( hDC, hbmBitmap ); - hfOld = ( HFONT ) SelectObject ( hDC, hFont ); - - // Set text properties - SetTextColor( hDC, RGB(255,255,255) ); - SetBkColor( hDC, 0x00000000 ); - SetTextAlign( hDC, TA_TOP ); - - // If requested texture is too big, use a smaller texture and smaller font, - // and scale up when rendering. - D3DCAPS9 d3dCaps; - m_pd3dDevice->GetDeviceCaps( &d3dCaps ); - - if(m_dwTexWidth > d3dCaps.MaxTextureWidth) { - m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth; - m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth; - }; - - // Create a new texture for the font - hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1, - 0, D3DFMT_A4R4G4B4, - D3DPOOL_MANAGED, &m_pTexture, NULL); - - if(FAILED(hr)) { - SelectObject ( hDC, hbmOld ); - SelectObject ( hDC, hfOld ); - - DeleteObject( hbmBitmap ); - DeleteObject( hFont ); - DeleteDC( hDC ); - - dxgsg9_cat.error() << "CD3DFont InitDeviceObjs CreateTexture failed!" << D3DERRORSTRING(hr); - return hr; - }; - - // Loop through all printable character and output them to the bitmap.. - // Meanwhile, keep track of the corresponding tex coords for each character. - x = 0 ; - y = 0 ; - - for(c=32; c<127; c++) { - str[0] = c; - GetTextExtentPoint32( hDC, str, 1, &size ); - if((DWORD)(x+size.cx+1) > m_dwTexWidth) { - x = 0; - y += size.cy+1; - } - - // We need one pixel on both sides - - // plus one here for one pixel on the left - ExtTextOut( hDC, x + 1, y, ETO_OPAQUE, NULL, str, 1, NULL ); - - m_fTexCoords[c-32][0] = ( (FLOAT) x + 0.5f ) / m_dwTexWidth ; - m_fTexCoords[c-32][1] = ( (FLOAT) y + 0.5f ) / m_dwTexHeight ; - m_fTexCoords[c-32][2] = ( (FLOAT) x + 0.5f + size.cx ) / m_dwTexWidth; - m_fTexCoords[c-32][3] = ( (FLOAT) y + 0.5f + size.cy ) / m_dwTexHeight; - - // plus two here because we also need one more pixel on the right side - x += size.cx + 2 ; - } - - // Lock the surface and write the alpha values for the set pixels - D3DLOCKED_RECT d3dlr; - m_pTexture->LockRect( 0, &d3dlr, 0, 0 ); - BYTE* pDstRow = (BYTE*)d3dlr.pBits; - WORD* pDst16; - BYTE bAlpha; // 4-bit measure of pixel intensity - - for(y=0; y < m_dwTexHeight; y++) { - pDst16 = (WORD*)pDstRow; - for(x=0; x < m_dwTexWidth; x++) { - bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4); - if(bAlpha > 0) { - *pDst16++ = (bAlpha << 12) | 0x0fff; - } else { - *pDst16++ = 0x0000; - } - } - pDstRow += d3dlr.Pitch; - } - - // Done updating texture, so clean up used objects - m_pTexture->UnlockRect(0); - - SelectObject ( hDC, hbmOld ); - SelectObject ( hDC, hfOld ); - - DeleteObject( hbmBitmap ); - DeleteObject( hFont ); - DeleteDC( hDC ); - - return RestoreDeviceObjects(); -} - -//----------------------------------------------------------------------------- -// Name: RestoreDeviceObjects() -// Desc: -//----------------------------------------------------------------------------- -HRESULT CD3DFont::RestoreDeviceObjects() { - HRESULT hr; - - // Create vertex buffer for the letters - if(FAILED( hr = m_pd3dDevice->CreateVertexBuffer( - // can be rendered 3d - MAX_NUM_VERTICES*sizeof(FONT3DVERTEX /*FONT2DVERTEX */ ), - D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, - D3DPOOL_DEFAULT, // D3DUSAGE_DYNAMIC makes D3DPOOL_MANAGED impossible - &m_pVB, NULL ) )) { - dxgsg9_cat.error() << "CD3DFont CreateVB failed!" << D3DERRORSTRING(hr); - return hr; - } - - PRINT_REFCNT(dxgsg9,m_pd3dDevice); - - // Create the state blocks for rendering text - for(UINT which=0; which<2; which++) { - m_pd3dDevice->BeginStateBlock(); - m_pd3dDevice->SetTexture( 0, m_pTexture ); - - if(D3DFONT_ZENABLE & m_dwFontFlags) - m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); - else - m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); - - m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); - m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); - m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); - m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); - m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 ); - m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL ); - m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); - m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); - m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE ); - m_pd3dDevice->SetRenderState( D3DRS_CLIPPING, TRUE ); - m_pd3dDevice->SetRenderState( D3DRS_ANTIALIASEDLINEENABLE, FALSE ); - m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE ); - m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, FALSE ); - m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE ); - m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); - m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT ); - m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT ); - m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); - m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); - m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); - - if(which==0) - m_pd3dDevice->EndStateBlock( &m_pSBSavedStateBlock ); - else - m_pd3dDevice->EndStateBlock( &m_pSBDrawTextStateBlock ); - } - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: InvalidateDeviceObjects() -// Desc: Destroys all device-dependent objects -//----------------------------------------------------------------------------- -HRESULT CD3DFont::InvalidateDeviceObjects() { - HRESULT hr; - - PRINT_REFCNT(dxgsg9,m_pd3dDevice); - - if(IS_VALID_PTR(m_pd3dDevice)) { - // undo SetStreamSource before releasing VB - - IDirect3DVertexBuffer9 *pStreamData=NULL; - UINT StreamStride; - hr = m_pd3dDevice->GetStreamSource(0,&pStreamData,NULL,&StreamStride); - SAFE_RELEASE(pStreamData); // undo GetStreamSource AddRef - if(pStreamData==m_pVB) - hr = m_pd3dDevice->SetStreamSource(0,NULL,0,0); - } - - PRINT_REFCNT(dxgsg9,m_pVB); - - RELEASE(m_pVB,dxgsg9,"d3dfont VB",RELEASE_ONCE); - - PRINT_REFCNT(dxgsg9,m_pd3dDevice); - - /* not necessary in DX9 - // Delete the state blocks - if(m_pd3dDevice) { - assert(IS_VALID_PTR(m_pd3dDevice)); - if(m_pSBSavedStateBlock) - m_pd3dDevice->DeleteStateBlock( m_pSBSavedStateBlock ); - if(m_pSBDrawTextStateBlock) - m_pd3dDevice->DeleteStateBlock( m_pSBDrawTextStateBlock ); - } - */ - - PRINT_REFCNT(dxgsg9,m_pd3dDevice); - - m_pSBSavedStateBlock = NULL; - m_pSBDrawTextStateBlock = NULL; - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: DeleteDeviceObjects() -// Desc: Destroys all device-dependent objects -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DeleteDeviceObjects() { - PRINT_REFCNT(dxgsg9,m_pd3dDevice); - - InvalidateDeviceObjects(); - - SAFE_RELEASE( m_pTexture ); - - PRINT_REFCNT(dxgsg9,m_pd3dDevice); - - m_pd3dDevice = NULL; - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: GetTextExtent() -// Desc: Get the dimensions of a text string -//----------------------------------------------------------------------------- -HRESULT CD3DFont::GetTextExtent( TCHAR* strText, SIZE* pSize ) { - if(NULL==strText || NULL==pSize) - return E_FAIL; - - FLOAT fRowWidth = 0.0f; - FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight; - FLOAT fWidth = 0.0f; - FLOAT fHeight = fRowHeight; - - while(*strText) { - TCHAR c = *strText++; - - if(c == _T('\n')) { - fRowWidth = 0.0f; - fHeight += fRowHeight; - } - if(c < _T(' ')) - continue; - - FLOAT tx1 = m_fTexCoords[c-32][0]; - FLOAT tx2 = m_fTexCoords[c-32][2]; - - fRowWidth += (tx2-tx1)*m_dwTexWidth; - - if(fRowWidth > fWidth) - fWidth = fRowWidth; - } - - pSize->cx = (int)fWidth; - pSize->cy = (int)fHeight; - - return S_OK; -} - -//----------------------------------------------------------------------------- -// Name: DrawTextScaled() -// Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates -// (ranging from -1 to +1). fXScale and fYScale are the size fraction -// relative to the entire viewport. For example, a fXScale of 0.25 is -// 1/8th of the screen width. This allows you to output text at a fixed -// fraction of the viewport, even if the screen or window size changes. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z, - FLOAT fXScale, FLOAT fYScale, DWORD dwColor, - TCHAR* strText, DWORD dwFlags ) { - if(m_pd3dDevice == NULL) - return E_FAIL; - - HRESULT hr ; - if(m_bBeginText) { - hr = DeferedDrawTextScaled ( x, y, z, fXScale, fYScale, dwColor, strText, dwFlags ) ; - } else { - BeginText ( ) ; - hr = DeferedDrawTextScaled ( x, y, z, fXScale, fYScale, dwColor, strText, dwFlags ) ; - if(! FAILED ( hr )) - EndText ( ) ; - } ; - - return hr ; -} - -//----------------------------------------------------------------------------- -// Name: DrawText() -// Desc: Draws 2D text -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor, - TCHAR* strText, DWORD dwFlags ) { - if(m_pd3dDevice == NULL) - return E_FAIL; - - HRESULT hr ; - if(m_bBeginText) { - hr = DeferedDrawText ( sx, sy, dwColor, strText, dwFlags ) ; - } else { - BeginText(); - hr = DeferedDrawText ( sx, sy, dwColor, strText, dwFlags ) ; - if(! FAILED ( hr )) - EndText ( ) ; - } ; - - return hr ; -} - - -void CD3DFont::ClearBeginEndData ( void ) { - m_nDeferedCalls = 0 ; - m_TextBuffer [ 0 ] = 0 ; - m_pTextBuffer = & m_TextBuffer [ 0 ] ; -} - -HRESULT CD3DFont::BeginText ( void ) { - m_bBeginText = true ; - ClearBeginEndData() ; - - return S_OK ; -} - -HRESULT CD3DFont::DeferedDrawTextScaled -( FLOAT x, FLOAT y, FLOAT z, - FLOAT fXScale, FLOAT fYScale, DWORD dwColor, - TCHAR* strText, DWORD dwFlags ) { - return - DeferedDraw ( true , x, y, z, fXScale, fYScale, dwColor, strText, dwFlags ) ; -} - -HRESULT CD3DFont::DeferedDrawText -( FLOAT x, FLOAT y, DWORD dwColor, - TCHAR* strText, DWORD dwFlags ) { - return - DeferedDraw ( false , x, y, 0.0f , 0.0f , 0.0f , dwColor, strText, dwFlags ) ; -} - -HRESULT CD3DFont::DeferedDraw -( bool bScaled , - FLOAT x, FLOAT y, FLOAT z, - FLOAT fXScale, FLOAT fYScale, DWORD dwColor, - TCHAR* strText, DWORD dwFlags ) { - if(m_nDeferedCalls >= MaxCalls) { - dxgsg9_cat.error() << "CD3DFont DeferedDraw() error, MaxCalls exceeded!\n"; - return E_FAIL ; - } - - // we need to make a deep copy of the string - // the user object might have fallen out of scope - // when it will be time to render - int nStrLen = strlen ( strText ) + 1 ; - int nUsed = m_pTextBuffer - & m_pTextBuffer [ 0 ] ; - if(nUsed + nStrLen > TextBufferLength) { - dxgsg9_cat.error() << "CD3DFont DeferedDraw() error, TextBufferLength exceeded!\n"; - return E_FAIL ; - } - - strcpy ( m_pTextBuffer , strText ) ; - m_DTArgs [ m_nDeferedCalls ].m_strText = m_pTextBuffer ; - m_pTextBuffer += nStrLen ; - - m_DTArgs [ m_nDeferedCalls ].m_bScaled = bScaled ; - m_DTArgs [ m_nDeferedCalls ].m_x = x ; - m_DTArgs [ m_nDeferedCalls ].m_y = y ; - m_DTArgs [ m_nDeferedCalls ].m_z = z ; - m_DTArgs [ m_nDeferedCalls ].m_fXScale = fXScale ; - m_DTArgs [ m_nDeferedCalls ].m_fYScale = fYScale ; - m_DTArgs [ m_nDeferedCalls ].m_dwColor = dwColor ; - m_DTArgs [ m_nDeferedCalls ].m_dwFlags = dwFlags ; - - m_nDeferedCalls ++ ; - - return S_OK ; -} - -HRESULT CD3DFont::EndText ( void ) { - if(m_pd3dDevice == NULL) - return E_FAIL; - HRESULT hr; - - assert(IS_VALID_PTR(m_pVB)); - - UINT SavedStreamStride; - IDirect3DVertexBuffer9 *pSavedStreamData=NULL; - IDirect3DVertexShader9 *pSavedVertexShader=NULL; - IDirect3DPixelShader9 *pSavedPixelShader=NULL; - - hr = m_pd3dDevice->GetVertexShader(&pSavedVertexShader); - hr = m_pd3dDevice->GetPixelShader(&pSavedPixelShader); - - // Set up renderstate - hr = m_pSBSavedStateBlock->Capture(); - hr = m_pSBDrawTextStateBlock->Apply(); - /* - if(pSavedVertexShader!=D3DFVF_FONT2DVERTEX) - hr = m_pd3dDevice->SetVertexShader(D3DFVF_FONT2DVERTEX); - if(pSavedPixelShader!=NULL) - hr = m_pd3dDevice->SetPixelShader(NULL); - */ - hr = m_pd3dDevice->SetVertexShader(NULL); - hr = m_pd3dDevice->SetPixelShader(NULL); - - hr = m_pd3dDevice->GetStreamSource(0,&pSavedStreamData,NULL,&SavedStreamStride); - if(FAILED(hr)) { - dxgsg9_cat.error() << "CD3DFont EndText GetStreamSource() failed!" << D3DERRORSTRING(hr); - return E_FAIL; - } - - // undo GetStreamSource AddRef - SAFE_RELEASE(pSavedStreamData); - - if((pSavedStreamData!=m_pVB)||(SavedStreamStride!=sizeof(FONT2DVERTEX))) { - hr = m_pd3dDevice->SetStreamSource(0,m_pVB,0,sizeof(FONT2DVERTEX)); - if(FAILED(hr)) { - dxgsg9_cat.error() << "CD3DFont EndText initial SetStreamSource() failed!" << D3DERRORSTRING(hr); - return E_FAIL; - } - } - - // Set filter states - // - // filter if any in our list is specified filtered - // - // This functionality is different from the original D3DFont - // but is a significant speed increase - // - // User will make another batch if necessary - // - bool bFiltered = false ; - UINT i; - for(i = 0 ; i < m_nDeferedCalls ; ++ i) { - DWORD dwFlags = m_DTArgs [ i ].m_dwFlags ; - if(dwFlags & D3DFONT_FILTERED) { - bFiltered = true ; - break ; - } - } ; - if(bFiltered) { - m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); - m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); - }; - - // useless if nothing is scaled but should be fast enough - D3DVIEWPORT9 vp; - m_pd3dDevice->GetViewport( &vp ); - FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight; - - // Fill vertex buffer - FONT2DVERTEX* pVertices; - DWORD dwNumTriangles = 0L; - m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD ); - - bool bItalic = 0 != ( m_dwFontFlags & D3DFONT_ITALIC ) ; - // loop on our batched sets of arguments - for(i = 0 ; i < m_nDeferedCalls ; ++ i) { - bool bScaled = m_DTArgs [ i ].m_bScaled ; - FLOAT x = m_DTArgs [ i ].m_x ; - FLOAT y = m_DTArgs [ i ].m_y ; - FLOAT z = m_DTArgs [ i ].m_z ; - FLOAT fXScale = m_DTArgs [ i ].m_fXScale ; - FLOAT fYScale = m_DTArgs [ i ].m_fYScale ; - DWORD dwColor = m_DTArgs [ i ].m_dwColor ; - TCHAR * strText = m_DTArgs [ i ].m_strText ; - - if(bScaled) { - - FLOAT sx = (x+1.0f)*vp.Width/2; - FLOAT sy = (y-1.0f)*vp.Height/2; - FLOAT sz = z; - FLOAT rhw = 1.0f; - FLOAT fStartX = sx; - - FLOAT fBend = 0.0f ; - if(bItalic) - fBend = fYScale*vp.Height / 4.0f ; - - while(*strText) { - TCHAR c = *strText++; - - if(c == _T('\n')) { - sx = fStartX; - sy += fYScale*vp.Height; - } - if(c < _T(' ')) - continue; - - FLOAT tx1 = m_fTexCoords[c-32][0]; - FLOAT ty1 = m_fTexCoords[c-32][1]; - FLOAT tx2 = m_fTexCoords[c-32][2]; - FLOAT ty2 = m_fTexCoords[c-32][3]; - - FLOAT w = (tx2-tx1)*m_dwTexWidth; - FLOAT h = (ty2-ty1)*m_dwTexHeight; - - w *= (fXScale*vp.Height)/fLineHeight; - h *= (fYScale*vp.Height)/fLineHeight; - - if(c != _T(' ')) { - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f + fBend,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 ); - dwNumTriangles += 2; - - if(dwNumTriangles*3 > (MAX_NUM_VERTICES-6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); - m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD ); - dwNumTriangles = 0L; - } - } - - sx += w; - } ; - } else { // not scaled - FLOAT fBend = 0.0f ; - if(bItalic) - fBend = fLineHeight / 4.0f ; - - // Lazy guy... - FLOAT sx = x ; - FLOAT sy = y ; - - FLOAT fStartX = sx; - while(*strText) { - TCHAR c = *strText++; - - if(c == _T('\n')) { - sx = fStartX ; - sy += fLineHeight ; - } - if(c < _T(' ')) - continue; - - FLOAT tx1 = m_fTexCoords[c-32][0]; - FLOAT ty1 = m_fTexCoords[c-32][1]; - FLOAT tx2 = m_fTexCoords[c-32][2]; - FLOAT ty2 = m_fTexCoords[c-32][3]; - - FLOAT w = (tx2-tx1) * m_dwTexWidth / m_fTextScale; - FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale; - - if(c != _T(' ')) { - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f + fBend,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 ); - *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f + fBend,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 ); - dwNumTriangles += 2; - - if(dwNumTriangles*3 > (MAX_NUM_VERTICES-6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); - pVertices = NULL; - m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD ); - dwNumTriangles = 0L; - } - }; // endif not blank - - sx += w; - } ; // end while - - } ; // end if else scaled - - } ; // end for - - m_bBeginText = false ; - ClearBeginEndData ( ) ; - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if(dwNumTriangles > 0) - m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); - - // Restore the modified renderstates - m_pSBSavedStateBlock->Apply(); - /* - if((hSavedVertexShader!=NULL) && (hSavedVertexShader!=D3DFVF_FONT2DVERTEX)) - m_pd3dDevice->SetVertexShader(hSavedVertexShader); - if(hSavedPixelShader!=NULL) - m_pd3dDevice->SetPixelShader(hSavedPixelShader); - */ - m_pd3dDevice->SetVertexShader(pSavedVertexShader); - m_pd3dDevice->SetPixelShader(pSavedPixelShader); - - if(IS_VALID_PTR(pSavedStreamData) && ((pSavedStreamData!=m_pVB)||(SavedStreamStride!=sizeof(FONT2DVERTEX)))) { - hr = m_pd3dDevice->SetStreamSource(0,pSavedStreamData,0,SavedStreamStride); - if(FAILED(hr)) { - dxgsg9_cat.error() << "CD3DFont EndText restore SetStreamSource() failed!" << D3DERRORSTRING(hr); - return E_FAIL; - } - pSavedStreamData->Release(); - } - - return S_OK; -} - -#if 0 -// dont need this now -//----------------------------------------------------------------------------- -// Name: Render3DText() -// Desc: Renders 3D text -//----------------------------------------------------------------------------- -HRESULT CD3DFont::Render3DText( TCHAR* strText, DWORD dwFlags ) { - if(m_pd3dDevice == NULL) - return E_FAIL; - - // Setup renderstate - m_pd3dDevice->CaptureStateBlock( m_pSBSavedStateBlock ); - m_pd3dDevice->ApplyStateBlock( m_pSBDrawTextStateBlock ); - m_pd3dDevice->SetVertexShader( D3DFVF_FONT3DVERTEX ); - m_pd3dDevice->SetPixelShader( NULL ); - m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(FONT3DVERTEX) ); - - // Set filter states - if(dwFlags & D3DFONT_FILTERED) { - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - } - - // Position for each text element - FLOAT x = 0.0f; - FLOAT y = 0.0f; - - // Center the text block at the origin - if(dwFlags & D3DFONT_CENTERED) { - SIZE sz; - GetTextExtent( strText, &sz ); - x = -(((FLOAT)sz.cx)/10.0f)/2.0f; - y = -(((FLOAT)sz.cy)/10.0f)/2.0f; - } - - // Turn off culling for two-sided text - if(dwFlags & D3DFONT_TWOSIDED) - m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); - - FLOAT fStartX = x; - TCHAR c; - - // Fill vertex buffer - FONT3DVERTEX* pVertices; - // DWORD dwVertex = 0L; // not ref'ed - DWORD dwNumTriangles = 0L; - m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD ); - - bool bItalic = 0 != ( m_dwFontFlags & D3DFONT_ITALIC ) ; - FLOAT fBend = 0.0f ; - if(bItalic) - fBend = ( ( m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f ) / 4.0f ; - - while(c = *strText++) { - if(c == '\n') { - x = fStartX; - y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f; - } - if(c < 32) - continue; - - FLOAT tx1 = m_fTexCoords[c-32][0]; - FLOAT ty1 = m_fTexCoords[c-32][1]; - FLOAT tx2 = m_fTexCoords[c-32][2]; - FLOAT ty2 = m_fTexCoords[c-32][3]; - - FLOAT w = (tx2-tx1) * m_dwTexWidth / ( 10.0f * m_fTextScale ); - FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale ); - - if(c != _T(' ')) { - *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 ); - *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0 + fBend ,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 ); - *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 ); - *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w + fBend ,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 ); - *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 ); - *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0 + fBend ,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 ); - dwNumTriangles += 2; - - if(dwNumTriangles*3 > (MAX_NUM_VERTICES-6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); - m_pVB->Lock( 0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD ); - dwNumTriangles = 0L; - } - } - - x += w; - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if(dwNumTriangles > 0) - m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles ); - - // Restore the modified renderstates - m_pd3dDevice->ApplyStateBlock( m_pSBSavedStateBlock ); - - return S_OK; -} -#endif diff --git a/panda/src/dxgsg9/d3dfont9.h b/panda/src/dxgsg9/d3dfont9.h deleted file mode 100755 index a94e3dcced..0000000000 --- a/panda/src/dxgsg9/d3dfont9.h +++ /dev/null @@ -1,112 +0,0 @@ -//-------------------------------------------------------------------------------------------- -// File: D3DFont.h -// -// Desc: Texture-based font class -// based on a modified version of DXSDK CD3DFont from http://www.lafaqmfc.com/directx.htm -// Note that this is faster than ID3DXFont, which calls GDI in Draw() -//--------------------------------------------------------------------------------------------- -#ifndef D3DFONT_H -#define D3DFONT_H -#include -#include - -// Font creation flags -#define D3DFONT_BOLD 0x0001 -#define D3DFONT_ITALIC 0x0002 -#define D3DFONT_ZENABLE 0x0004 - -// Font rendering flags -#define D3DFONT_CENTERED 0x0001 -#define D3DFONT_TWOSIDED 0x0002 -#define D3DFONT_FILTERED 0x0004 - -//----------------------------------------------------------------------------- -// Name: class CD3DFont -// Desc: Texture-based font class for doing text in a 3D scene. -//----------------------------------------------------------------------------- -class CD3DFont -{ - enum - { - D3DFVF_FONT2DVERTEX = (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) , - D3DFVF_FONT3DVERTEX = (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1) , - TextBufferLength = 1024 , - MAX_NUM_VERTICES = TextBufferLength * 6 , - MaxCalls = 30 - } ; - - TCHAR m_strFontName[80]; // Font properties - DWORD m_dwFontHeight; - DWORD m_dwFontFlags; - - LPDIRECT3DDEVICE9 m_pd3dDevice; // A D3DDevice used for rendering - LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font - LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text - DWORD m_dwTexWidth; // Texture dimensions - DWORD m_dwTexHeight; - FLOAT m_fTextScale; - FLOAT m_fTexCoords[128-32][4]; - - // Stateblocks for setting and restoring render states - IDirect3DStateBlock9* m_pSBSavedStateBlock; - IDirect3DStateBlock9* m_pSBDrawTextStateBlock; - - struct DrawTextArgs - { - bool m_bScaled ; - FLOAT m_x ; FLOAT m_y ; FLOAT m_z ; - FLOAT m_fXScale ; FLOAT m_fYScale ; - DWORD m_dwColor ; - TCHAR *m_strText ; - DWORD m_dwFlags ; - } ; - - DrawTextArgs m_DTArgs [ MaxCalls ] ; - char m_TextBuffer [ TextBufferLength ] ; - char *m_pTextBuffer ; - UINT m_nDeferedCalls ; - bool m_bBeginText ; - inline HRESULT DeferedDrawText( FLOAT x, FLOAT y, DWORD dwColor, - TCHAR* strText, DWORD dwFlags=0L ); - inline HRESULT DeferedDrawTextScaled ( FLOAT x, FLOAT y, FLOAT z, - FLOAT fXScale, FLOAT fYScale, DWORD dwColor, - TCHAR* strText, DWORD dwFlags=0L ) ; - inline HRESULT DeferedDraw - ( bool bScaled , - FLOAT x, FLOAT y, FLOAT z, - FLOAT fXScale, FLOAT fYScale, DWORD dwColor, - TCHAR* strText, DWORD dwFlags ) ; - - inline void ClearBeginEndData (void ) ; - - -public: - // 2D and 3D text drawing functions - HRESULT BeginText ( void ) ; - HRESULT EndText ( void ) ; - - HRESULT DrawText( FLOAT x, FLOAT y, DWORD dwColor, - TCHAR* strText, DWORD dwFlags=0L ); - HRESULT DrawTextScaled ( FLOAT x, FLOAT y, FLOAT z, - FLOAT fXScale, FLOAT fYScale, DWORD dwColor, - TCHAR* strText, DWORD dwFlags=0L ) ; - - // HRESULT Render3DText( TCHAR* strText, DWORD dwFlags=0L ); - - // Function to get extent of text - HRESULT GetTextExtent( TCHAR* strText, SIZE* pSize ); - - // Initializing and destroying device-dependent objects - HRESULT InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice); - HRESULT RestoreDeviceObjects(); - HRESULT InvalidateDeviceObjects(); - HRESULT DeleteDeviceObjects(); - - // Constructor / destructor - CD3DFont( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L ); - ~CD3DFont(); -}; - -#endif - - diff --git a/panda/src/dxgsg9/dxGeomMunger9.I b/panda/src/dxgsg9/dxGeomMunger9.I new file mode 100755 index 0000000000..7c68d2cfdb --- /dev/null +++ b/panda/src/dxgsg9/dxGeomMunger9.I @@ -0,0 +1,47 @@ +// Filename: dxGeomMunger9.I +// Created by: drose (11Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: DXGeomMunger9::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE DXGeomMunger9:: +DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) : + StandardMunger(gsg, state, 1, NT_packed_dabc, C_color), + _texture(state->get_texture()), + _tex_gen(state->get_tex_gen()) +{ + if (_texture != (TextureAttrib *)NULL) { + _texture = _texture->filter_to_max(gsg->get_max_texture_stages()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGeomMunger9::operator new +// Access: Public +// Description: Calls up to do_operator_new() to implement the +// low-overhead allocation/deallocation for this type of +// GeomMunger. +//////////////////////////////////////////////////////////////////// +INLINE void *DXGeomMunger9:: +operator new(size_t size) { + return do_operator_new(size, &_deleted_chain); +} + diff --git a/panda/src/dxgsg9/dxGeomMunger9.cxx b/panda/src/dxgsg9/dxGeomMunger9.cxx new file mode 100755 index 0000000000..6339e4ef7b --- /dev/null +++ b/panda/src/dxgsg9/dxGeomMunger9.cxx @@ -0,0 +1,189 @@ +// Filename: dxGeomMunger9.cxx +// Created by: drose (11Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "dxGeomMunger9.h" +#include "geomVertexReader.h" +#include "geomVertexWriter.h" +#include "config_dxgsg9.h" + +GeomMunger *DXGeomMunger9::_deleted_chain = NULL; +TypeHandle DXGeomMunger9::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: DXGeomMunger9::munge_format_impl +// Access: Protected, Virtual +// Description: Given a source GeomVertexFormat, converts it if +// necessary to the appropriate format for rendering. +//////////////////////////////////////////////////////////////////// +CPT(GeomVertexFormat) DXGeomMunger9:: +munge_format_impl(const GeomVertexFormat *orig, + const GeomVertexAnimationSpec &animation) { + if (dxgsg9_cat.is_debug()) { + if (animation.get_animation_type() != AT_none) { + dxgsg9_cat.debug() + << "preparing animation type " << animation << " for " << *orig + << "\n"; + } + } + // We have to build a completely new format that includes only the + // appropriate components, in the appropriate order, in just one + // array. + PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig); + new_format->set_animation(animation); + PT(GeomVertexArrayFormat) new_array_format = new GeomVertexArrayFormat; + + const GeomVertexColumn *vertex_type = orig->get_vertex_column(); + const GeomVertexColumn *normal_type = orig->get_normal_column(); + const GeomVertexColumn *color_type = orig->get_color_column(); + + if (vertex_type != (const GeomVertexColumn *)NULL) { + new_array_format->add_column + (InternalName::get_vertex(), 3, NT_float32, + vertex_type->get_contents()); + new_format->remove_column(vertex_type->get_name()); + + } else { + // If we don't have a vertex type, not much we can do. + return orig; + } + + if (animation.get_animation_type() == AT_hardware && + animation.get_num_transforms() > 0) { + if (animation.get_num_transforms() > 1) { + // If we want hardware animation, we need to reserve space for the + // blend weights. + new_array_format->add_column + (InternalName::get_transform_weight(), animation.get_num_transforms() - 1, + NT_float32, C_other); + } + + if (animation.get_indexed_transforms()) { + // Also, if we'll be indexing into the transform table, reserve + // space for the index. + new_array_format->add_column + (InternalName::get_transform_index(), 1, + NT_packed_dcba, C_index); + } + + // Make sure the old weights and indices are removed, just in + // case. + new_format->remove_column(InternalName::get_transform_weight()); + new_format->remove_column(InternalName::get_transform_index()); + + // And we don't need the transform_blend table any more. + new_format->remove_column(InternalName::get_transform_blend()); + } + + if (normal_type != (const GeomVertexColumn *)NULL) { + new_array_format->add_column + (InternalName::get_normal(), 3, NT_float32, C_vector); + new_format->remove_column(normal_type->get_name()); + } + + if (color_type != (const GeomVertexColumn *)NULL) { + new_array_format->add_column + (InternalName::get_color(), 1, NT_packed_dabc, C_color); + new_format->remove_column(color_type->get_name()); + } + + // To support multitexture, we will need to add all of the relevant + // texcoord types, and in the correct order. + + // Now set up each of the active texture coordinate stages--or at + // least those for which we're not generating texture coordinates + // automatically. + + // Now copy all of the texture coordinates in, in order by stage + // index. But we have to reuse previous columns. + if (_texture != (TextureAttrib *)NULL) { + typedef pset UsedStages; + UsedStages used_stages; + + int num_stages = _texture->get_num_on_stages(); + for (int i = 0; i < num_stages; ++i) { + TextureStage *stage = _texture->get_on_stage(i); + + const InternalName *name = stage->get_texcoord_name(); + if (used_stages.insert(name).second) { + // This is the first time we've encountered this texcoord name. + const GeomVertexColumn *texcoord_type = orig->get_column(name); + + if (texcoord_type != (const GeomVertexColumn *)NULL) { + new_array_format->add_column + (name, texcoord_type->get_num_values(), NT_float32, C_texcoord); + } else { + // We have to add something as a placeholder, even if the + // texture coordinates aren't defined. + new_array_format->add_column(name, 2, NT_float32, C_texcoord); + } + new_format->remove_column(name); + } + } + } + + // Make sure the FVF-style array we just built up is first in the + // list. + new_format->insert_array(0, new_array_format); + + return GeomVertexFormat::register_format(new_format); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGeomMunger9::compare_to_impl +// Access: Protected, Virtual +// Description: Called to compare two GeomMungers who are known to be +// of the same type, for an apples-to-apples comparison. +// This will never be called on two pointers of a +// different type. +//////////////////////////////////////////////////////////////////// +int DXGeomMunger9:: +compare_to_impl(const GeomMunger *other) const { + const DXGeomMunger9 *om = DCAST(DXGeomMunger9, other); + if (_texture != om->_texture) { + return _texture < om->_texture ? -1 : 1; + } + if (_tex_gen != om->_tex_gen) { + return _tex_gen < om->_tex_gen ? -1 : 1; + } + + return StandardMunger::compare_to_impl(other); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGeomMunger9::geom_compare_to_impl +// Access: Protected, Virtual +// Description: Called to compare two GeomMungers who are known to be +// of the same type, for an apples-to-apples comparison. +// This will never be called on two pointers of a +// different type. +//////////////////////////////////////////////////////////////////// +int DXGeomMunger9:: +geom_compare_to_impl(const GeomMunger *other) const { + // Unlike GLGeomMunger, we do consider _texture and _tex_gen + // important for this purpose, since they control the number and + // order of texture coordinates we might put into the FVF. + const DXGeomMunger9 *om = DCAST(DXGeomMunger9, other); + if (_texture != om->_texture) { + return _texture < om->_texture ? -1 : 1; + } + if (_tex_gen != om->_tex_gen) { + return _tex_gen < om->_tex_gen ? -1 : 1; + } + + return StandardMunger::geom_compare_to_impl(other); +} diff --git a/panda/src/dxgsg9/dxGeomMunger9.h b/panda/src/dxgsg9/dxGeomMunger9.h new file mode 100755 index 0000000000..c97bf834e2 --- /dev/null +++ b/panda/src/dxgsg9/dxGeomMunger9.h @@ -0,0 +1,75 @@ +// Filename: dxGeomMunger9.h +// Created by: drose (11Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DXGEOMMUNGER9_H +#define DXGEOMMUNGER9_H + +#include "pandabase.h" +#include "standardMunger.h" +#include "graphicsStateGuardian.h" + +//////////////////////////////////////////////////////////////////// +// Class : DXGeomMunger9 +// Description : This specialization on GeomMunger finesses vertices +// for DirectX rendering. In particular, it makes sure +// colors are stored in DirectX's packed_argb format, +// and that all relevant components are packed into a +// single array, in the correct order. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX DXGeomMunger9 : public StandardMunger { +public: + INLINE DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state); + +protected: + virtual CPT(GeomVertexFormat) munge_format_impl(const GeomVertexFormat *orig, + const GeomVertexAnimationSpec &animation); + + virtual int compare_to_impl(const GeomMunger *other) const; + virtual int geom_compare_to_impl(const GeomMunger *other) const; + +public: + INLINE void *operator new(size_t size); + +private: + CPT(TextureAttrib) _texture; + CPT(TexGenAttrib) _tex_gen; + + static GeomMunger *_deleted_chain; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + StandardMunger::init_type(); + register_type(_type_handle, "DXGeomMunger9", + StandardMunger::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "dxGeomMunger9.I" + +#endif + diff --git a/panda/src/dxgsg9/dxGraphicsDevice9.cxx b/panda/src/dxgsg9/dxGraphicsDevice9.cxx index 4f741856be..3359b45859 100755 --- a/panda/src/dxgsg9/dxGraphicsDevice9.cxx +++ b/panda/src/dxgsg9/dxGraphicsDevice9.cxx @@ -1,10 +1,10 @@ // Filename: dxGraphicsDevice.cxx -// Created by: masad (02Jan04) +// Created by: masad (22Jul03) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -30,8 +30,8 @@ DXGraphicsDevice9(wdxGraphicsPipe9 *pipe) : GraphicsDevice(pipe) { ZeroMemory(&_Scrn,sizeof(_Scrn)); - _pD3DDevice = NULL; - _pSwapChain = NULL; + _d3d_device = NULL; + _swap_chain = NULL; } //////////////////////////////////////////////////////////////////// @@ -43,4 +43,3 @@ DXGraphicsDevice9:: ~DXGraphicsDevice9() { } - diff --git a/panda/src/dxgsg9/dxGraphicsDevice9.h b/panda/src/dxgsg9/dxGraphicsDevice9.h index 12d5138664..7c54e083b4 100755 --- a/panda/src/dxgsg9/dxGraphicsDevice9.h +++ b/panda/src/dxgsg9/dxGraphicsDevice9.h @@ -1,10 +1,10 @@ // Filename: dxGraphicsDevice.h -// Created by: masad (02Jan04) +// Created by: masad (22Jul03) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -29,7 +29,7 @@ //////////////////////////////////////////////////////////////////// // Class : DXGraphicsDevice9 // Description : A GraphicsDevice necessary for multi-window rendering -// in DX. +// in DX. //////////////////////////////////////////////////////////////////// class EXPCL_PANDADX DXGraphicsDevice9 : public GraphicsDevice { friend class wdxGraphicsPipe9; @@ -39,8 +39,8 @@ public: ~DXGraphicsDevice9(); DXScreenData _Scrn; - LPDIRECT3DDEVICE9 _pD3DDevice; // same as pScrn->_pD3DDevice, cached for spd - IDirect3DSwapChain9 *_pSwapChain; + LPDIRECT3DDEVICE9 _d3d_device; // same as Scrn._d3d_device, cached for spd + IDirect3DSwapChain9 *_swap_chain; #if 0 protected: @@ -52,4 +52,3 @@ protected: }; #endif - diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.I b/panda/src/dxgsg9/dxGraphicsStateGuardian9.I index 32ba58e6e4..c0f52051a4 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.I +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.I @@ -1,10 +1,10 @@ -// Filename: dxGraphicsStateGuardian8.I -// Created by: masad (02Jan04) +// Filename: dxGraphicsStateGuardian9.I +// Created by: mike (02Feb99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -16,481 +16,97 @@ // //////////////////////////////////////////////////////////////////// -INLINE DWORD + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::Colorf_to_D3DCOLOR +// Access: Public, Static +// Description: Converts Panda's floating-point Colorf structure to +// DirectX's D3DCOLOR packed structure. +//////////////////////////////////////////////////////////////////// +INLINE DWORD DXGraphicsStateGuardian9:: Colorf_to_D3DCOLOR(const Colorf &cColorf) { // MS VC defines _M_IX86 for x86. gcc should define _X86_ #if defined(_M_IX86) || defined(_X86_) - DWORD d3dcolor,tempcolorval=255; + DWORD d3dcolor, tempcolorval=255; - // note the default FPU rounding mode will give 255*0.5f=0x80, not 0x7F as VC would force it to by resetting rounding mode - // dont think this makes much difference - - __asm { + // note the default FPU rounding mode will give 255*0.5f=0x80, not 0x7F as VC would force it to by resetting rounding mode + // dont think this makes much difference + + __asm { push ebx ; want to save this in case this fn is inlined push ecx mov ecx, cColorf fild tempcolorval fld DWORD PTR [ecx] - fmul ST(0),ST(1) + fmul ST(0), ST(1) fistp tempcolorval ; no way to store directly to int register mov eax, tempcolorval shl eax, 16 fld DWORD PTR [ecx+4] ;grn - fmul ST(0),ST(1) + fmul ST(0), ST(1) fistp tempcolorval - mov ebx,tempcolorval + mov ebx, tempcolorval shl ebx, 8 - or eax,ebx + or eax, ebx fld DWORD PTR [ecx+8] ;blue - fmul ST(0),ST(1) + fmul ST(0), ST(1) fistp tempcolorval - or eax,tempcolorval + or eax, tempcolorval fld DWORD PTR [ecx+12] ;alpha - fmul ST(0),ST(1) + fmul ST(0), ST(1) fistp tempcolorval ; simulate pop 255.0 off FP stack w/o store, mark top as empty and increment stk ptr ffree ST(0) fincstp - mov ebx,tempcolorval + mov ebx, tempcolorval shl ebx, 24 - or eax,ebx - mov d3dcolor,eax + or eax, ebx + mov d3dcolor, eax pop ecx pop ebx - } + } - // dxgsg9_cat.debug() << (void*)d3dcolor << endl; - return d3dcolor; + // dxgsg9_cat.debug() << (void*)d3dcolor << endl; + return d3dcolor; #else //!_X86_ - return MY_D3DRGBA(cColorf[0], cColorf[1], cColorf[2], cColorf[3]); + return MY_D3DRGBA(cColorf[0], cColorf[1], cColorf[2], cColorf[3]); #endif //!_X86_ } -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_line_smooth -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_line_smooth(bool val) { - if(_line_smooth_enabled != val) { - _line_smooth_enabled = val; - #ifndef NDEBUG - { - if(val && (_pScrn->d3dcaps.LineCaps & D3DLINECAPS_ANTIALIAS)) - dxgsg9_cat.error() << "no HW support for line smoothing!!\n"; - } - #endif - - _pD3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, (DWORD)val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_dither -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_dither(bool val) { - if (_dither_enabled != val) { - _dither_enabled = val; - - #ifndef NDEBUG - { - if(val && !(_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER)) - dxgsg9_cat.error() << "no HW support for color dithering!!\n"; - } - #endif - - _pD3DDevice->SetRenderState(D3DRS_DITHERENABLE, (DWORD)val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_stencil_test -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_stencil_test(bool val) { - if (_stencil_test_enabled != val) { - _stencil_test_enabled = val; - _pD3DDevice->SetRenderState(D3DRS_STENCILENABLE, (DWORD)val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_color_material -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_color_material(bool val) { - if (_color_material_enabled != val) { - _color_material_enabled = val; - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_blend -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_blend(bool val) { - if (_blend_enabled != val) { - _blend_enabled = val; - _pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, (DWORD)val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::set_color_writemask -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -set_color_writemask(UINT color_writemask) { - if (_color_writemask != color_writemask) { - _color_writemask = color_writemask; - if(_pScrn->bCanDirectDisableColorWrites) { - // only newer HW supports this rstate - _pD3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, (DWORD)color_writemask); - } else { - // blending can only handle on/off - assert((color_writemask==0x0)||(color_writemask==0xFFFFFFFF)); - set_blend_mode(); - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_blend -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_gouraud_shading(bool val) { - if (_bGouraudShadingOn != val) { - _bGouraudShadingOn = val; - _pD3DDevice->SetRenderState(D3DRS_SHADEMODE, (val ? D3DSHADE_GOURAUD : D3DSHADE_FLAT)); - } -} - -INLINE void DXGraphicsStateGuardian9:: -enable_primitive_clipping(bool val) { - if (_clipping_enabled != val) { - _clipping_enabled = val; - _pD3DDevice->SetRenderState(D3DRS_CLIPPING, (DWORD)val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_fog -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_fog(bool val) { - if ((_fog_enabled != val) && (_doFogType!=None)) { - _fog_enabled = val; - _pD3DDevice->SetRenderState(D3DRS_FOGENABLE, (DWORD)val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::set_vertex_format -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -set_vertex_format(DWORD NewFvfType) { -#ifdef USE_VERTEX_SHADERS - if(_CurVertexShader!=NULL) { - // this needs optimization - HRESULT hr = _pD3DDevice->SetVertexShader(_CurVertexShader); - #ifndef NDEBUG - if(FAILED(hr)) { - dxgsg9_cat.error() << "SetVertexShader for custom vtx shader failed" << D3DERRORSTRING(hr); - exit(1); - } - #endif - _CurFVFType = NewFvfType; - return; - } -#endif - - if (_CurFVFType != NewFvfType) { - _CurFVFType = NewFvfType; - - HRESULT hr = _pD3DDevice->SetVertexShader(NULL); - hr = _pD3DDevice->SetFVF(NewFvfType); - - // HRESULT hr = _pD3DDevice->SetVertexShader((IDirect3DVertexShader9*)NewFvfType); - #ifndef NDEBUG - if(FAILED(hr)) { - dxgsg9_cat.error() << "SetVertexShader(0x" << (void*)NewFvfType<<") failed" << D3DERRORSTRING(hr); - exit(1); - } - #endif - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_alpha_test -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_alpha_test(bool val ) -{ - if (_alpha_test_enabled != val) { - _alpha_test_enabled = val; - _pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, (DWORD)val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::call_dxLightModelAmbient -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -call_dxLightModelAmbient( const Colorf& color) -{ - if (_lmodel_ambient != color) { - _lmodel_ambient = color; -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "dxLightModel(LIGHT_MODEL_AMBIENT, " << color << ")" << endl; -#endif - _pD3DDevice->SetRenderState( D3DRS_AMBIENT, - D3DCOLOR_COLORVALUE(color[0], color[1], color[2], color[3])); - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::call_dxAlphaFunc -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -call_dxAlphaFunc(D3DCMPFUNC func, float reference_alpha) { - if (_alpha_func != func) { - _alpha_func = func; -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "dxAlphaFunc("; - switch (func) { - case D3DCMP_NEVER: - dxgsg9_cat.debug(false) << "D3DCMP_NEVER"; - break; - case D3DCMP_LESS: - dxgsg9_cat.debug(false) << "D3DCMP_LESS"; - break; - case D3DCMP_EQUAL: - dxgsg9_cat.debug(false) << "D3DCMP_EQUAL"; - break; -#ifdef D3DCMP_LEQUAL - case D3DCMP_LEQUAL: - dxgsg9_cat.debug(false) << "D3DCMP_LEQUAL"; - break; -#endif - case D3DCMP_GREATER: - dxgsg9_cat.debug(false) << "D3DCMP_GREATER"; - break; - case D3DCMP_NOTEQUAL: - dxgsg9_cat.debug(false) << "D3DCMP_NOTEQUAL"; - break; -#ifdef D3DCMP_GEQUAL - case D3DCMP_GEQUAL: - dxgsg9_cat.debug(false) << "D3DCMP_GEQUAL"; - break; -#endif - case D3DCMP_ALWAYS: - dxgsg9_cat.debug(false) << "D3DCMP_ALWAYS"; - break; - } - dxgsg9_cat.debug() << " , " << reference_alpha << ")" << endl; -#endif - _pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, func); - } - - if(_alpha_func_refval != reference_alpha) { - _alpha_func_refval = reference_alpha; - _pD3DDevice->SetRenderState(D3DRS_ALPHAREF, (UINT) (reference_alpha*255.0f)); //d3d uses 0x0-0xFF, not a float - } -} - - -INLINE void DXGraphicsStateGuardian9:: -call_dxBlendFunc(D3DBLEND sfunc, D3DBLEND dfunc ) -{ - if (_blend_source_func != sfunc) - { - _blend_source_func = sfunc; - _pD3DDevice->SetRenderState(D3DRS_SRCBLEND, sfunc); -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "dxSrcBlendFunc("; - switch (sfunc) - { - case D3DBLEND_ZERO: - dxgsg9_cat.debug(false) << "ZERO, "; - break; - case D3DBLEND_ONE: - dxgsg9_cat.debug(false) << "ONE, "; - break; - case D3DBLEND_DESTCOLOR: - dxgsg9_cat.debug(false) << "DESTCOLOR, "; - break; - case D3DBLEND_INVDESTCOLOR: - dxgsg9_cat.debug(false) << "INVDESTCOLOR, "; - break; - case D3DBLEND_SRCALPHA: - dxgsg9_cat.debug(false) << "SRCALPHA, "; - break; - case D3DBLEND_INVSRCALPHA: - dxgsg9_cat.debug(false) << "INVSRCALPHA, "; - break; - case D3DBLEND_DESTALPHA: - dxgsg9_cat.debug(false) << "DESTALPHA, "; - break; - case D3DBLEND_INVDESTALPHA: - dxgsg9_cat.debug(false) << "INVDESTALPHA, "; - break; - case D3DBLEND_SRCALPHASAT: - dxgsg9_cat.debug(false) << "SRCALPHASAT, "; - break; - default: - dxgsg9_cat.debug(false) << "unknown, "; - break; - } - dxgsg9_cat.debug(false) << endl; -#endif - } - if ( _blend_dest_func != dfunc) - { - _blend_dest_func = dfunc; - _pD3DDevice->SetRenderState(D3DRS_DESTBLEND, dfunc); -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "dxDstBlendFunc("; - switch (dfunc) - { - case D3DBLEND_ZERO: - dxgsg9_cat.debug(false) << "ZERO, "; - break; - case D3DBLEND_ONE: - dxgsg9_cat.debug(false) << "ONE, "; - break; - case D3DBLEND_DESTCOLOR: - dxgsg9_cat.debug(false) << "DESTCOLOR, "; - break; - case D3DBLEND_INVDESTCOLOR: - dxgsg9_cat.debug(false) << "INVDESTCOLOR, "; - break; - case D3DBLEND_SRCALPHA: - dxgsg9_cat.debug(false) << "SRCALPHA, "; - break; - case D3DBLEND_INVSRCALPHA: - dxgsg9_cat.debug(false) << "INVSRCALPHA, "; - break; - case D3DBLEND_DESTALPHA: - dxgsg9_cat.debug(false) << "DESTALPHA, "; - break; - case D3DBLEND_INVDESTALPHA: - dxgsg9_cat.debug(false) << "INVDESTALPHA, "; - break; - case D3DBLEND_SRCALPHASAT: - dxgsg9_cat.debug(false) << "SRCALPHASAT, "; - break; - } - dxgsg9_cat.debug(false) << endl; -#endif - } -} - -INLINE void DXGraphicsStateGuardian9:: -enable_zwritemask(bool val) { - if (_depth_write_enabled != val) { - _depth_write_enabled = val; - _pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, val); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::add_to_FVFBuf -// Access: Private -// Description: This adds data to the flexible vertex format -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -add_to_FVFBuf(void *data, size_t bytes) { - memcpy(_pCurFvfBufPtr, data, bytes); - _pCurFvfBufPtr += bytes; -} - -INLINE void DXGraphicsStateGuardian9:: -transform_color(Colorf &InColor,D3DCOLOR &OutRGBAColor) { - Colorf transformed - (InColor[0] * _current_color_scale[0], - InColor[1] * _current_color_scale[1], - InColor[2] * _current_color_scale[2], - InColor[3] * _current_color_scale[3]); - OutRGBAColor = Colorf_to_D3DCOLOR(transformed); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_texturing -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_texturing(bool val) { - _texturing_enabled = val; - - if (!val) { - _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE); - - } else { - nassertv(_pCurTexContext!=NULL); - SetTextureBlendMode(_CurTexBlendMode,true); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::wants_texcoords -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -INLINE bool DXGraphicsStateGuardian9:: -wants_texcoords() const { - return _texturing_enabled; -} - //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian9::get_texture_wrap_mode -// Access: Protected +// Access: Protected, Static // Description: Maps from the Texture's internal wrap mode symbols to // GL's. //////////////////////////////////////////////////////////////////// INLINE D3DTEXTUREADDRESS DXGraphicsStateGuardian9:: -get_texture_wrap_mode(Texture::WrapMode wm) const { - static D3DTEXTUREADDRESS PandaTexWrapMode_to_D3DTexWrapMode[Texture::WM_invalid] = { - D3DTADDRESS_CLAMP,D3DTADDRESS_WRAP,D3DTADDRESS_MIRROR,D3DTADDRESS_MIRRORONCE,D3DTADDRESS_BORDER}; - - return PandaTexWrapMode_to_D3DTexWrapMode[wm]; +get_texture_wrap_mode(Texture::WrapMode wm) { + switch (wm) { + case Texture::WM_clamp: + return D3DTADDRESS_CLAMP; + case Texture::WM_repeat: + return D3DTADDRESS_WRAP; + case Texture::WM_mirror: + return D3DTADDRESS_MIRROR; + case Texture::WM_mirror_once: + return D3DTADDRESS_MIRRORONCE; + case Texture::WM_border_color: + return D3DTADDRESS_BORDER; + } + dxgsg9_cat.error() << "Invalid Texture::Mode value" << endl; + return D3DTADDRESS_WRAP; } //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian9::get_fog_mode_type -// Access: Protected +// Access: Protected, Static // Description: Maps from the fog types to gl version //////////////////////////////////////////////////////////////////// INLINE D3DFOGMODE DXGraphicsStateGuardian9:: -get_fog_mode_type(Fog::Mode m) const { +get_fog_mode_type(Fog::Mode m) { switch (m) { case Fog::M_linear: return D3DFOG_LINEAR; @@ -504,78 +120,32 @@ get_fog_mode_type(Fog::Mode m) const { } //////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_clip_plane -// Access: Protected, Virtual -// Description: Intended to be overridden by a derived class to -// enable the indicated clip_plane id. A specific -// PlaneNode will already have been bound to this id via -// bind_clip_plane(). +// Function: DXGraphicsStateGuardian9::get_tex_mat_sym +// Access: Protected, Static +// Description: Returns the nth D3DTS_TEXTURE(n) constant. //////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_clip_plane(int plane_id, bool enable) { - assert(plane_id < D3DMAXUSERCLIPPLANES); +INLINE D3DTRANSFORMSTATETYPE DXGraphicsStateGuardian9:: +get_tex_mat_sym(int stage_index) { + return (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage_index); +} - DWORD bitflag = ((DWORD)1 << plane_id); - if (enable) { - _clip_plane_bits |= bitflag; - } else { - _clip_plane_bits &= ~bitflag; +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::get_safe_buffer_start +// Access: Protected, Static +// Description: Returns the address of a 64K buffer that is allocated +// at the beginning of a 64K block. +//////////////////////////////////////////////////////////////////// +INLINE unsigned char *DXGraphicsStateGuardian9:: +get_safe_buffer_start() { + if (_temp_buffer == NULL) { + // Guarantee we get a buffer of size 0x10000 bytes that begins + // on an even multiple of 0x10000. We do this by allocating + // double the required buffer, and then pointing to the first + // multiple of 0x10000 within that buffer. + _temp_buffer = new unsigned char[0x1ffff]; + _safe_buffer_start = (unsigned char *)(((long)_temp_buffer + 0xffff) & ~0xffff); } - _pD3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, _clip_plane_bits); + return _safe_buffer_start; } -/** unimplemented - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_multisample -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_multisample(bool val) { - _multisample_enabled = val; - #ifdef NDEBUG - dxgsg9_cat.error() << "dx multisample unimplemented!!\n"; - #endif -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_multisample_alpha_one -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_multisample_alpha_one(bool val) { - if (_multisample_alpha_one_enabled != val) { - _multisample_alpha_one_enabled = val; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_multisample_alpha_mask -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_multisample_alpha_mask(bool val) { - if (_multisample_alpha_mask_enabled != val) { - _multisample_alpha_mask_enabled = val; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_point_smooth -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void DXGraphicsStateGuardian9:: -enable_point_smooth(bool val) { - // _point_smooth_enabled = val; - - #ifdef NDEBUG - dxgsg9_cat.error() << "dx point smoothing unimplemented!!\n"; - #endif -} -*/ - diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 1ec76ae762..1fff7459ad 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -1,10 +1,10 @@ -// Filename: dxGraphicsStateGuardian.cxx -// Created by: masad (02Jan04) +// Filename: dxGraphicsStateGuardian9.cxx +// Created by: mike (02Feb99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -18,12 +18,9 @@ #include "dxGraphicsStateGuardian9.h" #include "config_dxgsg9.h" -#include #include "displayRegion.h" #include "renderBuffer.h" #include "geom.h" -#include "geomSphere.h" -#include "geomIssuer.h" #include "graphicsWindow.h" #include "graphicsEngine.h" #include "lens.h" @@ -32,7 +29,8 @@ #include "pointLight.h" #include "spotlight.h" #include "textureAttrib.h" -#include "lightAttrib.h" +#include "texGenAttrib.h" +#include "shadeModelAttrib.h" #include "cullFaceAttrib.h" #include "transparencyAttrib.h" #include "alphaTestAttrib.h" @@ -47,127 +45,35 @@ #include "depthOffsetAttrib.h" #include "fog.h" #include "throw_event.h" - -#ifdef DO_PSTATS +#include "geomVertexFormat.h" +#include "geomVertexData.h" +#include "geomTriangles.h" +#include "geomTristrips.h" +#include "geomTrifans.h" +#include "geomLines.h" +#include "geomLinestrips.h" +#include "geomPoints.h" +#include "geomVertexReader.h" +#include "dxGeomMunger9.h" +#include "config_gobj.h" +#include "dxVertexBufferContext9.h" +#include "dxIndexBufferContext9.h" #include "pStatTimer.h" #include "pStatCollector.h" -#endif - -// disable nameless struct 'warning' -#pragma warning (disable : 4201) +#include #include -// print out simple drawprim stats every few secs -//#define COUNT_DRAWPRIMS -//#define PRINT_RESOURCESTATS // uses d3d GetInfo - -//#define DISABLE_DECALING -#define DISABLE_POLYGON_OFFSET_DECALING -// currently doesnt work well enough in toontown models for us to use -// prob is when viewer gets close to decals, they disappear into wall poly, need to investigate - -//const int VERT_BUFFER_SIZE = (8*1024L); -// For sparkle particles, we can have 4 vertices per sparkle, and a -// particle pool size of 1024 particles - -// for sprites, 1000 prims, 6 verts/prim, 24 bytes/vert -const int VERT_BUFFER_SIZE = (32*6*1024L); - TypeHandle DXGraphicsStateGuardian9::_type_handle; -// bit masks used for drawing primitives -// bitmask type: normal=0x1,color=0x2,texcoord=0x4 -typedef enum { NothingSet=0,NormalOnly,ColorOnly,Normal_Color,TexCoordOnly, - Normal_TexCoord,Color_TexCoord,Normal_Color_TexCoord -} DrawLoopFlags; +D3DMATRIX DXGraphicsStateGuardian9::_d3d_ident_mat; -#define PER_NORMAL NormalOnly -#define PER_COLOR ColorOnly -#define PER_TEXCOORD TexCoordOnly - -static D3DMATRIX matIdentity; +unsigned char *DXGraphicsStateGuardian9::_temp_buffer = NULL; +unsigned char *DXGraphicsStateGuardian9::_safe_buffer_start = NULL; #define __D3DLIGHT_RANGE_MAX ((float)sqrt(FLT_MAX)) //for some reason this is missing in dx9 hdrs -#ifdef COUNT_DRAWPRIMS -// instead of this use nvidia stat drvr or GetInfo VtxStats? -static DWORD cDPcount=0; -static DWORD cVertcount=0; -static DWORD cTricount=0; -static DWORD cGeomcount=0; - -static IDirect3DTexture9 *pLastTexture=NULL; -static DWORD cDP_noTexChangeCount=0; -static LPDIRECT3DDEVICE9 global_pD3DDevice = NULL; - -static void CountDPs(DWORD nVerts,DWORD nTris) { - cDPcount++; - cVertcount+=nVerts; - cTricount+=nTris; - - if(_pCurDeviceTexture==pLastTexture) { - cDP_noTexChangeCount++; - } else pLastTexture = _pCurDeviceTexture; -} -#else -#define CountDPs(nv,nt) -#endif - -#define MY_D3DRGBA(r,g,b,a) ((D3DCOLOR) D3DCOLOR_COLORVALUE(r,g,b,a)) - -#if defined(DO_PSTATS) || defined(PRINT_RESOURCESTATS) -static bool bTexStatsRetrievalImpossible=false; -#endif - -//#define Colorf_to_D3DCOLOR(out_color) (MY_D3DRGBA((out_color)[0], (out_color)[1], (out_color)[2], (out_color)[3])) - -void DXGraphicsStateGuardian9:: -set_color_clear_value(const Colorf& value) { - _color_clear_value = value; - _d3dcolor_clear_value = Colorf_to_D3DCOLOR(value); -} - -#if defined(_DEBUG) || defined(COUNT_DRAWPRIMS) -typedef enum {DrawPrim,DrawIndexedPrim} DP_Type; -static const char *DP_Type_Strs[3] = {"DrawPrimitive","DrawIndexedPrimitive"}; - -void INLINE TestDrawPrimFailure(DP_Type dptype,HRESULT hr,IDirect3DDevice9 *pD3DDevice,DWORD nVerts,DWORD nTris) { - if(FAILED(hr)) { - // loss of exclusive mode is not a real DrawPrim problem, ignore it - HRESULT testcooplvl_hr = pD3DDevice->TestCooperativeLevel(); - if((testcooplvl_hr != D3DERR_DEVICELOST)||(testcooplvl_hr != D3DERR_DEVICENOTRESET)) { - dxgsg9_cat.fatal() << DP_Type_Strs[dptype] << "() failed: result = " << D3DERRORSTRING(hr); - exit(1); - } - } - - CountDPs(nVerts,nTris); -} -#else -#define TestDrawPrimFailure(a,b,c,nVerts,nTris) CountDPs(nVerts,nTris); -#endif - -void DXGraphicsStateGuardian9:: -reset_panda_gsg() { - GraphicsStateGuardian::reset(); - - _auto_rescale_normal = false; - - // overwrite gsg defaults with these values - - // All implementations have the following buffers. - _buffer_mask = (RenderBuffer::T_color | - RenderBuffer::T_back -// RenderBuffer::T_depth | -// RenderBuffer::T_stencil | -// RenderBuffer::T_accum - ); - - // stmt below is incorrect for general mono displays, need both right and left flags set. - // stereo not supported in dx9 - // _buffer_mask &= ~RenderBuffer::T_right; -} +#define MY_D3DRGBA(r, g, b, a) ((D3DCOLOR) D3DCOLOR_COLORVALUE(r, g, b, a)) //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian9::Constructor @@ -176,35 +82,41 @@ reset_panda_gsg() { //////////////////////////////////////////////////////////////////// DXGraphicsStateGuardian9:: DXGraphicsStateGuardian9(const FrameBufferProperties &properties) : - GraphicsStateGuardian(properties, CS_yup_left) + GraphicsStateGuardian(properties, CS_yup_left) { + _screen = NULL; + _d3d_device = NULL; - reset_panda_gsg(); + _dx_is_ready = false; + _vertex_blending_enabled = false; + _overlay_windows_supported = false; + _tex_stats_retrieval_impossible = false; - _pScrn = NULL; - _pD3DDevice = NULL; - - _bDXisReady = false; - _overlay_windows_supported = false; + _active_vbuffer = NULL; + _active_ibuffer = NULL; - _pFvfBufBasePtr = NULL; - _index_buf=NULL; + // This is a static member, but we initialize it here in the + // constructor anyway. It won't hurt if it gets repeatedly + // initalized. + ZeroMemory(&_d3d_ident_mat, sizeof(D3DMATRIX)); + _d3d_ident_mat._11 = _d3d_ident_mat._22 = _d3d_ident_mat._33 = _d3d_ident_mat._44 = 1.0f; - // _max_light_range = __D3DLIGHT_RANGE_MAX; + _cur_read_pixel_buffer = RenderBuffer::T_front; + set_color_clear_value(_color_clear_value); - // non-dx obj values inited here should not change if resize is - // called and dx objects need to be recreated (otherwise they - // belong in dx_init, with other renderstate + // DirectX drivers seem to consistently invert the texture when + // they copy framebuffer-to-texture. Ok. + _copy_texture_inverted = true; - ZeroMemory(&matIdentity,sizeof(D3DMATRIX)); - matIdentity._11 = matIdentity._22 = matIdentity._33 = matIdentity._44 = 1.0f; - - _cur_read_pixel_buffer=RenderBuffer::T_front; - set_color_clear_value(_color_clear_value); - - // DirectX drivers seem to consistently invert the texture when - // they copy framebuffer-to-texture. Ok. - _copy_texture_inverted = true; + // D3DRS_POINTSPRITEENABLE doesn't seem to support remapping the + // texture coordinates via a texture matrix, so we don't advertise + // GR_point_sprite_tex_matrix. + _supported_geom_rendering = + Geom::GR_point | Geom::GR_point_uniform_size | + Geom::GR_point_perspective | Geom::GR_point_sprite | + Geom::GR_indexed_other | + Geom::GR_triangle_strip | Geom::GR_triangle_fan | + Geom::GR_flat_first_vertex; } //////////////////////////////////////////////////////////////////// @@ -214,363 +126,372 @@ DXGraphicsStateGuardian9(const FrameBufferProperties &properties) : //////////////////////////////////////////////////////////////////// DXGraphicsStateGuardian9:: ~DXGraphicsStateGuardian9() { - if (IS_VALID_PTR(_pD3DDevice)) - _pD3DDevice->SetTexture(0, NULL); // this frees reference to the old texture - _pCurTexContext = NULL; - - //free_d3d_device(); ??? - - free_nondx_resources(); + if (IS_VALID_PTR(_d3d_device)) { + _d3d_device->SetTexture(0, NULL); // this frees reference to the old texture + } + free_nondx_resources(); } //////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::reset +// Function: DXGraphicsStateGuardian9::prepare_texture // Access: Public, Virtual -// Description: Resets all internal state as if the gsg were newly -// created. The GraphicsWindow pointer represents a -// typical window that might be used for this context; -// it may be required to set up the frame buffer -// properly the first time. +// Description: Creates a new retained-mode representation of the +// given texture, and returns a newly-allocated +// TextureContext pointer to reference it. It is the +// responsibility of the calling function to later +// call release_texture() with this same pointer (which +// will also delete the pointer). +// +// This function should not be called directly to +// prepare a texture. Instead, call Texture::prepare(). //////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -reset() { - reset_panda_gsg(); - dxgsg9_cat.error() << "DXGSG reset() not implemented properly yet!\n"; - // what else do we need to do? - // delete all the objs too, right? - // need to do a - //dx_init(); -} +TextureContext *DXGraphicsStateGuardian9:: +prepare_texture(Texture *tex) { + DXTextureContext9 *dtc = new DXTextureContext9(tex); + if (!dtc->create_texture(*_screen)) { + delete dtc; + return NULL; + } -// setup up for re-calling dx_init(), this is not the final exit cleanup routine (see dx_cleanup) -void DXGraphicsStateGuardian9:: -free_d3d_device() { - // dont want a full reset of gsg, just a state clear - set_state(RenderState::make_empty()); - // want gsg to pass all state settings through - - _bDXisReady = false; - - if(_pD3DDevice!=NULL) - for(int i=0;iSetTexture(i,NULL); // d3d should release this stuff internally anyway, but whatever - - DeleteAllDeviceObjects(); - - if (_pD3DDevice!=NULL) - RELEASE(_pD3DDevice,dxgsg9,"d3dDevice",RELEASE_DOWN_TO_ZERO); - - free_nondx_resources(); - - // obviously we dont release ID3D9, just ID3DDevice9 + return dtc; } //////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::free_nondx_resources +// Function: DXGraphicsStateGuardian9::apply_texture // Access: Public -// Description: Frees some memory that was explicitly allocated -// within the dxgsg. +// Description: Makes the texture the currently available texture for +// rendering on the ith stage. //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: -free_nondx_resources() { - // this must not release any objects associated with D3D/DX! - // those should be released in free_dxgsg_objects instead - SAFE_DELETE_ARRAY(_index_buf); - SAFE_DELETE_ARRAY(_pFvfBufBasePtr); -} +apply_texture(int i, TextureContext *tc) { + if (tc == (TextureContext *)NULL) { + // The texture wasn't bound properly or something, so ensure + // texturing is disabled and just return. + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE); + return; + } -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::reset -// Access: Public, Virtual -// Description: Handles initialization which assumes that DX has already been -// set up. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -dx_init() { - HRESULT hr; - - // make sure gsg passes all current state down to us - set_state(RenderState::make_empty()); - // want gsg to pass all state settings down so any non-matching defaults we set here get overwritten - - assert(_pScrn->pD3D9!=NULL); - assert(_pD3DDevice!=NULL); - - ZeroMemory(&_lmodel_ambient,sizeof(Colorf)); - _pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0x0); - - if(_pFvfBufBasePtr==NULL) - _pFvfBufBasePtr = new BYTE[VERT_BUFFER_SIZE]; // allocate storage for vertex info. - if(_index_buf==NULL) - _index_buf = new WORD[PANDA_MAXNUMVERTS]; // allocate storage for vertex index info. - - _pCurFvfBufPtr = NULL; - - _clip_plane_bits = 0; - _pD3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE , 0x0); - - _pD3DDevice->SetRenderState(D3DRS_CLIPPING, true); - _clipping_enabled = true; - - // these both reflect d3d defaults - _color_writemask = 0xFFFFFFFF; - _CurFVFType = 0x0; // guards SetVertexShader fmt - - _bGouraudShadingOn = false; - _pD3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); - -// this specifies if lighting model uses material color or vertex color -// (not related to gouraud/flat shading) -// _pD3DDevice->SetRenderState(D3DRS_COLORVERTEX, true); - - _depth_test_enabled = true; - _pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, _depth_test_enabled); - - _pCurTexContext = NULL; - - _line_smooth_enabled = false; - _pD3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, false); - - _color_material_enabled = false; - - _depth_test_enabled = D3DZB_FALSE; - _pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); - - _blend_enabled = false; - _pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, (DWORD)_blend_enabled); - - // just use whatever d3d defaults to here - _pD3DDevice->GetRenderState(D3DRS_SRCBLEND, (DWORD*)&_blend_source_func); - _pD3DDevice->GetRenderState(D3DRS_DESTBLEND, (DWORD*)&_blend_dest_func); - - _fog_enabled = false; - _pD3DDevice->SetRenderState(D3DRS_FOGENABLE, _fog_enabled); - - _current_projection_mat = LMatrix4f::ident_mat(); - _projection_mat_stack_count = 0; - _has_scene_graph_color = false; - -// GL stuff that hasnt been translated to DX - // none of these are implemented - //_multisample_enabled = false; // bugbug: translate this to dx_multisample_antialiasing_level? - //_point_smooth_enabled = false; - -// _scissor_enabled = false; -// _multisample_alpha_one_enabled = false; -// _multisample_alpha_mask_enabled = false; -// _line_width = 1.0f; -// _point_size = 1.0f; - -#ifdef COUNT_DRAWPRIMS - global_pD3DDevice = pDevice; +#ifdef DO_PSTATS + add_to_texture_record(tc); #endif - _bDrawPrimDoSetupVertexBuffer = false; - _last_testcooplevel_result = D3D_OK; + DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); - for(int i=0;ipD3D9->CheckDeviceFormat(_pScrn->CardIDNum,D3DDEVTYPE_HAL,_pScrn->DisplayMode.Format, - 0x0,D3DRTYPE_TEXTURE,g_D3DFORMATmap[fmtflag]); - if(SUCCEEDED(hr)){ - _pScrn->SupportedTexFmtsMask|=fmtflag; - } + int dirty = dtc->get_dirty_flags(); + + // If the texture image has changed, or if its use of mipmaps has + // changed, we need to re-create the image. Ignore other types of + // changes, which aren't significant for DX. + + if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) { + // If this is *only* because of a mipmap change, issue a + // warning--it is likely that this change is the result of an + // error or oversight. + if ((dirty & Texture::DF_image) == 0) { + dxgsg9_cat.warning() + << "Texture " << *dtc->_texture << " has changed mipmap state.\n"; } - // s3 virge drivers sometimes give crap values for these - if(_pScrn->d3dcaps.MaxTextureWidth==0) - _pScrn->d3dcaps.MaxTextureWidth=256; - - if(_pScrn->d3dcaps.MaxTextureHeight==0) - _pScrn->d3dcaps.MaxTextureHeight=256; - -#define REQUIRED_DESTBLENDCAPS (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE| D3DPBLENDCAPS_SRCALPHA) -#define REQUIRED_SRCBLENDCAPS (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE| D3DPBLENDCAPS_INVSRCALPHA) - - if (((_pScrn->d3dcaps.SrcBlendCaps & REQUIRED_SRCBLENDCAPS)!=REQUIRED_SRCBLENDCAPS) || - ((_pScrn->d3dcaps.DestBlendCaps & REQUIRED_DESTBLENDCAPS)!=REQUIRED_DESTBLENDCAPS)) { - dxgsg9_cat.error() << "device is missing alpha blending capabilities, blending may not work correctly: SrcBlendCaps: 0x"<< (void*) _pScrn->d3dcaps.SrcBlendCaps << " DestBlendCaps: "<< (void*) _pScrn->d3dcaps.DestBlendCaps << endl; + if (!dtc->create_texture(*_screen)) { + // Oops, we can't re-create the texture for some reason. + dxgsg9_cat.error() + << "Unable to re-create texture " << *dtc->_texture << endl; + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE); + return; } + } -// just 'require' bilinear with mip nearest. -#define REQUIRED_TEXFILTERCAPS (D3DPTFILTERCAPS_MAGFLINEAR | D3DPTFILTERCAPS_MIPFPOINT | D3DPTFILTERCAPS_MINFLINEAR) + Texture *tex = tc->_texture; + Texture::WrapMode wrap_u, wrap_v, wrap_w; + wrap_u = tex->get_wrap_u(); + wrap_v = tex->get_wrap_v(); + wrap_w = tex->get_wrap_w(); - if ((_pScrn->d3dcaps.TextureFilterCaps & REQUIRED_TEXFILTERCAPS)!=REQUIRED_TEXFILTERCAPS) { - dxgsg9_cat.error() << "device is missing texture bilinear filtering capability, textures may appear blocky! TextureFilterCaps: 0x"<< (void*) _pScrn->d3dcaps.TextureFilterCaps << endl; - } +/* + _d3d_device->SetTextureStageState(i, D3DTSS_ADDRESSU, get_texture_wrap_mode(wrap_u)); + _d3d_device->SetTextureStageState(i, D3DTSS_ADDRESSV, get_texture_wrap_mode(wrap_v)); + _d3d_device->SetTextureStageState(i, D3DTSS_ADDRESSW, get_texture_wrap_mode(wrap_w)); -#define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR) + _d3d_device->SetTextureStageState(i, D3DTSS_BORDERCOLOR, + Colorf_to_D3DCOLOR(tex->get_border_color())); +*/ + _d3d_device->SetSamplerState(i, D3DSAMP_ADDRESSU, get_texture_wrap_mode(wrap_u)); + _d3d_device->SetSamplerState(i, D3DSAMP_ADDRESSV, get_texture_wrap_mode(wrap_v)); + _d3d_device->SetSamplerState(i, D3DSAMP_ADDRESSW, get_texture_wrap_mode(wrap_w)); - // give a warning if we dont at least have bilinear + nearest mip filtering - if (!(_pScrn->d3dcaps.TextureCaps & D3DPTEXTURECAPS_MIPMAP)) { - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "device does not have mipmap texturing filtering capability! TextureFilterCaps: 0x"<< (void*) _pScrn->d3dcaps.TextureFilterCaps << endl; - dx_ignore_mipmaps = TRUE; - } else if ((_pScrn->d3dcaps.TextureFilterCaps & TRILINEAR_MIPMAP_TEXFILTERCAPS)!=TRILINEAR_MIPMAP_TEXFILTERCAPS) { - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "device is missing tri-linear mipmap filtering capability, textures may look crappy\n"; - } else if(_pScrn->d3dcaps.DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) { - // this cap is pretty much voodoo2-specific - // turn off trilinear filtering on voodoo2 since it doubles the reqd texture memory, degrade to mip point filtering - _pScrn->d3dcaps.TextureFilterCaps &= (~D3DPTFILTERCAPS_MIPFLINEAR); - } + _d3d_device->SetSamplerState(i, D3DSAMP_BORDERCOLOR, + Colorf_to_D3DCOLOR(tex->get_border_color())); -#define REQUIRED_TEXBLENDCAPS (D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2) - if ((_pScrn->d3dcaps.TextureOpCaps & REQUIRED_TEXBLENDCAPS)!=REQUIRED_TEXBLENDCAPS) { - dxgsg9_cat.error() << "device is missing some required texture blending capabilities, texture blending may not work properly! TextureOpCaps: 0x"<< (void*) _pScrn->d3dcaps.TextureOpCaps << endl; - } + uint aniso_degree = tex->get_anisotropic_degree(); + Texture::FilterType ft = tex->get_magfilter(); - if(_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) { - // watch out for drivers that emulate per-pixel fog with per-vertex fog (Riva128, Matrox Millen G200) - // some of these require gouraud-shading to be set to work, as if you were using vertex fog - _doFogType=PerPixelFog; - } else { - // every card is going to have vertex fog, since it's implemented in d3d runtime - assert((_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX )!=0); +// _d3d_device->SetTextureStageState(i, D3DTSS_MAXANISOTROPY, aniso_degree); + _d3d_device->SetSamplerState(i, D3DSAMP_MAXANISOTROPY, aniso_degree); - // vtx fog may look crappy if you have large polygons in the foreground and they get clipped, - // so you may want to disable it + D3DTEXTUREFILTERTYPE new_mag_filter; + if (aniso_degree <= 1) { + new_mag_filter = ((ft != Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT); + } else { + new_mag_filter = D3DTEXF_ANISOTROPIC; + } - if(dx_no_vertex_fog) { - _doFogType = None; - } else { - _doFogType = PerVertexFog; +// _d3d_device->SetTextureStageState(i, D3DTSS_MAGFILTER, new_mag_filter); + _d3d_device->SetSamplerState(i, D3DSAMP_MAGFILTER, new_mag_filter); - // range-based fog only works with vertex fog in dx7/8 - if(dx_use_rangebased_fog && (_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGRANGE)) - _pD3DDevice->SetRenderState(D3DRS_RANGEFOGENABLE, true); - } - } + // map Panda composite min+mip filter types to d3d's separate min & mip filter types + D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(tex->get_minfilter()); + D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(tex->get_minfilter()); - _pScrn->bCanDirectDisableColorWrites=((_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE)!=0); - - // Lighting, let's turn it off by default - _pD3DDevice->SetRenderState(D3DRS_LIGHTING, false); - - // turn on dithering if the rendertarget is < 8bits/color channel - _dither_enabled = ((!dx_no_dithering) && IS_16BPP_DISPLAY_FORMAT(_pScrn->PresParams.BackBufferFormat) - && (_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER)); - _pD3DDevice->SetRenderState(D3DRS_DITHERENABLE, _dither_enabled); - - _pD3DDevice->SetRenderState(D3DRS_CLIPPING,true); - - // Stencil test is off by default - _stencil_test_enabled = false; - _pD3DDevice->SetRenderState(D3DRS_STENCILENABLE, _stencil_test_enabled); - - // Antialiasing. - enable_line_smooth(false); -// enable_multisample(true); - - _current_fill_mode = RenderModeAttrib::M_filled; - _pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); - - _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1); // Use the diffuse vertex color. - - /* - Panda no longer requires us to specify the maximum number of - lights up front, but instead we can define slot_new_light() to - decide one-at-a-time whether a particular light fits within our - limit or not. Until we override this function, there is no - limit. - - if(_pScrn->d3dcaps.MaxActiveLights==0) { - // 0 indicates no limit on # of lights, but we use DXGSG_MAX_LIGHTS anyway for now - init_lights(DXGSG_MAX_LIGHTS); - } else { - init_lights(min(DXGSG_MAX_LIGHTS,_pScrn->d3dcaps.MaxActiveLights)); - } - */ - - // must do SetTSS here because redundant states are filtered out by our code based on current values above, so - // initial conditions must be correct - - _CurTexBlendMode = TextureStage::M_modulate; - SetTextureBlendMode(_CurTexBlendMode,false); - _texturing_enabled = false; - _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE); // disables texturing - - // Init more Texture State - _CurTexMagFilter=_CurTexMinFilter=_CurTexMipFilter=D3DTEXF_NONE; - _CurTexWrapModeU=_CurTexWrapModeV=Texture::WM_clamp; - _CurTexAnisoDegree=1; - - // this code must match apply_texture() code for states above - // so DX TSS renderstate matches dxgsg state - - _pD3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - _pD3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - _pD3DDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - _pD3DDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY,_CurTexAnisoDegree); - _pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU,get_texture_wrap_mode(_CurTexWrapModeU)); - _pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV,get_texture_wrap_mode(_CurTexWrapModeV)); - -#ifdef _DEBUG - if ((_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) && - (dx_global_miplevel_bias!=0.0f)) { - _pD3DDevice->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, *((LPDWORD) (&dx_global_miplevel_bias)) ); - } -#endif + if (!tex->might_have_ram_image()) { + // If the texture is completely dynamic, don't try to issue + // mipmaps--pandadx doesn't support auto-generated mipmaps at this + // point. + new_mip_filter = D3DTEXF_NONE; + } #ifndef NDEBUG - if(dx_force_backface_culling!=0) { - if((dx_force_backface_culling > 0) && - (dx_force_backface_culling < D3DCULL_FORCE_DWORD)) { - _pD3DDevice->SetRenderState(D3DRS_CULLMODE, dx_force_backface_culling); - } else { - dx_force_backface_culling=0; - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "error, invalid value for dx-force-backface-culling\n"; - } - } - _pD3DDevice->SetRenderState(D3DRS_CULLMODE, dx_force_backface_culling); -#else - _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + // sanity check + if ((!dtc->has_mipmaps()) && (new_mip_filter != D3DTEXF_NONE)) { + dxgsg9_cat.error() + << "Trying to set mipmap filtering for texture with no generated mipmaps!! texname[" + << tex->get_name() << "], filter(" + << tex->get_minfilter() << ")\n"; + new_mip_filter = D3DTEXF_NONE; + } #endif - _alpha_func = D3DCMP_ALWAYS; - _alpha_func_refval = 1.0f; - _pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, _alpha_func); - _pD3DDevice->SetRenderState(D3DRS_ALPHAREF, (UINT)(_alpha_func_refval*255.0f)); - _alpha_test_enabled = false; - _pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, _alpha_test_enabled); + if (aniso_degree >= 2) { + new_min_filter = D3DTEXF_ANISOTROPIC; + } - // must check (_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) (yes on GF2/Radeon8500, no on TNT) - _pD3DDevice->SetRenderState(D3DRS_BLENDOP,D3DBLENDOP_ADD); +/* + _d3d_device->SetTextureStageState(i, D3DTSS_MINFILTER, new_min_filter); + _d3d_device->SetTextureStageState(i, D3DTSS_MIPFILTER, new_mip_filter); +*/ + _d3d_device->SetSamplerState(i, D3DSAMP_MINFILTER, new_min_filter); + _d3d_device->SetSamplerState(i, D3DSAMP_MIPFILTER, new_mip_filter); - PRINT_REFCNT(dxgsg9,_pD3DDevice); - - // Make sure the DX state matches all of our initial attribute states. - CPT(RenderAttrib) dta = DepthTestAttrib::make(DepthTestAttrib::M_less); - CPT(RenderAttrib) dwa = DepthWriteAttrib::make(DepthWriteAttrib::M_on); - CPT(RenderAttrib) cfa = CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise); - - dta->issue(this); - dwa->issue(this); - cfa->issue(this); - - PRINT_REFCNT(dxgsg9,_pD3DDevice); + _d3d_device->SetTexture(i, dtc->get_d3d_texture()); } //////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::support_overlay_window -// Access: Public -// Description: Specifies whether dialog windows placed on top of the -// dx rendering window should be supported. This -// requires a bit of extra overhead, so it should only -// be activated when necessary; however, if it is not -// activated, a window that pops up over the fullscreen -// DX window (like a dialog box, or particularly like -// the IME composition or candidate windows) may not be -// visible. -// -// This is not necessary when running in windowed mode, -// but it does no harm. +// Function: DXGraphicsStateGuardian9::release_texture +// Access: Public, Virtual +// Description: Frees the GL resources previously allocated for the +// texture. //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: -support_overlay_window(bool flag) { - // How is this supposed to be done in DX9? +release_texture(TextureContext *tc) { + DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); + delete dtc; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::prepare_vertex_buffer +// Access: Public, Virtual +// Description: Creates a new retained-mode representation of the +// given data, and returns a newly-allocated +// VertexBufferContext pointer to reference it. It is the +// responsibility of the calling function to later +// call release_vertex_buffer() with this same pointer (which +// will also delete the pointer). +// +// This function should not be called directly to +// prepare a buffer. Instead, call Geom::prepare(). +//////////////////////////////////////////////////////////////////// +VertexBufferContext *DXGraphicsStateGuardian9:: +prepare_vertex_buffer(GeomVertexArrayData *data) { + DXVertexBufferContext9 *dvbc = new DXVertexBufferContext9(data); + return dvbc; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::apply_vertex_buffer +// Access: Public +// Description: Updates the vertex buffer with the current data, and +// makes it the current vertex buffer for rendering. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +apply_vertex_buffer(VertexBufferContext *vbc) { + DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc); + + if (dvbc->_vbuffer == NULL) { + // Attempt to create a new vertex buffer. + if (vertex_buffers && + dvbc->get_data()->get_usage_hint() != Geom::UH_client) { + dvbc->create_vbuffer(*_screen); + } + + if (dvbc->_vbuffer != NULL) { + dvbc->upload_data(); + + add_to_total_buffer_record(dvbc); + dvbc->mark_loaded(); + + _d3d_device->SetStreamSource + (0, dvbc->_vbuffer, 0, dvbc->get_data()->get_array_format()->get_stride()); + _active_vbuffer = dvbc; + _active_ibuffer = NULL; + add_to_vertex_buffer_record(dvbc); + + } else { + _active_vbuffer = NULL; + } + + } else { + if (dvbc->was_modified()) { + if (dvbc->changed_size()) { + // We have to destroy the old vertex buffer and create a new + // one. + dvbc->create_vbuffer(*_screen); + } + + dvbc->upload_data(); + + add_to_total_buffer_record(dvbc); + dvbc->mark_loaded(); + _active_vbuffer = NULL; + } + + if (_active_vbuffer != dvbc) { + _d3d_device->SetStreamSource + (0, dvbc->_vbuffer, 0, dvbc->get_data()->get_array_format()->get_stride()); + _active_vbuffer = dvbc; + _active_ibuffer = NULL; + add_to_vertex_buffer_record(dvbc); + } + } + +// HRESULT hr = _d3d_device->SetVertexShader(dvbc->_fvf); + HRESULT hr = _d3d_device->SetFVF(dvbc->_fvf); +#ifndef NDEBUG + if (FAILED(hr)) { + dxgsg9_cat.error() + << "SetVertexShader(0x" << (void*)dvbc->_fvf + << ") failed" << D3DERRORSTRING(hr); + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::release_vertex_buffer +// Access: Public, Virtual +// Description: Frees the GL resources previously allocated for the +// data. This function should never be called +// directly; instead, call Data::release() (or simply +// let the Data destruct). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +release_vertex_buffer(VertexBufferContext *vbc) { + DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc); + delete dvbc; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::prepare_index_buffer +// Access: Public, Virtual +// Description: Creates a new retained-mode representation of the +// given data, and returns a newly-allocated +// IndexBufferContext pointer to reference it. It is the +// responsibility of the calling function to later call +// release_index_buffer() with this same pointer (which +// will also delete the pointer). +// +// This function should not be called directly to +// prepare a buffer. Instead, call Geom::prepare(). +//////////////////////////////////////////////////////////////////// +IndexBufferContext *DXGraphicsStateGuardian9:: +prepare_index_buffer(GeomPrimitive *data) { + DXIndexBufferContext9 *dibc = new DXIndexBufferContext9(data); + return dibc; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::apply_index_buffer +// Access: Public +// Description: Updates the index buffer with the current data, and +// makes it the current index buffer for rendering. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +apply_index_buffer(IndexBufferContext *ibc) { + DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc); + + if (dibc->_ibuffer == NULL) { + // Attempt to create a new index buffer. + dibc->create_ibuffer(*_screen); + + if (dibc->_ibuffer != NULL) { + dibc->upload_data(); + add_to_total_buffer_record(dibc); + dibc->mark_loaded(); + + _d3d_device->SetIndices(dibc->_ibuffer); + _active_ibuffer = dibc; + add_to_index_buffer_record(dibc); + + } else { + _d3d_device->SetIndices(NULL); + _active_ibuffer = NULL; + } + + } else { + if (dibc->was_modified()) { + if (dibc->changed_size()) { + // We have to destroy the old index buffer and create a new + // one. + dibc->create_ibuffer(*_screen); + } + + dibc->upload_data(); + + add_to_total_buffer_record(dibc); + dibc->mark_loaded(); + _active_ibuffer = NULL; + } + + if (_active_ibuffer != dibc) { + _d3d_device->SetIndices(dibc->_ibuffer); + _active_ibuffer = dibc; + add_to_index_buffer_record(dibc); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::release_index_buffer +// Access: Public, Virtual +// Description: Frees the GL resources previously allocated for the +// data. This function should never be called +// directly; instead, call Data::release() (or simply +// let the Data destruct). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +release_index_buffer(IndexBufferContext *ibc) { + DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc); + delete dibc; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::make_geom_munger +// Access: Public, Virtual +// Description: Creates a new GeomMunger object to munge vertices +// appropriate to this GSG for the indicated state. +//////////////////////////////////////////////////////////////////// +PT(GeomMunger) DXGraphicsStateGuardian9:: +make_geom_munger(const RenderState *state) { + PT(DXGeomMunger9) munger = new DXGeomMunger9(this, state); + return GeomMunger::register_munger(munger); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::set_color_clear_value +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +set_color_clear_value(const Colorf& value) { + _color_clear_value = value; + _d3dcolor_clear_value = Colorf_to_D3DCOLOR(value); } //////////////////////////////////////////////////////////////////// @@ -581,38 +502,66 @@ support_overlay_window(bool flag) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: do_clear(const RenderBuffer &buffer) { - // DO_PSTATS_STUFF(PStatTimer timer(_win->_clear_pcollector)); + nassertv(buffer._gsg == this); + int buffer_type = buffer._buffer_type; - nassertv(buffer._gsg == this); - int buffer_type = buffer._buffer_type; + DWORD main_flags = 0; + DWORD aux_flags = 0; - DWORD flags = 0; + //set appropriate flags + if (buffer_type & RenderBuffer::T_back) { + main_flags |= D3DCLEAR_TARGET; + } - if(buffer_type & RenderBuffer::T_depth) { - flags |= D3DCLEAR_ZBUFFER; - assert(_pScrn->PresParams.EnableAutoDepthStencil); + if (buffer_type & RenderBuffer::T_depth) { + aux_flags |= D3DCLEAR_ZBUFFER; + nassertv(_screen->_presentation_params.EnableAutoDepthStencil); + } + + if (buffer_type & RenderBuffer::T_stencil) { + aux_flags |= D3DCLEAR_STENCIL; + nassertv(_screen->_presentation_params.EnableAutoDepthStencil && IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat)); + } + + if ((main_flags | aux_flags) != 0) { + HRESULT hr = _d3d_device->Clear(0, NULL, main_flags | aux_flags, _d3dcolor_clear_value, + _depth_clear_value, (DWORD)_stencil_clear_value); + if (FAILED(hr) && main_flags == D3DCLEAR_TARGET && aux_flags != 0) { + // Maybe there's a problem with the one or more of the auxiliary + // buffers. + hr = _d3d_device->Clear(0, NULL, D3DCLEAR_TARGET, _d3dcolor_clear_value, + _depth_clear_value, (DWORD)_stencil_clear_value); + if (!FAILED(hr)) { + // Yep, it worked without them. That's a problem. Which buffer + // poses the problem? + if (buffer_type & RenderBuffer::T_depth) { + aux_flags |= D3DCLEAR_ZBUFFER; + HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, _d3dcolor_clear_value, + _depth_clear_value, (DWORD)_stencil_clear_value); + if (FAILED(hr2)) { + dxgsg9_cat.error() + << "Unable to clear depth buffer; removing.\n"; + _buffer_mask &= ~RenderBuffer::T_depth; + } + } + if (buffer_type & RenderBuffer::T_stencil) { + aux_flags |= D3DCLEAR_STENCIL; + HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, _d3dcolor_clear_value, + _stencil_clear_value, (DWORD)_stencil_clear_value); + if (FAILED(hr2)) { + dxgsg9_cat.error() + << "Unable to clear stencil buffer; removing.\n"; + _buffer_mask &= ~RenderBuffer::T_stencil; + } + } + } } - if(buffer_type & RenderBuffer::T_back) //set appropriate flags - flags |= D3DCLEAR_TARGET; - - if(buffer_type & RenderBuffer::T_stencil) { - flags |= D3DCLEAR_STENCIL; - assert(_pScrn->PresParams.EnableAutoDepthStencil && IS_STENCIL_FORMAT(_pScrn->PresParams.AutoDepthStencilFormat)); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "clear_buffer failed: Clear returned " << D3DERRORSTRING(hr); } - - HRESULT hr = _pD3DDevice->Clear(0, NULL, flags, _d3dcolor_clear_value, - _depth_clear_value, (DWORD)_stencil_clear_value); - if(FAILED(hr)) { - dxgsg9_cat.error() << "clear_buffer failed: Clear returned " << D3DERRORSTRING(hr); - throw_event("panda3d-render-error"); - } - /* The following line will cause the background to always clear to a medium red - _color_clear_value[0] = .5; - /* The following lines will cause the background color to cycle from black to red. - _color_clear_value[0] += .001; - if (_color_clear_value[0] > 1.0f) _color_clear_value[0] = 0.0f; - */ + } } //////////////////////////////////////////////////////////////////// @@ -626,21 +575,35 @@ prepare_display_region() { if (_current_display_region == (DisplayRegion*)0L) { dxgsg9_cat.error() << "Invalid NULL display region in prepare_display_region()\n"; + } else if (_current_display_region != _actual_display_region) { _actual_display_region = _current_display_region; - + int l, u, w, h; _actual_display_region->get_region_pixels_i(l, u, w, h); // Create the viewport D3DVIEWPORT9 vp = { l, u, w, h, 0.0f, 1.0f }; - HRESULT hr = _pD3DDevice->SetViewport( &vp ); + HRESULT hr = _d3d_device->SetViewport(&vp); if (FAILED(hr)) { + dxgsg9_cat.error() + << "_screen->_swap_chain = " << _screen->_swap_chain << " _swap_chain = " << _swap_chain << "\n"; dxgsg9_cat.error() << "SetViewport(" << l << ", " << u << ", " << w << ", " << h << ") failed" << D3DERRORSTRING(hr); - throw_event("panda3d-render-error"); - nassertv(false); + + D3DVIEWPORT9 vp_old; + _d3d_device->GetViewport(&vp_old); + dxgsg9_cat.error() + << "GetViewport(" << vp_old.X << ", " << vp_old.Y << ", " << vp_old.Width << ", " + << vp_old.Height << ") returned: Trying to set that vp---->\n"; + hr = _d3d_device->SetViewport(&vp_old); + + if (FAILED(hr)) { + dxgsg9_cat.error() << "Failed again\n"; + throw_event("panda3d-render-error"); + nassertv(false); + } } // Note: for DX9, also change scissor clipping state here } @@ -669,12 +632,12 @@ prepare_lens() { } // Start with the projection matrix from the lens. - const LMatrix4f &projection_mat = _current_lens->get_projection_mat(); + const LMatrix4f &lens_mat = _current_lens->get_projection_mat(); // The projection matrix must always be left-handed Y-up internally, // to match DirectX's convention, even if our coordinate system of // choice is otherwise. - const LMatrix4f &convert_mat = + const LMatrix4f &convert_mat = LMatrix4f::convert_mat(CS_yup_left, _current_lens->get_coordinate_system()); // DirectX also uses a Z range of 0 to 1, whereas the Panda @@ -685,23 +648,2336 @@ prepare_lens() { 0, 1, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 1); - - LMatrix4f new_projection_mat = - convert_mat * projection_mat * rescale_mat; + + _projection_mat = convert_mat * lens_mat * rescale_mat; if (_scene_setup->get_inverted()) { // If the scene is supposed to be inverted, then invert the // projection matrix. static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f); - new_projection_mat *= invert_mat; + _projection_mat *= invert_mat; } - HRESULT hr = - _pD3DDevice->SetTransform(D3DTS_PROJECTION, - (D3DMATRIX*)new_projection_mat.get_data()); + HRESULT hr = + _d3d_device->SetTransform(D3DTS_PROJECTION, + (D3DMATRIX*)_projection_mat.get_data()); return SUCCEEDED(hr); } +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::begin_frame +// Access: Public, Virtual +// Description: Called before each frame is rendered, to allow the +// GSG a chance to do any internal cleanup before +// beginning the frame. +// +// The return value is true if successful (in which case +// the frame will be drawn and end_frame() will be +// called later), or false if unsuccessful (in which +// case nothing will be drawn and end_frame() will not +// be called). +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian9:: +begin_frame() { + return GraphicsStateGuardian::begin_frame(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::begin_scene +// Access: Public, Virtual +// Description: Called between begin_frame() and end_frame() to mark +// the beginning of drawing commands for a "scene" +// (usually a particular DisplayRegion) within a frame. +// All 3-D drawing commands, except the clear operation, +// must be enclosed within begin_scene() .. end_scene(). +// +// The return value is true if successful (in which case +// the scene will be drawn and end_scene() will be +// called later), or false if unsuccessful (in which +// case nothing will be drawn and end_scene() will not +// be called). +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian9:: +begin_scene() { + if (!GraphicsStateGuardian::begin_scene()) { + return false; + } + + HRESULT hr = _d3d_device->BeginScene(); + + if (FAILED(hr)) { + if (hr == D3DERR_DEVICELOST) { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "BeginScene returns D3DERR_DEVICELOST" << endl; + } + + check_cooperative_level(); + + } else { + dxgsg9_cat.error() + << "BeginScene failed, unhandled error hr == " + << D3DERRORSTRING(hr) << endl; + throw_event("panda3d-render-error"); + } + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::end_scene +// Access: Public, Virtual +// Description: Called between begin_frame() and end_frame() to mark +// the end of drawing commands for a "scene" (usually a +// particular DisplayRegion) within a frame. All 3-D +// drawing commands, except the clear operation, must be +// enclosed within begin_scene() .. end_scene(). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +end_scene() { + HRESULT hr = _d3d_device->EndScene(); + + if (FAILED(hr)) { + if (hr == D3DERR_DEVICELOST) { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "EndScene returns DeviceLost\n"; + } + check_cooperative_level(); + + } else { + dxgsg9_cat.error() + << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr); + throw_event("panda3d-render-error"); + } + return; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::end_frame +// Access: Public, Virtual +// Description: Called after each frame is rendered, to allow the +// GSG a chance to do any internal cleanup after +// rendering the frame, and before the window flips. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +end_frame() { + +#if defined(DO_PSTATS) + if (_texmgrmem_total_pcollector.is_active()) { +#define TICKS_PER_GETTEXINFO (2.5*1000) // 2.5 second interval + static DWORD last_tick_count = 0; + DWORD cur_tick_count = GetTickCount(); + + if (cur_tick_count - last_tick_count > TICKS_PER_GETTEXINFO) { + last_tick_count = cur_tick_count; + report_texmgr_stats(); + } + } +#endif + + // Note: regular GraphicsWindow::end_frame is being called, + // but we override gsg::end_frame, so need to explicitly call it here + // (currently it's an empty fn) + GraphicsStateGuardian::end_frame(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::begin_draw_primitives +// Access: Public, Virtual +// Description: Called before a sequence of draw_primitive() +// functions are called, this should prepare the vertex +// data for rendering. It returns true if the vertices +// are ok, false to abort this group of primitives. +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian9:: +begin_draw_primitives(const Geom *geom, const GeomMunger *munger, + const GeomVertexData *vertex_data) { + if (!GraphicsStateGuardian::begin_draw_primitives(geom, munger, vertex_data)) { + return false; + } + nassertr(_vertex_data != (GeomVertexData *)NULL, false); + + const GeomVertexFormat *format = _vertex_data->get_format(); + + // The munger should have put the FVF data in the first array. + const GeomVertexArrayData *data = _vertex_data->get_array(0); + + VertexBufferContext *vbc = ((GeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this); + nassertr(vbc != (VertexBufferContext *)NULL, false); + apply_vertex_buffer(vbc); + + const GeomVertexAnimationSpec &animation = + vertex_data->get_format()->get_animation(); + if (animation.get_animation_type() == Geom::AT_hardware) { + // Set up vertex blending. + switch (animation.get_num_transforms()) { + case 1: + // The MSDN docs suggest we should use D3DVBF_0WEIGHTS here, but + // that doesn't seem to work at all. On the other hand, + // D3DVBF_DISABLE *does* work, because it disables special + // handling, meaning only the world matrix affects these + // vertices--and by accident or design, the first matrix, + // D3DTS_WORLDMATRIX(0), *is* the world matrix. + _d3d_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); + break; + case 2: + _d3d_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS); + break; + case 3: + _d3d_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_2WEIGHTS); + break; + case 4: + _d3d_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS); + break; + } + + if (animation.get_indexed_transforms()) { + // Set up indexed vertex blending. + _d3d_device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE); + } else { + _d3d_device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + } + + const TransformTable *table = vertex_data->get_transform_table(); + if (table != (TransformTable *)NULL) { + for (int i = 0; i < table->get_num_transforms(); i++) { + LMatrix4f mat; + table->get_transform(i)->mult_matrix(mat, _internal_transform->get_mat()); + const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data(); + _d3d_device->SetTransform(D3DTS_WORLDMATRIX(i), d3d_mat); + } + + // Setting the first animation matrix steps on the world matrix, + // so we have to set a flag to reload the world matrix later. + _transform_stale = true; + } + _vertex_blending_enabled = true; + + } else { + // We're not using vertex blending. + if (_vertex_blending_enabled) { + _d3d_device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + _d3d_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); + _vertex_blending_enabled = false; + } + + if (_transform_stale && !_vertex_data->is_vertex_transformed()) { + const D3DMATRIX *d3d_mat = (const D3DMATRIX *)_internal_transform->get_mat().get_data(); + _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat); + _transform_stale = false; + } + } + + if (_vertex_data->is_vertex_transformed()) { + // If the vertex data claims to be already transformed into clip + // coordinates, wipe out the current projection and modelview + // matrix (so we don't attempt to transform it again). + + // It's tempting just to use the D3DFVF_XYZRHW specification on + // these vertices, but that turns out to be a bigger hammer than + // we want: that also prevents lighting calculations and user clip + // planes. + _d3d_device->SetTransform(D3DTS_WORLD, &_d3d_ident_mat); + static const LMatrix4f rescale_mat + (1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0.5, 0, + 0, 0, 0.5, 1); + _transform_stale = true; + + _d3d_device->SetTransform(D3DTS_PROJECTION, (const D3DMATRIX *)rescale_mat.get_data()); + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::draw_triangles +// Access: Public, Virtual +// Description: Draws a series of disconnected triangles. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +draw_triangles(const GeomTriangles *primitive) { + _vertices_tri_pcollector.add_level(primitive->get_num_vertices()); + _primitive_batches_tri_pcollector.add_level(1); + if (primitive->is_indexed()) { + int min_vertex = dx_broken_max_index ? 0 : primitive->get_min_vertex(); + int max_vertex = primitive->get_max_vertex(); + + if (_active_vbuffer != NULL) { + // Indexed, vbuffers. + IndexBufferContext *ibc = ((GeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + _d3d_device->DrawIndexedPrimitive + (D3DPT_TRIANGLELIST, + 0, + min_vertex, max_vertex - min_vertex + 1, + 0, primitive->get_num_primitives()); + + } else { + // Indexed, client arrays. + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); + draw_indexed_primitive_up + (D3DPT_TRIANGLELIST, + min_vertex, max_vertex, + primitive->get_num_primitives(), + primitive->get_data(), + index_type, + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } + } else { + if (_active_vbuffer != NULL) { + // Nonindexed, vbuffers. + _d3d_device->DrawPrimitive + (D3DPT_TRIANGLELIST, + primitive->get_first_vertex(), + primitive->get_num_primitives()); + + } else { + // Nonindexed, client arrays. + + draw_primitive_up(D3DPT_TRIANGLELIST, primitive->get_num_primitives(), + primitive->get_first_vertex(), + primitive->get_num_vertices(), + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::draw_tristrips +// Access: Public, Virtual +// Description: Draws a series of triangle strips. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +draw_tristrips(const GeomTristrips *primitive) { + if (connect_triangle_strips && _current_fill_mode != RenderModeAttrib::M_wireframe) { + // One long triangle strip, connected by the degenerate vertices + // that have already been set up within the primitive. + _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices()); + _primitive_batches_tristrip_pcollector.add_level(1); + if (primitive->is_indexed()) { + int min_vertex = dx_broken_max_index ? 0 : primitive->get_min_vertex(); + int max_vertex = primitive->get_max_vertex(); + + if (_active_vbuffer != NULL) { + // Indexed, vbuffers, one line triangle strip. + IndexBufferContext *ibc = ((GeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + _d3d_device->DrawIndexedPrimitive + (D3DPT_TRIANGLESTRIP, + 0, + min_vertex, max_vertex - min_vertex + 1, + 0, primitive->get_num_vertices() - 2); + + } else { + // Indexed, client arrays, one long triangle strip. + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); + draw_indexed_primitive_up + (D3DPT_TRIANGLESTRIP, + min_vertex, max_vertex, + primitive->get_num_vertices() - 2, + primitive->get_data(), index_type, + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } + } else { + if (_active_vbuffer != NULL) { + // Nonindexed, vbuffers, one long triangle strip. + _d3d_device->DrawPrimitive + (D3DPT_TRIANGLESTRIP, + primitive->get_first_vertex(), + primitive->get_num_vertices() - 2); + + } else { + // Indexed, client arrays, one long triangle strip. + draw_primitive_up(D3DPT_TRIANGLESTRIP, + primitive->get_num_vertices() - 2, + primitive->get_first_vertex(), + primitive->get_num_vertices(), + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } + } + + } else { + // Send the individual triangle strips, stepping over the + // degenerate vertices. + CPTA_int ends = primitive->get_ends(); + _primitive_batches_tristrip_pcollector.add_level(ends.size()); + + if (primitive->is_indexed()) { + CPTA_int ends = primitive->get_ends(); + int index_stride = primitive->get_index_stride(); + _primitive_batches_tristrip_pcollector.add_level(ends.size()); + + GeomVertexReader mins(primitive->get_mins(), 0); + GeomVertexReader maxs(primitive->get_maxs(), 0); + nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && + primitive->get_maxs()->get_num_rows() == (int)ends.size()); + + if (_active_vbuffer != NULL) { + // Indexed, vbuffers, individual triangle strips. + IndexBufferContext *ibc = ((GeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + _d3d_device->DrawIndexedPrimitive + (D3DPT_TRIANGLESTRIP, + 0, + min, max - min + 1, + start, ends[i] - start - 2); + + start = ends[i] + 2; + } + + } else { + // Indexed, client arrays, individual triangle strips. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + CPTA_uchar vertices = primitive->get_data(); + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + draw_indexed_primitive_up + (D3DPT_TRIANGLESTRIP, + min, max, + ends[i] - start - 2, + vertices + start * index_stride, index_type, + array_data, stride); + + start = ends[i] + 2; + } + } + } else { + unsigned int first_vertex = primitive->get_first_vertex(); + + if (_active_vbuffer != NULL) { + // Nonindexed, vbuffers, individual triangle strips. + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + _d3d_device->DrawPrimitive + (D3DPT_TRIANGLESTRIP, + first_vertex + start, ends[i] - start - 2); + + start = ends[i] + 2; + } + + } else { + // Nonindexed, client arrays, individual triangle strips. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + draw_primitive_up(D3DPT_TRIANGLESTRIP, ends[i] - start - 2, + first_vertex + start, + ends[i] - start, + array_data, stride); + + start = ends[i] + 2; + } + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::draw_trifans +// Access: Public, Virtual +// Description: Draws a series of triangle fans. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +draw_trifans(const GeomTrifans *primitive) { + CPTA_int ends = primitive->get_ends(); + _primitive_batches_trifan_pcollector.add_level(ends.size()); + + if (primitive->is_indexed()) { + int min_vertex = dx_broken_max_index ? 0 : primitive->get_min_vertex(); + int max_vertex = primitive->get_max_vertex(); + + // Send the individual triangle fans. There's no connecting fans + // with degenerate vertices, so no worries about that. + int index_stride = primitive->get_index_stride(); + + GeomVertexReader mins(primitive->get_mins(), 0); + GeomVertexReader maxs(primitive->get_maxs(), 0); + nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && + primitive->get_maxs()->get_num_rows() == (int)ends.size()); + + if (_active_vbuffer != NULL) { + // Indexed, vbuffers. + IndexBufferContext *ibc = ((GeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + _d3d_device->DrawIndexedPrimitive + (D3DPT_TRIANGLEFAN, + 0, + min, max - min + 1, + start, ends[i] - start - 2); + + start = ends[i]; + } + + } else { + // Indexed, client arrays. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + CPTA_uchar vertices = primitive->get_data(); + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + draw_indexed_primitive_up + (D3DPT_TRIANGLEFAN, + min, max, + ends[i] - start - 2, + vertices + start * index_stride, index_type, + array_data, stride); + + start = ends[i]; + } + } + } else { + unsigned int first_vertex = primitive->get_first_vertex(); + + if (_active_vbuffer != NULL) { + // Nonindexed, vbuffers. + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + _d3d_device->DrawPrimitive + (D3DPT_TRIANGLEFAN, + first_vertex + start, ends[i] - start - 2); + + start = ends[i]; + } + + } else { + // Nonindexed, client arrays. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + draw_primitive_up(D3DPT_TRIANGLEFAN, + ends[i] - start - 2, + first_vertex, + ends[i] - start, + array_data, stride); + start = ends[i]; + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::draw_lines +// Access: Public, Virtual +// Description: Draws a series of disconnected line segments. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +draw_lines(const GeomLines *primitive) { + _vertices_other_pcollector.add_level(primitive->get_num_vertices()); + _primitive_batches_other_pcollector.add_level(1); + + if (primitive->is_indexed()) { + int min_vertex = dx_broken_max_index ? 0 : primitive->get_min_vertex(); + int max_vertex = primitive->get_max_vertex(); + + if (_active_vbuffer != NULL) { + // Indexed, vbuffers. + IndexBufferContext *ibc = ((GeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + _d3d_device->DrawIndexedPrimitive + (D3DPT_LINELIST, + 0, + min_vertex, max_vertex - min_vertex + 1, + 0, primitive->get_num_primitives()); + + } else { + // Indexed, client arrays. + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); + + draw_indexed_primitive_up + (D3DPT_LINELIST, + min_vertex, max_vertex, + primitive->get_num_primitives(), + primitive->get_data(), + index_type, + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } + } else { + if (_active_vbuffer != NULL) { + // Nonindexed, vbuffers. + _d3d_device->DrawPrimitive + (D3DPT_LINELIST, + primitive->get_first_vertex(), + primitive->get_num_primitives()); + + } else { + // Nonindexed, client arrays. + draw_primitive_up(D3DPT_LINELIST, primitive->get_num_primitives(), + primitive->get_first_vertex(), + primitive->get_num_vertices(), + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::draw_linestrips +// Access: Public, Virtual +// Description: Draws a series of line strips. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +draw_linestrips(const GeomLinestrips *primitive) { +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::draw_points +// Access: Public, Virtual +// Description: Draws a series of disconnected points. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +draw_points(const GeomPoints *primitive) { + _vertices_other_pcollector.add_level(primitive->get_num_vertices()); + _primitive_batches_other_pcollector.add_level(1); + + // The munger should have protected us from indexed points--DirectX + // doesn't support them. + nassertv(!primitive->is_indexed()); + + if (_active_vbuffer != NULL) { + // Nonindexed, vbuffers. + _d3d_device->DrawPrimitive + (D3DPT_POINTLIST, + primitive->get_first_vertex(), + primitive->get_num_primitives()); + + } else { + // Nonindexed, client arrays. + draw_primitive_up(D3DPT_POINTLIST, primitive->get_num_primitives(), + primitive->get_first_vertex(), + primitive->get_num_vertices(), + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::end_draw_primitives() +// Access: Public, Virtual +// Description: Called after a sequence of draw_primitive() +// functions are called, this should do whatever cleanup +// is appropriate. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +end_draw_primitives() { + // Turn off vertex blending--it seems to cause problems if we leave + // it on. + if (_vertex_blending_enabled) { + _d3d_device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + _d3d_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); + _vertex_blending_enabled = false; + } + + if (_vertex_data->is_vertex_transformed()) { + // Restore the projection matrix that we wiped out above. + prepare_lens(); + } + + GraphicsStateGuardian::end_draw_primitives(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::framebuffer_copy_to_texture +// Access: Public, Virtual +// Description: Copy the pixels within the indicated display +// region from the framebuffer into texture memory. +// +// If z > -1, it is the cube map index into which to +// copy. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, + const RenderBuffer &rb) { + set_read_buffer(rb); + + int orig_x = tex->get_x_size(); + int orig_y = tex->get_y_size(); + + HRESULT hr; + int xo, yo, w, h; + dr->get_region_pixels_i(xo, yo, w, h); + tex->set_x_size(Texture::up_to_power_2(w)); + tex->set_y_size(Texture::up_to_power_2(h)); + + TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); + if (tc == (TextureContext *)NULL) { + return; + } + DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); + + if (tex->get_texture_type() != Texture::TT_2d_texture) { + // For a specialty texture like a cube map, go the slow route + // through RAM for now. + framebuffer_copy_to_ram(tex, z, dr, rb); + return; + } + nassertv(dtc->get_d3d_2d_texture() != NULL); + + IDirect3DSurface9 *tex_level_0; + hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0); + if (FAILED(hr)) { + dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr); + return; + } + + // If the texture is the wrong size, we need to do something about it. + D3DSURFACE_DESC texdesc; + hr = tex_level_0->GetDesc(&texdesc); + if (FAILED(hr)) { + dxgsg9_cat.error() << "GetDesc failed in copy_texture" << D3DERRORSTRING(hr); + SAFE_RELEASE(tex_level_0); + return; + } + if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) { + if ((orig_x != tex->get_x_size()) || (orig_y != tex->get_y_size())) { + // Texture might be wrong size because we resized it and need to recreate. + SAFE_RELEASE(tex_level_0); + if (!dtc->create_texture(*_screen)) { + // Oops, we can't re-create the texture for some reason. + dxgsg9_cat.error() + << "Unable to re-create texture " << *dtc->_texture << endl; + return; + } + hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0); + if (FAILED(hr)) { + dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr); + return; + } + hr = tex_level_0->GetDesc(&texdesc); + if (FAILED(hr)) { + dxgsg9_cat.error() << "GetDesc 2 failed in copy_texture" << D3DERRORSTRING(hr); + SAFE_RELEASE(tex_level_0); + return; + } + } + if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) { + // If it's still the wrong size, it's because driver can't create size + // that we want. In that case, there's no helping it, we have to give up. + dxgsg9_cat.error() + << "Unable to copy to texture, texture is wrong size: " << *dtc->_texture << endl; + SAFE_RELEASE(tex_level_0); + return; + } + } + + DWORD render_target_index; + IDirect3DSurface9 *render_target; + +/* ***** DX9 GetRenderTarget (render_target_index, ) */ +render_target_index = 0; + + hr = _d3d_device->GetRenderTarget(render_target_index, &render_target); + if (FAILED(hr)) { + dxgsg9_cat.error() << "GetRenderTgt failed in copy_texture" << D3DERRORSTRING(hr); + SAFE_RELEASE(tex_level_0); + return; + } + + RECT src_rect; + + src_rect.left = xo; + src_rect.right = xo+w; + src_rect.top = yo; + src_rect.bottom = yo+h; + + // now copy from fb to tex + +/* ***** DX9 CopyRects */ +// hr = _d3d_device->CopyRects(render_target, &src_rect, 1, tex_level_0, 0); + hr = -1; + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "CopyRects failed in copy_texture" << D3DERRORSTRING(hr); + } + + SAFE_RELEASE(render_target); + SAFE_RELEASE(tex_level_0); +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::framebuffer_copy_to_ram +// Access: Public, Virtual +// Description: Copy the pixels within the indicated display region +// from the framebuffer into system memory, not texture +// memory. Returns true on success, false on failure. +// +// This completely redefines the ram image of the +// indicated texture. +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian9:: +framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { + set_read_buffer(rb); + + RECT rect; + nassertr(tex != NULL && dr != NULL, false); + + int xo, yo, w, h; + dr->get_region_pixels_i(xo, yo, w, h); + + Texture::Format format = tex->get_format(); + Texture::ComponentType component_type = tex->get_component_type(); + + switch (format) { + case Texture::F_depth_component: + case Texture::F_stencil_index: + // Sorry, not (yet?) supported in pandadx. + return false; + + default: + format = Texture::F_rgb; + component_type = Texture::T_unsigned_byte; + } + + Texture::TextureType texture_type; + if (z >= 0) { + texture_type = Texture::TT_cube_map; + } else { + texture_type = Texture::TT_2d_texture; + } + + if (tex->get_x_size() != w || tex->get_y_size() != h || + tex->get_component_type() != component_type || + tex->get_format() != format || + tex->get_texture_type() != texture_type) { + // Re-setup the texture; its properties have changed. + tex->setup_texture(texture_type, w, h, tex->get_z_size(), + component_type, format); + } + + rect.top = yo; + rect.left = xo; + rect.right = xo + w; + rect.bottom = yo + h; + bool copy_inverted = false; + + IDirect3DSurface9 *temp_surface = NULL; + HRESULT hr; + + // Note if you try to grab the backbuffer and full-screen + // anti-aliasing is on, the backbuffer might be larger than the + // window size. For screenshots it's safer to get the front buffer. + if (_cur_read_pixel_buffer & RenderBuffer::T_back) { + DWORD render_target_index; + IDirect3DSurface9 *backbuffer = NULL; + // GetRenderTarget() seems to be a little more reliable than + // GetBackBuffer(). Might just be related to the swap_chain + // thing. + + render_target_index = 0; + hr = _d3d_device->GetRenderTarget(render_target_index, &backbuffer); + + if (FAILED(hr)) { + dxgsg9_cat.error() << "GetRenderTarget failed" << D3DERRORSTRING(hr); + return false; + } + + // Since we might not be able to Lock the back buffer, we will + // need to copy it to a temporary surface of the appropriate type + // first. + D3DPOOL pool; + + pool = D3DPOOL_SCRATCH; + hr = _d3d_device->CreateOffscreenPlainSurface(w, h, _screen->_display_mode.Format, + pool, + &temp_surface, + NULL); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "CreateImageSurface failed in copy_pixel_buffer()" + << D3DERRORSTRING(hr); + backbuffer->Release(); + return false; + } + + // Now we must copy from the backbuffer to our temporary surface. + +/* ***** DX9 CopyRects */ +// hr = _d3d_device->CopyRects(backbuffer, &rect, 1, temp_surface, NULL); + hr = -1; + + if (FAILED(hr)) { + dxgsg9_cat.error() << "CopyRects failed" << D3DERRORSTRING(hr); + temp_surface->Release(); + backbuffer->Release(); + return false; + } + + RELEASE(backbuffer, dxgsg9, "backbuffer", RELEASE_ONCE); + + } else if (_cur_read_pixel_buffer & RenderBuffer::T_front) { + + if (_screen->_presentation_params.Windowed) { + // GetFrontBuffer() retrieves the entire desktop for a monitor, + // so we need to reserve space for that. + + // We have to use GetMonitorInfo(), since this GSG may not be + // for the primary monitor. + MONITORINFO minfo; + minfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(_screen->_monitor, &minfo); + + w = RECT_XSIZE(minfo.rcMonitor); + h = RECT_YSIZE(minfo.rcMonitor); + + // set rect to client area of window in scrn coords + ClientToScreen(_screen->_window, (POINT*)&rect.left); + ClientToScreen(_screen->_window, (POINT*)&rect.right); + } + + // For GetFrontBuffer(), we need a temporary surface of type + // A8R8G8B8. Unlike GetBackBuffer(), GetFrontBuffer() implicitly + // performs a copy. + hr = _d3d_device->CreateOffscreenPlainSurface(w, h, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &temp_surface, NULL); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "CreateImageSurface failed in copy_pixel_buffer()" + << D3DERRORSTRING(hr); + return false; + } + + UINT swap_chain; + +/* ***** DX9 swap chain ??? */ + swap_chain = 0; + hr = _d3d_device->GetFrontBufferData(swap_chain,temp_surface); + + if (hr == D3DERR_DEVICELOST) { + dxgsg9_cat.error() + << "copy_pixel_buffer failed: device lost\n"; + temp_surface->Release(); + return false; + } + + // For some reason the front buffer comes out inverted, but the + // back buffer does not. + copy_inverted = true; + + } else { + dxgsg9_cat.error() + << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n"; + temp_surface->Release(); + return false; + } + + DXTextureContext9::d3d_surface_to_texture(rect, temp_surface, + copy_inverted, tex, z); + + RELEASE(temp_surface, dxgsg9, "temp_surface", RELEASE_ONCE); + + nassertr(tex->has_ram_image(), false); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::reset +// Access: Public, Virtual +// Description: Resets all internal state as if the gsg were newly +// created. The GraphicsWindow pointer represents a +// typical window that might be used for this context; +// it may be required to set up the frame buffer +// properly the first time. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +reset() { + GraphicsStateGuardian::reset(); + + _auto_rescale_normal = false; + + // overwrite gsg defaults with these values + + // We always have at least a color buffer (the depth and/or stencil + // buffer flags will be filled in by the window). + _buffer_mask = RenderBuffer::T_color; + + HRESULT hr; + + // make sure gsg passes all current state down to us + // set_state_and_transform(RenderState::make_empty(), + // TransformState::make_identity()); + // want gsg to pass all state settings down so any non-matching defaults we set here get overwritten + + assert(_screen->_d3d9 != NULL); + assert(_d3d_device != NULL); + + D3DCAPS9 d3d_caps; + _d3d_device->GetDeviceCaps(&d3d_caps); + + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "\nHwTransformAndLight = " << ((d3d_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0) + << "\nMaxTextureWidth = " << d3d_caps.MaxTextureWidth + << "\nMaxTextureHeight = " << d3d_caps.MaxTextureHeight + << "\nMaxVolumeExtent = " << d3d_caps.MaxVolumeExtent + << "\nMaxTextureAspectRatio = " << d3d_caps.MaxTextureAspectRatio + << "\nTexCoordCount = " << (d3d_caps.FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK) + << "\nMaxTextureBlendStages = " << d3d_caps.MaxTextureBlendStages + << "\nMaxSimultaneousTextures = " << d3d_caps.MaxSimultaneousTextures + << "\nMaxActiveLights = " << d3d_caps.MaxActiveLights + << "\nMaxUserClipPlanes = " << d3d_caps.MaxUserClipPlanes + << "\nMaxVertexBlendMatrices = " << d3d_caps.MaxVertexBlendMatrices + << "\nMaxVertexBlendMatrixIndex = " << d3d_caps.MaxVertexBlendMatrixIndex + << "\nMaxPointSize = " << d3d_caps.MaxPointSize + << "\nMaxPrimitiveCount = " << d3d_caps.MaxPrimitiveCount + << "\nMaxVertexIndex = " << d3d_caps.MaxVertexIndex + << "\nMaxStreams = " << d3d_caps.MaxStreams + << "\nMaxStreamStride = " << d3d_caps.MaxStreamStride + << "\nD3DTEXOPCAPS_MULTIPLYADD = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_MULTIPLYADD) != 0) + << "\nD3DTEXOPCAPS_LERP = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0) + << "\nD3DPMISCCAPS_TSSARGTEMP = " << ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0) + << "\n"; + } + + _max_vertices_per_array = d3d_caps.MaxVertexIndex; + _max_vertices_per_primitive = d3d_caps.MaxPrimitiveCount; + + _max_texture_stages = d3d_caps.MaxSimultaneousTextures; + + _max_texture_dimension = min(d3d_caps.MaxTextureWidth, d3d_caps.MaxTextureHeight); + + _supports_texture_combine = ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0); + _supports_texture_saved_result = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0); + _supports_texture_dot3 = true; + + _supports_3d_texture = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) != 0); + if (_supports_3d_texture) { + _max_3d_texture_dimension = d3d_caps.MaxVolumeExtent; + } + _supports_cube_map = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) != 0); + if (_supports_cube_map) { + _max_cube_map_dimension = _max_texture_dimension; + } + + _max_lights = (int)d3d_caps.MaxActiveLights; + _max_clip_planes = (int)d3d_caps.MaxUserClipPlanes; + _max_vertex_transforms = d3d_caps.MaxVertexBlendMatrices; + _max_vertex_transform_indices = d3d_caps.MaxVertexBlendMatrixIndex; + + _d3d_device->SetRenderState(D3DRS_AMBIENT, 0x0); + + _clip_plane_bits = 0; + _d3d_device->SetRenderState(D3DRS_CLIPPLANEENABLE , 0x0); + + _d3d_device->SetRenderState(D3DRS_CLIPPING, true); + + // these both reflect d3d defaults + _color_writemask = 0xFFFFFFFF; + + _d3d_device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + + _d3d_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + +/* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */ +// _d3d_device->SetRenderState(D3DRS_EDGEANTIALIAS, false); + + _d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + + _d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + _d3d_device->SetRenderState(D3DRS_FOGENABLE, FALSE); + + _projection_mat = LMatrix4f::ident_mat(); + _has_scene_graph_color = false; + + _last_testcooplevel_result = D3D_OK; + + for(int i = 0; i < MAX_POSSIBLE_TEXFMTS; i++) { + // look for all possible DX9 texture fmts + D3DFORMAT_FLAG fmtflag = D3DFORMAT_FLAG(1 << i); + hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format, + 0x0, D3DRTYPE_TEXTURE, g_D3DFORMATmap[fmtflag]); + if (SUCCEEDED(hr)){ + _screen->_supported_tex_formats_mask |= fmtflag; + } + } + + // s3 virge drivers sometimes give crap values for these + if (_screen->_d3dcaps.MaxTextureWidth == 0) + _screen->_d3dcaps.MaxTextureWidth = 256; + + if (_screen->_d3dcaps.MaxTextureHeight == 0) + _screen->_d3dcaps.MaxTextureHeight = 256; + + if (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) { + // Watch out for drivers that emulate per-pixel fog with + // per-vertex fog (Riva128, Matrox Millen G200). Some of these + // require gouraud-shading to be set to work, as if you were using + // vertex fog + _do_fog_type = PerPixelFog; + } else { + // every card is going to have vertex fog, since it's implemented + // in d3d runtime. + assert((_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) != 0); + + // vertex fog may look crappy if you have large polygons in the + // foreground and they get clipped, so you may want to disable it + + if (dx_no_vertex_fog) { + _do_fog_type = None; + } else { + _do_fog_type = PerVertexFog; + + // range-based fog only works with vertex fog in dx7/8 + if (dx_use_rangebased_fog && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGRANGE)) { + _d3d_device->SetRenderState(D3DRS_RANGEFOGENABLE, true); + } + } + } + + _screen->_can_direct_disable_color_writes = ((_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0); + + // Lighting, let's turn it off initially. + _d3d_device->SetRenderState(D3DRS_LIGHTING, false); + + // turn on dithering if the rendertarget is < 8bits/color channel + bool dither_enabled = ((!dx_no_dithering) && IS_16BPP_DISPLAY_FORMAT(_screen->_presentation_params.BackBufferFormat) + && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER)); + _d3d_device->SetRenderState(D3DRS_DITHERENABLE, dither_enabled); + + _d3d_device->SetRenderState(D3DRS_CLIPPING, true); + + // Stencil test is off by default + _d3d_device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + + // Antialiasing. +/* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */ +// _d3d_device->SetRenderState(D3DRS_EDGEANTIALIAS, FALSE); + + _current_fill_mode = RenderModeAttrib::M_filled; + _d3d_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + + // must do SetTSS here because redundant states are filtered out by + // our code based on current values above, so initial conditions + // must be correct + _d3d_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); // disables texturing + + _cull_face_mode = CullFaceAttrib::M_cull_none; + _d3d_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + _d3d_device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS); + _d3d_device->SetRenderState(D3DRS_ALPHAREF, 255); + _d3d_device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + + // this is a new DX8 state that lets you do additional operations other than ADD (e.g. subtract/max/min) + // must check (_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) (yes on GF2/Radeon8500, no on TNT) + _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + PRINT_REFCNT(dxgsg9, _d3d_device); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::apply_fog +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +apply_fog(Fog *fog) { + if (_do_fog_type == None) + return; + + Fog::Mode panda_fogmode = fog->get_mode(); + D3DFOGMODE d3dfogmode = get_fog_mode_type(panda_fogmode); + + _d3d_device->SetRenderState((D3DRENDERSTATETYPE)_do_fog_type, d3dfogmode); + + const Colorf &fog_colr = fog->get_color(); + _d3d_device->SetRenderState(D3DRS_FOGCOLOR, + MY_D3DRGBA(fog_colr[0], fog_colr[1], fog_colr[2], 0.0f)); // Alpha bits are not used + + // do we need to adjust fog start/end values based on D3DPRASTERCAPS_WFOG/D3DPRASTERCAPS_ZFOG ? + // if not WFOG, then docs say we need to adjust values to range [0, 1] + + switch (panda_fogmode) { + case Fog::M_linear: + { + float onset, opaque; + fog->get_linear_range(onset, opaque); + + _d3d_device->SetRenderState(D3DRS_FOGSTART, + *((LPDWORD) (&onset))); + _d3d_device->SetRenderState(D3DRS_FOGEND, + *((LPDWORD) (&opaque))); + } + break; + case Fog::M_exponential: + case Fog::M_exponential_squared: + { + // Exponential fog is always camera-relative. + float fog_density = fog->get_exp_density(); + _d3d_device->SetRenderState(D3DRS_FOGDENSITY, + *((LPDWORD) (&fog_density))); + } + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_transform +// Access: Protected +// Description: Sends the indicated transform matrix to the graphics +// API to be applied to future vertices. +// +// This transform is the internal_transform, already +// converted into the GSG's internal coordinate system. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_transform() { + const TransformState *transform = _internal_transform; + DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1)); + + const D3DMATRIX *d3d_mat = (const D3DMATRIX *)transform->get_mat().get_data(); + _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat); + _transform_stale = false; + + if (_auto_rescale_normal) { + do_auto_rescale_normal(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_alpha_test +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_alpha_test() { + const AlphaTestAttrib *attrib = _target._alpha_test; + AlphaTestAttrib::PandaCompareFunc mode = attrib->get_mode(); + if (mode == AlphaTestAttrib::M_none) { + _d3d_device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + + } else { + // AlphaTestAttrib::PandaCompareFunc === D3DCMPFUNC + _d3d_device->SetRenderState(D3DRS_ALPHAFUNC, (D3DCMPFUNC)mode); + _d3d_device->SetRenderState(D3DRS_ALPHAREF, (UINT) (attrib->get_reference_alpha()*255.0f)); //d3d uses 0x0-0xFF, not a float + _d3d_device->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_render_mode +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_render_mode() { + const RenderModeAttrib *attrib = _target._render_mode; + RenderModeAttrib::Mode mode = attrib->get_mode(); + + switch (mode) { + case RenderModeAttrib::M_unchanged: + case RenderModeAttrib::M_filled: + _d3d_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + break; + + case RenderModeAttrib::M_wireframe: + _d3d_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + break; + + case RenderModeAttrib::M_point: + _d3d_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT); + break; + + default: + dxgsg9_cat.error() + << "Unknown render mode " << (int)mode << endl; + } + + // This might also specify the point size. + float point_size = attrib->get_thickness(); + _d3d_device->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&point_size)); + + if (attrib->get_perspective()) { + _d3d_device->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE); + + LVector3f height(0.0f, point_size, 1.0f); + height = height * _projection_mat; + float s = height[1] / point_size; + + float zero = 0.0f; + float one_over_s2 = 1.0f / (s * s); + _d3d_device->SetRenderState(D3DRS_POINTSCALE_A, *((DWORD*)&zero)); + _d3d_device->SetRenderState(D3DRS_POINTSCALE_B, *((DWORD*)&zero)); + _d3d_device->SetRenderState(D3DRS_POINTSCALE_C, *((DWORD*)&one_over_s2)); + + } else { + _d3d_device->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE); + } + + _current_fill_mode = mode; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_rescale_normal +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_rescale_normal() { + const RescaleNormalAttrib *attrib = _target._rescale_normal; + RescaleNormalAttrib::Mode mode = attrib->get_mode(); + + _auto_rescale_normal = false; + + switch (mode) { + case RescaleNormalAttrib::M_none: + _d3d_device->SetRenderState(D3DRS_NORMALIZENORMALS, false); + break; + + case RescaleNormalAttrib::M_rescale: + case RescaleNormalAttrib::M_normalize: + _d3d_device->SetRenderState(D3DRS_NORMALIZENORMALS, true); + break; + + case RescaleNormalAttrib::M_auto: + _auto_rescale_normal = true; + do_auto_rescale_normal(); + break; + + default: + dxgsg9_cat.error() + << "Unknown rescale_normal mode " << (int)mode << endl; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_depth_test +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_depth_test() { + const DepthTestAttrib *attrib = _target._depth_test; + DepthTestAttrib::PandaCompareFunc mode = attrib->get_mode(); + if (mode == DepthTestAttrib::M_none) { + _d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } else { + _d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + _d3d_device->SetRenderState(D3DRS_ZFUNC, (D3DCMPFUNC) mode); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_depth_write +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_depth_write() { + const DepthWriteAttrib *attrib = _target._depth_write; + if (attrib->get_mode() == DepthWriteAttrib::M_on) { + _d3d_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + } else { + _d3d_device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_cull_face +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_cull_face() { + const CullFaceAttrib *attrib = _target._cull_face; + _cull_face_mode = attrib->get_effective_mode(); + + switch (_cull_face_mode) { + case CullFaceAttrib::M_cull_none: + _d3d_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + break; + case CullFaceAttrib::M_cull_clockwise: + _d3d_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); + break; + case CullFaceAttrib::M_cull_counter_clockwise: + _d3d_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); + break; + default: + dxgsg9_cat.error() + << "invalid cull face mode " << (int)_cull_face_mode << endl; + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_fog +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_fog() { + const FogAttrib *attrib = _target._fog; + if (!attrib->is_off()) { + _d3d_device->SetRenderState(D3DRS_FOGENABLE, TRUE); + Fog *fog = attrib->get_fog(); + nassertv(fog != (Fog *)NULL); + apply_fog(fog); + } else { + _d3d_device->SetRenderState(D3DRS_FOGENABLE, FALSE); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_depth_offset +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_depth_offset() { + const DepthOffsetAttrib *attrib = _target._depth_offset; + int offset = attrib->get_offset(); + +/* ***** DX9 ??? D3DRS_ZBIAS NOT IN DX9 ??? RENAMED D3DRS_DEPTHBIAS ??? */ + _d3d_device->SetRenderState(D3DRS_DEPTHBIAS, offset); + +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_shade_model +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_shade_model() { + const ShadeModelAttrib *attrib = _target._shade_model; + switch (attrib->get_mode()) { + case ShadeModelAttrib::M_smooth: + _d3d_device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + break; + + case ShadeModelAttrib::M_flat: + _d3d_device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::set_state_and_transform +// Access: Public, Virtual +// Description: Simultaneously resets the render state and the +// transform state. +// +// This transform specified is the "external" net +// transform, expressed in the external coordinate +// space; internally, it will be pretransformed by +// get_cs_transform() to express it in the GSG's +// internal coordinate space. +// +// Special case: if (state==NULL), then the target +// state is already stored in _target. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +set_state_and_transform(const RenderState *target, + const TransformState *transform) { +#ifndef NDEBUG + if (gsg_cat.is_spam()) { + gsg_cat.spam() << "Setting GSG state to " << (void *)target << ":\n"; + target->write(gsg_cat.spam(false), 2); + } +#endif + _state_pcollector.add_level(1); + + if (transform != _external_transform) { + _state_pcollector.add_level(1); + _external_transform = transform; + _internal_transform = _cs_transform->compose(transform); + do_issue_transform(); + } + + if (target == _state_rs) { + return; + } + _target_rs = target; + _target.clear_to_defaults(); + target->store_into_slots(&_target); + _state_rs = 0; + + // There might be some physical limits to the actual target + // attributes we issue. Impose them now. + _target._texture = _target._texture->filter_to_max(_max_texture_stages); + + if (_target._alpha_test != _state._alpha_test) { + do_issue_alpha_test(); + _state._alpha_test = _target._alpha_test; + } + + if (_target._antialias != _state._antialias) { + // Antialias not implemented under DX8 + _state._antialias = _target._antialias; + } + + if (_target._clip_plane != _state._clip_plane) { + do_issue_clip_plane(); + _state._clip_plane = _target._clip_plane; + } + + if (_target._color != _state._color) { + do_issue_color(); + _state._color = _target._color; + } + + if (_target._color_scale != _state._color_scale) { + do_issue_color_scale(); + _state._color_scale = _target._color_scale; + } + + if (_target._cull_face != _state._cull_face) { + do_issue_cull_face(); + _state._cull_face = _target._cull_face; + } + + if (_target._depth_offset != _state._depth_offset) { + do_issue_depth_offset(); + _state._depth_offset = _target._depth_offset; + } + + if (_target._depth_test != _state._depth_test) { + do_issue_depth_test(); + _state._depth_test = _target._depth_test; + } + + if (_target._depth_write != _state._depth_write) { + do_issue_depth_write(); + _state._depth_write = _target._depth_write; + } + + if (_target._fog != _state._fog) { + do_issue_fog(); + _state._fog = _target._fog; + } + + if (_target._render_mode != _state._render_mode) { + do_issue_render_mode(); + _state._render_mode = _target._render_mode; + } + + if (_target._rescale_normal != _state._rescale_normal) { + do_issue_rescale_normal(); + _state._rescale_normal = _target._rescale_normal; + } + + if (_target._shade_model != _state._shade_model) { + do_issue_shade_model(); + _state._shade_model = _target._shade_model; + } + + // Shaders not implemented under DX8 + if (_target._shader != _state._shader) { + _state._shader = _target._shader; + } + + if (_target._tex_gen != _state._tex_gen) { + _state._texture = 0; + _state._tex_gen = _target._tex_gen; + } + + if (_target._tex_matrix != _state._tex_matrix) { + _state._tex_matrix = _target._tex_matrix; + } + + if ((_target._transparency != _state._transparency)|| + (_target._color_write != _state._color_write)|| + (_target._color_blend != _state._color_blend)) { + do_issue_blending(); + _state._transparency = _target._transparency; + _state._color_write = _target._color_write; + _state._color_blend = _target._color_blend; + } + + if (_target._texture != _state._texture) { + do_issue_texture(); + _state._texture = _target._texture; + } + + if (_target._material != _state._material) { + do_issue_material(); + _state._material = _target._material; + } + + if (_target._light != _state._light) { + do_issue_light(); + _state._light = _target._light; + } + + _state_rs = _target_rs; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::bind_light +// Access: Public, Virtual +// Description: Called the first time a particular light has been +// bound to a given id within a frame, this should set +// up the associated hardware light with the light's +// properties. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +bind_light(PointLight *light_obj, const NodePath &light, int light_id) { + // Get the light in "world coordinates". This means the light in + // the coordinate space of the camera, converted to DX's coordinate + // system. + CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path()); + const LMatrix4f &light_mat = transform->get_mat(); + LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); + LPoint3f pos = light_obj->get_point() * rel_mat; + + D3DCOLORVALUE black; + black.r = black.g = black.b = black.a = 0.0f; + D3DLIGHT9 alight; + alight.Type = D3DLIGHT_POINT; + alight.Diffuse = get_light_color(light_obj); + alight.Ambient = black ; + alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); + + // Position needs to specify x, y, z, and w + // w == 1 implies non-infinite position + alight.Position = *(D3DVECTOR *)pos.get_data(); + + alight.Range = __D3DLIGHT_RANGE_MAX; + alight.Falloff = 1.0f; + + const LVecBase3f &att = light_obj->get_attenuation(); + alight.Attenuation0 = att[0]; + alight.Attenuation1 = att[1]; + alight.Attenuation2 = att[2]; + + HRESULT hr = _d3d_device->SetLight(light_id, &alight); + if (FAILED(hr)) { + wdxdisplay9_cat.warning() + << "Could not set light properties for " << light + << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::bind_light +// Access: Public, Virtual +// Description: Called the first time a particular light has been +// bound to a given id within a frame, this should set +// up the associated hardware light with the light's +// properties. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) { + // Get the light in "world coordinates". This means the light in + // the coordinate space of the camera, converted to DX's coordinate + // system. + CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path()); + const LMatrix4f &light_mat = transform->get_mat(); + LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); + LVector3f dir = light_obj->get_direction() * rel_mat; + + D3DCOLORVALUE black; + black.r = black.g = black.b = black.a = 0.0f; + + D3DLIGHT9 alight; + ZeroMemory(&alight, sizeof(D3DLIGHT9)); + + alight.Type = D3DLIGHT_DIRECTIONAL; + alight.Diffuse = get_light_color(light_obj); + alight.Ambient = black ; + alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); + + alight.Direction = *(D3DVECTOR *)dir.get_data(); + + alight.Range = __D3DLIGHT_RANGE_MAX; + alight.Falloff = 1.0f; + + alight.Attenuation0 = 1.0f; // constant + alight.Attenuation1 = 0.0f; // linear + alight.Attenuation2 = 0.0f; // quadratic + + HRESULT hr = _d3d_device->SetLight(light_id, &alight); + if (FAILED(hr)) { + wdxdisplay9_cat.warning() + << "Could not set light properties for " << light + << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::bind_light +// Access: Public, Virtual +// Description: Called the first time a particular light has been +// bound to a given id within a frame, this should set +// up the associated hardware light with the light's +// properties. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { + Lens *lens = light_obj->get_lens(); + nassertv(lens != (Lens *)NULL); + + // Get the light in "world coordinates". This means the light in + // the coordinate space of the camera, converted to DX's coordinate + // system. + CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path()); + const LMatrix4f &light_mat = transform->get_mat(); + LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); + LPoint3f pos = lens->get_nodal_point() * rel_mat; + LVector3f dir = lens->get_view_vector() * rel_mat; + + D3DCOLORVALUE black; + black.r = black.g = black.b = black.a = 0.0f; + + D3DLIGHT9 alight; + ZeroMemory(&alight, sizeof(D3DLIGHT9)); + + alight.Type = D3DLIGHT_SPOT; + alight.Ambient = black ; + alight.Diffuse = get_light_color(light_obj); + alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); + + alight.Position = *(D3DVECTOR *)pos.get_data(); + + alight.Direction = *(D3DVECTOR *)dir.get_data(); + + alight.Range = __D3DLIGHT_RANGE_MAX; + alight.Falloff = 1.0f; + alight.Theta = 0.0f; + alight.Phi = deg_2_rad(lens->get_hfov()); + + const LVecBase3f &att = light_obj->get_attenuation(); + alight.Attenuation0 = att[0]; + alight.Attenuation1 = att[1]; + alight.Attenuation2 = att[2]; + + HRESULT hr = _d3d_device->SetLight(light_id, &alight); + if (FAILED(hr)) { + wdxdisplay9_cat.warning() + << "Could not set light properties for " << light + << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::get_index_type +// Access: Protected, Static +// Description: Maps from the Geom's internal numeric type symbols +// to DirectX's. +//////////////////////////////////////////////////////////////////// +D3DFORMAT DXGraphicsStateGuardian9:: +get_index_type(Geom::NumericType numeric_type) { + switch (numeric_type) { + case Geom::NT_uint16: + return D3DFMT_INDEX16; + + case Geom::NT_uint32: + return D3DFMT_INDEX32; + } + + dxgsg9_cat.error() + << "Invalid index NumericType value (" << (int)numeric_type << ")\n"; + return D3DFMT_INDEX16; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_material +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_material() { + static Material empty; + const Material *material; + if (_target._material == (MaterialAttrib *)NULL || + _target._material->is_off()) { + material = ∅ + } else { + material = _target._material->get_material(); + } + + D3DMATERIAL9 cur_material; + cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data()); + cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data()); + cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data()); + cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data()); + cur_material.Power = material->get_shininess(); + + if (material->has_diffuse()) { + // If the material specifies an diffuse color, use it. + _d3d_device->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + // Otherwise, the diffuse color comes from the object color. + if (_has_material_force_color) { + cur_material.Diffuse = *(D3DCOLORVALUE *)_material_force_color.get_data(); + _d3d_device->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + _d3d_device->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); + } + } + if (material->has_ambient()) { + // If the material specifies an ambient color, use it. + _d3d_device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + // Otherwise, the ambient color comes from the object color. + if (_has_material_force_color) { + cur_material.Ambient = *(D3DCOLORVALUE *)_material_force_color.get_data(); + _d3d_device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); + } else { + _d3d_device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1); + } + } + + if (material->has_specular()) { + _d3d_device->SetRenderState(D3DRS_SPECULARENABLE, TRUE); + } else { + _d3d_device->SetRenderState(D3DRS_SPECULARENABLE, FALSE); + } + + if (material->get_local()) { + _d3d_device->SetRenderState(D3DRS_LOCALVIEWER, TRUE); + } else { + _d3d_device->SetRenderState(D3DRS_LOCALVIEWER, FALSE); + } + + _d3d_device->SetMaterial(&cur_material); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_issue_texture +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_texture() { + DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1)); + + int num_stages = _target._texture->get_num_on_stages(); + int num_old_stages = _max_texture_stages; + if (_state._texture != (TextureAttrib *)NULL) { + num_old_stages = _state._texture->get_num_on_stages(); + } + + nassertv(num_stages <= _max_texture_stages && + num_old_stages <= _max_texture_stages); + + _texture_involves_color_scale = false; + + // We have to match up the texcoord stage index to the order written + // out by the DXGeomMunger. This means the texcoord names are + // written in the order they are referenced by the TextureAttrib, + // except that if a name is repeated its index number is reused from + // the first time. + typedef pmap UsedTexcoordIndex; + UsedTexcoordIndex used_texcoord_index; + + int i; + for (i = 0; i < num_stages; i++) { + TextureStage *stage = _target._texture->get_on_stage(i); + Texture *texture = _target._texture->get_on_texture(stage); + nassertv(texture != (Texture *)NULL); + + const InternalName *name = stage->get_texcoord_name(); + + // This pair of lines will get the next consecutive texcoord index + // number if this is the first time we have referenced this + // particular texcoord name; otherwise, it will return the same + // index number it returned before. + UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first; + int texcoord_index = (*ti).second; + + // We always reissue every stage in DX, just in case the texcoord + // index or texgen mode or some other property has changed. + TextureContext *tc = texture->prepare_now(_prepared_objects, this); + apply_texture(i, tc); + set_texture_blend_mode(i, stage); + + int texcoord_dimensions = 0; + + CPT(TransformState) tex_mat = TransformState::make_identity(); + if (_state._tex_matrix->has_stage(stage)) { + tex_mat = _state._tex_matrix->get_transform(stage); + } + + // Issue the texgen mode. + TexGenAttrib::Mode mode = _state._tex_gen->get_mode(stage); + bool any_point_sprite = false; + + switch (mode) { + case TexGenAttrib::M_off: + case TexGenAttrib::M_light_vector: + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index); + break; + + case TexGenAttrib::M_eye_sphere_map: + { + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, + texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR); + // This texture matrix, applied on top of the texcoord + // computed by D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR, + // approximates the effect produced by OpenGL's GL_SPHERE_MAP. + static CPT(TransformState) sphere_map = + TransformState::make_mat(LMatrix4f(0.33f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.33f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 1.0f)); + tex_mat = tex_mat->compose(sphere_map); + texcoord_dimensions = 3; + } + break; + + case TexGenAttrib::M_world_cube_map: + // To achieve world reflection vector, we must transform camera + // coordinates to world coordinates; i.e. apply the camera + // transform. In the case of a vector, we should not apply the + // pos component of the transform. + { + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, + texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR); + texcoord_dimensions = 3; + CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform); + tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero())); + } + break; + + case TexGenAttrib::M_eye_cube_map: + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, + texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR); + tex_mat = tex_mat->compose(_inv_cs_transform); + texcoord_dimensions = 3; + break; + + case TexGenAttrib::M_world_normal: + // To achieve world normal, we must transform camera coordinates + // to world coordinates; i.e. apply the camera transform. In + // the case of a normal, we should not apply the pos component + // of the transform. + { + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, + texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL); + texcoord_dimensions = 3; + CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform); + tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero())); + } + break; + + case TexGenAttrib::M_eye_normal: + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, + texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL); + texcoord_dimensions = 3; + tex_mat = tex_mat->compose(_inv_cs_transform); + break; + + case TexGenAttrib::M_world_position: + // To achieve world position, we must transform camera + // coordinates to world coordinates; i.e. apply the + // camera transform. + { + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, + texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION); + texcoord_dimensions = 3; + CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform); + tex_mat = tex_mat->compose(camera_transform); + } + break; + + case TexGenAttrib::M_eye_position: + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, + texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION); + texcoord_dimensions = 3; + tex_mat = tex_mat->compose(_inv_cs_transform); + break; + + case TexGenAttrib::M_point_sprite: + _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index); + any_point_sprite = true; + break; + } + + _d3d_device->SetRenderState(D3DRS_POINTSPRITEENABLE, any_point_sprite); + + if (!tex_mat->is_identity()) { + if (tex_mat->is_2d() && texcoord_dimensions <= 2) { + // For 2-d texture coordinates, we have to reorder the matrix. + LMatrix4f m = tex_mat->get_mat(); + m.set(m(0, 0), m(0, 1), m(0, 3), 0.0f, + m(1, 0), m(1, 1), m(1, 3), 0.0f, + m(3, 0), m(3, 1), m(3, 3), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data()); + _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_COUNT2); + } else { + LMatrix4f m = tex_mat->get_mat(); + _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data()); + DWORD transform_flags = texcoord_dimensions; + if (m.get_col(3) != LVecBase4f(0.0f, 0.0f, 0.0f, 1.0f)) { + // If we have a projected texture matrix, we also need to + // set D3DTTFF_COUNT4. + transform_flags = D3DTTFF_COUNT4 | D3DTTFF_PROJECTED; + } + _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS, + transform_flags); + } + + } else { + _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS, + D3DTTFF_DISABLE); + // For some reason, "disabling" texture coordinate transforms + // doesn't seem to be sufficient. We'll load an identity matrix + // to underscore the point. + _d3d_device->SetTransform(get_tex_mat_sym(i), &_d3d_ident_mat); + } + } + + // Disable the texture stages that are no longer used. + for (i = num_stages; i < num_old_stages; i++) { + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::enable_lighting +// Access: Protected, Virtual +// Description: Intended to be overridden by a derived class to +// enable or disable the use of lighting overall. This +// is called by issue_light() according to whether any +// lights are in use or not. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +enable_lighting(bool enable) { + _d3d_device->SetRenderState(D3DRS_LIGHTING, (DWORD)enable); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::set_ambient_light +// Access: Protected, Virtual +// Description: Intended to be overridden by a derived class to +// indicate the color of the ambient light that should +// be in effect. This is called by issue_light() after +// all other lights have been enabled or disabled. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +set_ambient_light(const Colorf &color) { + Colorf c = color; + c.set(c[0] * _light_color_scale[0], + c[1] * _light_color_scale[1], + c[2] * _light_color_scale[2], + c[3] * _light_color_scale[3]); + + _d3d_device->SetRenderState(D3DRS_AMBIENT, Colorf_to_D3DCOLOR(c)); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::enable_light +// Access: Protected, Virtual +// Description: Intended to be overridden by a derived class to +// enable the indicated light id. A specific Light will +// already have been bound to this id via bind_light(). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +enable_light(int light_id, bool enable) { + HRESULT hr = _d3d_device->LightEnable(light_id, enable); + + if (FAILED(hr)) { + wdxdisplay9_cat.warning() + << "Could not enable light " << light_id << ": " + << D3DERRORSTRING(hr) << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::enable_clip_plane +// Access: Protected, Virtual +// Description: Intended to be overridden by a derived class to +// enable the indicated clip_plane id. A specific +// PlaneNode will already have been bound to this id via +// bind_clip_plane(). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +enable_clip_plane(int plane_id, bool enable) { + if (enable) { + _clip_plane_bits |= ((DWORD)1 << plane_id); + } else { + _clip_plane_bits &= ~((DWORD)1 << plane_id); + } + _d3d_device->SetRenderState(D3DRS_CLIPPLANEENABLE, _clip_plane_bits); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::bind_clip_plane +// Access: Protected, Virtual +// Description: Called the first time a particular clip_plane has been +// bound to a given id within a frame, this should set +// up the associated hardware clip_plane with the clip_plane's +// properties. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +bind_clip_plane(const NodePath &plane, int plane_id) { + // Get the plane in "world coordinates". This means the plane in + // the coordinate space of the camera, converted to DX's coordinate + // system. + CPT(TransformState) transform = plane.get_transform(_scene_setup->get_camera_path()); + const LMatrix4f &plane_mat = transform->get_mat(); + LMatrix4f rel_mat = plane_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); + const PlaneNode *plane_node; + DCAST_INTO_V(plane_node, plane.node()); + Planef world_plane = plane_node->get_plane() * rel_mat; + + HRESULT hr = _d3d_device->SetClipPlane(plane_id, world_plane.get_data()); + if (FAILED(hr)) { + wdxdisplay9_cat.warning() + << "Could not set clip plane for " << plane + << " to id " << plane_id << ": " << D3DERRORSTRING(hr) << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::set_blend_mode +// Access: Protected, Virtual +// Description: Called after any of the things that might change +// blending state have changed, this function is +// responsible for setting the appropriate color +// blending mode based on the current properties. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_issue_blending() { + + // Handle the color_write attrib. If color_write is off, then + // all the other blending-related stuff doesn't matter. If the + // device doesn't support color-write, we use blending tricks + // to effectively disable color write. + if (_target._color_write->get_channels() == ColorWriteAttrib::C_off) { + if (_target._color_write != _state._color_write) { + if (_screen->_can_direct_disable_color_writes) { + _d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + _d3d_device->SetRenderState(D3DRS_COLORWRITEENABLE, (DWORD)0x0); + } else { + _d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + _d3d_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + _d3d_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + } + } + return; + } else { + if (_target._color_write != _state._color_write) { + if (_screen->_can_direct_disable_color_writes) { + _d3d_device->SetRenderState(D3DRS_COLORWRITEENABLE, _target._color_write->get_channels()); + } + } + } + + CPT(ColorBlendAttrib) color_blend = _target._color_blend; + ColorBlendAttrib::Mode color_blend_mode = _target._color_blend->get_mode(); + TransparencyAttrib::Mode transparency_mode = _target._transparency->get_mode(); + + // Is there a color blend set? + if (color_blend_mode != ColorBlendAttrib::M_none) { + _d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + switch (color_blend_mode) { + case ColorBlendAttrib::M_add: + _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + break; + + case ColorBlendAttrib::M_subtract: + _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT); + break; + + case ColorBlendAttrib::M_inv_subtract: + _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT); + break; + + case ColorBlendAttrib::M_min: + _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MIN); + break; + + case ColorBlendAttrib::M_max: + _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MAX); + break; + } + + _d3d_device->SetRenderState(D3DRS_SRCBLEND, + get_blend_func(color_blend->get_operand_a())); + _d3d_device->SetRenderState(D3DRS_DESTBLEND, + get_blend_func(color_blend->get_operand_b())); + return; + } + + // No color blend; is there a transparency set? + switch (transparency_mode) { + case TransparencyAttrib::M_none: + case TransparencyAttrib::M_binary: + break; + + case TransparencyAttrib::M_alpha: + case TransparencyAttrib::M_multisample: + case TransparencyAttrib::M_multisample_mask: + case TransparencyAttrib::M_dual: + _d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + _d3d_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + _d3d_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + return; + + default: + dxgsg9_cat.error() + << "invalid transparency mode " << (int)transparency_mode << endl; + break; + } + + // Nothing's set, so disable blending. + _d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::free_nondx_resources +// Access: Public +// Description: Frees some memory that was explicitly allocated +// within the dxgsg. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +free_nondx_resources() { +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::free_d3d_device +// Access: Public +// Description: setup for re-calling dx_init(), this is not the final +// exit cleanup routine (see dx_cleanup) +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +free_d3d_device() { + // dont want a full reset of gsg, just a state clear + _state_rs = 0; + _state.clear_to_zero(); + // want gsg to pass all state settings through + + _dx_is_ready = false; + + if (_d3d_device != NULL) + for(int i = 0;iSetTexture(i, NULL); // d3d should release this stuff internally anyway, but whatever + + release_all(); + + if (_d3d_device != NULL) + RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO); + + free_nondx_resources(); + + // obviously we dont release ID3D9, just ID3DDevice9 +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::set_draw_buffer +// Access: Protected +// Description: Sets up the glDrawBuffer to render into the buffer +// indicated by the RenderBuffer object. This only sets +// up the color bits; it does not affect the depth, +// stencil, accum layers. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +set_draw_buffer(const RenderBuffer &rb) { + dxgsg9_cat.fatal() << "DX set_draw_buffer unimplemented!!!"; + return; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::set_read_buffer +// Access: Protected +// Description: Vestigial analog of glReadBuffer +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +set_read_buffer(const RenderBuffer &rb) { + if (rb._buffer_type & RenderBuffer::T_front) { + _cur_read_pixel_buffer = RenderBuffer::T_front; + } else if (rb._buffer_type & RenderBuffer::T_back) { + _cur_read_pixel_buffer = RenderBuffer::T_back; + } else { + dxgsg9_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n"; + } + return; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::do_auto_rescale_normal +// Access: Protected +// Description: Issues the appropriate GL commands to either rescale +// or normalize the normals according to the current +// transform. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +do_auto_rescale_normal() { + if (_external_transform->has_identity_scale()) { + // If there's no scale, don't normalize anything. + _d3d_device->SetRenderState(D3DRS_NORMALIZENORMALS, false); + + } else { + // If there is a scale, turn on normalization. + _d3d_device->SetRenderState(D3DRS_NORMALIZENORMALS, true); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::get_light_color +// Access: Public +// Description: Returns the array of four floats that should be +// issued as the light's color, as scaled by the current +// value of _light_color_scale, in the case of +// color_scale_via_lighting. +//////////////////////////////////////////////////////////////////// +const D3DCOLORVALUE &DXGraphicsStateGuardian9:: +get_light_color(Light *light) const { + static Colorf c; + c = light->get_color(); + c.set(c[0] * _light_color_scale[0], + c[1] * _light_color_scale[1], + c[2] * _light_color_scale[2], + c[3] * _light_color_scale[3]); + return *(D3DCOLORVALUE *)c.get_data(); +} + //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian9::get_blend_func // Access: Protected, Static @@ -774,3249 +3050,512 @@ get_blend_func(ColorBlendAttrib::Operand operand) { void DXGraphicsStateGuardian9:: report_texmgr_stats() { -#if defined(DO_PSTATS)||defined(PRINT_RESOURCESTATS) +#ifdef DO_PSTATS HRESULT hr; + hr = 0; #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM - DWORD dwTexTotal,dwTexFree,dwVidTotal,dwVidFree; + DWORD dwTexTotal, dwTexFree, dwVidTotal, dwVidFree; -#ifndef PRINT_RESOURCESTATS - if (_total_texmem_pcollector.is_active()) -#endif - { - DDSCAPS2 ddsCaps; + if (_total_texmem_pcollector.is_active()) { + DDSCAPS2 ddsCaps; - ZeroMemory(&ddsCaps,sizeof(ddsCaps)); + ZeroMemory(&ddsCaps, sizeof(ddsCaps)); - ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; - if(FAILED( hr = _pD3DDevice->GetAvailableVidMem(&ddsCaps,&dwVidTotal,&dwVidFree))) { - dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << D3DERRORSTRING(hr); - exit(1); - } + ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwVidTotal, &dwVidFree))) { + dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << D3DERRORSTRING(hr); + throw_event("panda3d-render-error"); + return; + } - ddsCaps.dwCaps = DDSCAPS_TEXTURE; - if(FAILED( hr = _pD3DDevice->GetAvailableVidMem(&ddsCaps,&dwTexTotal,&dwTexFree))) { - dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << D3DERRORSTRING(hr); - exit(1); - } + ddsCaps.dwCaps = DDSCAPS_TEXTURE; + if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwTexTotal, &dwTexFree))) { + dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << D3DERRORSTRING(hr); + throw_event("panda3d-render-error"); + return; + } } -#endif +#endif // TEXMGRSTATS_USES_GETAVAILVIDMEM - IDirect3DQuery9 *pQuery = NULL; D3DDEVINFO_RESOURCEMANAGER all_resource_stats; - ZeroMemory(&all_resource_stats,sizeof(D3DDEVINFO_RESOURCEMANAGER)); + ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER)); - if(!bTexStatsRetrievalImpossible) { - hr = _pD3DDevice->CreateQuery(D3DQUERYTYPE_RESOURCEMANAGER, &pQuery); - if (hr == D3D_OK) { - hr = pQuery->Issue(D3DISSUE_END); - } - if (hr == D3D_OK) { - hr = pQuery->GetData((void*)&all_resource_stats,sizeof(D3DDEVINFO_RESOURCEMANAGER), 0); - } - if (hr!=D3D_OK) { - if (hr==S_FALSE) { - static int PrintedMsg=2; - if(PrintedMsg>0) { - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "Error: texstats GetInfo() requires debug DX DLLs to be installed!! ***********\n"; - ZeroMemory(&all_resource_stats,sizeof(D3DDEVINFO_RESOURCEMANAGER)); - bTexStatsRetrievalImpossible=true; +/* ***** DX9, GetInfo ( ) NOT IN DX9 */ +/* + if (!_tex_stats_retrieval_impossible) { + hr = _d3d_device->GetInfo(D3DDEVINFOID_RESOURCEMANAGER, &all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER)); + if (hr != D3D_OK) { + if (hr == S_FALSE) { + static int PrintedMsg = 2; + if (PrintedMsg>0) { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "texstats GetInfo() requires debug DX DLLs to be installed!!\n"; + } + ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER)); + _tex_stats_retrieval_impossible = true; } } else { dxgsg9_cat.error() << "GetInfo(RESOURCEMANAGER) failed to get tex stats: result = " << D3DERRORSTRING(hr); - bTexStatsRetrievalImpossible = true; return; } } } +*/ -#ifdef PRINT_RESOURCESTATS -#ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM - char tmpstr1[50],tmpstr2[50],tmpstr3[50],tmpstr4[50]; - sprintf(tmpstr1,"%.4g",dwVidTotal/1000000.0); - sprintf(tmpstr2,"%.4g",dwVidFree/1000000.0); - sprintf(tmpstr3,"%.4g",dwTexTotal/1000000.0); - sprintf(tmpstr4,"%.4g",dwTexFree/1000000.0); - dxgsg9_cat.debug() << "\nAvailableVidMem for RenderSurfs: (megs) total: " << tmpstr1 << " free: " << tmpstr2 - << "\nAvailableVidMem for Textures: (megs) total: " << tmpstr3 << " free: " << tmpstr4 << endl; -#endif - - #define REAL_D3DRTYPECOUNT ((UINT) D3DRTYPE_INDEXBUFFER) // d3d boneheads defined D3DRTYPECOUNT wrong - static char *ResourceNameStrs[REAL_D3DRTYPECOUNT]={"SURFACE","VOLUME","TEXTURE","VOLUME TEXTURE","CUBE TEXTURE","VERTEX BUFFER","INDEX BUFFER"}; - static bool bDoGetInfo[REAL_D3DRTYPECOUNT]={true,false,true,false,false,true,false}; // not using volume or cube textures yet - - if(!bTexStatsRetrievalImpossible) { - for(UINT r=0; r<(UINT)REAL_D3DRTYPECOUNT;r++) { - if(!bDoGetInfo[r]) - continue; - - D3DRESOURCESTATS *pRStats=&all_resource_stats.stats[r]; - if(pRStats->NumUsed>0) { - char hitrate_str[20]; - float fHitRate = (pRStats->NumUsedInVidMem * 100.0f) / pRStats->NumUsed; - sprintf(hitrate_str,"%.1f",fHitRate); - - dxgsg9_cat.spam() - << "\n***** Stats for " << ResourceNameStrs[r] << " ********" - << "\n HitRate:\t" << hitrate_str << "%" - << "\n bThrashing:\t" << pRStats->bThrashing - << "\n NumEvicts:\t" << pRStats->NumEvicts - << "\n NumVidCreates:\t" << pRStats->NumVidCreates - << "\n NumUsed:\t" << pRStats->NumUsed - << "\n NumUsedInVidMem:\t" << pRStats->NumUsedInVidMem - << "\n WorkingSet:\t" << pRStats->WorkingSet - << "\n WorkingSetBytes:\t" << pRStats->WorkingSetBytes - << "\n ApproxBytesDownloaded:\t" << pRStats->ApproxBytesDownloaded - << "\n TotalManaged:\t" << pRStats->TotalManaged - << "\n TotalBytes:\t" << pRStats->TotalBytes - << "\n LastPri:\t" << pRStats->LastPri << endl; - } else { - dxgsg9_cat.spam() - << "\n***** Stats for " << ResourceNameStrs[r] << " ********" - << "\n NumUsed: 0\n"; - } - } - - D3DDEVINFO_D3DVERTEXSTATS vtxstats; - ZeroMemory(&vtxstats,sizeof(D3DDEVINFO_D3DVERTEXSTATS)); - hr = _pD3DDevice->GetInfo(D3DDEVINFOID_VERTEXSTATS,&vtxstats,sizeof(D3DDEVINFO_D3DVERTEXSTATS)); - if (hr!=D3D_OK) { - dxgsg9_cat.error() << "GetInfo(D3DVERTEXSTATS) failed : result = " << D3DERRORSTRING(hr); - return; - } else { - dxgsg9_cat.spam() - << "\n***** Triangle Stats ********" - << "\n NumRenderedTriangles:\t" << vtxstats.NumRenderedTriangles - << "\n NumExtraClippingTriangles:\t" << vtxstats.NumExtraClippingTriangles << endl; - } - } -#endif - -#ifdef DO_PSTATS // Tell PStats about the state of the texture memory. if (_texmgrmem_total_pcollector.is_active()) { - // report zero if no debug dlls, to signal this info is invalid - _texmgrmem_total_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].TotalBytes); - _texmgrmem_resident_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].WorkingSetBytes); + // report zero if no debug dlls, to signal this info is invalid + _texmgrmem_total_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].TotalBytes); + _texmgrmem_resident_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].WorkingSetBytes); } #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM if (_total_texmem_pcollector.is_active()) { _total_texmem_pcollector.set_level(dwTexTotal); _used_texmem_pcollector.set_level(dwTexTotal - dwTexFree); } -#endif -#endif -#endif -} - -// generates slightly fewer instrs -#define add_DWORD_to_FVFBuf(data) { *((DWORD *)_pCurFvfBufPtr) = (DWORD) data; _pCurFvfBufPtr += sizeof(DWORD);} - -typedef enum { - FlatVerts,IndexedVerts,MixedFmtVerts -} GeomVertFormat; - - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_prim_setup -// Access: Private -// Description: This adds data to the flexible vertex format -//////////////////////////////////////////////////////////////////// -size_t DXGraphicsStateGuardian9:: -draw_prim_setup(const Geom *geom) { - // Set the flags for the flexible vertex format and compute the bytes - // required to store a single vertex. - // Assumes _perVertex,_perPrim,_perComp flags are setup prior to entry - // (especially for shademode). maybe should change this, since we usually - // get attr info anyway) - - #ifdef _DEBUG - assert(geom->get_binding(G_COORD) != G_OFF); - #endif - -#define GET_NEXT_VERTEX(NEXTVERT) { NEXTVERT = geom->get_next_vertex(vi); } -#define GET_NEXT_NORMAL() { p_normal = geom->get_next_normal(ni); } -#define GET_NEXT_TEXCOORD() { p_texcoord = geom->get_next_texcoord(ti); } - -#define GET_NEXT_COLOR() { \ - Colorf tempcolor = geom->get_next_color(ci); \ - if(!_color_scale_enabled) { \ - _curD3Dcolor = Colorf_to_D3DCOLOR(tempcolor); \ - } else { \ - transform_color(tempcolor,_curD3Dcolor); \ - }} - -//////// - - // this stuff should eventually replace the iterators below - PTA_Vertexf coords; - PTA_ushort vindexes; - - geom->get_coords(coords,vindexes); - if(vindexes!=NULL) { - _pCurCoordIndex = _coordindex_array = &vindexes[0]; - } else { - _pCurCoordIndex = _coordindex_array = NULL; - } - _pCurCoord = _coord_array = &coords[0]; - - /////////////// - - vi = geom->make_vertex_iterator(); - DWORD newFVFflags = D3DFVF_XYZ; - size_t vertex_size = sizeof(float) * 3; - - GeomBindType ColorBinding=geom->get_binding(G_COLOR); - bool bDoColor=(ColorBinding != G_OFF); - - if (bDoColor || _has_scene_graph_color) { - ci = geom->make_color_iterator(); - newFVFflags |= D3DFVF_DIFFUSE; - vertex_size += sizeof(D3DCOLOR); - - if (_has_scene_graph_color) { - if (_scene_graph_color_stale) { - // Compute the D3DCOLOR for the scene graph override color. - if(!_color_scale_enabled) { - _scene_graph_color_D3DCOLOR = Colorf_to_D3DCOLOR(_scene_graph_color); - } else { - transform_color(_scene_graph_color, _scene_graph_color_D3DCOLOR); - } - _scene_graph_color_stale = false; - } - _curD3Dcolor = _scene_graph_color_D3DCOLOR; // set primitive color if there is one. - - _perVertex &= ~PER_COLOR; - _perPrim &= ~PER_COLOR; - _perComp &= ~PER_COLOR; - } else if(ColorBinding == G_OVERALL){ - GET_NEXT_COLOR(); - _perVertex &= ~PER_COLOR; - _perPrim &= ~PER_COLOR; - _perComp &= ~PER_COLOR; - } - } - if (geom->get_binding(G_NORMAL) != G_OFF) { - ni = geom->make_normal_iterator(); - newFVFflags |= D3DFVF_NORMAL; - vertex_size += sizeof(float) * 3; - - if (geom->get_binding(G_NORMAL) == G_OVERALL) - p_normal = geom->get_next_normal(ni); // set overall normal if there is one - } - - - GeomBindType TexCoordBinding; - PTA_TexCoordf texcoords; - PTA_ushort tindexes; - geom->get_texcoords(texcoords,TexCoordBinding,tindexes); - if (TexCoordBinding != G_OFF) { - assert(TexCoordBinding == G_PER_VERTEX); - - // used by faster path - if(tindexes!=NULL) { - _pCurTexCoordIndex = _texcoordindex_array = &tindexes[0]; - } else { - _pCurTexCoordIndex = _texcoordindex_array = NULL; - } - _pCurTexCoord = _texcoord_array = &texcoords[0]; - ////// - - ti = geom->make_texcoord_iterator(); - newFVFflags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); - vertex_size += sizeof(float) * 2; - } - - // If we have per-vertex colors or normals, we need smooth shading. - // Otherwise we want flat shading for performance reasons. - - // Note on fogging: - // the fogging expression should really be || (_fog_enabled && (_doFogType==PerVertexFog)) - // instead of just || (_fog_enabled), since GOURAUD shading should not be required for PerPixel - // fog, but the problem is some cards (Riva128,Matrox G200) emulate pixel fog with table fog - // but dont force the shading mode to gouraud internally, so you end up with flat-shaded fog colors - // (note, TNT does the right thing tho). So I guess we must do gouraud shading for all fog rendering for now - // note that if _doFogType==None, _fog_enabled will always be false - - bool need_gouraud_shading = ((_perVertex & (PER_COLOR | (wants_normals() ? PER_NORMAL : 0))) || _fog_enabled); - - enable_gouraud_shading(need_gouraud_shading); - set_vertex_format(newFVFflags); - - return vertex_size; +#endif // TEXMGRSTATS_USES_GETAVAILVIDMEM +#endif // DO_PSTATS } //////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_prim_inner_loop -// Access: Private -// Description: This adds data to the flexible vertex format with a check -// for component normals and color -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_prim_inner_loop(int nVerts, const Geom *geom, ushort perFlags) { - Vertexf NextVert; - - for(;nVerts > 0;nVerts--) { - // coord info will always be _perVertex - GET_NEXT_VERTEX(NextVert); // need to optimize these - add_to_FVFBuf((void *)&NextVert, 3*sizeof(float)); - - if(perFlags==(ushort)TexCoordOnly) { - // break out the common case (for animated chars) 1st - GET_NEXT_TEXCOORD(); - } else { - switch (DrawLoopFlags(perFlags)) { - case Color_TexCoord: - GET_NEXT_TEXCOORD(); - case ColorOnly: - GET_NEXT_COLOR(); - break; - case Normal_Color: - GET_NEXT_COLOR(); - case NormalOnly: - GET_NEXT_NORMAL(); - break; - case Normal_Color_TexCoord: - GET_NEXT_COLOR(); - case Normal_TexCoord: - GET_NEXT_NORMAL(); - // case TexCoordOnly: - GET_NEXT_TEXCOORD(); - break; - } - } - - if (_CurFVFType & D3DFVF_NORMAL) - add_to_FVFBuf((void *)&p_normal, 3*sizeof(float)); - if (_CurFVFType & D3DFVF_DIFFUSE) - add_DWORD_to_FVFBuf(_curD3Dcolor); - if (_CurFVFType & D3DFVF_TEXCOUNT_MASK) - add_to_FVFBuf((void *)&p_texcoord, sizeof(TexCoordf)); - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_prim_inner_loop_coordtexonly -// Access: Private -// Description: FastPath loop used by animated character data -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_prim_inner_loop_coordtexonly(int nVerts, const Geom *geom) { - // assumes coord and texcoord data is per-vertex, - // color is not per-vert/component (which would require fetching new vals in the vertex loop), - // and no normal data. this should be common situation for animated character data - // inc'ing local ptrs instead of member ones, seems to optimize better - // bypass all the slow vertex iterator stuff - - #ifdef _DEBUG - { - assert(geom->get_binding(G_NORMAL) == G_OFF); - GeomBindType ColorBinding = geom->get_binding(G_COLOR); - assert((ColorBinding != G_PER_VERTEX) || (ColorBinding != G_PER_COMPONENT)); - assert(geom->get_binding(G_TEXCOORD) == G_PER_VERTEX); - } - #endif - - Vertexf *pCurCoord = _pCurCoord; - ushort *pCurCoordIndex = _pCurCoordIndex; - TexCoordf *pCurTexCoord = _pCurTexCoord; - ushort *pCurTexCoordIndex = _pCurTexCoordIndex; - - BYTE *pLocalFvfBufPtr = _pCurFvfBufPtr; - DWORD cur_color = _curD3Dcolor; - bool bDoIndexedTexCoords = (_texcoordindex_array != NULL); - bool bDoIndexedCoords = (_coordindex_array != NULL); - - for(;nVerts>0;nVerts--) { - if(bDoIndexedCoords) { - memcpy(pLocalFvfBufPtr,(void*)&_coord_array[*pCurCoordIndex],3*sizeof(float)); - pCurCoordIndex++; - } else { - memcpy(pLocalFvfBufPtr,(void*)pCurCoord,3*sizeof(float)); - pCurCoord++; - } - - pLocalFvfBufPtr+=3*sizeof(float); - - *((DWORD *)pLocalFvfBufPtr) = cur_color; - pLocalFvfBufPtr += sizeof(DWORD); - - if(bDoIndexedTexCoords) { - memcpy(pLocalFvfBufPtr,(void*)&_texcoord_array[*pCurTexCoordIndex],sizeof(TexCoordf)); - pCurTexCoordIndex++; - } else { - memcpy(pLocalFvfBufPtr,(void*)pCurTexCoord,sizeof(TexCoordf)); - pCurTexCoord++; - } - pLocalFvfBufPtr+=sizeof(TexCoordf); - } - - _pCurFvfBufPtr=pLocalFvfBufPtr; - _pCurCoord = pCurCoord; - _pCurCoordIndex = pCurCoordIndex; - _pCurTexCoord = pCurTexCoord; - _pCurTexCoordIndex = pCurTexCoordIndex; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_point -// Access: Public, Virtual +// Function: DXGraphicsStateGuardian9::set_context +// Access: Protected // Description: //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: -draw_point(GeomPoint *geom, GeomContext *gc) { - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_point()" << endl; -#endif - - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices())); - - // The DX Way - - int nPrims = geom->get_num_prims(); - - if (nPrims==0) { - dxgsg9_cat.warning() << "draw_point() called with ZERO vertices!!" << endl; - return; - } - - //#ifdef _DEBUG - // static bool bPrintedMsg=false; - // - // if (!bPrintedMsg && (geom->get_size()!=1.0f)) { - // bPrintedMsg=true; - // dxgsg9_cat.warning() << "D3D does not support drawing points of non-unit size, setting point size to 1.0f!\n"; - // } - //#endif - - nassertv(nPrims < PANDA_MAXNUMVERTS ); - - PTA_Vertexf coords; - PTA_Normalf norms; - PTA_Colorf colors; - PTA_TexCoordf texcoords; - GeomBindType bind; - PTA_ushort vindexes,nindexes,tindexes,cindexes; - - geom->get_coords(coords,vindexes); - geom->get_normals(norms,bind,nindexes); - geom->get_colors(colors,bind,cindexes); - geom->get_texcoords(texcoords,bind,tindexes); - - // for Indexed Prims and mixed indexed/non-indexed prims, we will use old pipeline for now - // need to add code to handle fully indexed mode (and handle cases with index arrays of different lengths, - // values (may only be possible to handle certain cases without reverting to old pipeline) - - _perVertex = 0x0; - _perPrim = 0; - if (geom->get_binding(G_NORMAL) == G_PER_VERTEX) _perVertex |= PER_NORMAL; - if (geom->get_binding(G_COLOR) == G_PER_VERTEX) _perVertex |= PER_COLOR; - - size_t vertex_size = draw_prim_setup(geom); - - nassertv(_pCurFvfBufPtr == NULL); // make sure the storage pointer is clean. - nassertv(nPrims * vertex_size < VERT_BUFFER_SIZE); - _pCurFvfBufPtr = _pFvfBufBasePtr; // _pCurFvfBufPtr changes, _pFvfBufBasePtr doesn't - - // iterate through the point - draw_prim_inner_loop(nPrims, geom, _perVertex | _perPrim); - - HRESULT hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_POINTLIST, nPrims, _pFvfBufBasePtr, vertex_size); - TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nPrims,0); - - _pCurFvfBufPtr = NULL; +set_context(DXScreenData *new_context) { + nassertv(new_context != NULL); + _screen = new_context; + _d3d_device = _screen->_d3d_device; //copy this one field for speed of deref + _swap_chain = _screen->_swap_chain; //copy this one field for speed of deref } +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::set_render_target +// Access: Protected +// Description: Set render target to the backbuffer of current swap +// chain. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +set_render_target() { + LPDIRECT3DSURFACE9 back = NULL, stencil = NULL; + + UINT swap_chain; + + /* ***** DX9 swap_chain ??? */ + swap_chain = 0; + + if (!_swap_chain) //maybe fullscreen mode or main/single window + _d3d_device->GetBackBuffer(swap_chain, 0, D3DBACKBUFFER_TYPE_MONO, &back); + else + _swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &back); + + //wdxdisplay9_cat.debug() << "swapchain is " << _swap_chain << "\n"; + //wdxdisplay9_cat.debug() << "back buffer is " << back << "\n"; + + _d3d_device->GetDepthStencilSurface(&stencil); + +// _d3d_device->SetRenderTarget(back, stencil); + DWORD render_target_index; + render_target_index = 0; + _d3d_device->SetRenderTarget(render_target_index, back); + + if (back) { + back->Release(); + } + if (stencil) { + stencil->Release(); + } +} //////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_line -// Access: Public, Virtual +// Function: DXGraphicsStateGuardian9::set_texture_blend_mode +// Access: Protected // Description: //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: -draw_line(GeomLine* geom, GeomContext *gc) { - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_line()" << endl; -#endif - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices())); - - //#ifdef _DEBUG - // static bool bPrintedMsg=false; - // - // // note: need to implement approximation of non-1.0 width lines with quads - // - // if (!bPrintedMsg && (geom->get_width()!=1.0f)) { - // bPrintedMsg=true; - // if(dxgsg9_cat.is_debug()) - // dxgsg9_cat.debug() << "DX does not support drawing lines with a non-1.0f pixel width, setting width to 1.0f!\n"; - // } - //#endif - - int nPrims = geom->get_num_prims(); - - if (nPrims==0) { - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "draw_line() called with ZERO vertices!!" << endl; - return; - } - - _perVertex = 0x0; - _perPrim = 0x0; - _perComp = 0x0; - - switch(geom->get_binding(G_COLOR)) { - case G_PER_VERTEX: - _perVertex |= PER_COLOR; - break; - case G_PER_COMPONENT: - _perComp |= PER_COLOR; - break; - default: - _perPrim |= PER_COLOR; - } - - switch(geom->get_binding(G_NORMAL)) { - case G_PER_VERTEX: - _perVertex |= PER_NORMAL; - break; - case G_PER_COMPONENT: - _perComp |= PER_NORMAL; - break; - default: - _perPrim |= PER_NORMAL; - } - - size_t vertex_size = draw_prim_setup(geom); - - BYTE *_tmp_fvfOverrunBuf = NULL; - nassertv(_pCurFvfBufPtr == NULL); // make sure the storage pointer is clean. -// nassertv(nPrims * 2 * vertex_size < VERT_BUFFER_SIZE); - - if (nPrims * 2 * vertex_size > VERT_BUFFER_SIZE) { - // bugbug: need cleaner way to handle tmp buffer size overruns (malloc/realloc?) - _pCurFvfBufPtr = _tmp_fvfOverrunBuf = new BYTE[nPrims * 2 * vertex_size]; - } else _pCurFvfBufPtr = _pFvfBufBasePtr; // _pCurFvfBufPtr changes, _pFvfBufBasePtr doesn't - - for (int i = 0; i < nPrims; i++) { - if (_perPrim & PER_COLOR) { - GET_NEXT_COLOR(); - } - if (_perPrim & PER_NORMAL) - p_normal = geom->get_next_normal(ni); // set primitive normal if there is one. - draw_prim_inner_loop(2, geom, _perVertex); - } - - HRESULT hr; - - DWORD nVerts = nPrims<<1; - - if (_tmp_fvfOverrunBuf == NULL) { - nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr)); - hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, nPrims, _pFvfBufBasePtr, vertex_size); - } else { - nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_tmp_fvfOverrunBuf)); - hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, nPrims, _tmp_fvfOverrunBuf, vertex_size); - delete [] _tmp_fvfOverrunBuf; - } - TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,0); - - _pCurFvfBufPtr = NULL; -} - -void DXGraphicsStateGuardian9:: -draw_linestrip(GeomLinestrip* geom, GeomContext *gc) { - - //#ifdef _DEBUG - // static BOOL bPrintedMsg=false; - // - // if (!bPrintedMsg && (geom->get_width()!=1.0f)) { - // bPrintedMsg=true; - // dxgsg9_cat.warning() << "DX does not support drawing lines with a non-1.0f pixel width, setting width to 1.0f!\n"; - // } - //#endif - - draw_linestrip_base(geom,gc,false); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_linestrip -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_linestrip_base(Geom* geom, GeomContext *gc, bool bConnectEnds) { -// Note draw_linestrip_base() may be called from non-line draw_fns to support wireframe mode - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_linestrip()" << endl; -#endif - - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices())); - - int nPrims = geom->get_num_prims(); - const int *pLengthArr = geom->get_lengths(); - - if(nPrims==0) { - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "draw_linestrip() called with ZERO vertices!!" << endl; - return; - } - - _perVertex = 0x0; - _perPrim = 0x0; - _perComp = 0x0; - - switch(geom->get_binding(G_COLOR)) { - case G_PER_VERTEX: - _perVertex |= PER_COLOR; - break; - case G_PER_COMPONENT: - _perComp |= PER_COLOR; - break; - default: - _perPrim |= PER_COLOR; - } - - switch(geom->get_binding(G_NORMAL)) { - case G_PER_VERTEX: - _perVertex |= PER_NORMAL; - break; - case G_PER_COMPONENT: - _perComp |= PER_NORMAL; - break; - default: - _perPrim |= PER_NORMAL; - } - - size_t vertex_size = draw_prim_setup(geom); - ushort perFlags = _perVertex | _perComp; - - bool bPerPrimColor = ((_perPrim & PER_COLOR)!=0); - bool bPerPrimNormal = ((_perPrim & PER_NORMAL)!=0); - - DWORD nVerts; - - if(pLengthArr==NULL) // we've been called by draw_quad, which has no lengths array - nVerts=4; - - for (int i = 0; i < nPrims; i++) { - if (bPerPrimColor) { - GET_NEXT_COLOR(); - } - - if (bPerPrimNormal) { - p_normal = geom->get_next_normal(ni); // set primitive normal if there is one. - } - - if(pLengthArr!=NULL) { - nVerts= *(pLengthArr++); - nassertv(nVerts >= 2); - } - - nassertv(_pCurFvfBufPtr == NULL); // make sure the storage pointer is clean. - nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE); - _pCurFvfBufPtr = _pFvfBufBasePtr; // _pCurFvfBufPtr changes, _pFvfBufBasePtr doesn't - - draw_prim_inner_loop(nVerts, geom, perFlags); - - if(bConnectEnds) { - // append first vertex to end - memcpy(_pCurFvfBufPtr,_pFvfBufBasePtr,vertex_size); - _pCurFvfBufPtr+=vertex_size; - nVerts++; - } - - nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr)); - - HRESULT hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, nVerts-1, _pFvfBufBasePtr, vertex_size); - TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,0); - - _pCurFvfBufPtr = NULL; - } -} - -// this class exists because an alpha sort is necessary for correct -// sprite rendering, and we can't simply sort the vertex arrays as -// each vertex may or may not have corresponding information in the -// x/y texel-world-ratio and rotation arrays. -typedef struct { - Vertexf _v; - D3DCOLOR _c; - float _x_ratio; - float _y_ratio; - float _theta; -} WrappedSprite; - -class WrappedSpriteSortPtr { -public: - float z; - WrappedSprite *pSpr; -}; - -// this struct exists because the STL can sort faster than i can. -struct draw_sprite_vertex_less { - INLINE bool operator ()(const WrappedSpriteSortPtr& v0, - const WrappedSpriteSortPtr& v1) const { - return v0.z > v1.z; // reversed from gl due to left-handed coordsys of d3d - } -}; - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_sprite -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_sprite(GeomSprite *geom, GeomContext *gc) { - - // this is a little bit of a mess, but it's ok. Here's the deal: - // we want to draw, and draw quickly, an arbitrarily large number - // of sprites all facing the screen. Performing the billboard math - // for ~1000 sprites is way too slow. Ideally, we want one - // matrix transformation that will handle everything, and this is - // just about what ends up happening. We're getting the front-facing - // effect by setting up a new frustum (of the same z-depth as the - // current one) that is very small in x and y. This way regularly - // rendered triangles that might not be EXACTLY facing the camera - // will certainly look close enough. Then, we transform to camera-space - // by hand and apply the inverse frustum to the transformed point. - // For some cracked out reason, this actually works. - - - // Note: for DX9, try to use the PointSprite primitive instead of doing all the stuff below - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_sprite()" << endl; -#endif - // get the array traversal set up. - int nPrims = geom->get_num_prims(); - - if (nPrims==0) { - return; - } - - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - - DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(nPrims)); - - D3DMATRIX OldD3DWorldMatrix; - _pD3DDevice->GetTransform(D3DTS_WORLD, &OldD3DWorldMatrix); - - bool bReEnableDither=false; - - _pD3DDevice->GetTransform(D3DTS_WORLD, &OldD3DWorldMatrix); - - Geom::VertexIterator vi = geom->make_vertex_iterator(); - Geom::ColorIterator ci = geom->make_color_iterator(); - - // note although sprite particles technically dont require a texture, - // the texture dimensions are used to initialize the size calculations - // the code in spriteParticleRenderer.cxx does not handle the no-texture case now - - float tex_xsize = 1.0f; - float tex_ysize = 1.0f; - - Texture *tex = geom->get_texture(); - if(tex !=NULL) { - // set up the texture-rendering state - modify_state(RenderState::make(TextureAttrib::make(tex))); - tex_xsize = tex->get_x_size(); - tex_ysize = tex->get_y_size(); - } - - // save the modelview matrix - const LMatrix4f &modelview_mat = _internal_transform->get_mat(); - - // We don't need to mess with the aspect ratio, since we are now - // using the default projection matrix, which has the right aspect - // ratio built in. - - // null the world xform, so sprites are orthog to scrn - _pD3DDevice->SetTransform(D3DTS_WORLD, &matIdentity); - // only need to change _WORLD xform, _VIEW xform is Identity - - // precomputation stuff - float tex_left = geom->get_ll_uv()[0]; - float tex_right = geom->get_ur_uv()[0]; - float tex_bottom = geom->get_ll_uv()[1]; - float tex_top = geom->get_ur_uv()[1]; - - float half_width = 0.5f * tex_xsize * fabs(tex_right - tex_left); - float half_height = 0.5f * tex_ysize * fabs(tex_top - tex_bottom); - float scaled_width, scaled_height; - - // the user can override alpha sorting if they want - bool alpha = false; - - if (!geom->get_alpha_disable()) { - // figure out if alpha's enabled (if not, no reason to sort) - const TransparencyAttrib *trans = _state->get_transparency(); - if (trans != (const TransparencyAttrib *)NULL) { - alpha = (trans->get_mode() != TransparencyAttrib::M_none); - } - } - - // inner loop vars - int i; - Vertexf source_vert, cameraspace_vert; - float *x_walk, *y_walk, *theta_walk; - float theta; - - nassertv(geom->get_x_bind_type() != G_PER_VERTEX); - nassertv(geom->get_y_bind_type() != G_PER_VERTEX); - - // set up the non-built-in bindings - bool x_overall = (geom->get_x_bind_type() == G_OVERALL); - bool y_overall = (geom->get_y_bind_type() == G_OVERALL); - bool theta_overall = (geom->get_theta_bind_type() == G_OVERALL); - bool color_overall = (geom->get_binding(G_COLOR) == G_OVERALL); - bool theta_on = !(geom->get_theta_bind_type() == G_OFF); - - // x direction - if (x_overall) - scaled_width = geom->_x_texel_ratio[0] * half_width; - else { - nassertv(((int)geom->_x_texel_ratio.size() >= geom->get_num_prims())); - x_walk = &geom->_x_texel_ratio[0]; - } - - // y direction - if (y_overall) - scaled_height = geom->_y_texel_ratio[0] * half_height; - else { - nassertv(((int)geom->_y_texel_ratio.size() >= geom->get_num_prims())); - y_walk = &geom->_y_texel_ratio[0]; - } - - // theta - if (theta_on) { - if (theta_overall) - theta = geom->_theta[0]; - else { - nassertv(((int)geom->_theta.size() >= geom->get_num_prims())); - theta_walk = &geom->_theta[0]; - } - } - - ///////////////////////////////////////////////////////////////////// - // INNER LOOP PART 1 STARTS HERE - // Here we transform each point to cameraspace and fill our sort - // vector with the final geometric information. - ///////////////////////////////////////////////////////////////////// - - Colorf v_color; - - // sort container and iterator - pvector< WrappedSpriteSortPtr > sorted_sprite_vector; - pvector< WrappedSpriteSortPtr >::iterator sorted_vec_iter; - - WrappedSprite *SpriteArray = new WrappedSprite[nPrims]; - - //BUGBUG: could we use _fvfbuf for this to avoid perframe alloc? - // alternately, alloc once when retained mode becomes available - - if (SpriteArray==NULL) { - dxgsg9_cat.fatal() << "draw_sprite() out of memory!!" << endl; - return; - } - - // the state is set, start running the prims - - WrappedSprite *pSpr; - - for (pSpr=SpriteArray,i = 0; i < nPrims; i++,pSpr++) { - - source_vert = geom->get_next_vertex(vi); - cameraspace_vert = source_vert * modelview_mat; - - pSpr->_v.set(cameraspace_vert[0],cameraspace_vert[1],cameraspace_vert[2]); - - if (!color_overall) { - GET_NEXT_COLOR(); - pSpr->_c = _curD3Dcolor; - } - if (!x_overall) - pSpr->_x_ratio = *x_walk++; - if (!y_overall) - pSpr->_y_ratio = *y_walk++; // go along array of ratio values stored in geom - if (theta_on && (!theta_overall)) - pSpr->_theta = *theta_walk++; - } - - if (alpha) { - sorted_sprite_vector.reserve(nPrims); //pre-alloc space for nPrims - - for (pSpr=SpriteArray,i = 0; i < nPrims; i++,pSpr++) { // build STL-sortable array - WrappedSpriteSortPtr ws_ptr; - ws_ptr.z=pSpr->_v[2]; - ws_ptr.pSpr=pSpr; - sorted_sprite_vector.push_back(ws_ptr); - } - - // sort the verts properly by alpha (if necessary). Of course, - // the sort is only local, not scene-global, so if you look closely you'll - // notice that alphas may be screwy. It's ok though, because this is fast. - // if you want accuracy, use billboards and take the speed hit. - - sort(sorted_sprite_vector.begin(), sorted_sprite_vector.end(), draw_sprite_vertex_less()); - sorted_vec_iter = sorted_sprite_vector.begin(); - - // disabling dither for alpha particle-systems. - // ATI sez: most applications ignore the fact that since alpha blended primitives - // combine the data in the frame buffer with the data in the current pixel, pixels - // can be dithered multiple times and accentuate the dither pattern. This is particularly - // true in particle systems which rely on the cumulative visual effect of many overlapping - // alpha blended primitives. - - if(_dither_enabled) { - bReEnableDither=true; - enable_dither(false); - } - } - - Vertexf ul, ur, ll, lr; - - //////////////////////////////////////////////////////////////////////////// - // INNER LOOP PART 2 STARTS HERE - // Now we run through the cameraspace vector and compute the geometry for each - // tristrip. This includes scaling as per the ratio arrays, as well as - // rotating in the z. - //////////////////////////////////////////////////////////////////////////// - - D3DCOLOR CurColor; - DWORD FVFType = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) | D3DFVF_DIFFUSE; - DWORD vertex_size = sizeof(float) * 2 + sizeof(float) * 3 + sizeof(D3DCOLOR); - - if (color_overall) { - GET_NEXT_COLOR(); - CurColor = _curD3Dcolor; - } - - // see note on fog and gouraud-shading in draw_prim_setup - bool bUseGouraudShadedColor=_fog_enabled; - enable_gouraud_shading(_fog_enabled); - set_vertex_format(FVFType); - - #ifdef _DEBUG - nassertv(_pCurFvfBufPtr == NULL); // make sure the storage pointer is clean. - nassertv(nPrims * 4 * vertex_size < VERT_BUFFER_SIZE); - nassertv(nPrims * 6 < PANDA_MAXNUMVERTS ); - #endif - - _pCurFvfBufPtr = _pFvfBufBasePtr; // _pCurFvfBufPtr changes, _pFvfBufBasePtr doesn't - - const float TexCrdSets[4][2] = { - { tex_left, tex_bottom }, - { tex_right, tex_bottom }, - { tex_left, tex_top }, - { tex_right, tex_top } - }; - -#define QUADVERTLISTLEN 6 - - DWORD QuadVertIndexList[QUADVERTLISTLEN] = { 0, 1, 2, 3, 2, 1}; - DWORD CurDPIndexArrLength=0,CurVertCount=0; - - for (pSpr=SpriteArray,i = 0; i < nPrims; i++,pSpr++) { // build STL-sortable array - - if (alpha) { - pSpr = sorted_vec_iter->pSpr; - sorted_vec_iter++; - } - - // if not G_OVERALL, calculate the scale factors //huh?? - if (!x_overall) - scaled_width = pSpr->_x_ratio * half_width; - - if (!y_overall) - scaled_height = pSpr->_y_ratio * half_height; - - // if not G_OVERALL, do some trig for this z rotate //what is the theta angle?? - if (theta_on) { - if (!theta_overall) - theta = pSpr->_theta; - - // create the rotated points. BUGBUG: this matmult will be slow if we dont get inlining - // rotate_mat calls sin() on an unbounded val, possible to make it faster with lookup table (modulate to 0-360 range?) - - LMatrix3f xform_mat = LMatrix3f::rotate_mat(theta) * - LMatrix3f::scale_mat(scaled_width, scaled_height); - - ur = (LVector3f( 1.0f, 1.0f, 0.0f) * xform_mat) + pSpr->_v; - ul = (LVector3f(-1.0f, 1.0f, 0.0f) * xform_mat) + pSpr->_v; - lr = (LVector3f( 1.0f, -1.0f, 0.0f) * xform_mat) + pSpr->_v; - ll = (LVector3f(-1.0f, -1.0f, 0.0f) * xform_mat) + pSpr->_v; - } else { - // create points for unrotated rect sprites - float x,y,negx,negy,z; - - x = pSpr->_v[0] + scaled_width; - y = pSpr->_v[1] + scaled_height; - negx = pSpr->_v[0] - scaled_width; - negy = pSpr->_v[1] - scaled_height; - z = pSpr->_v[2]; - - ur.set(x, y, z); - ul.set(negx, y, z); - lr.set(x, negy, z); - ll.set(negx, negy, z); - } - - // can no longer assume flat-shaded (because of vtx fog), so always copy full color in there - - /********* LL vertex **********/ - - add_to_FVFBuf((void *)ll.get_data(), 3*sizeof(float)); - if (!color_overall) // otherwise its already been set globally - CurColor = pSpr->_c; - add_DWORD_to_FVFBuf(CurColor); // only need to cpy color on 1st vert, others are just empty ignored space - add_to_FVFBuf((void *)TexCrdSets[0], sizeof(float)*2); - - /********* LR vertex **********/ - - add_to_FVFBuf((void *)lr.get_data(), 3*sizeof(float)); - - // if flat shading, dont need to write color for middle vtx, just incr ptr - if(bUseGouraudShadedColor) - *((DWORD *)_pCurFvfBufPtr) = (DWORD) CurColor; - _pCurFvfBufPtr += sizeof(D3DCOLOR); - - add_to_FVFBuf((void *)TexCrdSets[1], sizeof(float)*2); - - /********* UL vertex **********/ - - add_to_FVFBuf((void *)ul.get_data(), 3*sizeof(float)); - // if flat shading, dont need to write color for middle vtx, just incr ptr - if(bUseGouraudShadedColor) - *((DWORD *)_pCurFvfBufPtr) = (DWORD) CurColor; - _pCurFvfBufPtr += sizeof(D3DCOLOR); - add_to_FVFBuf((void *)TexCrdSets[2], sizeof(float)*2); - - /********* UR vertex **********/ - - add_to_FVFBuf((void *)ur.get_data(), 3*sizeof(float)); - add_DWORD_to_FVFBuf(CurColor); - add_to_FVFBuf((void *)TexCrdSets[3], sizeof(float)*2); - - for (int ii=0;iiDrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, // start index in array - nVerts, numTris, - _index_buf, D3DFMT_INDEX16, - _pFvfBufBasePtr, vertex_size); - TestDrawPrimFailure(DrawIndexedPrim,hr,_pD3DDevice,QUADVERTLISTLEN*nPrims,numTris); - - _pCurFvfBufPtr = NULL; - delete [] SpriteArray; - - // restore the matrices - _pD3DDevice->SetTransform(D3DTS_WORLD, - (D3DMATRIX*)modelview_mat.get_data()); - - if(bReEnableDither) - enable_dither(true); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_polygon -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_polygon(GeomPolygon *geom, GeomContext *gc) { - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_polygon()" << endl; -#endif - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices())); - - // wireframe polygon will be drawn as linestrip, otherwise draw as multi-tri trifan - DWORD rstate; - _pD3DDevice->GetRenderState(D3DRS_FILLMODE, &rstate); - if(rstate==D3DFILL_WIREFRAME) { - draw_linestrip_base(geom,gc,true); - } else { - draw_multitri(geom, D3DPT_TRIANGLEFAN); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_quad -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_quad(GeomQuad *geom, GeomContext *gc) { - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_quad()" << endl; -#endif - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices())); - - // wireframe quad will be drawn as linestrip, otherwise draw as multi-tri trifan - DWORD rstate; - _pD3DDevice->GetRenderState(D3DRS_FILLMODE, &rstate); - if(rstate==D3DFILL_WIREFRAME) { - draw_linestrip_base(geom,gc,true); - } else { - draw_multitri(geom, D3DPT_TRIANGLEFAN); - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_tri -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_tri(GeomTri *geom, GeomContext *gc) { -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_tri()" << endl; -#endif - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_tri_pcollector.add_level(geom->get_num_vertices())); - -#if 0 - if (_pCurTexContext!=NULL) { - dxgsg9_cat.spam() << "Cur active DX texture: " << _pCurTexContext->_tex->get_name() << "\n"; - } -#endif - -#ifdef COUNT_DRAWPRIMS - cGeomcount++; -#endif - - DWORD nPrims = geom->get_num_prims(); - HRESULT hr; - - PTA_Vertexf coords; - PTA_Normalf norms; - PTA_Colorf colors; - PTA_TexCoordf texcoords; - GeomBindType TexCoordBinding,ColorBinding,NormalBinding; - PTA_ushort vindexes,nindexes,tindexes,cindexes; - - geom->get_coords(coords,vindexes); - geom->get_normals(norms,NormalBinding,nindexes); - geom->get_colors(colors,ColorBinding,cindexes); - geom->get_texcoords(texcoords,TexCoordBinding,tindexes); - - // this is the old geom setup, it reformats every vtx into an output array passed to d3d - - _perVertex = 0x0; - _perPrim = 0x0; - - bool bUseTexCoordOnlyLoop = ((ColorBinding != G_PER_VERTEX) && - (NormalBinding == G_OFF) && - (TexCoordBinding != G_OFF)); - - bool bPerPrimNormal; - - bool bPerPrimColor=(ColorBinding == G_PER_PRIM); - if(bPerPrimColor) - _perPrim = PER_COLOR; - else if(ColorBinding == G_PER_VERTEX) - _perVertex = PER_COLOR; - - if(bUseTexCoordOnlyLoop) { - _perVertex |= PER_TEXCOORD; // TexCoords are either G_OFF or G_PER_VERTEX - } else { - if(NormalBinding == G_PER_VERTEX) - _perVertex |= PER_NORMAL; - else if(NormalBinding == G_PER_PRIM) - _perPrim |= PER_NORMAL; - - bPerPrimNormal=((_perPrim & PER_NORMAL)!=0); - - if(TexCoordBinding == G_PER_VERTEX) - _perVertex |= PER_TEXCOORD; - } - - size_t vertex_size = draw_prim_setup(geom); - - // Note: draw_prim_setup could unset color flags if global color is set, so must - // recheck this flag here! - bPerPrimColor=(_perPrim & PER_COLOR)!=0x0; - -#ifdef _DEBUG - // is it Ok not to recompute bUseTexCoordOnlyLoop even if draw_prim_setup unsets color flags? - // add this check to make sure - bool bNewUseTexCoordOnlyLoop = (((_perVertex & PER_COLOR)==0x0) && - ((_CurFVFType & D3DFVF_NORMAL)==0x0) && - ((_CurFVFType & D3DFVF_TEX1)!=0x0)); - if(bUseTexCoordOnlyLoop && (!bNewUseTexCoordOnlyLoop)) { - // ok for bUseTexCoordOnlyLoop to be false, and bNew to be true. - // draw_prim_setup can sometimes turn off the _perComp color for - // G_OVERALL and scene-graph-color cases, which causes bNew to be true, - // while the original bUseTexCoordOnly is still false. - // the case we want to prevent is accidently using the texcoordloop - // instead of the general one, using the general one should always work. - - DebugBreak(); - assert(0); - } -#endif - - nassertv(_pCurFvfBufPtr == NULL); // make sure the storage pointer is clean. - nassertv(nPrims * 3 * vertex_size < VERT_BUFFER_SIZE); - _pCurFvfBufPtr = _pFvfBufBasePtr; // _pCurFvfBufPtr changes, _pFvfBufBasePtr doesn't - - // iterate through the triangle primitive - - for (uint i = 0; i < nPrims; i++) { - if(bPerPrimColor) { // remember color might be G_OVERALL too! - GET_NEXT_COLOR(); - } - - if(bUseTexCoordOnlyLoop) { - draw_prim_inner_loop_coordtexonly(3, geom); - } else { - if(bPerPrimNormal) - p_normal = geom->get_next_normal(ni); // set primitive normal if there is one. - - draw_prim_inner_loop(3, geom, _perVertex); - } - } - - DWORD nVerts=nPrims*3; - - nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr)); - - hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, nPrims, _pFvfBufBasePtr, vertex_size); - TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,nPrims); - - _pCurFvfBufPtr = NULL; - - - /////////////////////////// -#if 0 - // test triangle for me to dbg experiments only - float vert_buf[15] = { - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 33.0, 0.0f, 0.0f, 0.0f, 2.0, - 0.0f, 0.0f, 33.0, 2.0, 0.0f - }; - - _pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_BORDER); - _pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_BORDER); - _pD3DDevice->SetTextureStageState(0,D3DTSS_BORDERCOLOR,MY_D3DRGBA(0,0,0,0)); - - DWORD FVFType = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) ; - set_vertex_format(FVFType); - HRESULT hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, vert_buf, 1, 5*sizeof(float)); - TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,3,1); -#endif - -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_tristrip -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_tristrip(GeomTristrip *geom, GeomContext *gc) { - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_tristrip()" << endl; -#endif - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_tristrip_pcollector.add_level(geom->get_num_vertices())); - - draw_multitri(geom, D3DPT_TRIANGLESTRIP); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_trifan -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_trifan(GeomTrifan *geom, GeomContext *gc) { - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() << "draw_trifan()" << endl; -#endif - DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); - DO_PSTATS_STUFF(_vertices_trifan_pcollector.add_level(geom->get_num_vertices())); - - draw_multitri(geom, D3DPT_TRIANGLEFAN); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::draw_multitri -// Access: Public, Virtual -// Description: handles trifans and tristrips -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -draw_multitri(Geom *geom, D3DPRIMITIVETYPE trilisttype) { - - DWORD nPrims = geom->get_num_prims(); - const uint *pLengthArr = (const uint *) ((const int *)geom->get_lengths()); - HRESULT hr; - - if(nPrims==0) { - #ifdef _DEBUG - dxgsg9_cat.warning() << "draw_multitri() called with ZERO vertices!!" << endl; - #endif - return; - } - -#ifdef COUNT_DRAWPRIMS - cGeomcount++; -#endif - - PTA_Vertexf coords; - PTA_Normalf norms; - PTA_Colorf colors; - PTA_TexCoordf texcoords; - GeomBindType TexCoordBinding,ColorBinding,NormalBinding; - PTA_ushort vindexes,nindexes,tindexes,cindexes; - - geom->get_coords(coords,vindexes); - geom->get_normals(norms,NormalBinding,nindexes); - geom->get_colors(colors,ColorBinding,cindexes); - geom->get_texcoords(texcoords,TexCoordBinding,tindexes); - +set_texture_blend_mode(int i, const TextureStage *stage) { + switch (stage->get_mode()) { + case TextureStage::M_modulate: + // emulates GL_MODULATE glTexEnv mode + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_MODULATE); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + break; + + case TextureStage::M_decal: + // emulates GL_DECAL glTexEnv mode + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT); + + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_CURRENT); + break; + + case TextureStage::M_replace: + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); + + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + break; + + case TextureStage::M_add: + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_ADD); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT); + + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + break; + + case TextureStage::M_blend: + case TextureStage::M_blend_color_scale: { - // this is the old geom setup, it reformats every vtx into an output array passed to d3d - _perVertex = 0x0; - _perPrim = 0x0; - _perComp = 0x0; + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_LERP); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG0, D3DTA_TEXTURE); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT); + _d3d_device->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TFACTOR); - bool bIsTriList=(trilisttype==D3DPT_TRIANGLESTRIP); - bool bPerPrimColor=(ColorBinding == G_PER_PRIM); - bool bPerPrimNormal; - bool bUseTexCoordOnlyLoop = (((ColorBinding == G_OVERALL) || bPerPrimColor) && - (NormalBinding == G_OFF) && - (TexCoordBinding != G_OFF)); - - if(bUseTexCoordOnlyLoop) { - if(bPerPrimColor) { - _perPrim = PER_COLOR; - } - } else { - switch (ColorBinding) { - case G_PER_PRIM: - _perPrim = PER_COLOR; - break; - case G_PER_COMPONENT: - _perComp = PER_COLOR; - break; - case G_PER_VERTEX: - _perVertex = PER_COLOR; - break; - } - - switch (NormalBinding) { - case G_PER_VERTEX: - _perVertex |= PER_NORMAL; - break; - case G_PER_PRIM: - _perPrim |= PER_NORMAL; - break; - case G_PER_COMPONENT: - _perComp |= PER_NORMAL; - break; - } - - bPerPrimNormal=((_perPrim & PER_NORMAL)!=0); - - if (TexCoordBinding == G_PER_VERTEX) - _perVertex |= PER_TEXCOORD; - } - - size_t vertex_size = draw_prim_setup(geom); - - // Note: draw_prim_setup could unset color flags if global color is set, so must - // recheck this flag here! - bPerPrimColor=(_perPrim & PER_COLOR)!=0; - - #ifdef _DEBUG - // is it Ok not to recompute bUseTexCoordOnlyLoop even if draw_prim_setup unsets color flags? - // add this check to make sure. texcoordonly needs input that with unchanging color, except per-prim - bool bNewUseTexCoordOnlyLoop = ((((_perComp|_perVertex) & PER_COLOR)==0x0) && - ((_CurFVFType & D3DFVF_NORMAL)==0x0) && - ((_CurFVFType & D3DFVF_TEX1)!=0x0)); - - if(bUseTexCoordOnlyLoop && (!bNewUseTexCoordOnlyLoop)) { - // ok for bUseTexCoordOnlyLoop to be false, and bNew to be true. - // draw_prim_setup can sometimes turn off the _perComp color for - // G_OVERALL and scene-graph-color cases, which causes bNew to be true, - // while the original bUseTexCoordOnly is still false. - // the case we want to prevent is accidently using the texcoordloop - // instead of the general one, using the general one should always work. - - DebugBreak(); - assert(0); - } - - #endif - - // iterate through the triangle primitives - - int nVerts; - if(pLengthArr==NULL) { - // we've been called by draw_quad, which has no lengths array - nVerts=4; - } - - for (uint i = 0; i < nPrims; i++) { - - if(pLengthArr!=NULL) { - nVerts = *(pLengthArr++); - } - - if(bPerPrimColor) { // remember color might be G_OVERALL too! - GET_NEXT_COLOR(); - } - -#ifdef _DEBUG - nassertv(nVerts >= 3); - nassertv(_pCurFvfBufPtr == NULL); // make sure the storage pointer is clean. - nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE); -#endif - _pCurFvfBufPtr = _pFvfBufBasePtr; // _pCurFvfBufPtr changes, _pFvfBufBasePtr doesn't - - if(_perComp==0x0) { - if(bUseTexCoordOnlyLoop) { - draw_prim_inner_loop_coordtexonly(nVerts, geom); - } else { - if (bPerPrimNormal) - p_normal = geom->get_next_normal(ni); // set primitive normal if there is one. - - draw_prim_inner_loop(nVerts, geom, _perVertex); - } - } else { - if(bPerPrimNormal) - p_normal = geom->get_next_normal(ni); // set primitive normal if there is one. - - if(bIsTriList) { - // in flat shade mode, D3D strips color using the 1st vertex. - // (note: differs from OGL, which always uses last vtx for strips&fans - - // Store all but last 2 verts - draw_prim_inner_loop(nVerts-2, geom, _perVertex | _perComp); - - // _perComp attribs should not be fetched for last 2 verts - draw_prim_inner_loop(2, geom, _perVertex); - } else { - // in flat shade mode, D3D fans color using the 2nd vertex. - // (note: differs from OGL, which always uses last vtx for strips&fans - // _perComp attribs should not be fetched for first & last verts, they will - // be associated with middle n-2 verts - - draw_prim_inner_loop(1, geom, _perVertex); - draw_prim_inner_loop(nVerts-2, geom, _perVertex | _perComp); - draw_prim_inner_loop(1, geom, _perVertex); - } - } - - assert((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr)); - DWORD numTris=nVerts-2; - - hr = _pD3DDevice->DrawPrimitiveUP(trilisttype, numTris, _pFvfBufBasePtr, vertex_size); - TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,numTris); - - _pCurFvfBufPtr = NULL; - } + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + _d3d_device->SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT); } - -} - -//----------------------------------------------------------------------------- -// Name: GenerateSphere() -// Desc: Makes vertex and index data for ellipsoid w/scaling factors sx,sy,sz -// tries to match gluSphere behavior -//----------------------------------------------------------------------------- - -// probably want to replace this with D3DX9 call - -void DXGraphicsStateGuardian9:: -GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize, - void *pIndexSpace,DWORD dwIndexSpaceByteSize, - D3DXVECTOR3 *pCenter, float fRadius, - DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz, - DWORD *pNumVertices,DWORD *pNumTris,DWORD fvfFlags,DWORD dwVertSize) { - float x, y, z, rsintheta; - D3DXVECTOR3 vPoint; - -//#define DBG_GENSPHERE -#define M_PI 3.1415926f // probably should get this from mathNumbers.h instead - - nassertv(wNumRings>=2 && wNumSections>=2); - wNumRings--; // wNumRings indicates number of vertex rings (not tri-rings). - // gluSphere 'stacks' arg for 1 vert ring is 2, so convert to our '1'. - wNumSections++; // to make us equiv to gluSphere - - //Figure out needed space for the triangles and vertices. - DWORD dwNumVertices,dwNumIndices,dwNumTriangles; - -#define DO_SPHERE_TEXTURING (fvfFlags & D3DFVF_TEXCOUNT_MASK) -#define DO_SPHERE_NORMAL (fvfFlags & D3DFVF_NORMAL) -#define DO_SPHERE_COLOR (fvfFlags & D3DFVF_DIFFUSE) - - if (DO_SPHERE_TEXTURING) { - // if texturing, we need full rings of identical position verts at poles to hold diff texture coords - wNumRings+=2; - dwNumVertices = *pNumVertices = wNumRings * wNumSections; - dwNumTriangles = (wNumRings-1) * wNumSections * 2; - } else { - dwNumVertices = *pNumVertices = wNumRings * wNumSections + 2; - dwNumTriangles = wNumRings*wNumSections*2; - } - - dwNumIndices = dwNumTriangles*3; - *pNumTris = dwNumTriangles; - -// D3DVERTEX* pvVertices = (D3DVERTEX*) pVertexSpace; - WORD *pwIndices = (WORD *) pIndexSpace; - - nassertv(dwNumVertices*dwVertSize < VERT_BUFFER_SIZE); - nassertv(dwNumIndices < PANDA_MAXNUMVERTS ); - - // Generate vertex at the top point - D3DXVECTOR3 vTopPoint = *pCenter; - D3DXVECTOR3 vBotPoint = *pCenter; - float yRadius=sy*fRadius; - vTopPoint.y+=yRadius; - vBotPoint.y-=yRadius; - D3DXVECTOR3 vNormal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f); - float texCoords[2]; - - nassertv(pVertexSpace==_pCurFvfBufPtr); // add_to_FVFBuf requires this - -#define ADD_GENSPHERE_VERTEX_TO_BUFFER(VERT) \ - add_to_FVFBuf((void *)&(VERT), 3*sizeof(float)); \ - if(fvfFlags & D3DFVF_NORMAL) \ - add_to_FVFBuf((void *)&vNormal, 3*sizeof(float)); \ - if(fvfFlags & D3DFVF_DIFFUSE) \ - add_DWORD_to_FVFBuf(_curD3Dcolor); \ - if(fvfFlags & D3DFVF_TEXCOUNT_MASK) \ - add_to_FVFBuf((void *)texCoords, sizeof(TexCoordf)); - -#ifdef DBG_GENSPHERE - int nvs_written=0; - memset(pVertexSpace,0xFF,dwNumVertices*dwVertSize); -#endif - - if (! DO_SPHERE_TEXTURING) { - ADD_GENSPHERE_VERTEX_TO_BUFFER(vTopPoint); -#ifdef DBG_GENSPHERE - nvs_written++; -#endif - } - - // Generate vertex points for rings - float inv_radius = 1.0f/fRadius; - const float reciprocal_PI=1.0f/M_PI; - const float reciprocal_2PI=1.0f/(2.0*M_PI); - DWORD i; - float theta,dtheta; - - if (DO_SPHERE_TEXTURING) { - // numRings already includes 1st and last rings for this case - dtheta = (float)(M_PI / (wNumRings-1)); //Angle between each ring (ignore 2 fake rings) - theta = 0.0f; - } else { - dtheta = (float)(M_PI / (wNumRings + 1)); //Angle between each ring - theta = dtheta; - } - float phi,dphi = (float)(2*M_PI / (wNumSections-1)); //Angle between each section - - for (i = 0; i < wNumRings; i++) { - float costheta,sintheta,cosphi,sinphi; - phi = 0.0f; - - if (DO_SPHERE_TEXTURING) { - texCoords[1] = theta * reciprocal_PI; // v is the same for each ring - } - - // could optimize all this sin/cos stuff w/tables - csincos(theta,&sintheta,&costheta); - y = fRadius * costheta; // y is the same for each ring - - rsintheta = fRadius * sintheta; - - for (DWORD j = 0; j < wNumSections; j++) { - csincos(phi,&sinphi,&cosphi); - x = rsintheta * sinphi; - z = rsintheta * cosphi; - -#ifdef DBG_GENSPHERE - nvs_written++; -#endif - vPoint.x = pCenter->x + sx*x; - vPoint.y = pCenter->y + sy*y; - vPoint.z = pCenter->z + sz*z; - - add_to_FVFBuf((void *)&vPoint, 3*sizeof(float)); - - if (DO_SPHERE_NORMAL) { - // bugbug: this is wrong normal for the non-spherical case (i think you need to multiply by 1/scale factor per component) - D3DXVECTOR3 vVec = D3DXVECTOR3( x*inv_radius, y*inv_radius, z*inv_radius ); - D3DXVec3Normalize(&vNormal,&vVec); - add_to_FVFBuf((float *)&vNormal, 3*sizeof(float)); - } - - if (DO_SPHERE_COLOR) - add_DWORD_to_FVFBuf(_curD3Dcolor); - - if (DO_SPHERE_TEXTURING) { - texCoords[0] = 1.0f - phi*reciprocal_2PI; - add_to_FVFBuf((void *)texCoords, sizeof(TexCoordf)); - } - - phi += dphi; - } - theta += dtheta; - } - - if (! DO_SPHERE_TEXTURING) { - // Generate bottom vertex - vNormal = D3DXVECTOR3( 0.0f, -1.0f, 0.0f ); - ADD_GENSPHERE_VERTEX_TO_BUFFER(vBotPoint); -#ifdef DBG_GENSPHERE - nvs_written++; -#endif - } - -#ifdef DBG_GENSPHERE - assert(nvs_written == dwNumVertices); -#endif - - -#ifdef DBG_GENSPHERE - memset(pwIndices,0xFF,dwNumIndices*sizeof(WORD)); -#endif - - // inited for textured case - DWORD cur_vertring_startidx=0; // first vertex in current ring - DWORD CurFinalTriIndex = 0; // index of next tri to be written - - if (! DO_SPHERE_TEXTURING) { - // Generate caps using unique the bot/top vert - // for non-textured case, could render the caps as indexed trifans, - // but should be no perf difference b/w indexed trilists and indexed trifans - // and this has advantage of being aggregable into 1 big DPrim call for whole sphere - - for (i = 0; i < wNumSections; i++) { - DWORD TopCapTriIndex=3*i; - DWORD BotCapTriIndex=3*(dwNumTriangles - wNumSections + i); - DWORD i_incd = ((i + 1) % wNumSections); - - pwIndices[TopCapTriIndex++] = 0; - pwIndices[TopCapTriIndex++] = i + 1; - pwIndices[TopCapTriIndex] = i_incd + 1; - - pwIndices[BotCapTriIndex++] = (WORD)( dwNumVertices - 1 ); - pwIndices[BotCapTriIndex++] = (WORD)( dwNumVertices - 2 - i ); - pwIndices[BotCapTriIndex] = (WORD)( dwNumVertices - 2 - i_incd); - } - - cur_vertring_startidx = 1; // first vertex in current ring (skip top vert) - CurFinalTriIndex = wNumSections; // index of tri to be written, wNumSections to skip the top cap row - } - - DWORD j_incd,base_index; - - // technically we could break into a strip for every row (or 1 big strip connected w/degenerate tris) - // but indexed trilists should actually be just as fast on HW - - // Generate triangles for the rings - for (i = 0; i < wNumRings-1; i++) { - for (DWORD j = 0; j < wNumSections; j++) { - - base_index=3*CurFinalTriIndex; // final vert index is 3*finaltriindex - j_incd=(j+1) % wNumSections; - - DWORD v1_row1_idx,v2_row1_idx,v1_row2_idx,v2_row2_idx; - - v1_row1_idx = cur_vertring_startidx + j; - v2_row1_idx = cur_vertring_startidx + j_incd; - v1_row2_idx = v1_row1_idx + wNumSections; - v2_row2_idx = v2_row1_idx + wNumSections; - -#ifdef DBG_GENSPHERE - assert(v2_row2_idxget_num_vertices())); - - int nprims = geom->get_num_prims(); - - if (nprims==0) { - dxgsg9_cat.warning() << "draw_sphere() called with ZERO vertices!!" << endl; - return; - } - - Geom::VertexIterator vi = geom->make_vertex_iterator(); - Geom::ColorIterator ci; - bool bPerPrimColor = (geom->get_binding(G_COLOR) == G_PER_PRIM); - if (bPerPrimColor) - ci = geom->make_color_iterator(); - - for (int i = 0; i < nprims; i++) { - - DWORD nVerts,nTris; - Vertexf center = geom->get_next_vertex(vi); - Vertexf edge = geom->get_next_vertex(vi); - LVector3f v = edge - center; - float fRadius = sqrt(dot(v, v)); - - size_t vertex_size = draw_prim_setup(geom); - - _pCurFvfBufPtr = _pFvfBufBasePtr; - - if (bPerPrimColor) { - GET_NEXT_COLOR(); - } - - GenerateSphere(_pCurFvfBufPtr, VERT_BUFFER_SIZE, - _index_buf, PANDA_MAXNUMVERTS*2, - (D3DXVECTOR3 *)¢er, fRadius, - SPHERE_NUMSTACKS, SPHERE_NUMSLICES, - 1.0f, 1.0f, 1.0f, // no scaling factors, do a sphere not ellipsoid - &nVerts,&nTris,_CurFVFType,vertex_size); - - // possible optimization: make DP 1 for all spheres call here, since trilist is independent tris. - // indexes couldnt start w/0 tho, need to pass offset to gensph - HRESULT hr = _pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, // start index in array - nVerts, nTris, _index_buf, D3DFMT_INDEX16, - _pFvfBufBasePtr, vertex_size); - TestDrawPrimFailure(DrawIndexedPrim,hr,_pD3DDevice,nVerts,nTris); - } - - _pCurFvfBufPtr = NULL; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::prepare_texture -// Access: Public, Virtual -// Description: Creates a new retained-mode representation of the -// given texture, and returns a newly-allocated -// TextureContext pointer to reference it. It is the -// responsibility of the calling function to later -// call release_texture() with this same pointer (which -// will also delete the pointer). -//////////////////////////////////////////////////////////////////// -TextureContext *DXGraphicsStateGuardian9:: -prepare_texture(Texture *tex) { - DXTextureContext9 *dtc = new DXTextureContext9(tex); - if (dtc->CreateTexture(*_pScrn) == NULL) { - delete dtc; - return NULL; - } - return dtc; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::apply_texture -// Access: Public -// Description: Makes the texture the currently available texture for -// rendering. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -apply_texture(TextureContext *tc, int index) { - if (tc==NULL) { - // The texture wasn't bound properly or something, so ensure - // texturing is disabled and just return. - enable_texturing(false); - return; - } - -#ifdef DO_PSTATS - add_to_texture_record(tc); -#endif - - // Note: if this code changes, make sure to change initialization - // SetTSS code in dx_init as well so DX TSS renderstate matches - // dxgsg state - - DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); - - int dirty = dtc->get_dirty_flags(); - - if (dirty) { - // If the texture image has changed, or if its use of mipmaps has - // changed, we need to re-create the image. Ignore other types of - // changes, which arent significant for dx - - if((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) { - // If this is *only* because of a mipmap change, issue a - // warning--it is likely that this change is the result of an - // error or oversight. - if ((dirty & Texture::DF_image) == 0) { - dxgsg9_cat.warning() - << "Texture " << *dtc->_texture << " has changed mipmap state.\n"; - } - - dtc->DeleteTexture(); - if (dtc->CreateTexture(*_pScrn) == NULL) { - - // Oops, we can't re-create the texture for some reason. - dxgsg9_cat.error() << "Unable to re-create texture " << *dtc->_texture << endl; - - enable_texturing(false); - return; - } - } - dtc->clear_dirty_flags(); - } else { - if(_pCurTexContext == dtc) { - enable_texturing(true); - return; - } - } - - Texture *tex = tc->_texture; - Texture::WrapMode wrapU,wrapV; - wrapU=tex->get_wrap_u(); - wrapV=tex->get_wrap_v(); - - if (wrapU!=_CurTexWrapModeU) { - _pD3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSU,get_texture_wrap_mode(wrapU)); - _CurTexWrapModeU = wrapU; - } - if (wrapV!=_CurTexWrapModeV) { - _pD3DDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,get_texture_wrap_mode(wrapV)); - _CurTexWrapModeV = wrapV; - } - - uint aniso_degree=tex->get_anisotropic_degree(); - Texture::FilterType ft=tex->get_magfilter(); - - if(_CurTexAnisoDegree != aniso_degree) { - _pD3DDevice->SetSamplerState(0,D3DSAMP_MAXANISOTROPY,aniso_degree); - _CurTexAnisoDegree = aniso_degree; - } - - D3DTEXTUREFILTERTYPE newMagFilter; - if (aniso_degree<=1) { - newMagFilter=((ft!=Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT); - -#ifdef _DEBUG - if((ft!=Texture::FT_linear)&&(ft!=Texture::FT_nearest)) { - dxgsg9_cat.error() << "MipMap filter type setting for texture magfilter makes no sense, texture: " << tex->get_name() << "\n"; - } -#endif - } else { - newMagFilter=D3DTEXF_ANISOTROPIC; - } - - if(_CurTexMagFilter!=newMagFilter) { - _CurTexMagFilter=newMagFilter; - _pD3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, newMagFilter); - } - -#ifdef _DEBUG - assert(Texture::FT_linear_mipmap_linear < 8); -#endif - /* - enum FilterType { - FT_nearest,FT_linear,FT_nearest_mipmap_nearest,FT_linear_mipmap_nearest, - FT_nearest_mipmap_linear, FT_linear_mipmap_linear, }; - */ - // map Panda composite min+mip filter types to d3d's separate min & mip filter types - static D3DTEXTUREFILTERTYPE PandaToD3DMinType[8] = - {D3DTEXF_POINT,D3DTEXF_LINEAR,D3DTEXF_POINT,D3DTEXF_LINEAR,D3DTEXF_POINT,D3DTEXF_LINEAR}; - static D3DTEXTUREFILTERTYPE PandaToD3DMipType[8] = - {D3DTEXF_NONE,D3DTEXF_NONE,D3DTEXF_POINT,D3DTEXF_POINT,D3DTEXF_LINEAR,D3DTEXF_LINEAR}; - - ft=tex->get_minfilter(); - -#ifdef _DEBUG - if(ft > Texture::FT_linear_mipmap_linear) { - dxgsg9_cat.error() << "Unknown tex filter type for tex: " << tex->get_name() << " filter: "<<(DWORD)ft<<"\n"; - return; - } -#endif - - D3DTEXTUREFILTERTYPE newMipFilter = PandaToD3DMipType[(DWORD)ft]; - - if (!tex->might_have_ram_image()) { - // If the texture is completely dynamic, don't try to issue - // mipmaps--pandadx doesn't support auto-generated mipmaps at this - // point. - newMipFilter = D3DTEXF_NONE; - } - -#ifndef NDEBUG - // sanity check - extern char *PandaFilterNameStrs[]; - if((!(dtc->_bHasMipMaps))&&(newMipFilter!=D3DTEXF_NONE)) { - dxgsg9_cat.error() << "Trying to set mipmap filtering for texture with no generated mipmaps!! texname[" << tex->get_name() << "], filter("<=2) { - newMinFilter=D3DTEXF_ANISOTROPIC; - } - - if(newMinFilter!=_CurTexMinFilter) { - _CurTexMinFilter = newMinFilter; - _pD3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, newMinFilter); - } - - if(newMipFilter!=_CurTexMipFilter) { - _CurTexMipFilter = newMipFilter; - _pD3DDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, newMipFilter); - } - - // bugbug: does this handle the case of untextured geometry? - // we dont see this bug cause we never mix textured/untextured - _pD3DDevice->SetTexture(index, dtc->_pD3DTexture9); - -#if 0 - if (dtc!=NULL) { - dxgsg9_cat.info() << "Setting active DX texture " << index << " : " - << dtc->_tex->get_name() << "\n"; - } -#endif - - _pCurTexContext = dtc; // enable_texturing needs this - enable_texturing(true); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::release_texture -// Access: Public, Virtual -// Description: Frees the GL resources previously allocated for the -// texture. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -release_texture(TextureContext *tc) { - DXTextureContext9 *gtc = DCAST(DXTextureContext9, tc); - gtc->DeleteTexture(); - delete gtc; -} - -// copies current display region in framebuffer to the texture -// usually its more efficient to do SetRenderTgt -void DXGraphicsStateGuardian9:: -framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { - set_read_buffer(rb); - - HRESULT hr; - int xo, yo, w, h; - dr->get_region_pixels_i(xo, yo, w, h); - - tex->set_x_size(w); - tex->set_y_size(h); - - TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); - if (tc == (TextureContext *)NULL) { - return; - } - DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); - - IDirect3DSurface9 *pTexSurfaceLev0,*pCurRenderTarget; - hr = dtc->_pD3DTexture9->GetSurfaceLevel(0,&pTexSurfaceLev0); - if(FAILED(hr)) { - dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr); - return; - } - - hr = _pD3DDevice->GetRenderTarget(0, &pCurRenderTarget); - if(FAILED(hr)) { - dxgsg9_cat.error() << "GetRenderTgt failed in copy_texture" << D3DERRORSTRING(hr); - SAFE_RELEASE(pTexSurfaceLev0); - return; - } - - RECT SrcRect; - - SrcRect.left = xo; - SrcRect.right = xo+w; - SrcRect.top = yo; - SrcRect.bottom = yo+h; - - // now copy from fb to tex - //hr = _pD3DDevice->UpdateSurface(pCurRenderTarget,&SrcRect,pTexSurfaceLev0,0); - // the following call does what we want. Interesting though, why Dx9 took out the - // functionality of copying from VRAM to VRAM and put it in D3DX library. Perhaps - // to promote D3DX!? - hr = D3DXLoadSurfaceFromSurface(pTexSurfaceLev0, NULL, NULL, pCurRenderTarget, NULL, &SrcRect, D3DX_FILTER_NONE, 0); - - if(FAILED(hr)) { - dxgsg9_cat.error() - << "UpdateSurface failed in copy_texture" << D3DERRORSTRING(hr); - } - - SAFE_RELEASE(pCurRenderTarget); - SAFE_RELEASE(pTexSurfaceLev0); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::framebuffer_copy_to_ram -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -bool DXGraphicsStateGuardian9:: -framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) { - set_read_buffer(rb); - - RECT SrcCopyRect; - nassertr(tex != NULL && dr != NULL, false); - - int xo, yo, w, h; - dr->get_region_pixels_i(xo, yo, w, h); - - tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgb); - - SrcCopyRect.top = yo; - SrcCopyRect.left = xo; - SrcCopyRect.right = xo + w; - SrcCopyRect.bottom = yo + h; - - IDirect3DSurface9 *pD3DSurf; - HRESULT hr; - - if(_cur_read_pixel_buffer & RenderBuffer::T_back) { - hr=_pD3DDevice->GetBackBuffer(0, 0,D3DBACKBUFFER_TYPE_MONO,&pD3DSurf); - - if(FAILED(hr)) { - dxgsg9_cat.error() << "GetBackBuffer failed" << D3DERRORSTRING(hr); - return false; - } - - // note if you try to grab the backbuffer and full-screen anti-aliasing is on, - // the backbuffer might be larger than the window size. for screenshots its safer to get the front buffer. - - } else if(_cur_read_pixel_buffer & RenderBuffer::T_front) { - // must create a A8R8G8B8 sysmem surface for GetFrontBuffer to copy to - - DWORD TmpSurfXsize,TmpSurfYsize; - - if(_pScrn->PresParams.Windowed) { - // GetFrontBuffer retrieves the entire desktop for a monitor, so - // need space for that - - MONITORINFO minfo; - minfo.cbSize = sizeof(MONITORINFO); - GetMonitorInfo(_pScrn->hMon, &minfo); // have to use GetMonitorInfo, since this gsg may not be for primary monitor - - TmpSurfXsize = RECT_XSIZE(minfo.rcMonitor); - TmpSurfYsize = RECT_YSIZE(minfo.rcMonitor); - - // set SrcCopyRect to client area of window in scrn coords - ClientToScreen( _pScrn->hWnd, (POINT*)&SrcCopyRect.left ); - ClientToScreen( _pScrn->hWnd, (POINT*)&SrcCopyRect.right ); - - } else { - RECT WindRect; - GetWindowRect(_pScrn->hWnd,&WindRect); - TmpSurfXsize = RECT_XSIZE(WindRect); - TmpSurfYsize = RECT_YSIZE(WindRect); - } - - hr=_pD3DDevice->CreateOffscreenPlainSurface(TmpSurfXsize,TmpSurfYsize,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM, &pD3DSurf, NULL); - if(FAILED(hr)) { - dxgsg9_cat.error() << "CreateImageSurface failed in copy_pixel_buffer()" << D3DERRORSTRING(hr); - return false; - } - - hr=_pD3DDevice->GetFrontBufferData(0, pD3DSurf); - - if(hr==D3DERR_DEVICELOST) { - pD3DSurf->Release(); - dxgsg9_cat.error() << "copy_pixel_buffer failed: device lost\n"; - return false; - } - - } else { - dxgsg9_cat.error() << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n"; - return false; - } - - () ConvertD3DSurftoPixBuf(SrcCopyRect,pD3DSurf,tex); - - RELEASE(pD3DSurf,dxgsg9,"pD3DSurf",RELEASE_ONCE); - - nassertr(tex->has_ram_image(), false); - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::apply_material -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9::apply_material( const Material* material ) { - D3DMATERIAL9 cur_material; - cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data()); - cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data()); - cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data()); - cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data()); - cur_material.Power = material->get_shininess(); - _pD3DDevice->SetMaterial(&cur_material); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::apply_fog -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -apply_fog(Fog *fog) { - - if(_doFogType==None) - return; - - Fog::Mode panda_fogmode = fog->get_mode(); - D3DFOGMODE d3dfogmode = get_fog_mode_type(panda_fogmode); - - - // should probably avoid doing redundant SetRenderStates, but whatever - _pD3DDevice->SetRenderState((D3DRENDERSTATETYPE)_doFogType, d3dfogmode); - - const Colorf &fog_colr = fog->get_color(); - _pD3DDevice->SetRenderState(D3DRS_FOGCOLOR, - MY_D3DRGBA(fog_colr[0], fog_colr[1], fog_colr[2], 0.0f)); // Alpha bits are not used - - // do we need to adjust fog start/end values based on D3DPRASTERCAPS_WFOG/D3DPRASTERCAPS_ZFOG ? - // if not WFOG, then docs say we need to adjust values to range [0,1] - - switch (panda_fogmode) { - case Fog::M_linear: - { - float onset, opaque; - fog->get_linear_range(onset, opaque); - - _pD3DDevice->SetRenderState( D3DRS_FOGSTART, - *((LPDWORD) (&onset)) ); - _pD3DDevice->SetRenderState( D3DRS_FOGEND, - *((LPDWORD) (&opaque)) ); - } - break; - case Fog::M_exponential: - case Fog::M_exponential_squared: - { - // Exponential fog is always camera-relative. - float fog_density = fog->get_exp_density(); - _pD3DDevice->SetRenderState( D3DRS_FOGDENSITY, - *((LPDWORD) (&fog_density)) ); - } - break; - } -} - -void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bCanJustEnable) { - -/*class TextureStage { - enum Mode { - M_modulate,M_decal,M_blend,M_replace,M_add}; -*/ - static D3DTEXTUREOP TexBlendColorOp1[/* TextureStage::Mode maxval*/ 10] = - {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD}; - - //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly - /* - if (bCanJustEnable && (TexBlendMode==_CurTexBlendMode)) { - // just reset COLOROP 0 to enable pipeline, rest is already set properly - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] ); - return; - } - */ - - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] ); - - switch (TexBlendMode) { - - case TextureStage::M_modulate: - // emulates GL_MODULATE glTexEnv mode - // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv) - /* - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); - */ - // Program Stage 0: - //_pD3DDevice->SetTexture(0, pTex0 ); - _pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - _pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - // Program Stage 1: - //_pD3DDevice->SetTexture(1, pTex1 ); - _pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); - _pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); - _pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); - //dxgsg9_cat.info() << "--------------modulating--------------" << endl; - break; - case TextureStage::M_decal: - // emulates GL_DECAL glTexEnv mode - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); - - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); - - break; - case TextureStage::M_replace: - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); - break; - case TextureStage::M_add: - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); - - // since I'm making up 'add' mode, use modulate. "adding" alpha never makes sense right? - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); - - break; - case TextureStage::M_blend: - dxgsg9_cat.error() - << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl; -/* - // emulate GL_BLEND glTexEnv - - GL requires 2 independent operations on 3 input vars for this mode - DX texture pipeline requires re-using input of last stage on each new op, so I dont think - exact emulation is possible - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); - - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); - - need to SetTexture(1,tex) also - _pD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); wrong - _pD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - _pD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR ); - - _pD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); - _pD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT ); -*/ - - - break; - default: - dxgsg9_cat.error() << "Unknown texture blend mode " << (int) TexBlendMode << endl; - break; - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_transform -// Access: Public, Virtual -// Description: Sends the indicated transform matrix to the graphics -// API to be applied to future vertices. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_transform(const TransformState *transform) { - DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1)); - - // if we're using ONLY vertex shaders, could get avoid calling SetTrans - D3DMATRIX *pMat = (D3DMATRIX*)transform->get_mat().get_data(); - _pD3DDevice->SetTransform(D3DTS_WORLD,pMat); - - if (_auto_rescale_normal) { - do_auto_rescale_normal(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_tex_matrix -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_tex_matrix(const TexMatrixAttrib *attrib) { - const LMatrix4f &m = attrib->get_mat(); - - if (!attrib->has_stage(TextureStage::get_default())) { - _pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, - D3DTTFF_DISABLE); - // For some reason, "disabling" texture coordinate transforms - // doesn't seem to be sufficient. We'll load an identity matrix - // to underscore the point. - _pD3DDevice->SetTransform(D3DTS_TEXTURE0, &matIdentity); - - } else { - // We have to reorder the elements of the matrix for some reason. - LMatrix4f dm(m(0, 0), m(0, 1), m(0, 3), 0.0f, - m(1, 0), m(1, 1), m(1, 3), 0.0f, - m(3, 0), m(3, 1), m(3, 3), 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - _pD3DDevice->SetTransform(D3DTS_TEXTURE0, (D3DMATRIX *)dm.get_data()); - _pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, - D3DTTFF_COUNT2); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian8::issue_tex_gen -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_tex_gen(const TexGenAttrib *attrib) { - /* - * Automatically generate texture coordinates for stage 0. - * Use the wrap mode from the texture coordinate set at index 1. - */ - DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1)); - if (attrib->is_empty()) { - - //enable_texturing(false); - // reset the texcoordindex lookup to 0 - //_pD3DDevice->SetTransform(D3DTS_TEXTURE0, (D3DMATRIX *)dm.get_data()); - _pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0); - _pD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); - - } else if (attrib->get_mode(TextureStage::get_default()) == TexGenAttrib::M_eye_sphere_map) { - -#if 0 - // best reflection on a sphere is achieved by camera space normals in directx - _pD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, - D3DTSS_TCI_CAMERASPACENORMAL); - // We have set up the texture matrix to scale and translate the - // texture coordinates to get from camera space (-1, +1) to - // texture space (0,1) - LMatrix4f dm(0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.0f, 1.0f); -#else - // since this is a reflection map, we want the camera space - // reflection vector. A close approximation of the asin(theta)/pi - // + 0.5 is achieved by the following matrix - _pD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, - D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR); - LMatrix4f dm(0.33f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.33f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.0f, 1.0f); -#endif - _pD3DDevice->SetTransform(D3DTS_TEXTURE0, (D3DMATRIX *)dm.get_data()); - _pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, - D3DTTFF_COUNT2); - //_pD3DDevice->SetRenderState(D3DRS_LOCALVIEWER, false); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_texture -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_texture(const TextureAttrib *attrib) { - DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1)); - if (attrib->is_off()) { - enable_texturing(false); - } else { - int num_stages = attrib->get_num_on_stages(); - //dxgsg9_cat.info() << "num_on_texture: " << num_stages << endl; - for (int i=0; iget_on_stage(i); - Texture *tex = attrib->get_on_texture(stage); - nassertv(tex != (Texture *)NULL); - - TextureContext *tc = tex->prepare_now(_prepared_objects, this); - apply_texture(tc, 1-i); - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_material -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_material(const MaterialAttrib *attrib) { - const Material *material = attrib->get_material(); - if (material != (const Material *)NULL) { - apply_material(material); - } else { - // Apply a default material when materials are turned off. - Material empty; - apply_material(&empty); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_render_mode -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_render_mode(const RenderModeAttrib *attrib) { - RenderModeAttrib::Mode mode = attrib->get_mode(); - - switch (mode) { - case RenderModeAttrib::M_unchanged: - case RenderModeAttrib::M_filled: - _pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); break; - case RenderModeAttrib::M_wireframe: - _pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); - break; + case TextureStage::M_combine: + // M_combine mode begins a collection of more sophisticated modes, + // which match up more closely with DirectX's built-in modes. + _d3d_device->SetTextureStageState + (i, D3DTSS_COLOROP, + get_texture_operation(stage->get_combine_rgb_mode(), + stage->get_rgb_scale())); - case RenderModeAttrib::M_point: - _pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT); + switch (stage->get_num_combine_rgb_operands()) { + case 3: + _d3d_device->SetTextureStageState + (i, D3DTSS_COLORARG0, + get_texture_argument(stage->get_combine_rgb_source2(), + stage->get_combine_rgb_operand2())); + // fall through + + case 2: + _d3d_device->SetTextureStageState + (i, D3DTSS_COLORARG2, + get_texture_argument(stage->get_combine_rgb_source1(), + stage->get_combine_rgb_operand1())); + // fall through + + case 1: + _d3d_device->SetTextureStageState + (i, D3DTSS_COLORARG1, + get_texture_argument(stage->get_combine_rgb_source0(), + stage->get_combine_rgb_operand0())); + // fall through + + default: + break; + } + + _d3d_device->SetTextureStageState + (i, D3DTSS_ALPHAOP, + get_texture_operation(stage->get_combine_alpha_mode(), + stage->get_alpha_scale())); + + switch (stage->get_num_combine_alpha_operands()) { + case 3: + _d3d_device->SetTextureStageState + (i, D3DTSS_ALPHAARG0, + get_texture_argument(stage->get_combine_alpha_source2(), + stage->get_combine_alpha_operand2())); + // fall through + + case 2: + _d3d_device->SetTextureStageState + (i, D3DTSS_ALPHAARG2, + get_texture_argument(stage->get_combine_alpha_source1(), + stage->get_combine_alpha_operand1())); + // fall through + + case 1: + _d3d_device->SetTextureStageState + (i, D3DTSS_ALPHAARG1, + get_texture_argument(stage->get_combine_alpha_source0(), + stage->get_combine_alpha_operand0())); + // fall through + + default: + break; + } break; default: dxgsg9_cat.error() - << "Unknown render mode " << (int)mode << endl; + << "Unknown texture mode " << (int)stage->get_mode() << endl; + break; } - _current_fill_mode = mode; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_rescale_normal -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_rescale_normal(const RescaleNormalAttrib *attrib) { - RescaleNormalAttrib::Mode mode = attrib->get_mode(); - - _auto_rescale_normal = false; - - switch (mode) { - case RescaleNormalAttrib::M_none: - _pD3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, false); - break; - - case RescaleNormalAttrib::M_rescale: - case RescaleNormalAttrib::M_normalize: - _pD3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true); - break; - - case RescaleNormalAttrib::M_auto: - _auto_rescale_normal = true; - do_auto_rescale_normal(); - break; - - default: - dxgsg9_cat.error() - << "Unknown rescale_normal mode " << (int)mode << endl; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_depth_test -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_depth_test(const DepthTestAttrib *attrib) { - DepthTestAttrib::PandaCompareFunc mode = attrib->get_mode(); - if (mode == DepthTestAttrib::M_none) { - _depth_test_enabled = false; - _pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + if (stage->get_saved_result()) { + _d3d_device->SetTextureStageState(i, D3DTSS_RESULTARG, D3DTA_TEMP); } else { - _depth_test_enabled = true; - _pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); - _pD3DDevice->SetRenderState(D3DRS_ZFUNC, (D3DCMPFUNC) mode); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_alpha_test -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_alpha_test(const AlphaTestAttrib *attrib) { - AlphaTestAttrib::PandaCompareFunc mode = attrib->get_mode(); - if (mode == AlphaTestAttrib::M_none) { - enable_alpha_test(false); - } else { - // AlphaTestAttrib::PandaCompareFunc === D3DCMPFUNC - call_dxAlphaFunc((D3DCMPFUNC)mode, attrib->get_reference_alpha()); - enable_alpha_test(true); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_depth_write -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_depth_write(const DepthWriteAttrib *attrib) { - enable_zwritemask(attrib->get_mode() == DepthWriteAttrib::M_on); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_cull_face -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_cull_face(const CullFaceAttrib *attrib) { - CullFaceAttrib::Mode mode = attrib->get_effective_mode(); - - switch (mode) { - case CullFaceAttrib::M_cull_none: - _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - break; - case CullFaceAttrib::M_cull_clockwise: - _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); - break; - case CullFaceAttrib::M_cull_counter_clockwise: - _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); - break; - default: - dxgsg9_cat.error() - << "invalid cull face mode " << (int)mode << endl; - break; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_fog -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_fog(const FogAttrib *attrib) { - if (!attrib->is_off()) { - enable_fog(true); - Fog *fog = attrib->get_fog(); - nassertv(fog != (Fog *)NULL); - apply_fog(fog); - } else { - enable_fog(false); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::issue_depth_offset -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -issue_depth_offset(const DepthOffsetAttrib *attrib) { - int offset = attrib->get_offset(); - _pD3DDevice->SetRenderState(D3DRS_DEPTHBIAS, offset); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::bind_light -// Access: Public, Virtual -// Description: Called the first time a particular light has been -// bound to a given id within a frame, this should set -// up the associated hardware light with the light's -// properties. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -bind_light(PointLight *light_obj, const NodePath &light, int light_id) { - // Get the light in "world coordinates". This means the light in - // the coordinate space of the camera, converted to DX's coordinate - // system. - CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path()); - const LMatrix4f &light_mat = transform->get_mat(); - LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); - LPoint3f pos = light_obj->get_point() * rel_mat; - - D3DCOLORVALUE black; - black.r = black.g = black.b = black.a = 0.0f; - D3DLIGHT9 alight; - alight.Type = D3DLIGHT_POINT; - alight.Diffuse = *(D3DCOLORVALUE *)(light_obj->get_color().get_data()); - alight.Ambient = black ; - alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); - - // Position needs to specify x, y, z, and w - // w == 1 implies non-infinite position - alight.Position = *(D3DVECTOR *)pos.get_data(); - - alight.Range = __D3DLIGHT_RANGE_MAX; - alight.Falloff = 1.0f; - - const LVecBase3f &att = light_obj->get_attenuation(); - alight.Attenuation0 = att[0]; - alight.Attenuation1 = att[1]; - alight.Attenuation2 = att[2]; - - HRESULT res = _pD3DDevice->SetLight(light_id, &alight); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::bind_light -// Access: Public, Virtual -// Description: Called the first time a particular light has been -// bound to a given id within a frame, this should set -// up the associated hardware light with the light's -// properties. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) { - // Get the light in "world coordinates". This means the light in - // the coordinate space of the camera, converted to DX's coordinate - // system. - CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path()); - const LMatrix4f &light_mat = transform->get_mat(); - LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); - LVector3f dir = light_obj->get_direction() * rel_mat; - - D3DCOLORVALUE black; - black.r = black.g = black.b = black.a = 0.0f; - - D3DLIGHT9 alight; - ZeroMemory(&alight, sizeof(D3DLIGHT9)); - - alight.Type = D3DLIGHT_DIRECTIONAL; - alight.Diffuse = *(D3DCOLORVALUE *)(light_obj->get_color().get_data()); - alight.Ambient = black ; - alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); - - alight.Direction = *(D3DVECTOR *)dir.get_data(); - - alight.Range = __D3DLIGHT_RANGE_MAX; - alight.Falloff = 1.0f; - - alight.Attenuation0 = 1.0f; // constant - alight.Attenuation1 = 0.0f; // linear - alight.Attenuation2 = 0.0f; // quadratic - - HRESULT res = _pD3DDevice->SetLight(light_id, &alight); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::bind_light -// Access: Public, Virtual -// Description: Called the first time a particular light has been -// bound to a given id within a frame, this should set -// up the associated hardware light with the light's -// properties. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { - Lens *lens = light_obj->get_lens(); - nassertv(lens != (Lens *)NULL); - - // Get the light in "world coordinates". This means the light in - // the coordinate space of the camera, converted to DX's coordinate - // system. - CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path()); - const LMatrix4f &light_mat = transform->get_mat(); - LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); - LPoint3f pos = lens->get_nodal_point() * rel_mat; - LVector3f dir = lens->get_view_vector() * rel_mat; - - D3DCOLORVALUE black; - black.r = black.g = black.b = black.a = 0.0f; - - D3DLIGHT9 alight; - ZeroMemory(&alight, sizeof(D3DLIGHT9)); - - alight.Type = D3DLIGHT_SPOT; - alight.Ambient = black ; - alight.Diffuse = *(D3DCOLORVALUE *)(light_obj->get_color().get_data()); - alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data()); - - alight.Position = *(D3DVECTOR *)pos.get_data(); - - alight.Direction = *(D3DVECTOR *)dir.get_data(); - - alight.Range = __D3DLIGHT_RANGE_MAX; - alight.Falloff = 1.0f; - alight.Theta = 0.0f; - alight.Phi = deg_2_rad(lens->get_hfov()); - - const LVecBase3f &att = light_obj->get_attenuation(); - alight.Attenuation0 = att[0]; - alight.Attenuation1 = att[1]; - alight.Attenuation2 = att[2]; - - HRESULT res = _pD3DDevice->SetLight(light_id, &alight); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::begin_frame -// Access: Public, Virtual -// Description: Called before each frame is rendered, to allow the -// GSG a chance to do any internal cleanup before -// beginning the frame. -// -// The return value is true if successful (in which case -// the frame will be drawn and end_frame() will be -// called later), or false if unsuccessful (in which -// case nothing will be drawn and end_frame() will not -// be called). -//////////////////////////////////////////////////////////////////// -bool DXGraphicsStateGuardian9:: -begin_frame() { - return GraphicsStateGuardian::begin_frame(); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::begin_scene -// Access: Public, Virtual -// Description: Called between begin_frame() and end_frame() to mark -// the beginning of drawing commands for a "scene" -// (usually a particular DisplayRegion) within a frame. -// All 3-D drawing commands, except the clear operation, -// must be enclosed within begin_scene() .. end_scene(). -// -// The return value is true if successful (in which case -// the scene will be drawn and end_scene() will be -// called later), or false if unsuccessful (in which -// case nothing will be drawn and end_scene() will not -// be called). -//////////////////////////////////////////////////////////////////// -bool DXGraphicsStateGuardian9:: -begin_scene() { - if (!GraphicsStateGuardian::begin_scene()) { - return false; + _d3d_device->SetTextureStageState(i, D3DTSS_RESULTARG, D3DTA_CURRENT); } - HRESULT hr = _pD3DDevice->BeginScene(); + if (stage->uses_color()) { + // Set up the constant color for this stage. - if (FAILED(hr)) { - if (hr == D3DERR_DEVICELOST) { - if (dxgsg9_cat.is_debug()) { - dxgsg9_cat.debug() - << "BeginScene returns D3DERR_DEVICELOST" << endl; - } - - CheckCooperativeLevel(); + // Actually, DX8 doesn't support a per-stage constant color, but + // it does support one TEXTUREFACTOR color for the whole pipeline. + // This does mean you can't have two different blends in effect + // with different colors on the same object. However, DX9 does + // support a per-stage constant color with the D3DTA_CONSTANT + // argument--so we should implement that when this code gets + // ported to DX9. + D3DCOLOR texture_factor; + if (stage->involves_color_scale() && _color_scale_enabled) { + Colorf color = stage->get_color(); + color.set(color[0] * _current_color_scale[0], + color[1] * _current_color_scale[1], + color[2] * _current_color_scale[2], + color[3] * _current_color_scale[3]); + _texture_involves_color_scale = true; + texture_factor = Colorf_to_D3DCOLOR(color); } else { - dxgsg9_cat.error() - << "BeginScene failed, unhandled error hr == " - << D3DERRORSTRING(hr) << endl; - exit(1); + texture_factor = Colorf_to_D3DCOLOR(stage->get_color()); } - return false; - } - - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::end_scene -// Access: Public, Virtual -// Description: Called between begin_frame() and end_frame() to mark -// the end of drawing commands for a "scene" (usually a -// particular DisplayRegion) within a frame. All 3-D -// drawing commands, except the clear operation, must be -// enclosed within begin_scene() .. end_scene(). -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -end_scene() { - HRESULT hr = _pD3DDevice->EndScene(); - - if (FAILED(hr)) { - - if (hr == D3DERR_DEVICELOST) { - if(dxgsg9_cat.is_debug()) { - dxgsg9_cat.debug() - << "EndScene returns DeviceLost\n"; - } - CheckCooperativeLevel(); - - } else { - dxgsg9_cat.error() - << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr); - exit(1); - } - return; + _d3d_device->SetRenderState(D3DRS_TEXTUREFACTOR, texture_factor); } } //////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::end_frame -// Access: Public, Virtual -// Description: Called after each frame is rendered, to allow the -// GSG a chance to do any internal cleanup after -// rendering the frame, and before the window flips. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -end_frame() { -#ifdef COUNT_DRAWPRIMS - { - #define FRAMES_PER_DPINFO 90 - static DWORD LastDPInfoFrame=0; - static DWORD LastTickCount=0; - const float one_thousandth = 1.0f/1000.0f; - - if (_cur_frame_count-LastDPInfoFrame > FRAMES_PER_DPINFO) { - DWORD CurTickCount=GetTickCount(); - float delta_secs=(CurTickCount-LastTickCount)*one_thousandth; - - float numframes=_cur_frame_count-LastDPInfoFrame; - float verts_per_frame = cVertcount/numframes; - float tris_per_frame = cTricount/numframes; - float DPs_per_frame = cDPcount/numframes; - float DPs_notexchange_per_frame = cDP_noTexChangeCount/numframes; - float verts_per_DP = cVertcount/(float)cDPcount; - float verts_per_sec = cVertcount/delta_secs; - float tris_per_sec = cTricount/delta_secs; - float Geoms_per_frame = cGeomcount/numframes; - float DrawPrims_per_Geom = cDPcount/(float)cGeomcount; - float verts_per_Geom = cVertcount/(float)cGeomcount; - - dxgsg9_cat.debug() << "===================================" - << "\n Avg Verts/sec:\t\t" << verts_per_sec - << "\n Avg Tris/sec:\t\t" << tris_per_sec - << "\n Avg Verts/frame:\t" << verts_per_frame - << "\n Avg Tris/frame:\t" << tris_per_frame - << "\n Avg DrawPrims/frm:\t" << DPs_per_frame - << "\n Avg Verts/DrawPrim:\t" << verts_per_DP - << "\n Avg DrawPrims w/no Texture Change from prev DrawPrim/frm:\t" << DPs_notexchange_per_frame - << "\n Avg Geoms/frm:\t" << Geoms_per_frame - << "\n Avg DrawPrims/Geom:\t" << DrawPrims_per_Geom - << "\n Avg Verts/Geom:\t" << verts_per_Geom - << endl; - - LastDPInfoFrame=_cur_frame_count; - cDPcount = cVertcount=cTricount=cDP_noTexChangeCount=cGeomcount=0; - LastTickCount=CurTickCount; - } - } -#endif - -#if defined(DO_PSTATS)||defined(PRINT_RESOURCESTATS) -#ifndef PRINT_RESOURCESTATS - if (_texmgrmem_total_pcollector.is_active()) -#endif - { - #define TICKS_PER_GETTEXINFO (2.5*1000) // 2.5 second interval - static DWORD LastTickCount=0; - DWORD CurTickCount=GetTickCount(); - - if (CurTickCount-LastTickCount > TICKS_PER_GETTEXINFO) { - LastTickCount=CurTickCount; - report_texmgr_stats(); - } - } -#endif - - // Note: regular GraphicsWindow::end_frame is being called, - // but we override gsg::end_frame, so need to explicitly call it here - // (currently it's an empty fn) - GraphicsStateGuardian::end_frame(); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::set_draw_buffer +// Function: DXGraphicsStateGuardian9::dx_cleanup // Access: Protected -// Description: Sets up the glDrawBuffer to render into the buffer -// indicated by the RenderBuffer object. This only sets -// up the color bits; it does not affect the depth, -// stencil, accum layers. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -set_draw_buffer(const RenderBuffer &rb) { - dxgsg9_cat.fatal() << "DX set_draw_buffer unimplemented!!!"; - return; - -#ifdef WBD_GL_MODE - switch (rb._buffer_type & RenderBuffer::T_color) { - case RenderBuffer::T_front: - call_glDrawBuffer(GL_FRONT); - break; - - case RenderBuffer::T_back: - call_glDrawBuffer(GL_BACK); - break; - - case RenderBuffer::T_right: - call_glDrawBuffer(GL_RIGHT); - break; - - case RenderBuffer::T_left: - call_glDrawBuffer(GL_LEFT); - break; - - case RenderBuffer::T_front_right: - call_glDrawBuffer(GL_FRONT_RIGHT); - break; - - case RenderBuffer::T_front_left: - call_glDrawBuffer(GL_FRONT_LEFT); - break; - - case RenderBuffer::T_back_right: - call_glDrawBuffer(GL_BACK_RIGHT); - break; - - case RenderBuffer::T_back_left: - call_glDrawBuffer(GL_BACK_LEFT); - break; - - default: - call_glDrawBuffer(GL_FRONT_AND_BACK); - } -#endif // WBD_GL_MODE -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::set_read_buffer -// Access: Protected -// Description: Vestigial analog of glReadBuffer -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -set_read_buffer(const RenderBuffer &rb) { - - if(rb._buffer_type & RenderBuffer::T_front) { - _cur_read_pixel_buffer=RenderBuffer::T_front; - } else if(rb._buffer_type & RenderBuffer::T_back) { - _cur_read_pixel_buffer=RenderBuffer::T_back; - } else { - dxgsg9_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n"; - } - return; -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::do_auto_rescale_normal -// Access: Protected -// Description: Issues the appropriate GL commands to either rescale -// or normalize the normals according to the current -// transform. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -do_auto_rescale_normal() { - if (_external_transform->has_identity_scale()) { - // If there's no scale, don't normalize anything. - _pD3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, false); - - } else { - // If there is a scale, turn on normalization. - _pD3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_lighting -// Access: Protected, Virtual -// Description: Intended to be overridden by a derived class to -// enable or disable the use of lighting overall. This -// is called by issue_light() according to whether any -// lights are in use or not. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -enable_lighting(bool enable) { - _pD3DDevice->SetRenderState(D3DRS_LIGHTING, (DWORD)enable); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::set_ambient_light -// Access: Protected, Virtual -// Description: Intended to be overridden by a derived class to -// indicate the color of the ambient light that should -// be in effect. This is called by issue_light() after -// all other lights have been enabled or disabled. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -set_ambient_light(const Colorf &color) { - _pD3DDevice->SetRenderState(D3DRS_AMBIENT, - Colorf_to_D3DCOLOR(color)); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::enable_light -// Access: Protected, Virtual -// Description: Intended to be overridden by a derived class to -// enable the indicated light id. A specific Light will -// already have been bound to this id via bind_light(). -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -enable_light(int light_id, bool enable) { - HRESULT res = _pD3DDevice->LightEnable(light_id, enable); - -#ifdef GSG_VERBOSE - dxgsg9_cat.debug() - << "LightEnable(" << light_id << "=" << enable << ")" << endl; -#endif -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::slot_new_clip_plane -// Access: Protected, Virtual -// Description: This will be called by the base class before a -// particular clip plane id will be used for the first -// time. It is intended to allow the derived class to -// reserve any additional resources, if required, for -// the new clip plane; and also to indicate whether the -// hardware supports this many simultaneous clipping -// planes. -// -// The return value should be true if the additional -// plane is supported, or false if it is not. -//////////////////////////////////////////////////////////////////// -bool DXGraphicsStateGuardian9:: -slot_new_clip_plane(int plane_id) { - return (plane_id < D3DMAXUSERCLIPPLANES); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::bind_clip_plane -// Access: Protected, Virtual -// Description: Called the first time a particular clip_plane has been -// bound to a given id within a frame, this should set -// up the associated hardware clip_plane with the clip_plane's -// properties. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -bind_clip_plane(const NodePath &plane, int plane_id) { - // Get the plane in "world coordinates". This means the plane in - // the coordinate space of the camera, converted to DX's coordinate - // system. - CPT(TransformState) transform = plane.get_transform(_scene_setup->get_camera_path()); - const LMatrix4f &plane_mat = transform->get_mat(); - LMatrix4f rel_mat = plane_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default); - const PlaneNode *plane_node; - DCAST_INTO_V(plane_node, plane.node()); - Planef world_plane = plane_node->get_plane() * rel_mat; - - _pD3DDevice->SetClipPlane(plane_id, world_plane.get_data()); -} - -void DXGraphicsStateGuardian9:: -issue_color_write(const ColorWriteAttrib *attrib) { - _color_write_mode = attrib->get_mode(); - set_color_writemask((_color_write_mode ==ColorWriteAttrib::M_on) ? 0xFFFFFFFF : 0x0); -} - -//////////////////////////////////////////////////////////////////// -// Function: DXGraphicsStateGuardian9::set_blend_mode -// Access: Protected, Virtual -// Description: Called after any of the things that might change -// blending state have changed, this function is -// responsible for setting the appropriate color -// blending mode based on the current properties. -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9:: -set_blend_mode() { - - if((_color_write_mode == ColorWriteAttrib::M_off) && !_pScrn->bCanDirectDisableColorWrites) { - // need !_pScrn->bCanDirectDisableColorWrites guard because other issue_colorblend,issue_transp - // will come this way, and they should ignore the colorwriteattrib value since it's been - // handled separately in set_color_writemask - enable_blend(true); - _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); - call_dxBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE); - return; - } - - // Is there a color blend set? - if (_color_blend_mode != ColorBlendAttrib::M_none) { - enable_blend(true); - - switch (_color_blend_mode) { - case ColorBlendAttrib::M_add: - _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); - break; - - case ColorBlendAttrib::M_subtract: - _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT); - break; - - case ColorBlendAttrib::M_inv_subtract: - _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT); - break; - - case ColorBlendAttrib::M_min: - _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MIN); - break; - - case ColorBlendAttrib::M_max: - _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MAX); - break; - } - - call_dxBlendFunc(get_blend_func(_color_blend->get_operand_a()), - get_blend_func(_color_blend->get_operand_b())); - return; - } - - // No color blend; is there a transparency set? - switch (_transparency_mode) { - case TransparencyAttrib::M_none: - case TransparencyAttrib::M_binary: - break; - - case TransparencyAttrib::M_alpha: - case TransparencyAttrib::M_multisample: - case TransparencyAttrib::M_multisample_mask: - case TransparencyAttrib::M_dual: - enable_blend(true); - _pD3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); - call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); - return; - - default: - dxgsg9_cat.error() - << "invalid transparency mode " << (int)_transparency_mode << endl; - break; - } - - // Nothing's set, so disable blending. - enable_blend(false); -} - -TypeHandle DXGraphicsStateGuardian9::get_type() const { - return get_class_type(); -} - -TypeHandle DXGraphicsStateGuardian9::get_class_type() { - return _type_handle; -} - -void DXGraphicsStateGuardian9::init_type() { - GraphicsStateGuardian::init_type(); - register_type(_type_handle, "DXGraphicsStateGuardian9", - GraphicsStateGuardian::get_class_type()); -} - -//////////////////////////////////////////////////////////////////// -// Function: dx_cleanup // Description: Clean up the DirectX environment, accounting for exit() //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: -dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) { - static bool bAtExitFnEverCalled=false; +dx_cleanup() { + if (!_d3d_device) { + return; + } - if(dxgsg9_cat.is_spam()) { - dxgsg9_cat.spam() << "dx_cleanup called, bAtExitFnCalled=" << bAtExitFnCalled << ", bAtExitFnEverCalled=" << bAtExitFnEverCalled << endl; - } + free_nondx_resources(); + PRINT_REFCNT(dxgsg9, _d3d_device); - bAtExitFnEverCalled = (bAtExitFnEverCalled || bAtExitFnCalled); + // Do a safe check for releasing the D3DDEVICE. RefCount should be zero. + // if we're called from exit(), _d3d_device may already have been released + RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO); + _screen->_d3d_device = NULL; - // for now, I can't trust any of the ddraw/d3d releases during atexit(), - // so just return directly. maybe revisit this later, if have problems - // restarting d3d/ddraw after one of these uncleaned-up exits - // if(bAtExitFnEverCalled) - // return; - - if (!_pD3DDevice) - return; - - // unsafe to do the D3D releases after exit() called, since DLL_PROCESS_DETACH - // msg already delivered to d3d.dll and it's unloaded itself - - wdxdisplay9_cat.debug() << "called dx_cleanup\n"; - free_nondx_resources(); - - wdxdisplay9_cat.debug() << "device : " << _pD3DDevice << endl; - PRINT_REFCNT(dxgsg9,_pD3DDevice); - - PRINT_REFCNT(dxgsg9,_pD3DDevice); - - // Do a safe check for releasing the D3DDEVICE. RefCount should be zero. - // if we're called from exit(), _pD3DDevice may already have been released - if (_pD3DDevice!=NULL) { - for(int i=0;iSetTexture(i,NULL); // d3d should release this stuff internally anyway, but whatever - RELEASE(_pD3DDevice,dxgsg9,"d3dDevice",RELEASE_DOWN_TO_ZERO); - _pScrn->pD3DDevice = NULL; - } - - // Releasing pD3D is now the responsibility of the GraphicsPipe destructor + // Releasing pD3D is now the responsibility of the GraphicsPipe destructor } -void DXGraphicsStateGuardian9:: -set_context(DXScreenData *pNewContextData) { - // dont do copy from window since dx_init sets fields too. - // simpler to keep all of it in one place, so use ptr to window struct - - assert(pNewContextData!=NULL); - _pScrn = pNewContextData; - _pD3DDevice = _pScrn->pD3DDevice; //copy this one field for speed of deref - _pSwapChain = _pScrn->pSwapChain; //copy this one field for speed of deref - - //wdxdisplay9_cat.debug() << "SwapChain = "<< _pSwapChain << "\n"; +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::reset_d3d_device +// Access: Protected +// Description: This function checks current device's framebuffer +// dimension against passed p_presentation_params backbuffer +// dimension to determine a device reset if there is +// only one window or it is the main window or +// fullscreen mode then, it resets the device. Finally +// it returns the new DXScreenData through parameter +// screen +//////////////////////////////////////////////////////////////////// +HRESULT DXGraphicsStateGuardian9:: +reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params, + DXScreenData **screen) { + HRESULT hr; + + assert(IS_VALID_PTR(presentation_params)); + assert(IS_VALID_PTR(_screen->_d3d9)); + assert(IS_VALID_PTR(_d3d_device)); + + // for windowed mode make sure our format matches the desktop fmt, + // in case the desktop mode has been changed + _screen->_d3d9->GetAdapterDisplayMode(_screen->_card_id, &_screen->_display_mode); + presentation_params->BackBufferFormat = _screen->_display_mode.Format; + + // here we have to look at the _presentation_reset frame buffer dimension + // if current window's dimension is bigger than _presentation_reset + // we have to reset the device before creating new swapchain. + // inorder to reset properly, we need to release all swapchains + + if (!(_screen->_swap_chain) + || (_presentation_reset.BackBufferWidth < presentation_params->BackBufferWidth) + || (_presentation_reset.BackBufferHeight < presentation_params->BackBufferHeight)) { + if (wdxdisplay9_cat.is_debug()) { + wdxdisplay9_cat.debug() + << "swap_chain = " << _screen->_swap_chain << " _presentation_reset = " + << _presentation_reset.BackBufferWidth << "x" << _presentation_reset.BackBufferHeight + << " presentation_params = " + << presentation_params->BackBufferWidth << "x" << presentation_params->BackBufferHeight << "\n"; + } + + get_engine()->reset_all_windows(false);// reset old swapchain by releasing + + if (_screen->_swap_chain) { //other windows might be using bigger buffers + _presentation_reset.BackBufferWidth = max(_presentation_reset.BackBufferWidth, presentation_params->BackBufferWidth); + _presentation_reset.BackBufferHeight = max(_presentation_reset.BackBufferHeight, presentation_params->BackBufferHeight); + + } else { // single window, must reset to the new presentation_params dimension + _presentation_reset.BackBufferWidth = presentation_params->BackBufferWidth; + _presentation_reset.BackBufferHeight = presentation_params->BackBufferHeight; + } + + // Calling this forces all of the textures and vbuffers to be + // regenerated, a prerequisite to calling Reset(). Actually, this + // shouldn't be necessary, because all of our textures and + // vbuffers are stored in the D3DPOOL_MANAGED memory class. + // release_all(); + + // Just to be extra-conservative for now, we'll go ahead and + // release the vbuffers and ibuffers at least; they're relatively + // cheap to replace. + release_all_vertex_buffers(); + release_all_index_buffers(); + + hr = _d3d_device->Reset(&_presentation_reset); + if (FAILED(hr)) { + return hr; + } + + get_engine()->reset_all_windows(true);// reset with new swapchains by creating + if (screen) { + *screen = NULL; + } + + if (presentation_params != &_screen->_presentation_params) { + memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS)); + } + + return hr; + } + + // release the old swapchain and create a new one + if (_screen && _screen->_swap_chain) { + _screen->_swap_chain->Release(); + wdxdisplay9_cat.debug() + << "swap chain " << _screen->_swap_chain << " is released\n"; + _screen->_swap_chain = NULL; + hr = _d3d_device->CreateAdditionalSwapChain(presentation_params, &_screen->_swap_chain); + } + if (SUCCEEDED(hr)) { + if (presentation_params != &_screen->_presentation_params) { + memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS)); + } + if (screen) { + *screen = _screen; + } + } + return hr; } -bool DXGraphicsStateGuardian9:: -create_swap_chain(DXScreenData *pNewContextData) { +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::check_cooperative_level +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian9:: +check_cooperative_level() { + bool bDoReactivateWindow = false; + HRESULT hr = _d3d_device->TestCooperativeLevel(); + + if (SUCCEEDED(hr)) { + assert(SUCCEEDED(_last_testcooplevel_result)); + return true; + } + + switch (hr) { + case D3DERR_DEVICENOTRESET: + _dx_is_ready = false; + hr = reset_d3d_device(&_screen->_presentation_params); + if (FAILED(hr)) { + // I think this shouldnt fail unless I've screwed up the + // _presentation_params from the original working ones somehow + dxgsg9_cat.error() + << "check_cooperative_level Reset() failed, hr = " << D3DERRORSTRING(hr); + } + + hr = _d3d_device->TestCooperativeLevel(); + if (FAILED(hr)) { + // internal chk, shouldnt fail + dxgsg9_cat.error() + << "TestCooperativeLevel following Reset() failed, hr = " << D3DERRORSTRING(hr); + + } + + _dx_is_ready = TRUE; + break; + + case D3DERR_DEVICELOST: + if (SUCCEEDED(_last_testcooplevel_result)) { + if (_dx_is_ready) { + _dx_is_ready = false; + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() << "D3D Device was Lost, waiting...\n"; + } + } + } + } + + _last_testcooplevel_result = hr; + return SUCCEEDED(hr); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::show_frame +// Access: Protected +// Description: redraw primary buffer +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +show_frame() { + if (_d3d_device == NULL) { + return; + } + + HRESULT hr; + + if (_swap_chain) { + DWORD flags; + flags = 0; + hr = _swap_chain->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL, flags); + } else { + hr = _d3d_device->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL); + } + + if (FAILED(hr)) { + if (hr == D3DERR_DEVICELOST) { + check_cooperative_level(); + } else { + dxgsg9_cat.error() + << "show_frame() - Present() failed" << D3DERRORSTRING(hr); + throw_event("panda3d-render-error"); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::create_swap_chain +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian9:: +create_swap_chain(DXScreenData *new_context) { // Instead of creating a device and rendering as d3ddevice->present() // we should render using SwapChain->present(). This is done to support // multiple windows rendering. For that purpose, we need to set additional // swap chains here. - + HRESULT hr; - hr = pNewContextData->pD3DDevice->CreateAdditionalSwapChain(&pNewContextData->PresParams, &pNewContextData->pSwapChain); + hr = new_context->_d3d_device->CreateAdditionalSwapChain(&new_context->_presentation_params, &new_context->_swap_chain); if (FAILED(hr)) { wdxdisplay9_cat.debug() << "Swapchain creation failed :"<pSwapChain) { - hr = pNewContextData->pSwapChain->Release(); + if (new_context->_swap_chain) { + hr = new_context->_swap_chain->Release(); if (FAILED(hr)) { wdxdisplay9_cat.debug() << "Swapchain release failed:" << D3DERRORSTRING(hr) << "\n"; return false; @@ -4038,512 +3581,282 @@ release_swap_chain(DXScreenData *pNewContextData) { return true; } -bool refill_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) { - DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); -// DXGraphicsStateGuardian9 *dxgsg = (DXGraphicsStateGuardian9 *)void_dxgsg_ptr; not needed? - - // Re-fill the contents of textures and vertex buffers - // which just got restored now. - HRESULT hr=dtc->FillDDSurfTexturePixels(); - return hr==S_OK; -} - -bool delete_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) { - DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); - - // release DDSurf (but not the texture context) - dtc->DeleteTexture(); - return true; -} - -bool recreate_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) { - DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc); - DXGraphicsStateGuardian9 *dxgsg = (DXGraphicsStateGuardian9 *)void_dxgsg_ptr; - - // Re-fill the contents of textures and vertex buffers - // which just got restored now. - - IDirect3DTexture9 *ddtex = dtc->CreateTexture(*dxgsg->_pScrn); - return ddtex!=NULL; -} - -// release all textures and vertex/index buffers -HRESULT DXGraphicsStateGuardian9::DeleteAllDeviceObjects() { - // BUGBUG: need to release any vertexbuffers here - - // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it - - // dont call release_all_textures() because we want the panda tex obj around so it can reload its texture - - // bugbug: do I still need to delete all the textures since they are all D3DPOOL_MANAGED now? - traverse_prepared_textures(delete_tex_callback,this); - - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "release of all textures complete\n"; - - assert(_pD3DDevice); - - return S_OK; -} - -// recreate all textures and vertex/index buffers -HRESULT DXGraphicsStateGuardian9::RecreateAllDeviceObjects() { - // BUGBUG: need to handle vertexbuffer handling here - - // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it - traverse_prepared_textures(recreate_tex_callback,this); - - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "recreation of all textures complete\n"; - return S_OK; -} - -HRESULT DXGraphicsStateGuardian9::ReleaseAllDeviceObjects() { - // release any D3DPOOL_DEFAULT objects here (currently none) - return S_OK; -} - -#if 0 //////////////////////////////////////////////////////////////////// -// Function: show_frame -// Access: -// Description: redraw primary buffer +// Function: DXGraphicsStateGuardian9::copy_pres_reset +// Access: Protected +// Description: copies the PresReset from passed DXScreenData //////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9::show_frame(bool bNoNewFrameDrawn) { - if(_pD3DDevice==NULL) - return; +void DXGraphicsStateGuardian9:: +copy_pres_reset(DXScreenData *screen) { + memcpy(&_presentation_reset, &_screen->_presentation_params, sizeof(D3DPRESENT_PARAMETERS)); +} - // DO_PSTATS_STUFF(PStatTimer timer(_win->_swap_pcollector)); // this times just the flip, so it must go here in dxgsg, instead of wdxdisplay, which would time the whole frame - HRESULT hr; +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::get_d3d_min_type +// Access: Protected, Static +// Description: +//////////////////////////////////////////////////////////////////// +D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9:: +get_d3d_min_type(Texture::FilterType filter_type) { + switch (filter_type) { + case Texture::FT_nearest: + return D3DTEXF_POINT; - if(bNoNewFrameDrawn) { - // a new frame has not been rendered, we just want to display the last thing - // that was drawn into backbuf, if backbuf is valid - if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_DISCARD) { - // in DISCARD mode, old backbufs are not guaranteed to have valid pixels, - // so we cant copy back->front here. just give up. - return; - } else if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_FLIP) { - /* bugbug: here we should use CopyRects here to copy backbuf to front (except in - the case of frames 1 and 2 where we have no valid data in the backbuffer yet, - for those cases give up and return). - not implemented yet since right now we always do discard mode for fullscrn Present() - for speed. - */ - return; - } + case Texture::FT_linear: + return D3DTEXF_LINEAR; - // otherwise we have D3DSWAPEFFECT_COPY, so fall-thru to normal Present() - // may work ok as long as backbuf hasnt been touched + case Texture::FT_nearest_mipmap_nearest: + return D3DTEXF_POINT; + + case Texture::FT_linear_mipmap_nearest: + return D3DTEXF_LINEAR; + + case Texture::FT_nearest_mipmap_linear: + return D3DTEXF_POINT; + + case Texture::FT_linear_mipmap_linear: + return D3DTEXF_LINEAR; } - hr = _pD3DDevice->Present((CONST RECT*)NULL,(CONST RECT*)NULL,(HWND)NULL,NULL); - if(FAILED(hr)) { - if(hr == D3DERR_DEVICELOST) { - CheckCooperativeLevel(); + dxgsg9_cat.error() + << "Invalid FilterType value (" << (int)filter_type << ")\n"; + return D3DTEXF_POINT; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::get_d3d_mip_type +// Access: Protected, Static +// Description: +//////////////////////////////////////////////////////////////////// +D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9:: +get_d3d_mip_type(Texture::FilterType filter_type) { + switch (filter_type) { + case Texture::FT_nearest: + return D3DTEXF_NONE; + + case Texture::FT_linear: + return D3DTEXF_NONE; + + case Texture::FT_nearest_mipmap_nearest: + return D3DTEXF_POINT; + + case Texture::FT_linear_mipmap_nearest: + return D3DTEXF_POINT; + + case Texture::FT_nearest_mipmap_linear: + return D3DTEXF_LINEAR; + + case Texture::FT_linear_mipmap_linear: + return D3DTEXF_LINEAR; + } + + dxgsg9_cat.error() + << "Invalid FilterType value (" << (int)filter_type << ")\n"; + return D3DTEXF_NONE; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::get_texture_operation +// Access: Protected, Static +// Description: Returns the D3DTEXTUREOP value corresponding to the +// indicated TextureStage::CombineMode enumerated type. +//////////////////////////////////////////////////////////////////// +D3DTEXTUREOP DXGraphicsStateGuardian9:: +get_texture_operation(TextureStage::CombineMode mode, int scale) { + switch (mode) { + case TextureStage::CM_undefined: + case TextureStage::CM_replace: + return D3DTOP_SELECTARG1; + + case TextureStage::CM_modulate: + if (scale < 2) { + return D3DTOP_MODULATE; + } else if (scale < 4) { + return D3DTOP_MODULATE2X; } else { - dxgsg9_cat.error() << "show_frame() - Present() failed" << D3DERRORSTRING(hr); - exit(1); + return D3DTOP_MODULATE4X; } - } -} -#endif -//////////////////////////////////////////////////////////////////// -// Function: show_frame -// Access: -// Description: redraw primary buffer -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9::show_frame(bool bNoNewFrameDrawn) { - if(_pD3DDevice==NULL) - return; + case TextureStage::CM_add: + return D3DTOP_ADD; - // DO_PSTATS_STUFF(PStatTimer timer(_win->_swap_pcollector)); // this times just the flip, so it must go here in dxgsg, instead of wdxdisplay, which would time the whole frame - HRESULT hr; - - if(bNoNewFrameDrawn) { - // a new frame has not been rendered, we just want to display the last thing - // that was drawn into backbuf, if backbuf is valid - if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_DISCARD) { - // in DISCARD mode, old backbufs are not guaranteed to have valid pixels, - // so we cant copy back->front here. just give up. - return; - } else if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_FLIP) { - /* bugbug: here we should use CopyRects here to copy backbuf to front (except in - the case of frames 1 and 2 where we have no valid data in the backbuffer yet, - for those cases give up and return). - not implemented yet since right now we always do discard mode for fullscrn Present() - for speed. - */ - return; - } - - // otherwise we have D3DSWAPEFFECT_COPY, so fall-thru to normal Present() - // may work ok as long as backbuf hasnt been touched - } - - if (_pSwapChain) - hr = _pSwapChain->Present((CONST RECT*)NULL,(CONST RECT*)NULL,(HWND)NULL,NULL, 0); - else - hr = _pD3DDevice->Present((CONST RECT*)NULL,(CONST RECT*)NULL,(HWND)NULL,NULL); - - if(FAILED(hr)) { - if(hr == D3DERR_DEVICELOST) { - CheckCooperativeLevel(); + case TextureStage::CM_add_signed: + if (scale < 2) { + return D3DTOP_ADDSIGNED; } else { - dxgsg9_cat.error() << "show_frame() - Present() failed" << D3DERRORSTRING(hr); - exit(1); + return D3DTOP_ADDSIGNED2X; } + + case TextureStage::CM_interpolate: + return D3DTOP_LERP; + + case TextureStage::CM_subtract: + return D3DTOP_SUBTRACT; + + case TextureStage::CM_dot3_rgb: + case TextureStage::CM_dot3_rgba: + return D3DTOP_DOTPRODUCT3; + } + + dxgsg9_cat.error() + << "Invalid TextureStage::CombineMode value (" << (int)mode << ")\n"; + return D3DTOP_DISABLE; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::get_texture_argument +// Access: Protected, Static +// Description: Returns the D3DTA value corresponding to the +// indicated TextureStage::CombineSource and +// TextureStage::CombineOperand enumerated types. +//////////////////////////////////////////////////////////////////// +DWORD DXGraphicsStateGuardian9:: +get_texture_argument(TextureStage::CombineSource source, + TextureStage::CombineOperand operand) { + switch (source) { + case TextureStage::CS_undefined: + case TextureStage::CS_texture: + return D3DTA_TEXTURE | get_texture_argument_modifier(operand); + + case TextureStage::CS_constant: + case TextureStage::CS_constant_color_scale: + return D3DTA_TFACTOR | get_texture_argument_modifier(operand); + + case TextureStage::CS_primary_color: + return D3DTA_DIFFUSE | get_texture_argument_modifier(operand); + + case TextureStage::CS_previous: + return D3DTA_CURRENT | get_texture_argument_modifier(operand); + + case TextureStage::CS_last_saved_result: + return D3DTA_TEMP | get_texture_argument_modifier(operand); + } + dxgsg9_cat.error() + << "Invalid TextureStage::CombineSource value (" << (int)source << ")\n"; + return D3DTA_CURRENT; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::get_texture_argument_modifier +// Access: Protected, Static +// Description: Returns the extra bits that modify the D3DTA +// argument, according to the indicated +// TextureStage::CombineOperand enumerated type. +//////////////////////////////////////////////////////////////////// +DWORD DXGraphicsStateGuardian9:: +get_texture_argument_modifier(TextureStage::CombineOperand operand) { + switch (operand) { + case TextureStage::CO_src_color: + return 0; + + case TextureStage::CO_one_minus_src_color: + return D3DTA_COMPLEMENT; + + case TextureStage::CO_src_alpha: + return D3DTA_ALPHAREPLICATE; + + case TextureStage::CO_one_minus_src_alpha: + return D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT; + + case TextureStage::CO_undefined: + break; + } + dxgsg9_cat.error() + << "Invalid TextureStage::CombineOperand value (" << (int)operand << ")\n"; + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::draw_primitive_up +// Access: Protected +// Description: Issues the DrawPrimitiveUP call to draw the indicated +// primitive_type from the given buffer. We add the +// num_vertices parameter, so we can determine the size +// of the buffer. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian9:: +draw_primitive_up(D3DPRIMITIVETYPE primitive_type, + unsigned int primitive_count, + unsigned int first_vertex, + unsigned int num_vertices, + const unsigned char *buffer, size_t stride) { + + // It appears that the common ATI driver seems to fail to draw + // anything in the DrawPrimitiveUP() call if the address range of + // the buffer supplied crosses over a multiple of 0x10000. That's + // incredibly broken, yet it undeniably appears to be true. We'll + // have to hack around it. + + const unsigned char *buffer_start = buffer + stride * first_vertex; + const unsigned char *buffer_end = buffer_start + stride * num_vertices; + + if (buffer_end - buffer_start > 0x10000) { + // Actually, the buffer doesn't fit within the required limit + // anyway. Go ahead and draw it and hope for the best. + _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count, + buffer_start, stride); + + } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) { + // No problem; we can draw the buffer directly. + _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count, + buffer_start, stride); + + } else { + // We have a problem--the buffer crosses over a 0x10000 boundary. + // We have to copy the buffer to a temporary buffer that we can + // draw from. + unsigned char *safe_buffer_start = get_safe_buffer_start(); + memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start); + _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count, + safe_buffer_start, stride); + } } //////////////////////////////////////////////////////////////////// -// Function: set_render_target -// Access: -// Description: Set render target to the backbuffer of -// current swap chain. +// Function: DXGraphicsStateGuardian9::draw_indexed_primitive_up +// Access: Protected +// Description: Issues the DrawIndexedPrimitiveUP call to draw the +// indicated primitive_type from the given buffer. As +// in draw_primitive_up(), above, the parameter list is +// not exactly one-for-one with the +// DrawIndexedPrimitiveUP() call, but it's similar (in +// particular, we pass max_index instead of NumVertices, +// which always seemed ambiguous to me). //////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9::set_render_target() { - LPDIRECT3DSURFACE9 pBack=NULL, pStencil=NULL; +void DXGraphicsStateGuardian9:: +draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type, + unsigned int min_index, unsigned int max_index, + unsigned int num_primitives, + const unsigned char *index_data, + D3DFORMAT index_type, + const unsigned char *buffer, size_t stride) { + // As above, we'll hack the case of the buffer crossing the 0x10000 + // boundary. + const unsigned char *buffer_start = buffer + stride * min_index; + const unsigned char *buffer_end = buffer + stride * (max_index + 1); - if (!_pSwapChain) //maybe fullscreen mode or main/single window - _pD3DDevice->GetBackBuffer(0, 0,D3DBACKBUFFER_TYPE_MONO,&pBack); - else - _pSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBack); + if (buffer_end - buffer_start > 0x10000) { + // Actually, the buffer doesn't fit within the required limit + // anyway. Go ahead and draw it and hope for the best. + _d3d_device->DrawIndexedPrimitiveUP + (primitive_type, min_index, max_index - min_index + 1, num_primitives, + index_data, index_type, buffer, stride); - //wdxdisplay9_cat.debug() << "swapchain is " << _pSwapChain << "\n"; - //wdxdisplay9_cat.debug() << "back buffer is " << pBack << "\n"; + } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) { + // No problem; we can draw the buffer directly. + _d3d_device->DrawIndexedPrimitiveUP + (primitive_type, min_index, max_index - min_index + 1, num_primitives, + index_data, index_type, buffer, stride); - _pD3DDevice->GetDepthStencilSurface(&pStencil); - _pD3DDevice->SetDepthStencilSurface(pStencil); - _pD3DDevice->SetRenderTarget(0, pBack); - if (pBack) - pBack->Release(); - if (pStencil) - pStencil->Release(); -} - -//////////////////////////////////////////////////////////////////// -// Function: copy_pres_reset -// Access: -// Description: copies the PresReset from passed DXScreenData -//////////////////////////////////////////////////////////////////// -void DXGraphicsStateGuardian9::copy_pres_reset(DXScreenData *pScrn) { - memcpy(&_PresReset, &_pScrn->PresParams,sizeof(D3DPRESENT_PARAMETERS)); -} - -///////////////////////////////////////////////////////////////////////////////////// -// Function: reset_d3d_device -// Access: -// Description: This function checks current device's framebuffer dimension against -// passed pPresParams backbuffer dimension to determine a device reset -// if there is only one window or it is the main window or fullscreen -// mode then, it resets the device. Finally it returns the new -// DXScreenData through parameter pScrn -///////////////////////////////////////////////////////////////////////////////////// -HRESULT DXGraphicsStateGuardian9:: -reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams, DXScreenData **pScrn) { - HRESULT hr; - - assert(IS_VALID_PTR(pPresParams)); - assert(IS_VALID_PTR(_pScrn->pD3D9)); - assert(IS_VALID_PTR(_pD3DDevice)); - - ReleaseAllDeviceObjects(); - - // for windowed mode make sure our format matches the desktop fmt, - // in case the desktop mode has been changed - - _pScrn->pD3D9->GetAdapterDisplayMode(_pScrn->CardIDNum, &_pScrn->DisplayMode); - pPresParams->BackBufferFormat = _pScrn->DisplayMode.Format; - - // here we have to look at the _PresReset frame buffer dimension - // if current window's dimension is bigger than _PresReset - // we have to reset the device before creating new swapchain. - // inorder to reset properly, we need to release all swapchains - - if ( !(_pScrn->pSwapChain) - || (_PresReset.BackBufferWidth < pPresParams->BackBufferWidth) - || (_PresReset.BackBufferHeight < pPresParams->BackBufferHeight) ) { - - wdxdisplay9_cat.debug() << "Swpachain = " << _pScrn->pSwapChain << " _PresReset = " - << _PresReset.BackBufferWidth << "x" << _PresReset.BackBufferHeight << "pPresParams = " - << pPresParams->BackBufferWidth << "x" << pPresParams->BackBufferHeight << "\n"; - - get_engine()->reset_all_windows(false);// reset old swapchain by releasing - - if (_pScrn->pSwapChain) { //other windows might be using bigger buffers - _PresReset.BackBufferWidth = max(_PresReset.BackBufferWidth, pPresParams->BackBufferWidth); - _PresReset.BackBufferHeight = max(_PresReset.BackBufferHeight, pPresParams->BackBufferHeight); - } - else { // single window, must reset to the new pPresParams dimension - _PresReset.BackBufferWidth = pPresParams->BackBufferWidth; - _PresReset.BackBufferHeight = pPresParams->BackBufferHeight; - } - - hr=_pD3DDevice->Reset(&_PresReset); - if (FAILED(hr)) { - return hr; - } - - get_engine()->reset_all_windows(true);// reset with new swapchains by creating - - if (pScrn) - *pScrn = NULL; - if(pPresParams!=&_pScrn->PresParams) - memcpy(&_pScrn->PresParams,pPresParams,sizeof(D3DPRESENT_PARAMETERS)); - return hr; + } else { + // We have a problem--the buffer crosses over a 0x10000 boundary. + // We have to copy the buffer to a temporary buffer that we can + // draw from. + unsigned char *safe_buffer_start = get_safe_buffer_start(); + memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start); + _d3d_device->DrawIndexedPrimitiveUP + (primitive_type, min_index, max_index - min_index + 1, num_primitives, + index_data, index_type, safe_buffer_start - stride * min_index, stride); } - - // release the old swapchain and create a new one - if (_pScrn && _pScrn->pSwapChain) { - _pScrn->pSwapChain->Release(); - wdxdisplay9_cat.debug() << "SwapChain " << _pScrn->pSwapChain << " is released\n"; - _pScrn->pSwapChain = NULL; - hr=_pD3DDevice->CreateAdditionalSwapChain(pPresParams,&_pScrn->pSwapChain); - } - if(SUCCEEDED(hr)) { - if(pPresParams!=&_pScrn->PresParams) - memcpy(&_pScrn->PresParams,pPresParams,sizeof(D3DPRESENT_PARAMETERS)); - if (pScrn) - *pScrn = _pScrn; - } - return hr; } - -bool DXGraphicsStateGuardian9:: -CheckCooperativeLevel(bool bDoReactivateWindow) { - HRESULT hr = _pD3DDevice->TestCooperativeLevel(); - - if(SUCCEEDED(hr)) { - assert(SUCCEEDED(_last_testcooplevel_result)); - return true; - } - - switch(hr) { - case D3DERR_DEVICENOTRESET: - _bDXisReady = false; - hr=reset_d3d_device(&_pScrn->PresParams); - if (FAILED(hr)) { - // I think this shouldnt fail unless I've screwed up the PresParams from the original working ones somehow - dxgsg9_cat.error() - << "CheckCooperativeLevel Reset() failed, hr = " << D3DERRORSTRING(hr); - // drose is commenting out this exit() call; it's getting - // triggered on some actual client hardware (with - // DRIVERINTERNALERROR) but maybe that's ok. - //exit(1); - } - - // BUGBUG: is taking this out wrong?? - /* - if(bDoReactivateWindow) { - _win->reactivate_window(); //must reactivate window before you can restore surfaces (otherwise you are in WRONGVIDEOMODE, and DDraw RestoreAllSurfaces fails) - } - */ - - hr = _pD3DDevice->TestCooperativeLevel(); - if(FAILED(hr)) { - // internal chk, shouldnt fail - dxgsg9_cat.error() - << "TestCooperativeLevel following Reset() failed, hr = " << D3DERRORSTRING(hr); - - // drose is commenting out this exit() call; maybe it's ok if the above fails. - //exit(1); - } - - _bDXisReady = TRUE; - break; - - case D3DERR_DEVICELOST: - if(SUCCEEDED(_last_testcooplevel_result)) { - if(_bDXisReady) { - // _win->deactivate_window(); - _bDXisReady = false; - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "D3D Device was Lost, waiting...\n"; - } - } - } - - _last_testcooplevel_result = hr; - return SUCCEEDED(hr); -} - -HRESULT CreateDX9Cursor(LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,BOOL bAddWatermark) { -// copied directly from dxsdk SetDeviceCursor - HRESULT hr = E_FAIL; - ICONINFO iconinfo; - LPDIRECT3DSURFACE9 pCursorBitmap = NULL; - HDC hdcColor = NULL; - HDC hdcMask = NULL; - HDC hdcScreen = NULL; - BITMAP bm; - DWORD dwWidth,dwHeightSrc,dwHeightDest; - COLORREF crColor,crMask; - UINT x,y; - BITMAPINFO bmi; - COLORREF* pcrArrayColor = NULL; - COLORREF* pcrArrayMask = NULL; - DWORD* pBitmap; - HGDIOBJ hgdiobjOld; - bool bBWCursor; - - ZeroMemory( &iconinfo, sizeof(iconinfo) ); - if( !GetIconInfo( hCursor, &iconinfo ) ) - goto End; - - if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm)) - goto End; - dwWidth = bm.bmWidth; - dwHeightSrc = bm.bmHeight; - - if( iconinfo.hbmColor == NULL ) { - bBWCursor = true; - dwHeightDest = dwHeightSrc / 2; - } else { - bBWCursor = false; - dwHeightDest = dwHeightSrc; - } - - // Create a surface for the cursor - if( FAILED( hr = pd3dDevice->CreateOffscreenPlainSurface( dwWidth, dwHeightDest, - D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pCursorBitmap, NULL ) ) ) { - goto End; - } - - pcrArrayMask = new DWORD[dwWidth * dwHeightSrc]; - - ZeroMemory(&bmi, sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); - bmi.bmiHeader.biWidth = dwWidth; - bmi.bmiHeader.biHeight = dwHeightSrc; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - - hdcScreen = GetDC( NULL ); - hdcMask = CreateCompatibleDC( hdcScreen ); - if( hdcMask == NULL ) - { - hr = E_FAIL; - goto End; - } - hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask); - GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc, - pcrArrayMask, &bmi, DIB_RGB_COLORS); - SelectObject(hdcMask, hgdiobjOld); - - if (!bBWCursor) - { - pcrArrayColor = new DWORD[dwWidth * dwHeightDest]; - hdcColor = CreateCompatibleDC( GetDC( NULL ) ); - if( hdcColor == NULL ) - { - hr = E_FAIL; - goto End; - } - SelectObject(hdcColor, iconinfo.hbmColor); - GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest, - pcrArrayColor, &bmi, DIB_RGB_COLORS); - } - - // Transfer cursor image into the surface - D3DLOCKED_RECT lr; - pCursorBitmap->LockRect( &lr, NULL, 0 ); - pBitmap = (DWORD*)lr.pBits; - for( y = 0; y < dwHeightDest; y++ ) - { - for( x = 0; x < dwWidth; x++ ) - { - if (bBWCursor) - { - crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x]; - crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x]; - } - else - { - crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x]; - crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x]; - } - if (crMask == 0) - pBitmap[dwWidth*y + x] = 0xff000000 | crColor; - else - pBitmap[dwWidth*y + x] = 0x00000000; - - // It may be helpful to make the D3D cursor look slightly - // different from the Windows cursor so you can distinguish - // between the two when developing/testing code. When - // bAddWatermark is TRUE, the following code adds some - // small grey "D3D" characters to the upper-left corner of - // the D3D cursor image. - if( bAddWatermark && x < 12 && y < 5 ) - { - // 11.. 11.. 11.. .... CCC0 - // 1.1. ..1. 1.1. .... A2A0 - // 1.1. .1.. 1.1. .... A4A0 - // 1.1. ..1. 1.1. .... A2A0 - // 11.. 11.. 11.. .... CCC0 - - const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 }; - if( wMask[y] & (1 << (15 - x)) ) - { - pBitmap[dwWidth*y + x] |= 0xff808080; - } - } - } - } - pCursorBitmap->UnlockRect(); - - // Set the device cursor - if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot, - iconinfo.yHotspot, pCursorBitmap ) ) ) - { - goto End; - } - - hr = S_OK; - -End: - if( iconinfo.hbmMask != NULL ) - DeleteObject( iconinfo.hbmMask ); - if( iconinfo.hbmColor != NULL ) - DeleteObject( iconinfo.hbmColor ); - if( hdcScreen != NULL ) - ReleaseDC( NULL, hdcScreen ); - if( hdcColor != NULL ) - DeleteDC( hdcColor ); - if( hdcMask != NULL ) - DeleteDC( hdcMask ); - - SAFE_DELETE_ARRAY( pcrArrayColor ); - SAFE_DELETE_ARRAY( pcrArrayMask ); - RELEASE(pCursorBitmap,dxgsg9,"pCursorBitmap",RELEASE_ONCE); - return hr; -} - -#ifdef _DEBUG -// defns for print formatting in debugger -typedef struct { - float x,y,z; - float nx,ny,nz; - D3DCOLOR diffuse; - float u,v; -} POS_NORM_COLOR_TEX_VERTEX; - -typedef struct { - float x,y,z; - D3DCOLOR diffuse; - float u,v; -} POS_COLOR_TEX_VERTEX; - -typedef struct { - float x,y,z; - float u,v; -} POS_TEX_VERTEX; - -// define junk vars so symbols are included in dbginfo -POS_TEX_VERTEX junk11; -POS_COLOR_TEX_VERTEX junk22; -POS_NORM_COLOR_TEX_VERTEX junk33; -#endif - diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index ec0f78c778..ca23e176cb 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -1,10 +1,10 @@ -// Filename: dxGraphicsStateGuardian.h -// Created by: masad (02Jan04) +// Filename: dxGraphicsStateGuardian9.h +// Created by: mike (02Feb99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -16,343 +16,250 @@ // //////////////////////////////////////////////////////////////////// -#ifndef DXGRAPHICSSTATEGUARDIAN_H -#define DXGRAPHICSSTATEGUARDIAN_H - -//#define GSG_VERBOSE 1 +#ifndef DXGRAPHICSSTATEGUARDIAN9_H +#define DXGRAPHICSSTATEGUARDIAN9_H #include "dxgsg9base.h" #include "dxTextureContext9.h" -#include "d3dfont9.h" #include "config_dxgsg9.h" #include "graphicsStateGuardian.h" -#include "geomprimitives.h" #include "texture.h" -#include "texGenAttrib.h" #include "displayRegion.h" #include "material.h" #include "depthTestAttrib.h" +#include "cullFaceAttrib.h" #include "renderModeAttrib.h" #include "fog.h" #include "pointerToArray.h" class Light; -//#if defined(NOTIFY_DEBUG) || defined(DO_PSTATS) -//#ifdef _DEBUG -// is there something in DX9 to replace this? -#if 0 -// This function now serves both to print a debug message to the -// console, as well as to notify PStats about the change in texture -// memory. Thus, we compile it in if we are building with support for -// either notify debug messages or PStats; otherwise, we compile it -// out. -extern void dbgPrintVidMem(LPDIRECTDRAW7 pDD, LPDDSCAPS2 lpddsCaps,const char *pMsg); -#define PRINTVIDMEM(pDD,pCaps,pMsg) dbgPrintVidMem(pDD,pCaps,pMsg) -#else -#define PRINTVIDMEM(pDD,pCaps,pMsg) -#endif +class DXVertexBufferContext9; +class DXIndexBufferContext9; //////////////////////////////////////////////////////////////////// -// Class : DXGraphicsStateGuardian9 -// Description : A GraphicsStateGuardian specialized for rendering -// into DX. There should be no DX calls -// outside of this object. +// Class : DXGraphicsStateGuardian9 +// Description : A GraphicsStateGuardian for rendering into DirectX9 +// contexts. //////////////////////////////////////////////////////////////////// class EXPCL_PANDADX DXGraphicsStateGuardian9 : public GraphicsStateGuardian { - friend class wdxGraphicsWindow9; - friend class wdxGraphicsPipe9; - friend class wdxGraphicsWindowGroup9; - friend class DXTextureContext9; - public: DXGraphicsStateGuardian9(const FrameBufferProperties &properties); ~DXGraphicsStateGuardian9(); - virtual void reset(); + virtual TextureContext *prepare_texture(Texture *tex); + void apply_texture(int i, TextureContext *tc); + virtual void release_texture(TextureContext *tc); + + virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data); + void apply_vertex_buffer(VertexBufferContext *vbc); + virtual void release_vertex_buffer(VertexBufferContext *vbc); + + virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data); + void apply_index_buffer(IndexBufferContext *ibc); + virtual void release_index_buffer(IndexBufferContext *ibc); + + virtual PT(GeomMunger) make_geom_munger(const RenderState *state); + + virtual void set_color_clear_value(const Colorf &value); virtual void do_clear(const RenderBuffer &buffer); virtual void prepare_display_region(); virtual bool prepare_lens(); - virtual void draw_point(GeomPoint *geom, GeomContext *gc); - virtual void draw_line(GeomLine *geom, GeomContext *gc); - virtual void draw_linestrip(GeomLinestrip *geom, GeomContext *gc); - void draw_linestrip_base(Geom *geom, GeomContext *gc, bool bConnectEnds); - virtual void draw_sprite(GeomSprite *geom, GeomContext *gc); - virtual void draw_polygon(GeomPolygon *geom, GeomContext *gc); - virtual void draw_quad(GeomQuad *geom, GeomContext *gc); - virtual void draw_tri(GeomTri *geom, GeomContext *gc); - virtual void draw_tristrip(GeomTristrip *geom, GeomContext *gc); - virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc); - virtual void draw_sphere(GeomSphere *geom, GeomContext *gc); + virtual bool begin_frame(); + virtual bool begin_scene(); + virtual void end_scene(); + virtual void end_frame(); - virtual TextureContext *prepare_texture(Texture *tex); - void apply_texture(TextureContext *tc, int index); - virtual void release_texture(TextureContext *tc); + virtual bool begin_draw_primitives(const Geom *geom, + const GeomMunger *munger, + const GeomVertexData *vertex_data); + virtual void draw_triangles(const GeomTriangles *primitive); + virtual void draw_tristrips(const GeomTristrips *primitive); + virtual void draw_trifans(const GeomTrifans *primitive); + virtual void draw_lines(const GeomLines *primitive); + virtual void draw_linestrips(const GeomLinestrips *primitive); + virtual void draw_points(const GeomPoints *primitive); + virtual void end_draw_primitives(); virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb); - virtual void apply_material(const Material *material); + virtual void reset(); + virtual void apply_fog(Fog *fog); - virtual void issue_transform(const TransformState *transform); - virtual void issue_tex_matrix(const TexMatrixAttrib *attrib); - virtual void issue_tex_gen(const TexGenAttrib *attrib); - virtual void issue_texture(const TextureAttrib *attrib); - virtual void issue_material(const MaterialAttrib *attrib); - virtual void issue_render_mode(const RenderModeAttrib *attrib); - virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib); - virtual void issue_alpha_test(const AlphaTestAttrib *attrib); - virtual void issue_depth_test(const DepthTestAttrib *attrib); - virtual void issue_depth_write(const DepthWriteAttrib *attrib); - virtual void issue_color_write(const ColorWriteAttrib *attrib); - virtual void issue_cull_face(const CullFaceAttrib *attrib); - virtual void issue_fog(const FogAttrib *attrib); - virtual void issue_depth_offset(const DepthOffsetAttrib *attrib); - - virtual void bind_light(PointLight *light_obj, const NodePath &light, + virtual void bind_light(PointLight *light_obj, const NodePath &light, int light_id); - virtual void bind_light(DirectionalLight *light_obj, const NodePath &light, + virtual void bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id); - virtual void bind_light(Spotlight *light_obj, const NodePath &light, + virtual void bind_light(Spotlight *light_obj, const NodePath &light, int light_id); - virtual bool begin_frame(); - virtual bool begin_scene(); - virtual void end_scene(); - virtual void end_frame(); + static D3DFORMAT get_index_type(Geom::NumericType numeric_type); + INLINE static DWORD Colorf_to_D3DCOLOR(const Colorf &cColorf); - virtual bool wants_texcoords() const; - - virtual void set_color_clear_value(const Colorf& value); - -public: - // recreate_tex_callback needs these to be public - DXScreenData *_pScrn; - LPDIRECT3DDEVICE9 _pD3DDevice; // same as pScrn->_pD3DDevice, cached for spd - IDirect3DSwapChain9 *_pSwapChain; - D3DPRESENT_PARAMETERS _PresReset; // This is built during reset device + virtual void set_state_and_transform(const RenderState *state, + const TransformState *transform); protected: + void do_issue_transform(); + void do_issue_alpha_test(); + void do_issue_render_mode(); + void do_issue_rescale_normal(); + void do_issue_color_write(); + void do_issue_depth_test(); + void do_issue_depth_write(); + void do_issue_cull_face(); + void do_issue_fog(); + void do_issue_depth_offset(); + void do_issue_tex_gen(); + void do_issue_shade_model(); + void do_issue_material(); + void do_issue_texture(); + void do_issue_blending(); + virtual void enable_lighting(bool enable); virtual void set_ambient_light(const Colorf &color); virtual void enable_light(int light_id, bool enable); - virtual bool slot_new_clip_plane(int plane_id); virtual void enable_clip_plane(int plane_id, bool enable); virtual void bind_clip_plane(const NodePath &plane, int plane_id); - virtual void set_blend_mode(); - - void free_nondx_resources(); // free local internal buffers + void free_nondx_resources(); void free_d3d_device(); void set_draw_buffer(const RenderBuffer &rb); void set_read_buffer(const RenderBuffer &rb); - INLINE void add_to_FVFBuf(void *data, size_t bytes) ; - void do_auto_rescale_normal(); - bool _bDXisReady; - HRESULT _last_testcooplevel_result; - DXTextureContext9 *_pCurTexContext; +protected: + INLINE static D3DTEXTUREADDRESS get_texture_wrap_mode(Texture::WrapMode wm); + INLINE static D3DFOGMODE get_fog_mode_type(Fog::Mode m); + const D3DCOLORVALUE &get_light_color(Light *light) const; + INLINE static D3DTRANSFORMSTATETYPE get_tex_mat_sym(int stage_index); - bool _bTransformIssued; // decaling needs to tell when a transform has been issued - D3DMATRIX _SavedTransform; + static D3DBLEND get_blend_func(ColorBlendAttrib::Operand operand); + void report_texmgr_stats(); + + void set_context(DXScreenData *new_context); + void set_render_target(); + + void set_texture_blend_mode(int i, const TextureStage *stage); + + void dx_cleanup(); + HRESULT reset_d3d_device(D3DPRESENT_PARAMETERS *p_presentation_params, + DXScreenData **screen = NULL); + + bool check_cooperative_level(); + + void show_frame(); + + bool create_swap_chain (DXScreenData *new_context); + bool release_swap_chain (DXScreenData *new_context); + void copy_pres_reset(DXScreenData *new_context); + + static D3DTEXTUREFILTERTYPE get_d3d_min_type(Texture::FilterType filter_type); + static D3DTEXTUREFILTERTYPE get_d3d_mip_type(Texture::FilterType filter_type); + static D3DTEXTUREOP get_texture_operation(TextureStage::CombineMode mode, int scale); + static DWORD get_texture_argument(TextureStage::CombineSource source, + TextureStage::CombineOperand operand); + static DWORD get_texture_argument_modifier(TextureStage::CombineOperand operand); + + void draw_primitive_up(D3DPRIMITIVETYPE primitive_type, + unsigned int primitive_count, + unsigned int first_vertex, + unsigned int num_vertices, + const unsigned char *buffer, size_t stride); + void draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type, + unsigned int min_index, unsigned int max_index, + unsigned int num_primitives, + const unsigned char *index_data, + D3DFORMAT index_type, + const unsigned char *buffer, size_t stride); + + INLINE static unsigned char *get_safe_buffer_start(); + +protected: + DXScreenData *_screen; + LPDIRECT3DDEVICE9 _d3d_device; // same as _screen->_d3d_device, cached for spd + IDirect3DSwapChain9 *_swap_chain; + D3DPRESENT_PARAMETERS _presentation_reset; // This is built during reset device + + bool _dx_is_ready; + HRESULT _last_testcooplevel_result; + + bool _vertex_blending_enabled; RenderBuffer::Type _cur_read_pixel_buffer; // source for copy_pixel_buffer operation bool _auto_rescale_normal; - void GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize, - void *pIndexSpace,DWORD dwIndexSpaceByteSize, - D3DXVECTOR3 *pCenter, float fRadius, - DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz, - DWORD *pNumVertices,DWORD *pNumTris,DWORD fvfFlags,DWORD dwVertSize); - HRESULT ReleaseAllDeviceObjects(); - HRESULT RecreateAllDeviceObjects(); - HRESULT DeleteAllDeviceObjects(); - -/* - INLINE void enable_multisample_alpha_one(bool val); - INLINE void enable_multisample_alpha_mask(bool val); - INLINE void enable_multisample(bool val); -*/ - - INLINE void enable_color_material(bool val); - INLINE void enable_fog(bool val); - INLINE void enable_zwritemask(bool val); - INLINE void set_color_writemask(UINT color_writemask); - INLINE void enable_gouraud_shading(bool val); - INLINE void set_vertex_format(DWORD NewFvfType); - - INLINE D3DTEXTUREADDRESS get_texture_wrap_mode(Texture::WrapMode wm) const; - INLINE D3DFOGMODE get_fog_mode_type(Fog::Mode m) const; - - INLINE void enable_primitive_clipping(bool val); - INLINE void enable_alpha_test(bool val); - INLINE void enable_line_smooth(bool val); - INLINE void enable_blend(bool val); - INLINE void enable_point_smooth(bool val); - INLINE void enable_texturing(bool val); - INLINE void call_dxLightModelAmbient(const Colorf& color); - INLINE void call_dxAlphaFunc(D3DCMPFUNC func, float refval); - INLINE void call_dxBlendFunc(D3DBLEND sfunc, D3DBLEND dfunc); - static D3DBLEND get_blend_func(ColorBlendAttrib::Operand operand); - INLINE void enable_dither(bool val); - INLINE void enable_stencil_test(bool val); - void report_texmgr_stats(); - void draw_multitri(Geom *geom, D3DPRIMITIVETYPE tri_id); - - void draw_prim_inner_loop(int nVerts, const Geom *geom, ushort perFlags); - void draw_prim_inner_loop_coordtexonly(int nVerts, const Geom *geom); - size_t draw_prim_setup(const Geom *geom) ; - - // for drawing primitives - Normalf p_normal; // still used to hold G_OVERALL, G_PER_PRIM values - TexCoordf p_texcoord; - D3DCOLOR _curD3Dcolor; - DWORD _perPrim,_perVertex,_perComp; // these hold DrawLoopFlags bitmask values - DWORD _CurFVFType; - // for storage of the flexible vertex format - BYTE *_pCurFvfBufPtr,*_pFvfBufBasePtr; - WORD *_index_buf; // base of malloced array - - D3DCOLOR _scene_graph_color_D3DCOLOR; D3DCOLOR _d3dcolor_clear_value; -// D3DSHADEMODE _CurShadeMode; - bool _bGouraudShadingOn; UINT _color_writemask; - bool _bDrawPrimDoSetupVertexBuffer; // if true, draw methods just copy vertex data into pCurrentGeomContext - // iterators for primitives - Geom::VertexIterator vi; - Geom::NormalIterator ni; - Geom::TexCoordIterator ti; - Geom::ColorIterator ci; - - // these are used for fastpaths that bypass the iterators above - // pointers to arrays in current geom, used to traverse indexed and non-indexed arrays - Vertexf *_coord_array,*_pCurCoord; - ushort *_coordindex_array,*_pCurCoordIndex; - - TexCoordf *_texcoord_array,*_pCurTexCoord; - ushort *_texcoordindex_array,*_pCurTexCoordIndex; - -/* - PTA_Normalf _norms; - PTA_Colorf _colors; - PTA_ushort _cindexes,_nindexes; -*/ - - Colorf _lmodel_ambient; float _material_ambient; float _material_diffuse; float _material_specular; float _material_shininess; float _material_emission; - typedef enum {None, - PerVertexFog=D3DRS_FOGVERTEXMODE, - PerPixelFog=D3DRS_FOGTABLEMODE - } DxgsgFogType; - DxgsgFogType _doFogType; - bool _fog_enabled; -/* - TODO: cache fog state - float _fog_start,_fog_end,_fog_density,float _fog_color; -*/ + enum DxgsgFogType { + None, + PerVertexFog=D3DRS_FOGVERTEXMODE, + PerPixelFog=D3DRS_FOGTABLEMODE + }; + DxgsgFogType _do_fog_type; - float _alpha_func_refval; // d3d stores UINT, panda stores this as float. we store float - D3DCMPFUNC _alpha_func; - - D3DBLEND _blend_source_func; - D3DBLEND _blend_dest_func; - - bool _line_smooth_enabled; - bool _color_material_enabled; - bool _texturing_enabled; - bool _clipping_enabled; - bool _dither_enabled; - bool _stencil_test_enabled; - bool _blend_enabled; - bool _depth_test_enabled; - bool _depth_write_enabled; - bool _alpha_test_enabled; DWORD _clip_plane_bits; + CullFaceAttrib::Mode _cull_face_mode; + RenderModeAttrib::Mode _current_fill_mode; //point/wireframe/solid - RenderModeAttrib::Mode _current_fill_mode; //poinr/wireframe/solid - - // unused right now - //GraphicsChannel *_panda_gfx_channel; // cache the 1 channel dx supports - - // Cur Texture State - TextureStage::Mode _CurTexBlendMode; - D3DTEXTUREFILTERTYPE _CurTexMagFilter,_CurTexMinFilter,_CurTexMipFilter; - DWORD _CurTexAnisoDegree; - Texture::WrapMode _CurTexWrapModeU,_CurTexWrapModeV; - LMatrix4f _current_projection_mat; - int _projection_mat_stack_count; + LMatrix4f _projection_mat; CPT(DisplayRegion) _actual_display_region; - - // Color/Alpha Matrix Transition stuff - INLINE void transform_color(Colorf &InColor,D3DCOLOR &OutColor); + const DXVertexBufferContext9 *_active_vbuffer; + const DXIndexBufferContext9 *_active_ibuffer; bool _overlay_windows_supported; + bool _tex_stats_retrieval_impossible; -#if 0 - // This is here just as a temporary hack so this file will still - // compile. However, it is never initialized and will certainly - // cause the code to crash when it is referenced. (This used to be - // inherited from the base class, but the new design requires that a - // GSG may be used for multiple windows, so it doesn't make sense to - // store a single window pointer any more.) - GraphicsWindow *_win; -#endif + static D3DMATRIX _d3d_ident_mat; + + static unsigned char *_temp_buffer; + static unsigned char *_safe_buffer_start; public: - static GraphicsStateGuardian* - make_DXGraphicsStateGuardian9(const FactoryParams ¶ms); - void set_context(DXScreenData *pNewContextData); - void set_render_target(); - - static TypeHandle get_class_type(); - static void init_type(); - virtual TypeHandle get_type() const; + virtual TypeHandle get_type() const { + return get_class_type(); + } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - INLINE void SetDXReady(bool status) { _bDXisReady = status; } - INLINE bool GetDXReady() { return _bDXisReady;} - void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bJustEnable); - void dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled); - void reset_panda_gsg(); - HRESULT reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams, DXScreenData **pScrn=NULL); + static TypeHandle get_class_type() { + return _type_handle; + } - #define DO_REACTIVATE_WINDOW true - bool CheckCooperativeLevel(bool bDoReactivateWindow = false); - - void show_frame(bool bNoNewFrameDrawn = false); - void dx_init(); - - void support_overlay_window(bool flag); - - bool create_swap_chain (DXScreenData *pNewContextData); - bool release_swap_chain (DXScreenData *pNewContextData); - void copy_pres_reset(DXScreenData *pNewContextData); +public: + static void init_type() { + GraphicsStateGuardian::init_type(); + register_type(_type_handle, "DXGraphicsStateGuardian9", + GraphicsStateGuardian::get_class_type()); + } private: static TypeHandle _type_handle; + + friend class wdxGraphicsWindow9; + friend class wdxGraphicsPipe9; + friend class wdxGraphicsWindowGroup9; + friend class DXTextureContext9; }; -HRESULT CreateDX9Cursor(LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,BOOL bAddWatermark); +#include "dxGraphicsStateGuardian9.I" -#include "DXGraphicsStateGuardian9.I" #endif - diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.I b/panda/src/dxgsg9/dxIndexBufferContext9.I new file mode 100755 index 0000000000..6bcc3c4153 --- /dev/null +++ b/panda/src/dxgsg9/dxIndexBufferContext9.I @@ -0,0 +1,17 @@ +// Filename: dxIndexBufferContext9.I +// Created by: drose (18Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.cxx b/panda/src/dxgsg9/dxIndexBufferContext9.cxx new file mode 100755 index 0000000000..07821cdf3c --- /dev/null +++ b/panda/src/dxgsg9/dxIndexBufferContext9.cxx @@ -0,0 +1,132 @@ +// Filename: dxIndexBufferContext9.cxx +// Created by: drose (18Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "dxIndexBufferContext9.h" +#include "geomPrimitive.h" +#include "config_dxgsg9.h" +#include "graphicsStateGuardian.h" +#include "pStatTimer.h" +#include + +TypeHandle DXIndexBufferContext9::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: DXIndexBufferContext9::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DXIndexBufferContext9:: +DXIndexBufferContext9(GeomPrimitive *data) : + IndexBufferContext(data), + _ibuffer(NULL) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: DXIndexBufferContext9::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DXIndexBufferContext9:: +~DXIndexBufferContext9() { + if (_ibuffer != NULL) { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "deleting index buffer " << _ibuffer << "\n"; + } + + RELEASE(_ibuffer, dxgsg9, "index buffer", RELEASE_ONCE); + _ibuffer = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXIndexBufferContext9::create_ibuffer +// Access: Public +// Description: Creates a new index buffer (but does not upload data +// to it). +//////////////////////////////////////////////////////////////////// +void DXIndexBufferContext9:: +create_ibuffer(DXScreenData &scrn) { + if (_ibuffer != NULL) { + RELEASE(_ibuffer, dxgsg9, "index buffer", RELEASE_ONCE); + _ibuffer = NULL; + } + + PStatTimer timer(GraphicsStateGuardian::_create_index_buffer_pcollector); + + D3DFORMAT index_type = + DXGraphicsStateGuardian9::get_index_type(get_data()->get_index_type()); + + HRESULT hr = scrn._d3d_device->CreateIndexBuffer + +// (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY, +// index_type, D3DPOOL_MANAGED, &_ibuffer, NULL); + (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, + index_type, D3DPOOL_DEFAULT, &_ibuffer, NULL); + + if (FAILED(hr)) { + dxgsg9_cat.warning() + << "CreateIndexBuffer failed" << D3DERRORSTRING(hr); + _ibuffer = NULL; + } else { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "creating index buffer " << _ibuffer << ": " + << get_data()->get_num_vertices() << " indices (" + << get_data()->get_vertices()->get_array_format()->get_column(0)->get_numeric_type() + << ")\n"; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXIndexBufferContext9::upload_data +// Access: Public +// Description: Copies the latest data from the client store to +// DirectX. +//////////////////////////////////////////////////////////////////// +void DXIndexBufferContext9:: +upload_data() { + nassertv(_ibuffer != NULL); + PStatTimer timer(GraphicsStateGuardian::_load_index_buffer_pcollector); + + int data_size = get_data()->get_data_size_bytes(); + + if (dxgsg9_cat.is_spam()) { + dxgsg9_cat.spam() + << "copying " << data_size + << " bytes into index buffer " << _ibuffer << "\n"; + } + + BYTE *local_pointer; + +// HRESULT hr = _ibuffer->Lock(0, data_size, (void **) &local_pointer, 0); + HRESULT hr = _ibuffer->Lock(0, data_size, (void **) &local_pointer, D3DLOCK_DISCARD); + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "IndexBuffer::Lock failed" << D3DERRORSTRING(hr); + return; + } + + GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size); + memcpy(local_pointer, get_data()->get_data(), data_size); + + _ibuffer->Unlock(); +} diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.h b/panda/src/dxgsg9/dxIndexBufferContext9.h new file mode 100755 index 0000000000..c085fb25e2 --- /dev/null +++ b/panda/src/dxgsg9/dxIndexBufferContext9.h @@ -0,0 +1,61 @@ +// Filename: dxIndexBufferContext9.h +// Created by: drose (18Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DXINDEXBUFFERCONTEXT9_H +#define DXINDEXBUFFERCONTEXT9_H + +#include "pandabase.h" +#include "dxgsg9base.h" +#include "indexBufferContext.h" + +//////////////////////////////////////////////////////////////////// +// Class : DXIndexBufferContext9 +// Description : Caches a GeomPrimitive in the DirectX device as +// an index buffer. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX DXIndexBufferContext9 : public IndexBufferContext { +public: + DXIndexBufferContext9(GeomPrimitive *data); + virtual ~DXIndexBufferContext9(); + + void create_ibuffer(DXScreenData &scrn); + void upload_data(); + + IDirect3DIndexBuffer9 *_ibuffer; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + IndexBufferContext::init_type(); + register_type(_type_handle, "DXIndexBufferContext9", + IndexBufferContext::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "dxIndexBufferContext9.I" + +#endif diff --git a/panda/src/dxgsg9/dxInput9.cxx b/panda/src/dxgsg9/dxInput9.cxx index 40b0c9e303..408825434a 100755 --- a/panda/src/dxgsg9/dxInput9.cxx +++ b/panda/src/dxgsg9/dxInput9.cxx @@ -1,10 +1,10 @@ -// Filename: dxInput8.cxx -// Created by: masad (02Jan04) +// Filename: dxInput9.cxx +// Created by: angelina jolie (07Oct99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -102,7 +102,7 @@ bool DInput9Info::InitDirectInput() { return true; } -bool DInput9Info::CreateJoystickOrPad(HWND hWnd) { +bool DInput9Info::CreateJoystickOrPad(HWND _window) { bool bFoundDev = false; UINT devnum=0; char *errstr=NULL; @@ -156,7 +156,7 @@ bool DInput9Info::CreateJoystickOrPad(HWND hWnd) { // Set the cooperative level to let DInput know how this device should // interact with the system and with other DInput applications. - hr = pJoyDevice->SetCooperativeLevel( hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND); + hr = pJoyDevice->SetCooperativeLevel( _window, DISCL_EXCLUSIVE | DISCL_FOREGROUND); if(FAILED(hr)) { errstr="SetCooperativeLevel"; goto handle_error; @@ -272,5 +272,3 @@ bool DInput9Info::ReadJoystick(int devnum, DIJOYSTATE2 &js) { wdxdisplay_cat.fatal() << errstr << D3DERRORSTRING(hr); return false; } - - diff --git a/panda/src/dxgsg9/dxInput9.h b/panda/src/dxgsg9/dxInput9.h index cd7d14a546..22fc10dc68 100755 --- a/panda/src/dxgsg9/dxInput9.h +++ b/panda/src/dxgsg9/dxInput9.h @@ -1,10 +1,10 @@ -// Filename: dxInput8.h -// Created by: masad (02Jan04) +// Filename: dxInput9.h +// Created by: blllyjo (07Oct99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -19,7 +19,7 @@ #ifndef DXINPUT9_H #define DXINPUT9_H -#define DIRECTINPUT_VERSION 0x800 +#define DIRECTINPUT_VERSION 0x900 #include typedef vector DI_DeviceInfos; typedef vector DI_DeviceObjInfos; @@ -29,7 +29,7 @@ public: DInput9Info(); ~DInput9Info(); bool InitDirectInput(); - bool CreateJoystickOrPad(HWND hWnd); + bool CreateJoystickOrPad(HWND _window); bool ReadJoystick(int devnum, DIJOYSTATE2 &js); HINSTANCE _hDInputDLL; @@ -43,3 +43,4 @@ public: }; #endif + diff --git a/panda/src/dxgsg9/dxTextureContext9.I b/panda/src/dxgsg9/dxTextureContext9.I new file mode 100755 index 0000000000..a104041608 --- /dev/null +++ b/panda/src/dxgsg9/dxTextureContext9.I @@ -0,0 +1,73 @@ +// Filename: dxTextureContext9.I +// Created by: drose (23May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::has_mipmaps +// Access: Public +// Description: Returns true if the texture was created with mipmaps, +// false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool DXTextureContext9:: +has_mipmaps() const { + return _has_mipmaps; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::get_d3d_texture +// Access: Public +// Description: Returns the Direct3D object that represents the +// texture, whatever kind of texture it is. +//////////////////////////////////////////////////////////////////// +INLINE IDirect3DBaseTexture9 *DXTextureContext9:: +get_d3d_texture() const { + return _d3d_texture; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::get_d3d_2d_texture +// Access: Public +// Description: Returns the Direct3D object that represents the +// texture, in the case of a 1-d or 2-d texture. +//////////////////////////////////////////////////////////////////// +INLINE IDirect3DTexture9 *DXTextureContext9:: +get_d3d_2d_texture() const { + return _d3d_2d_texture; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::get_d3d_volume_texture +// Access: Public +// Description: Returns the Direct3D object that represents the +// texture, in the case of a 3-d texture. +//////////////////////////////////////////////////////////////////// +INLINE IDirect3DVolumeTexture9 *DXTextureContext9:: +get_d3d_volume_texture() const { + return _d3d_volume_texture; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::get_d3d_cube_texture +// Access: Public +// Description: Returns the Direct3D object that represents the +// texture, in the case of a cube map texture. +//////////////////////////////////////////////////////////////////// +INLINE IDirect3DCubeTexture9 *DXTextureContext9:: +get_d3d_cube_texture() const { + return _d3d_cube_texture; +} diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index d61d060155..38b03eee3c 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -1,10 +1,10 @@ -// Filename: dxTextureContext8.cxx -// Created by: masad (02Jan04) +// Filename: dxTextureContext9.cxx +// Created by: georges (02Feb02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -16,1079 +16,17 @@ // //////////////////////////////////////////////////////////////////// -#include -#include #include "dxTextureContext9.h" #include "config_dxgsg9.h" #include "dxGraphicsStateGuardian9.h" -//#include "pnmImage.h" +#include "pStatTimer.h" #include - -//#define FORCE_16bpp_1555 -static const DWORD g_LowByteMask = 0x000000FF; - -#define PANDA_BGRA_ORDER - -#ifdef PANDA_BGRA_ORDER -// assume Panda uses byte-order BGRA/LA to store pixels, which when read into little-endian word is ARGB/AL -// these macros GET from Texture, (wont work from DDSurface) -#define GET_RED_BYTE(PIXEL_DWORD) ((BYTE)((PIXEL_DWORD >> 16) & g_LowByteMask)) -#define GET_BLUE_BYTE(PIXEL_DWORD) ((BYTE)((PIXEL_DWORD) & g_LowByteMask)) -#else -// otherwise Panda uses int ABGR (big-endian RGBA order), (byte-order RGBA or RGB) -#define GET_RED_BYTE(PIXEL_DWORD) ((BYTE)(PIXEL_DWORD & g_LowByteMask)) -#define GET_BLUE_BYTE(PIXEL_DWORD) ((BYTE)((PIXEL_DWORD >> 16) & g_LowByteMask)) -#endif - -#define GET_GREEN_BYTE(PIXEL_DWORD) ((BYTE)((PIXEL_DWORD >> 8) & g_LowByteMask)) -#define GET_ALPHA_BYTE(PIXEL_DWORD) ((BYTE)(((DWORD)PIXEL_DWORD) >> 24)) // unsigned >> shifts in 0's, so dont need to mask off upper bits - -char *PandaFilterNameStrs[] = {"FT_nearest","FT_linear","FT_nearest_mipmap_nearest","FT_linear_mipmap_nearest", - "FT_nearest_mipmap_linear", "FT_linear_mipmap_linear" -}; - +#include +#include TypeHandle DXTextureContext9::_type_handle; -#define SWAPDWORDS(X,Y) { DWORD temp=X; X=Y; Y=temp; } - -#ifdef _DEBUG -/* -static void DebugPrintPixFmt(DDPIXELFORMAT* pddpf) { - static int iddpfnum=0; - ostream *dbgout = &dxgsg_cat.debug(); - - *dbgout << "DDPF[" << iddpfnum << "]: RGBBitCount:" << pddpf->dwRGBBitCount - << " Flags:" << (void *)pddpf->dwFlags ; - - if(pddpf->dwFlags & DDPF_RGB) { - *dbgout << " RGBmask:" << (void *) (pddpf->dwRBitMask | pddpf->dwGBitMask | pddpf->dwBBitMask); - *dbgout << " Rmask:" << (void *) (pddpf->dwRBitMask); - } - - if(pddpf->dwFlags & DDPF_ALPHAPIXELS) { - *dbgout << " Amask:" << (void *) pddpf->dwRGBAlphaBitMask; - } - - if(pddpf->dwFlags & DDPF_LUMINANCE) { - *dbgout << " Lummask:" << (void *) pddpf->dwLuminanceBitMask; - } - - *dbgout << endl; - - iddpfnum++; -} -*/ -void PrintLastError(char *msgbuf) { - DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; - - if(msgbuf==NULL) { - LPVOID lpMsgBuf; - dwFlags|=FORMAT_MESSAGE_ALLOCATE_BUFFER; - FormatMessage( dwFlags, - NULL,GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf,0,NULL ); - MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION ); - LocalFree(lpMsgBuf); - } else { - FormatMessage( dwFlags, - NULL,GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) msgbuf,500,NULL ); - } -} - -#endif - - -/* for reference -enum Format { - F_color_index, - F_stencil_index, - F_depth_component, - F_red, - F_green, - F_blue, - F_alpha, - F_rgb, // any suitable RGB mode, whatever the hardware prefers - F_rgb5, // specifically, 5 bits per R,G,B channel - F_rgb8, // 8 bits per R,G,B channel - F_rgb12, // 12 bits per R,G,B channel - F_rgb332, // 3 bits per R & G, 2 bits for B - F_rgba, // any suitable RGBA mode, whatever the hardware prefers - F_rgbm, // as above, but only requires 1 bit for alpha (i.e. mask) - F_rgba4, // 4 bits per R,G,B,A channel - F_rgba5, // 5 bits per R,G,B channel, 1 bit alpha - F_rgba8, // 8 bits per R,G,B,A channel - F_rgba12, // 12 bits per R,G,B,A channel - F_luminance, - F_luminance_alpha -}; - - enum Type { - T_unsigned_byte, // 1 byte per channel - T_unsigned_short, // 2 byte per channel - T_unsigned_byte_332, // RGB in 1 byte - T_float, // 1 channel stored as float - }; -*/ - -//////////////////////////////////////////////////////////////////// -// Function: DXTextureContext9::get_bits_per_pixel -// Access: Protected -// Description: Maps from the Texture's Format symbols -// to bpp. returns # of alpha bits -// Note: Texture's format indicates REQUESTED final format, -// not the stored format, which is indicated by pixelbuffer type -//////////////////////////////////////////////////////////////////// - -unsigned int DXTextureContext9:: -get_bits_per_pixel(Texture::Format format, int *alphbits) { - *alphbits = 0; // assume no alpha bits - switch(format) { - case Texture::F_alpha: - *alphbits = 8; - case Texture::F_color_index: - case Texture::F_red: - case Texture::F_green: - case Texture::F_blue: - case Texture::F_rgb332: - return 8; - case Texture::F_luminance_alphamask: - *alphbits = 1; - return 16; - case Texture::F_luminance_alpha: - *alphbits = 8; - return 16; - case Texture::F_luminance: - return 8; - case Texture::F_rgba4: - *alphbits = 4; - return 16; - case Texture::F_rgba5: - *alphbits = 1; - return 16; - case Texture::F_depth_component: - case Texture::F_rgb5: - return 16; - case Texture::F_rgb8: - case Texture::F_rgb: - return 24; - case Texture::F_rgba8: - case Texture::F_rgba: - case Texture::F_rgbm: - if(format==Texture::F_rgbm) // does this make any sense? - *alphbits = 1; - else *alphbits = 8; - return 32; - case Texture::F_rgb12: - return 36; - case Texture::F_rgba12: - *alphbits = 12; - return 48; - } - return 8; -} - -// still need custom conversion since d3d/d3dx has no way to convert arbitrary fmt to ARGB in-memory user buffer -HRESULT ConvertD3DSurftoPixBuf(RECT &SrcRect,IDirect3DSurface9 *pD3DSurf9,Texture *texture) { -// copies SrcRect in pD3DSurf to upper left of texture - HRESULT hr; - DWORD dwNumComponents=texture->get_num_components(); - - assert(texture->get_component_width()==sizeof(BYTE)); // cant handle anything else now - assert(texture->get_component_type()==Texture::T_unsigned_byte); // cant handle anything else now - assert((dwNumComponents==3) || (dwNumComponents==4)); // cant handle anything else now - assert(IS_VALID_PTR(pD3DSurf9)); - - BYTE *pbuf=texture->modify_ram_image().p(); - - if(IsBadWritePtr(pD3DSurf9,sizeof(DWORD))) { - dxgsg9_cat.error() << "ConvertDDSurftoTexture failed: bad pD3DSurf ptr value (" << ((void*)pD3DSurf9) << ")\n"; - exit(1); - } - - DWORD dwXWindowOffset,dwYWindowOffset; - DWORD dwCopyWidth,dwCopyHeight; - - D3DLOCKED_RECT LockedRect; - D3DSURFACE_DESC SurfDesc; - - hr = pD3DSurf9->GetDesc(&SurfDesc); - - dwXWindowOffset=SrcRect.left,dwYWindowOffset=SrcRect.top; - dwCopyWidth=RECT_XSIZE(SrcRect); - dwCopyHeight=RECT_YSIZE(SrcRect); - - //make sure there's enough space in the texture, its size must match (especially xsize) - // or scanlines will be too long - - if(!((dwCopyWidth==texture->get_x_size()) && (dwCopyHeight<=(DWORD)texture->get_y_size()))) { - dxgsg9_cat.error() << "ConvertDDSurftoPixBuf, Texture size too small to hold display surface!\n"; - assert(0); - return E_FAIL; - } - - hr = pD3DSurf9->LockRect(&LockedRect,(CONST RECT*)NULL,(D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE /* | D3DLOCK_NOSYSLOCK */)); - if(FAILED(hr)) { - dxgsg9_cat.error() << "ConvertDDSurftoPixBuf LockRect() failed!" << D3DERRORSTRING(hr); - return hr; - } - - // ones not listed not handled yet - assert((SurfDesc.Format==D3DFMT_A8R8G8B8)||(SurfDesc.Format==D3DFMT_X8R8G8B8)||(SurfDesc.Format==D3DFMT_R8G8B8)|| - (SurfDesc.Format==D3DFMT_R5G6B5)||(SurfDesc.Format==D3DFMT_X1R5G5B5)||(SurfDesc.Format==D3DFMT_A1R5G5B5)|| - (SurfDesc.Format==D3DFMT_A4R4G4B4)); - - //pbuf contains raw ARGB in Texture byteorder - - DWORD BytePitch = LockedRect.Pitch; - BYTE* pSurfBytes = (BYTE*)LockedRect.pBits; - - // writes out last line in DDSurf first in PixelBuf, so Y line order precedes inversely - - if(dxgsg9_cat.is_debug()) { - dxgsg9_cat.debug() - << "ConvertD3DSurftoPixBuf converting " << D3DFormatStr(SurfDesc.Format) << "bpp DDSurf to " - << dwNumComponents << "-channel panda Texture\n"; - } - - DWORD *pDstWord = (DWORD *) pbuf; - BYTE *pDstByte = (BYTE *) pbuf; - - switch(SurfDesc.Format) { - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: { - if(dwNumComponents==4) { - DWORD *pSrcWord; - #ifdef PANDA_BGRA_ORDER - BYTE *pDstLine = (BYTE*)pDstWord; - #endif - - pSurfBytes+=BytePitch*(dwYWindowOffset+dwCopyHeight-1); - for(DWORD y=0; y> 16) & g_LowByteMask); - b = (BYTE) (dwPixel & g_LowByteMask); - - // want to write out ABGR - *pDstWord = (dwPixel & 0xFF00FF00) | (b<<16) | r; - } - #endif - } - } else { - // 24bpp texture case (numComponents==3) - DWORD *pSrcWord; - pSurfBytes+=BytePitch*(dwYWindowOffset+dwCopyHeight-1); - for(DWORD y=0; y>16) & g_LowByteMask); - g = (BYTE)((dwPixel>> 8) & g_LowByteMask); - b = (BYTE)((dwPixel ) & g_LowByteMask); - - #ifdef PANDA_BGRA_ORDER - *pDstByte++ = b; - *pDstByte++ = g; - *pDstByte++ = r; - #else - *pDstByte++ = r; - *pDstByte++ = g; - *pDstByte++ = b; - #endif - } - } - } - break; - } - - case D3DFMT_R8G8B8: { - BYTE *pSrcByte; - pSurfBytes+=BytePitch*(dwYWindowOffset+dwCopyHeight-1); - - if(dwNumComponents==4) { - for(DWORD y=0; y> greenshift; - r = (dwPixel & redmask) >> redshift; - - // alpha is just set to 0xFF - - #ifdef PANDA_BGRA_ORDER - *pDstWord = 0xFF000000 | (r << 16) | (g << 8) | b; - #else - *pDstWord = 0xFF000000 | (b << 16) | (g << 8) | r; - #endif - } - } - } else { - // 24bpp texture case (numComponents==3) - for(DWORD y=0; y> greenshift; - r = (dwPixel & redmask) >> redshift; - - #ifdef PANDA_BGRA_ORDER - *pDstByte++ = b; - *pDstByte++ = g; - *pDstByte++ = r; - #else - *pDstByte++ = r; - *pDstByte++ = g; - *pDstByte++ = b; - #endif - } - } - } - break; - } - - default: - dxgsg9_cat.error() << "ConvertD3DSurftoPixBuf: unsupported D3DFORMAT!\n"; - } - - pD3DSurf9->UnlockRect(); - return S_OK; -} - -//----------------------------------------------------------------------------- -// Name: CreateTexture() -// Desc: Use panda texture's pixelbuffer to create a texture for the specified device. -// This code gets the attributes of the texture from the bitmap, creates the -// texture, and then copies the bitmap into the texture. -//----------------------------------------------------------------------------- -IDirect3DTexture9 *DXTextureContext9::CreateTexture(DXScreenData &scrn) { - HRESULT hr; - int cNumAlphaBits; // number of alpha bits in texture pixfmt - D3DFORMAT TargetPixFmt=D3DFMT_UNKNOWN; - bool bNeedLuminance = false; - - assert(IS_VALID_PTR(_texture)); - - // bpp indicates requested fmt, not texture fmt - DWORD target_bpp = get_bits_per_pixel(_texture->get_format(), &cNumAlphaBits); - DWORD cNumColorChannels = _texture->get_num_components(); - - //PRINT_REFCNT(dxgsg9,scrn.pD3D9); - - DWORD dwOrigWidth = (DWORD)_texture->get_x_size(); - DWORD dwOrigHeight = (DWORD)_texture->get_y_size(); - - if((_texture->get_format() == Texture::F_luminance_alpha)|| - (_texture->get_format() == Texture::F_luminance_alphamask) || - (_texture->get_format() == Texture::F_luminance)) { - bNeedLuminance = true; - } - - if(cNumAlphaBits>0) { - if(cNumColorChannels==3) { - dxgsg9_cat.error() << "ERROR: texture " << _tex->get_name() << " has no inherent alpha channel, but alpha format is requested (that would be wasteful)!\n"; - exit(1); - } - } - - _PixBufD3DFmt=D3DFMT_UNKNOWN; - - // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows how to perform copy - - switch(cNumColorChannels) { - case 1: - if(cNumAlphaBits>0) - _PixBufD3DFmt=D3DFMT_A8; - else if(bNeedLuminance) - _PixBufD3DFmt=D3DFMT_L8; - break; - case 2: - assert(bNeedLuminance && (cNumAlphaBits>0)); - _PixBufD3DFmt=D3DFMT_A8L8; - break; - case 3: - _PixBufD3DFmt=D3DFMT_R8G8B8; - break; - case 4: - _PixBufD3DFmt=D3DFMT_A8R8G8B8; - break; - } - - // make sure we handled all the possible cases - assert(_PixBufD3DFmt!=D3DFMT_UNKNOWN); - - DWORD TargetWidth=dwOrigWidth; - DWORD TargetHeight=dwOrigHeight; - - if(!ISPOW2(dwOrigWidth) || !ISPOW2(dwOrigHeight)) { - dxgsg9_cat.error() << "ERROR: texture dimensions are not a power of 2 for " << _tex->get_name() << "! Please rescale them so it doesnt have to be done at runtime.\n"; - #ifndef NDEBUG - exit(1); // want to catch badtexsize errors - #else - goto error_exit; - #endif - } - - bool bShrinkOriginal; - bShrinkOriginal=false; - - if((dwOrigWidth>scrn.d3dcaps.MaxTextureWidth)||(dwOrigHeight>scrn.d3dcaps.MaxTextureHeight)) { - #ifdef _DEBUG - dxgsg9_cat.error() << "WARNING: " <<_tex->get_name() << ": Image size exceeds max texture dimensions of (" << scrn.d3dcaps.MaxTextureWidth << "," << scrn.d3dcaps.MaxTextureHeight << ") !!\n" - << "Scaling "<< _tex->get_name() << " ("<< dwOrigWidth<<"," < ("<< scrn.d3dcaps.MaxTextureWidth << "," << scrn.d3dcaps.MaxTextureHeight << ") !\n"; - #endif - - if(dwOrigWidth>scrn.d3dcaps.MaxTextureWidth) - TargetWidth=scrn.d3dcaps.MaxTextureWidth; - if(dwOrigHeight>scrn.d3dcaps.MaxTextureHeight) - TargetHeight=scrn.d3dcaps.MaxTextureHeight; - bShrinkOriginal=true; - } - - // checks for SQUARE reqmt (nvidia riva128 needs this) - if((TargetWidth != TargetHeight) && (scrn.d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)) { - // assume pow2 textures. sum exponents, divide by 2 rounding down to get sq size - int i,width_exp,height_exp; - for(i=TargetWidth,width_exp=0;i>1;width_exp++,i>>=1); - for(i=TargetHeight,height_exp=0;i>1;height_exp++,i>>=1); - TargetHeight = TargetWidth = 1<<((width_exp+height_exp)>>1); - bShrinkOriginal=true; - -#ifdef _DEBUG - dxgsg9_cat.debug() << "Scaling "<< _tex->get_name() << " ("<< dwOrigWidth<<"," < ("<< TargetWidth<<"," << TargetHeight << ") to meet HW square texture reqmt\n"; -#endif - } -/* - // we now use D3DXLoadSurfFromMem to do resizing as well as fmt conversion - if(bShrinkOriginal) { - // need 2 add checks for errors - PNMImage pnmi_src; - PNMImage *pnmi = new PNMImage(TargetWidth, TargetHeight, cNumColorChannels); - _texture->store(pnmi_src); - pnmi->quick_filter_from(pnmi_src,0,0); - - _texture->load(*pnmi); // violates device independence of pixbufs - - dwOrigWidth = (DWORD)_texture->get_x_size(); - dwOrigHeight = (DWORD)_texture->get_y_size(); - delete pnmi; - } -*/ - - char *szErrorMsg; - - szErrorMsg = "CreateTexture failed: couldn't find compatible device Texture Pixel Format for input texture"; - - if(dxgsg9_cat.is_spam()) - dxgsg9_cat.spam() << "CreateTexture handling target bitdepth: " << target_bpp << " alphabits: " << cNumAlphaBits << endl; - - // I could possibly replace some of this logic with D3DXCheckTextureRequirements(), but - // it wouldnt handle all my specialized low-memory cases perfectly - -#define CONVTYPE_STMT - -#define CHECK_FOR_FMT(FMT,CONV) \ - if(scrn.SupportedTexFmtsMask & FMT##_FLAG) { \ - CONVTYPE_STMT; \ - TargetPixFmt=D3DFMT_##FMT; \ - goto found_matching_format; } - - // handle each target bitdepth separately. might be less confusing to reorg by cNumColorChannels (input type, rather - // than desired 1st target) - switch(target_bpp) { - - // IMPORTANT NOTE: - // target_bpp is REQUESTED bpp, not what exists in the texture array (the texture array contains cNumColorChannels*8bits) - - case 32: - if(!((cNumColorChannels==3) || (cNumColorChannels==4))) - break; //bail - - if(!dx_force_16bpptextures) { - if(cNumColorChannels==4) { - CHECK_FOR_FMT(A8R8G8B8,Conv32to32); - } else { - CHECK_FOR_FMT(A8R8G8B8,Conv24to32); - } - } - - if(cNumAlphaBits>0) { - assert(cNumColorChannels==4); - - // no 32-bit fmt, look for 16 bit w/alpha (1-15) - - // 32 bit RGBA was requested, but only 16 bit alpha fmts are avail - // by default, convert to 4-4-4-4 which has 4-bit alpha for blurry edges - // if we know tex only needs 1 bit alpha (i.e. for a mask), use 1555 instead - -// ConversionType ConvTo1=Conv32to16_4444,ConvTo2=Conv32to16_1555; -// DWORD dwAlphaMask1=0xF000,dwAlphaMask2=0x8000; - // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify 32->16 conversion - // this should be true on most cards. - -#ifndef FORCE_16bpp_1555 - if(cNumAlphaBits==1) -#endif - { - CHECK_FOR_FMT(A1R5G5B5,Conv32to16_1555); - } - - // normally prefer 4444 due to better alpha channel resolution - CHECK_FOR_FMT(A4R4G4B4,Conv32to16_4444); - CHECK_FOR_FMT(A1R5G5B5,Conv32to16_1555); - - // at this point, bail. dont worry about converting to non-alpha formats yet, - // I think this will be a very rare case - szErrorMsg = "CreateTexture failed: couldn't find compatible Tex DDPIXELFORMAT! no available 16 or 32-bit alpha formats!"; - } else { - // convert 3 or 4 channel to closest 16bpp color fmt - - if(cNumColorChannels==3) { - CHECK_FOR_FMT(R5G6B5,Conv24to16_4444); - CHECK_FOR_FMT(X1R5G5B5,Conv24to16_X555); - } else { - CHECK_FOR_FMT(R5G6B5,Conv32to16_4444); - CHECK_FOR_FMT(X1R5G5B5,Conv32to16_X555); - } - } - break; - - case 24: - assert(cNumColorChannels==3); - - if(!dx_force_16bpptextures) { - CHECK_FOR_FMT(R8G8B8,Conv24to24); - - // no 24-bit fmt. look for 32 bit fmt (note: this is memory-hogging choice - // instead I could look for memory-conserving 16-bit fmt). - - CHECK_FOR_FMT(X8R8G8B8,Conv24to32); - } - - // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st) - CHECK_FOR_FMT(R5G6B5,Conv24to16_0565); - CHECK_FOR_FMT(X1R5G5B5,Conv24to16_X555); - break; - - case 16: - if(bNeedLuminance) { - assert(cNumAlphaBits>0); - assert(cNumColorChannels==2); - - CHECK_FOR_FMT(A8L8,ConvLum16to16); - - if(!dx_force_16bpptextures) { - CHECK_FOR_FMT(A8R8G8B8,ConvLum16to32); - } - - #ifndef FORCE_16bpp_1555 - if(cNumAlphaBits==1) - #endif - { - CHECK_FOR_FMT(A1R5G5B5,ConvLum16to16_1555); - } - - // normally prefer 4444 due to better alpha channel resolution - CHECK_FOR_FMT(A4R4G4B4,ConvLum16to16_4444); - CHECK_FOR_FMT(A1R5G5B5,ConvLum16to16_1555); - } else { - assert((cNumColorChannels==3)||(cNumColorChannels==4)); - // look for compatible 16bit fmts, if none then give up - // (dont worry about other bitdepths for 16 bit) - switch(cNumAlphaBits) { - case 0: - if(cNumColorChannels==3) { - CHECK_FOR_FMT(R5G6B5,Conv24to16_0565); - CHECK_FOR_FMT(X1R5G5B5,Conv24to16_X555); - } else { - assert(cNumColorChannels==4); - // it could be 4 if user asks us to throw away the alpha channel - CHECK_FOR_FMT(R5G6B5,Conv32to16_0565); - CHECK_FOR_FMT(X1R5G5B5,Conv32to16_X555); - } - break; - case 1: - // app specifically requests 1-5-5-5 F_rgba5 case, where you explicitly want 1-5-5-5 fmt, as opposed - // to F_rgbm, which could use 32bpp ARGB. fail if this particular fmt not avail. - assert(cNumColorChannels==4); - CHECK_FOR_FMT(X1R5G5B5,Conv32to16_X555); - break; - case 4: - // app specifically requests 4-4-4-4 F_rgba4 case, as opposed to F_rgba, which could use 32bpp ARGB - assert(cNumColorChannels==4); - CHECK_FOR_FMT(A4R4G4B4,Conv32to16_4444); - break; - default: assert(0); // problem in get_bits_per_pixel()? - } - } - case 8: - if(bNeedLuminance) { - // dont bother handling those other 8bit lum fmts like 4-4, since 16 8-8 is usually supported too - assert(cNumColorChannels==1); - - // look for native lum fmt first - CHECK_FOR_FMT(L8,ConvLum8to8); - CHECK_FOR_FMT(L8,ConvLum8to16_A8L8); - - if(!dx_force_16bpptextures) { - CHECK_FOR_FMT(R8G8B8,ConvLum8to24); - CHECK_FOR_FMT(X8R8G8B8,ConvLum8to32); - } - - CHECK_FOR_FMT(R5G6B5,ConvLum8to16_0565); - CHECK_FOR_FMT(X1R5G5B5,ConvLum8to16_X555); - - } else if(cNumAlphaBits==8) { - // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444. - - // skip 8bit alpha only (D3DFMT_A8), because I think only voodoo supports it - // and the voodoo support isn't the kind of blending model we need somehow - // (is it that voodoo assumes color is white? isnt that what we do in ConvAlpha8to32 anyway?) - - CHECK_FOR_FMT(A8L8,ConvAlpha8to16_A8L8); - - if(!dx_force_16bpptextures) { - CHECK_FOR_FMT(A8R8G8B8,ConvAlpha8to32); - } - - CHECK_FOR_FMT(A4R4G4B4,ConvAlpha8to16_4444); - } - break; - - default: - szErrorMsg = "CreateTexture failed: unhandled pixel bitdepth in DX loader"; - } - - // if we've gotten here, haven't found a match - dxgsg9_cat.error() << szErrorMsg << ": " << _tex->get_name() << endl - << "NumColorChannels: " <get_match_framebuffer_format()) { - // Instead of creating a texture with the found format, we will - // need to make one that exactly matches the framebuffer's - // format. Look up what that format is. - IDirect3DSurface9 *pCurRenderTarget; - hr = scrn.pD3DDevice->GetRenderTarget(0, &pCurRenderTarget); - if(FAILED(hr)) { - dxgsg9_cat.error() << "GetRenderTgt failed in CreateTexture: " << D3DERRORSTRING(hr); - } else { - D3DSURFACE_DESC SurfDesc; - hr = pCurRenderTarget->GetDesc(&SurfDesc); - if (FAILED(hr)) { - dxgsg9_cat.error() - << "GetDesc failed in CreateTexture: " << D3DERRORSTRING(hr); - } else { - if (TargetPixFmt != SurfDesc.Format) { - if (dxgsg9_cat.is_debug()) { - dxgsg9_cat.debug() - << "Chose format " << D3DFormatStr(SurfDesc.Format) - << " instead of " << D3DFormatStr(TargetPixFmt) - << " for texture to match framebuffer.\n"; - } - TargetPixFmt = SurfDesc.Format; - } - } - SAFE_RELEASE(pCurRenderTarget); - } - } - - // validate magfilter setting - // degrade filtering if no HW support - - Texture::FilterType ft; - - ft =_tex->get_magfilter(); - if((ft!=Texture::FT_linear) && ft!=Texture::FT_nearest) { - // mipmap settings make no sense for magfilter - if(ft==Texture::FT_nearest_mipmap_nearest) - ft=Texture::FT_nearest; - else ft=Texture::FT_linear; - } - - if((ft==Texture::FT_linear) && !(scrn.d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)) - ft=Texture::FT_nearest; - _tex->set_magfilter(ft); - - // figure out if we are mipmapping this texture - ft =_tex->get_minfilter(); - _bHasMipMaps=FALSE; - - if(!dx_ignore_mipmaps) { // set if no HW mipmap capable - switch(ft) { - case Texture::FT_nearest_mipmap_nearest: - case Texture::FT_linear_mipmap_nearest: - case Texture::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them - case Texture::FT_linear_mipmap_linear: - _bHasMipMaps=TRUE; - } - - if(dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost - _bHasMipMaps=TRUE; - if(dxgsg9_cat.is_spam()) { - if(ft != Texture::FT_linear_mipmap_linear) - dxgsg9_cat.spam() << "Forcing trilinear mipmapping on DX texture [" << _tex->get_name() << "]\n"; - } - ft = Texture::FT_linear_mipmap_linear; - _tex->set_minfilter(ft); - } - } else if((ft==Texture::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types - (ft==Texture::FT_nearest_mipmap_linear)) { - ft=Texture::FT_nearest; - } else if((ft==Texture::FT_linear_mipmap_nearest) || - (ft==Texture::FT_linear_mipmap_linear)) { - ft=Texture::FT_linear; - } - - assert((scrn.d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0); - -#define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR) - - // do any other filter type degradations necessary - switch(ft) { - case Texture::FT_linear_mipmap_linear: - if((scrn.d3dcaps.TextureFilterCaps & TRILINEAR_MIPMAP_TEXFILTERCAPS)!=TRILINEAR_MIPMAP_TEXFILTERCAPS) { - if(scrn.d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) - ft=Texture::FT_linear_mipmap_nearest; - else ft=Texture::FT_nearest_mipmap_nearest; // if you cant do linear in a level, you probably cant do linear b/w levels, so just do nearest-all - } - break; - case Texture::FT_nearest_mipmap_linear: - // if we dont have bilinear, do nearest_nearest - if(!((scrn.d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MIPFPOINT) && - (scrn.d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR))) - ft=Texture::FT_nearest_mipmap_nearest; - break; - case Texture::FT_linear_mipmap_nearest: - // if we dont have mip linear, do nearest_nearest - if(!(scrn.d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MIPFLINEAR)) - ft=Texture::FT_nearest_mipmap_nearest; - break; - case Texture::FT_linear: - if(!(scrn.d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)) - ft=Texture::FT_nearest; - break; - } - - _tex->set_minfilter(ft); - - uint aniso_degree; - - aniso_degree=1; - if(scrn.d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) { - aniso_degree=_tex->get_anisotropic_degree(); - if((aniso_degree>scrn.d3dcaps.MaxAnisotropy) || dx_force_anisotropic_filtering) - aniso_degree=scrn.d3dcaps.MaxAnisotropy; - } - _tex->set_anisotropic_degree(aniso_degree); - -#ifdef _DEBUG - dxgsg9_cat.spam() << "CreateTexture: setting aniso degree for "<< _tex->get_name() << " to: " << aniso_degree << endl; -#endif - - UINT cMipLevelCount; - - if(_bHasMipMaps) { - cMipLevelCount=0; // tell CreateTex to alloc space for all mip levels down to 1x1 - - if(dxgsg9_cat.is_debug()) - dxgsg9_cat.debug() << "CreateTexture: generating mipmaps for "<< _tex->get_name() << endl; - } else cMipLevelCount=1; - - if(FAILED( hr = scrn.pD3DDevice->CreateTexture(TargetWidth,TargetHeight,cMipLevelCount,0x0, - TargetPixFmt,D3DPOOL_MANAGED,&_pD3DTexture9, NULL) )) { - dxgsg9_cat.error() << "D3D CreateTexture failed!" << D3DERRORSTRING(hr); - goto error_exit; - } - - if (dxgsg9_cat.is_debug()) { - dxgsg9_cat.debug() << "CreateTexture: "<< _tex->get_name() <<" converting panda equivalent of " << D3DFormatStr(_PixBufD3DFmt) << " => " << D3DFormatStr(TargetPixFmt) << endl; - } - - hr = FillDDSurfTexturePixels(); - if(FAILED(hr)) { - goto error_exit; - } - - // PRINT_REFCNT(dxgsg9,scrn.pD3D9); - - // Return the newly created texture - return _pD3DTexture9; - - error_exit: - - RELEASE(_pD3DTexture9,dxgsg9,"texture",RELEASE_ONCE); - return NULL; -} - -HRESULT DXTextureContext9:: -FillDDSurfTexturePixels() { - HRESULT hr=E_FAIL; - assert(IS_VALID_PTR(_texture)); - - CPTA_uchar image = _texture->get_ram_image(); - if (image.is_null()) { - // The texture doesn't have an image to load. That's ok; it - // might be a texture we've rendered to by frame buffer - // operations or something. - return S_OK; - } - - assert(IS_VALID_PTR(_pD3DTexture9)); - - DWORD OrigWidth = (DWORD) _texture->get_x_size(); - DWORD OrigHeight = (DWORD) _texture->get_y_size(); - DWORD cNumColorChannels = _texture->get_num_components(); - D3DFORMAT SrcFormat=_PixBufD3DFmt; - BYTE *pPixels=(BYTE*)image.p(); - int component_width = _texture->get_component_width(); - - assert(IS_VALID_PTR(pPixels)); - - IDirect3DSurface9 *pMipLevel0; - hr=_pD3DTexture9->GetSurfaceLevel(0,&pMipLevel0); - if(FAILED(hr)) { - dxgsg9_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", GetSurfaceLevel failed" << D3DERRORSTRING(hr); - return E_FAIL; - } - - RECT SrcSize; - SrcSize.left = SrcSize.top = 0; - SrcSize.right = OrigWidth; - SrcSize.bottom = OrigHeight; - - UINT SrcPixBufRowByteLength=OrigWidth*cNumColorChannels; - - DWORD Lev0Filter,MipFilterFlags; - bool bUsingTempPixBuf=false; - - // need filtering if size changes, (also if bitdepth reduced (need dithering)??) - Lev0Filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures - - // D3DXLoadSurfaceFromMemory will load black luminance and we want full white, - // so convert to explicit luminance-alpha format - if (_PixBufD3DFmt==D3DFMT_A8) { - // alloc buffer for explicit D3DFMT_A8L8 - USHORT *pTempPixBuf=new USHORT[OrigWidth*OrigHeight]; - if(!IS_VALID_PTR(pTempPixBuf)) { - dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; - goto exit_FillDDSurf; - } - bUsingTempPixBuf=true; - - USHORT *pOutPix=pTempPixBuf; - BYTE *pSrcPix=pPixels + component_width - 1; - for (UINT y = 0; y < OrigHeight; y++) { - for (UINT x = 0; - x < OrigWidth; - x++, pSrcPix += component_width, pOutPix++) { - // add full white, which is our interpretation of alpha-only - // (similar to default adding full opaque alpha 0xFF to - // RGB-only textures) - *pOutPix = ((*pSrcPix) << 8 ) | 0xFF; - } - } - - SrcFormat=D3DFMT_A8L8; - SrcPixBufRowByteLength=OrigWidth*sizeof(USHORT); - pPixels=(BYTE*)pTempPixBuf; - - } else if (component_width != 1) { - // Convert from 16-bit per channel (or larger) format down to - // 8-bit per channel. This throws away precision in the - // original image. dx9 does support some of these - // high-precision formats, but we don't right now. - - int num_components = _texture->get_num_components(); - int num_pixels = OrigWidth * OrigHeight * num_components; - BYTE *pTempPixBuf = new BYTE[num_pixels]; - if(!IS_VALID_PTR(pTempPixBuf)) { - dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; - goto exit_FillDDSurf; - } - bUsingTempPixBuf=true; - - BYTE *pSrcPix = pPixels + component_width - 1; - for (int i = 0; i < num_pixels; i++) { - pTempPixBuf[i] = *pSrcPix; - pSrcPix += component_width; - } - pPixels=(BYTE*)pTempPixBuf; - } - - - // filtering may be done here if texture if targetsize!=origsize - hr=D3DXLoadSurfaceFromMemory(pMipLevel0,(PALETTEENTRY*)NULL,(RECT*)NULL,(LPCVOID)pPixels,SrcFormat, - SrcPixBufRowByteLength,(PALETTEENTRY*)NULL,&SrcSize,Lev0Filter,(D3DCOLOR)0x0); - if(FAILED(hr)) { - dxgsg9_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr); - goto exit_FillDDSurf; - } - - if(_bHasMipMaps) { - if(!dx_use_triangle_mipgen_filter) - MipFilterFlags = D3DX_FILTER_BOX; - else MipFilterFlags = D3DX_FILTER_TRIANGLE; - - // MipFilterFlags|= D3DX_FILTER_DITHER; - - hr=D3DXFilterTexture(_pD3DTexture9,(PALETTEENTRY*)NULL,0,MipFilterFlags); - if(FAILED(hr)) { - dxgsg9_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXFilterTex failed" << D3DERRORSTRING(hr); - goto exit_FillDDSurf; - } - } - - exit_FillDDSurf: - if(bUsingTempPixBuf) { - SAFE_DELETE_ARRAY(pPixels); - } - RELEASE(pMipLevel0,dxgsg9,"FillDDSurf MipLev0 texture ptr",RELEASE_ONCE); - return hr; -} - -//----------------------------------------------------------------------------- -// Name: DeleteTexture() -// Desc: Release the surface used to store the texture -//----------------------------------------------------------------------------- -void DXTextureContext9:: -DeleteTexture( ) { - if(_pD3DTexture9==NULL) { - // dont bother printing the msg below, since we already released it. - return; - } - - if(dxgsg9_cat.is_spam()) { - dxgsg9_cat.spam() << "Deleting DX texture for " << _tex->get_name() << "\n"; - } - - RELEASE(_pD3DTexture9,dxgsg9,"texture",RELEASE_ONCE); -/* -#ifdef DEBUG_RELEASES - if(_surface) { - LPDIRECTDRAW7 pDD; - _surface->GetDDInterface( (VOID**)&pDD ); - pDD->Release(); - - PRINTREFCNT(pDD,"before DeleteTex, IDDraw7"); - RELEASE(_surface,dxgsg9,"texture",false); - PRINTREFCNT(pDD,"after DeleteTex, IDDraw7"); - } -#else - - RELEASE(_pD3DSurf9,dxgsg9,"texture",false); - #endif -*/ -} - +static const DWORD g_LowByteMask = 0x000000FF; //////////////////////////////////////////////////////////////////// // Function: DXTextureContext9::Constructor @@ -1097,24 +35,1339 @@ DeleteTexture( ) { //////////////////////////////////////////////////////////////////// DXTextureContext9:: DXTextureContext9(Texture *tex) : -TextureContext(tex) { + TextureContext(tex) { - if(dxgsg9_cat.is_spam()) { - dxgsg9_cat.spam() << "Creating DX texture [" << tex->get_name() << "], minfilter(" << PandaFilterNameStrs[tex->get_minfilter()] << "), magfilter("<get_magfilter()] << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n"; - } + if (dxgsg9_cat.is_spam()) { + dxgsg9_cat.spam() + << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n"; + } - _pD3DTexture9 = NULL; - _bHasMipMaps = FALSE; - _tex = tex; + _d3d_texture = NULL; + _d3d_2d_texture = NULL; + _d3d_volume_texture = NULL; + _d3d_cube_texture = NULL; + _has_mipmaps = false; } +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// DXTextureContext9:: ~DXTextureContext9() { - if(dxgsg9_cat.is_spam()) { - dxgsg9_cat.spam() << "Deleting DX9 TexContext for " << _tex->get_name() << "\n"; - } - DeleteTexture(); - TextureContext::~TextureContext(); - _tex = NULL; + if (dxgsg9_cat.is_spam()) { + dxgsg9_cat.spam() + << "Deleting texture context for " << _texture->get_name() << "\n"; + } + delete_texture(); + TextureContext::~TextureContext(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::create_texture +// Access: Public +// Description: Use panda texture's pixelbuffer to create a texture +// for the specified device. This code gets the +// attributes of the texture from the bitmap, creates +// the texture, and then copies the bitmap into the +// texture. The return value is true if the texture is +// successfully created, false otherwise. +//////////////////////////////////////////////////////////////////// +bool DXTextureContext9:: +create_texture(DXScreenData &scrn) { + HRESULT hr; + int num_alpha_bits; // number of alpha bits in texture pixfmt + D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN; + bool needs_luminance = false; + + nassertr(IS_VALID_PTR(_texture), false); + + delete_texture(); + + clear_dirty_flags(Texture::DF_image | Texture::DF_mipmap); + + // bpp indicates requested fmt, not texture fmt + DWORD target_bpp = get_bits_per_pixel(_texture->get_format(), &num_alpha_bits); + DWORD num_color_channels = _texture->get_num_components(); + + //PRINT_REFCNT(dxgsg9, scrn._d3d9); + + DWORD orig_width = (DWORD)_texture->get_x_size(); + DWORD orig_height = (DWORD)_texture->get_y_size(); + DWORD orig_depth = (DWORD)_texture->get_z_size(); + + if ((_texture->get_format() == Texture::F_luminance_alpha)|| + (_texture->get_format() == Texture::F_luminance_alphamask) || + (_texture->get_format() == Texture::F_luminance)) { + needs_luminance = true; + } + + if (num_alpha_bits > 0) { + if (num_color_channels == 3) { + dxgsg9_cat.error() + << "texture " << _texture->get_name() + << " has no inherent alpha channel, but alpha format is requested!\n"; + } + } + + _d3d_format = D3DFMT_UNKNOWN; + + // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows how to perform copy + + switch (num_color_channels) { + case 1: + if (num_alpha_bits > 0) { + _d3d_format = D3DFMT_A8; + } else if (needs_luminance) { + _d3d_format = D3DFMT_L8; + } + break; + case 2: + nassertr(needs_luminance && (num_alpha_bits > 0), false); + _d3d_format = D3DFMT_A8L8; + break; + case 3: + _d3d_format = D3DFMT_R8G8B8; + break; + case 4: + _d3d_format = D3DFMT_A8R8G8B8; + break; + } + + // make sure we handled all the possible cases + nassertr(_d3d_format != D3DFMT_UNKNOWN, false); + + DWORD target_width = orig_width; + DWORD target_height = orig_height; + DWORD target_depth = orig_depth; + + DWORD filter_caps; + + switch (_texture->get_texture_type()) { + case Texture::TT_1d_texture: + case Texture::TT_2d_texture: + filter_caps = scrn._d3dcaps.TextureFilterCaps; + + if (target_width > scrn._d3dcaps.MaxTextureWidth) { + target_width = scrn._d3dcaps.MaxTextureWidth; + } + if (target_height > scrn._d3dcaps.MaxTextureHeight) { + target_height = scrn._d3dcaps.MaxTextureHeight; + } + + if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) { + if (!ISPOW2(target_width)) { + target_width = down_to_power_2(target_width); + } + if (!ISPOW2(target_height)) { + target_height = down_to_power_2(target_height); + } + } + break; + + case Texture::TT_3d_texture: + if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) { + dxgsg9_cat.warning() + << "3-d textures are not supported by this graphics driver.\n"; + return false; + } + + filter_caps = scrn._d3dcaps.VolumeTextureFilterCaps; + + if (target_width > scrn._d3dcaps.MaxVolumeExtent) { + target_width = scrn._d3dcaps.MaxVolumeExtent; + } + if (target_height > scrn._d3dcaps.MaxVolumeExtent) { + target_height = scrn._d3dcaps.MaxVolumeExtent; + } + if (target_depth > scrn._d3dcaps.MaxVolumeExtent) { + target_depth = scrn._d3dcaps.MaxVolumeExtent; + } + + if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) { + if (!ISPOW2(target_width)) { + target_width = down_to_power_2(target_width); + } + if (!ISPOW2(target_height)) { + target_height = down_to_power_2(target_height); + } + if (!ISPOW2(target_depth)) { + target_depth = down_to_power_2(target_depth); + } + } + break; + + case Texture::TT_cube_map: + if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) { + dxgsg9_cat.warning() + << "Cube map textures are not supported by this graphics driver.\n"; + return false; + } + + filter_caps = scrn._d3dcaps.CubeTextureFilterCaps; + + if (target_width > scrn._d3dcaps.MaxTextureWidth) { + target_width = scrn._d3dcaps.MaxTextureWidth; + } + + if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) { + if (!ISPOW2(target_width)) { + target_width = down_to_power_2(target_width); + } + } + + target_height = target_width; + break; + } + + // checks for SQUARE reqmt (nvidia riva128 needs this) + if ((target_width != target_height) && + (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0) { + // assume pow2 textures. sum exponents, divide by 2 rounding down + // to get sq size + int i, width_exp, height_exp; + for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1) { + } + for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1) { + } + target_height = target_width = 1<<((width_exp+height_exp)>>1); + } + + bool shrink_original = false; + + if (orig_width != target_width || orig_height != target_height || + orig_depth != target_depth) { + if (_texture->get_texture_type() == Texture::TT_3d_texture) { + dxgsg9_cat.info() + << "Reducing size of " << _texture->get_name() + << " from " << orig_width << "x" << orig_height << "x" << orig_depth + << " to " << target_width << "x" << target_height + << "x" << target_depth << "\n"; + } else { + dxgsg9_cat.info() + << "Reducing size of " << _texture->get_name() + << " from " << orig_width << "x" << orig_height + << " to " << target_width << "x" << target_height << "\n"; + } + + shrink_original = true; + } + + const char *error_message; + + error_message = "create_texture failed: couldn't find compatible device Texture Pixel Format for input texture"; + + if (dxgsg9_cat.is_spam()) { + dxgsg9_cat.spam() + << "create_texture handling target bitdepth: " << target_bpp + << " alphabits: " << num_alpha_bits << endl; + } + + // I could possibly replace some of this logic with + // D3DXCheckTextureRequirements(), but it wouldn't handle all my + // specialized low-memory cases perfectly + +#define CONVTYPE_STMT + +#define CHECK_FOR_FMT(FMT, CONV) \ + if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \ + CONVTYPE_STMT; \ + target_pixel_format = D3DFMT_##FMT; \ + goto found_matching_format; } + + // handle each target bitdepth separately. might be less confusing + // to reorg by num_color_channels (input type, rather than desired + // 1st target) + switch (target_bpp) { + + // IMPORTANT NOTE: + // target_bpp is REQUESTED bpp, not what exists in the texture + // array (the texture array contains num_color_channels*8bits) + + case 32: + if (!((num_color_channels == 3) || (num_color_channels == 4))) + break; //bail + + if (!dx_force_16bpptextures) { + if (num_color_channels == 4) { + CHECK_FOR_FMT(A8R8G8B8, Conv32to32); + } else { + CHECK_FOR_FMT(A8R8G8B8, Conv24to32); + } + } + + if (num_alpha_bits>0) { + nassertr(num_color_channels == 4, false); + + // no 32-bit fmt, look for 16 bit w/alpha (1-15) + + // 32 bit RGBA was requested, but only 16 bit alpha fmts are + // avail. By default, convert to 4-4-4-4 which has 4-bit alpha + // for blurry edges. If we know tex only needs 1 bit alpha + // (i.e. for a mask), use 1555 instead. + + + // ConversionType ConvTo1 = Conv32to16_4444, ConvTo2 = Conv32to16_1555; + // DWORD dwAlphaMask1 = 0xF000, dwAlphaMask2 = 0x8000; + + // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify + // 32->16 conversion. This should be true on most cards. + +#ifndef FORCE_16bpp_1555 + if (num_alpha_bits == 1) +#endif + { + CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555); + } + + // normally prefer 4444 due to better alpha channel resolution + CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444); + CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555); + + // At this point, bail. Don't worry about converting to + // non-alpha formats yet, I think this will be a very rare case. + error_message = "create_texture failed: couldn't find compatible Tex DDPIXELFORMAT! no available 16 or 32-bit alpha formats!"; + } else { + // convert 3 or 4 channel to closest 16bpp color fmt + + if (num_color_channels == 3) { + CHECK_FOR_FMT(R5G6B5, Conv24to16_4444); + CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + } else { + CHECK_FOR_FMT(R5G6B5, Conv32to16_4444); + CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + } + } + break; + + case 24: + nassertr(num_color_channels == 3, false); + + if (!dx_force_16bpptextures) { + CHECK_FOR_FMT(R8G8B8, Conv24to24); + + // no 24-bit fmt. look for 32 bit fmt (note: this is + // memory-hogging choice instead I could look for + // memory-conserving 16-bit fmt). + + CHECK_FOR_FMT(X8R8G8B8, Conv24to32); + } + + // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st) + CHECK_FOR_FMT(R5G6B5, Conv24to16_0565); + CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + break; + + case 16: + if (needs_luminance) { + nassertr(num_alpha_bits > 0, false); + nassertr(num_color_channels == 2, false); + + CHECK_FOR_FMT(A8L8, ConvLum16to16); + + if (!dx_force_16bpptextures) { + CHECK_FOR_FMT(A8R8G8B8, ConvLum16to32); + } + +#ifndef FORCE_16bpp_1555 + if (num_alpha_bits == 1) +#endif + { + CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555); + } + + // normally prefer 4444 due to better alpha channel resolution + CHECK_FOR_FMT(A4R4G4B4, ConvLum16to16_4444); + CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555); + } else { + nassertr((num_color_channels == 3)||(num_color_channels == 4), false); + // look for compatible 16bit fmts, if none then give up + // (dont worry about other bitdepths for 16 bit) + switch(num_alpha_bits) { + case 0: + if (num_color_channels == 3) { + CHECK_FOR_FMT(R5G6B5, Conv24to16_0565); + CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + } else { + nassertr(num_color_channels == 4, false); + // it could be 4 if user asks us to throw away the alpha channel + CHECK_FOR_FMT(R5G6B5, Conv32to16_0565); + CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + } + break; + case 1: + // app specifically requests 1-5-5-5 F_rgba5 case, where you + // explicitly want 1-5-5-5 fmt, as opposed to F_rgbm, which + // could use 32bpp ARGB. fail if this particular fmt not + // avail. + nassertr(num_color_channels == 4, false); + CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + break; + case 4: + // app specifically requests 4-4-4-4 F_rgba4 case, as opposed + // to F_rgba, which could use 32bpp ARGB + nassertr(num_color_channels == 4, false); + CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444); + break; + default: + nassertr(false, false); // problem in get_bits_per_pixel()? + } + } + case 8: + if (needs_luminance) { + // dont bother handling those other 8bit lum fmts like 4-4, + // since 16 8-8 is usually supported too + nassertr(num_color_channels == 1, false); + + // look for native lum fmt first + CHECK_FOR_FMT(L8, ConvLum8to8); + CHECK_FOR_FMT(L8, ConvLum8to16_A8L8); + + if (!dx_force_16bpptextures) { + CHECK_FOR_FMT(R8G8B8, ConvLum8to24); + CHECK_FOR_FMT(X8R8G8B8, ConvLum8to32); + } + + CHECK_FOR_FMT(R5G6B5, ConvLum8to16_0565); + CHECK_FOR_FMT(X1R5G5B5, ConvLum8to16_X555); + + } else if (num_alpha_bits == 8) { + // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444. + + // skip 8bit alpha only (D3DFMT_A8), because I think only voodoo + // supports it and the voodoo support isn't the kind of blending + // model we need somehow (is it that voodoo assumes color is + // white? isnt that what we do in ConvAlpha8to32 anyway?) + + CHECK_FOR_FMT(A8L8, ConvAlpha8to16_A8L8); + + if (!dx_force_16bpptextures) { + CHECK_FOR_FMT(A8R8G8B8, ConvAlpha8to32); + } + + CHECK_FOR_FMT(A4R4G4B4, ConvAlpha8to16_4444); + } + break; + + default: + error_message = "create_texture failed: unhandled pixel bitdepth in DX loader"; + } + + // if we've gotten here, haven't found a match + dxgsg9_cat.error() + << error_message << ": " << _texture->get_name() << endl + << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: " + << num_alpha_bits << "; targetbpp: " <get_match_framebuffer_format()) { + // Instead of creating a texture with the found format, we will + // need to make one that exactly matches the framebuffer's + // format. Look up what that format is. + DWORD render_target_index; + IDirect3DSurface9 *render_target; + + render_target_index = 0; + hr = scrn._d3d_device->GetRenderTarget(render_target_index, &render_target); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr); + } else { + D3DSURFACE_DESC surface_desc; + hr = render_target->GetDesc(&surface_desc); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr); + } else { + if (target_pixel_format != surface_desc.Format) { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "Chose format " << D3DFormatStr(surface_desc.Format) + << " instead of " << D3DFormatStr(target_pixel_format) + << " for texture to match framebuffer.\n"; + } + target_pixel_format = surface_desc.Format; + } + } + SAFE_RELEASE(render_target); + } + } + + // validate magfilter setting + // degrade filtering if no HW support + + Texture::FilterType ft; + + ft = _texture->get_magfilter(); + if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) { + // mipmap settings make no sense for magfilter + if (ft == Texture::FT_nearest_mipmap_nearest) { + ft = Texture::FT_nearest; + } else { + ft = Texture::FT_linear; + } + } + + if (ft == Texture::FT_linear && + (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) { + ft = Texture::FT_nearest; + } + _texture->set_magfilter(ft); + + // figure out if we are mipmapping this texture + ft = _texture->get_minfilter(); + _has_mipmaps = false; + + if (!dx_ignore_mipmaps) { // set if no HW mipmap capable + switch(ft) { + case Texture::FT_nearest_mipmap_nearest: + case Texture::FT_linear_mipmap_nearest: + case Texture::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them + case Texture::FT_linear_mipmap_linear: + _has_mipmaps = true; + } + + if (dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost + _has_mipmaps = true; + if (dxgsg9_cat.is_spam()) { + if (ft != Texture::FT_linear_mipmap_linear) { + dxgsg9_cat.spam() + << "Forcing trilinear mipmapping on DX texture [" + << _texture->get_name() << "]\n"; + } + } + ft = Texture::FT_linear_mipmap_linear; + _texture->set_minfilter(ft); + } + + } else if ((ft == Texture::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types + (ft == Texture::FT_nearest_mipmap_linear)) { + ft = Texture::FT_nearest; + + } else if ((ft == Texture::FT_linear_mipmap_nearest) || + (ft == Texture::FT_linear_mipmap_linear)) { + ft = Texture::FT_linear; + } + + nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false); + +#define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR) + + // do any other filter type degradations necessary + switch(ft) { + case Texture::FT_linear_mipmap_linear: + if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) { + if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) { + ft = Texture::FT_linear_mipmap_nearest; + } else { + // if you cant do linear in a level, you probably cant do + // linear b/w levels, so just do nearest-all + ft = Texture::FT_nearest_mipmap_nearest; + } + } + break; + + case Texture::FT_nearest_mipmap_linear: + // if we dont have bilinear, do nearest_nearest + if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) && + (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) { + ft = Texture::FT_nearest_mipmap_nearest; + } + break; + + case Texture::FT_linear_mipmap_nearest: + // if we dont have mip linear, do nearest_nearest + if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) { + ft = Texture::FT_nearest_mipmap_nearest; + } + break; + + case Texture::FT_linear: + if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) { + ft = Texture::FT_nearest; + } + break; + } + + _texture->set_minfilter(ft); + + uint aniso_degree; + + aniso_degree = 1; + if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) { + aniso_degree = _texture->get_anisotropic_degree(); + if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) || + dx_force_anisotropic_filtering) { + aniso_degree = scrn._d3dcaps.MaxAnisotropy; + } + } + _texture->set_anisotropic_degree(aniso_degree); + +#ifdef _DEBUG + dxgsg9_cat.spam() + << "create_texture: setting aniso degree for " << _texture->get_name() + << " to: " << aniso_degree << endl; +#endif + + UINT mip_level_count; + + if (_has_mipmaps) { + // tell CreateTex to alloc space for all mip levels down to 1x1 + mip_level_count = 0; + + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "create_texture: generating mipmaps for " << _texture->get_name() + << endl; + } + } else { + mip_level_count = 1; + } + + switch (_texture->get_texture_type()) { + case Texture::TT_1d_texture: + case Texture::TT_2d_texture: + hr = scrn._d3d_device->CreateTexture + (target_width, target_height, mip_level_count, 0x0, + target_pixel_format, D3DPOOL_MANAGED, &_d3d_2d_texture, NULL); + _d3d_texture = _d3d_2d_texture; + break; + + case Texture::TT_3d_texture: + hr = scrn._d3d_device->CreateVolumeTexture + (target_width, target_height, target_depth, mip_level_count, 0x0, + target_pixel_format, D3DPOOL_MANAGED, &_d3d_volume_texture, NULL); + _d3d_texture = _d3d_volume_texture; + break; + + case Texture::TT_cube_map: + hr = scrn._d3d_device->CreateCubeTexture + (target_width, mip_level_count, 0x0, + target_pixel_format, D3DPOOL_MANAGED, &_d3d_cube_texture, NULL); + _d3d_texture = _d3d_cube_texture; + break; + } + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "D3D create_texture failed!" << D3DERRORSTRING(hr); + goto error_exit; + } + + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "create_texture: " << _texture->get_name() + << " converting panda equivalent of " << D3DFormatStr(_d3d_format) + << " => " << D3DFormatStr(target_pixel_format) << endl; + } + + hr = fill_d3d_texture_pixels(); + if (FAILED(hr)) { + goto error_exit; + } + + // PRINT_REFCNT(dxgsg9, scrn._d3d9); + + return true; + + error_exit: + + RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE); + _d3d_2d_texture = NULL; + _d3d_volume_texture = NULL; + _d3d_cube_texture = NULL; + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::delete_texture +// Access: Public +// Description: Release the surface used to store the texture +//////////////////////////////////////////////////////////////////// +void DXTextureContext9:: +delete_texture() { + if (_d3d_texture == NULL) { + // dont bother printing the msg below, since we already released it. + return; + } + + RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE); + _d3d_2d_texture = NULL; + _d3d_volume_texture = NULL; + _d3d_cube_texture = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::d3d_surface_to_texture +// Access: Public, Static +// Description: copies source_rect in pD3DSurf to upper left of +// texture +//////////////////////////////////////////////////////////////////// +HRESULT DXTextureContext9:: +d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface, + bool inverted, Texture *result, int z) { + // still need custom conversion since d3d/d3dx has no way to convert + // arbitrary fmt to ARGB in-memory user buffer + + HRESULT hr; + DWORD num_components = result->get_num_components(); + + nassertr(result->get_component_width() == sizeof(BYTE), E_FAIL); // cant handle anything else now + nassertr(result->get_component_type() == Texture::T_unsigned_byte, E_FAIL); // cant handle anything else now + nassertr((num_components == 3) || (num_components == 4), E_FAIL); // cant handle anything else now + nassertr(IS_VALID_PTR(d3d_surface), E_FAIL); + + BYTE *buf = result->modify_ram_image(); + if (z >= 0) { + nassertr(z < result->get_z_size(), E_FAIL); + buf += z * result->get_expected_ram_page_size(); + } + + if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) { + dxgsg9_cat.error() + << "d3d_surface_to_texture failed: bad pD3DSurf ptr value (" + << ((void*)d3d_surface) << ")\n"; + exit(1); + } + + DWORD x_window_offset, y_window_offset; + DWORD copy_width, copy_height; + + D3DLOCKED_RECT locked_rect; + D3DSURFACE_DESC surface_desc; + + hr = d3d_surface->GetDesc(&surface_desc); + + x_window_offset = source_rect.left, y_window_offset = source_rect.top; + copy_width = RECT_XSIZE(source_rect); + copy_height = RECT_YSIZE(source_rect); + + // make sure there's enough space in the texture, its size must + // match (especially xsize) or scanlines will be too long + + if (!((copy_width == result->get_x_size()) && (copy_height <= (DWORD)result->get_y_size()))) { + dxgsg9_cat.error() + << "d3d_surface_to_texture, Texture size (" << result->get_x_size() + << ", " << result->get_y_size() + << ") too small to hold display surface (" + << copy_width << ", " << copy_height << ")\n"; + nassertr(false, E_FAIL); + return E_FAIL; + } + + hr = d3d_surface->LockRect(&locked_rect, (CONST RECT*)NULL, (D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE)); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr); + return hr; + } + + // ones not listed not handled yet + nassertr((surface_desc.Format == D3DFMT_A8R8G8B8) || + (surface_desc.Format == D3DFMT_X8R8G8B8) || + (surface_desc.Format == D3DFMT_R8G8B8) || + (surface_desc.Format == D3DFMT_R5G6B5) || + (surface_desc.Format == D3DFMT_X1R5G5B5) || + (surface_desc.Format == D3DFMT_A1R5G5B5) || + (surface_desc.Format == D3DFMT_A4R4G4B4), E_FAIL); + + //buf contains raw ARGB in Texture byteorder + + int byte_pitch = locked_rect.Pitch; + BYTE *surface_bytes = (BYTE *)locked_rect.pBits; + + if (inverted) { + surface_bytes += byte_pitch * (y_window_offset + copy_height - 1); + byte_pitch = -byte_pitch; + } else { + surface_bytes += byte_pitch * y_window_offset; + } + + // writes out last line in DDSurf first in PixelBuf, so Y line order + // precedes inversely + + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "d3d_surface_to_texture converting " + << D3DFormatStr(surface_desc.Format) + << " DDSurf to " << num_components << "-channel panda Texture\n"; + } + + DWORD *dest_word = (DWORD *)buf; + BYTE *dest_byte = (BYTE *)buf; + + switch(surface_desc.Format) { + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: { + if (num_components == 4) { + DWORD *source_word; + BYTE *dest_line = (BYTE*)dest_word; + + for (DWORD y = 0; y < copy_height; y++) { + source_word = ((DWORD*)surface_bytes) + x_window_offset; + memcpy(dest_line, source_word, byte_pitch); + dest_line += byte_pitch; + surface_bytes += byte_pitch; + } + } else { + // 24bpp texture case (numComponents == 3) + DWORD *source_word; + for (DWORD y = 0; y < copy_height; y++) { + source_word = ((DWORD*)surface_bytes) + x_window_offset; + + for (DWORD x = 0; x < copy_width; x++) { + BYTE r, g, b; + DWORD pixel = *source_word; + + r = (BYTE)((pixel>>16) & g_LowByteMask); + g = (BYTE)((pixel>> 8) & g_LowByteMask); + b = (BYTE)((pixel ) & g_LowByteMask); + + *dest_byte++ = b; + *dest_byte++ = g; + *dest_byte++ = r; + source_word++; + } + surface_bytes += byte_pitch; + } + } + break; + } + + case D3DFMT_R8G8B8: { + BYTE *source_byte; + + if (num_components == 4) { + for (DWORD y = 0; y < copy_height; y++) { + source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE); + for (DWORD x = 0; x < copy_width; x++) { + DWORD r, g, b; + + b = *source_byte++; + g = *source_byte++; + r = *source_byte++; + + *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b; + dest_word++; + } + surface_bytes += byte_pitch; + } + } else { + // 24bpp texture case (numComponents == 3) + for (DWORD y = 0; y < copy_height; y++) { + source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE); + memcpy(dest_byte, source_byte, byte_pitch); + dest_byte += byte_pitch; + surface_bytes += byte_pitch; + } + } + break; + } + + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A4R4G4B4: { + WORD *source_word; + // handle 0555, 1555, 0565, 4444 in same loop + + BYTE redshift, greenshift, blueshift; + DWORD redmask, greenmask, bluemask; + + if (surface_desc.Format == D3DFMT_R5G6B5) { + redshift = (11-3); + redmask = 0xF800; + greenmask = 0x07E0; + greenshift = (5-2); + bluemask = 0x001F; + blueshift = 3; + } else if (surface_desc.Format == D3DFMT_A4R4G4B4) { + redmask = 0x0F00; + redshift = 4; + greenmask = 0x00F0; + greenshift = 0; + bluemask = 0x000F; + blueshift = 4; + } else { // 1555 or x555 + redmask = 0x7C00; + redshift = (10-3); + greenmask = 0x03E0; + greenshift = (5-3); + bluemask = 0x001F; + blueshift = 3; + } + + if (num_components == 4) { + // Note: these 16bpp loops ignore input alpha completely (alpha + // is set to fully opaque in texture!) + + // if we need to capture alpha, probably need to make separate + // loops for diff 16bpp fmts for best speed + + for (DWORD y = 0; y < copy_height; y++) { + source_word = ((WORD*)surface_bytes) + x_window_offset; + for (DWORD x = 0; x < copy_width; x++) { + WORD pixel = *source_word; + BYTE r, g, b; + + b = (pixel & bluemask) << blueshift; + g = (pixel & greenmask) >> greenshift; + r = (pixel & redmask) >> redshift; + + // alpha is just set to 0xFF + + *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b; + source_word++; + dest_word++; + } + surface_bytes += byte_pitch; + } + } else { + // 24bpp texture case (numComponents == 3) + for (DWORD y = 0; y < copy_height; y++) { + source_word = ((WORD*)surface_bytes) + x_window_offset; + for (DWORD x = 0; x < copy_width; x++) { + WORD pixel = *source_word; + BYTE r, g, b; + + b = (pixel & bluemask) << blueshift; + g = (pixel & greenmask) >> greenshift; + r = (pixel & redmask) >> redshift; + + *dest_byte += b; + *dest_byte += g; + *dest_byte += r; + source_word++; + } + surface_bytes += byte_pitch; + } + } + break; + } + + default: + dxgsg9_cat.error() + << "d3d_surface_to_texture: unsupported D3DFORMAT!\n"; + } + + d3d_surface->UnlockRect(); + return S_OK; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::fill_d3d_texture_pixels +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +HRESULT DXTextureContext9:: +fill_d3d_texture_pixels() { + if (_texture->get_texture_type() == Texture::TT_3d_texture) { + return fill_d3d_volume_texture_pixels(); + } + + HRESULT hr = E_FAIL; + nassertr(IS_VALID_PTR(_texture), E_FAIL); + + CPTA_uchar image = _texture->get_ram_image(); + if (image.is_null()) { + // The texture doesn't have an image to load. That's ok; it + // might be a texture we've rendered to by frame buffer + // operations or something. + return S_OK; + } + + PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector); + + nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL); + + DWORD orig_width = (DWORD) _texture->get_x_size(); + DWORD orig_height = (DWORD) _texture->get_y_size(); + DWORD orig_depth = (DWORD) _texture->get_z_size(); + DWORD num_color_channels = _texture->get_num_components(); + D3DFORMAT source_format = _d3d_format; + BYTE *image_pixels = (BYTE*)image.p(); + int component_width = _texture->get_component_width(); + + nassertr(IS_VALID_PTR(image_pixels), E_FAIL); + + IDirect3DSurface9 *mip_level_0 = NULL; + bool using_temp_buffer = false; + BYTE *pixels = NULL; + + for (unsigned int di = 0; di < orig_depth; di++) { + pixels = image_pixels + di * _texture->get_expected_ram_page_size(); + mip_level_0 = NULL; + + if (_texture->get_texture_type() == Texture::TT_cube_map) { + nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL); + hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)di, 0, &mip_level_0); + } else { + nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL); + hr = _d3d_2d_texture->GetSurfaceLevel(0, &mip_level_0); + } + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels failed for " << _texture->get_name() + << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr); + return E_FAIL; + } + + RECT source_size; + source_size.left = source_size.top = 0; + source_size.right = orig_width; + source_size.bottom = orig_height; + + UINT source_row_byte_length = orig_width * num_color_channels; + + DWORD level_0_filter, mip_filter_flags; + using_temp_buffer = false; + + // need filtering if size changes, (also if bitdepth reduced (need + // dithering)??) + level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures + + // D3DXLoadSurfaceFromMemory will load black luminance and we want + // full white, so convert to explicit luminance-alpha format + if (_d3d_format == D3DFMT_A8) { + // alloc buffer for explicit D3DFMT_A8L8 + USHORT *temp_buffer = new USHORT[orig_width * orig_height]; + if (!IS_VALID_PTR(temp_buffer)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; + goto exit_FillDDSurf; + } + using_temp_buffer = true; + + USHORT *out_pixels = temp_buffer; + BYTE *source_pixels = pixels + component_width - 1; + for (UINT y = 0; y < orig_height; y++) { + for (UINT x = 0; + x < orig_width; + x++, source_pixels += component_width, out_pixels++) { + // add full white, which is our interpretation of alpha-only + // (similar to default adding full opaque alpha 0xFF to + // RGB-only textures) + *out_pixels = ((*source_pixels) << 8 ) | 0xFF; + } + } + + source_format = D3DFMT_A8L8; + source_row_byte_length = orig_width * sizeof(USHORT); + pixels = (BYTE*)temp_buffer; + + } else if (component_width != 1) { + // Convert from 16-bit per channel (or larger) format down to + // 8-bit per channel. This throws away precision in the + // original image, but dx8 doesn't support high-precision images + // anyway. + + int num_components = _texture->get_num_components(); + int num_pixels = orig_width * orig_height * num_components; + BYTE *temp_buffer = new BYTE[num_pixels]; + if (!IS_VALID_PTR(temp_buffer)) { + dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; + goto exit_FillDDSurf; + } + using_temp_buffer = true; + + BYTE *source_pixels = pixels + component_width - 1; + for (int i = 0; i < num_pixels; i++) { + temp_buffer[i] = *source_pixels; + source_pixels += component_width; + } + pixels = (BYTE*)temp_buffer; + } + + + // filtering may be done here if texture if targetsize != origsize +#ifdef DO_PSTATS + GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * orig_height); +#endif + hr = D3DXLoadSurfaceFromMemory + (mip_level_0, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)pixels, + source_format, source_row_byte_length, (PALETTEENTRY*)NULL, + &source_size, level_0_filter, (D3DCOLOR)0x0); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels failed for " << _texture->get_name() + << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr); + goto exit_FillDDSurf; + } + + if (_has_mipmaps) { + if (!dx_use_triangle_mipgen_filter) { + mip_filter_flags = D3DX_FILTER_BOX; + } else { + mip_filter_flags = D3DX_FILTER_TRIANGLE; + } + + // mip_filter_flags| = D3DX_FILTER_DITHER; + + hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, + mip_filter_flags); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels failed for " << _texture->get_name() + << ", D3DXFilterTex failed" << D3DERRORSTRING(hr); + goto exit_FillDDSurf; + } + } + if (using_temp_buffer) { + SAFE_DELETE_ARRAY(pixels); + } + RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE); + } + return hr; + + exit_FillDDSurf: + if (using_temp_buffer) { + SAFE_DELETE_ARRAY(pixels); + } + RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE); + return hr; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::fill_d3d_volume_texture_pixels +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +HRESULT DXTextureContext9:: +fill_d3d_volume_texture_pixels() { + HRESULT hr = E_FAIL; + nassertr(IS_VALID_PTR(_texture), E_FAIL); + + CPTA_uchar image = _texture->get_ram_image(); + if (image.is_null()) { + // The texture doesn't have an image to load. That's ok; it + // might be a texture we've rendered to by frame buffer + // operations or something. + return S_OK; + } + + PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector); + + nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL); + nassertr(_texture->get_texture_type() == Texture::TT_3d_texture, E_FAIL); + + DWORD orig_width = (DWORD) _texture->get_x_size(); + DWORD orig_height = (DWORD) _texture->get_y_size(); + DWORD orig_depth = (DWORD) _texture->get_z_size(); + DWORD num_color_channels = _texture->get_num_components(); + D3DFORMAT source_format = _d3d_format; + BYTE *image_pixels = (BYTE*)image.p(); + int component_width = _texture->get_component_width(); + + nassertr(IS_VALID_PTR(image_pixels), E_FAIL); + + IDirect3DVolume9 *mip_level_0 = NULL; + bool using_temp_buffer = false; + BYTE *pixels = image_pixels; + + nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL); + hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0); + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels failed for " << _texture->get_name() + << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr); + return E_FAIL; + } + + D3DBOX source_size; + source_size.Left = source_size.Top = source_size.Front = 0; + source_size.Right = orig_width; + source_size.Bottom = orig_height; + source_size.Back = orig_depth; + + UINT source_row_byte_length = orig_width * num_color_channels; + UINT source_page_byte_length = orig_height * source_row_byte_length; + + DWORD level_0_filter, mip_filter_flags; + using_temp_buffer = false; + + // need filtering if size changes, (also if bitdepth reduced (need + // dithering)??) + level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures + + // D3DXLoadSurfaceFromMemory will load black luminance and we want + // full white, so convert to explicit luminance-alpha format + if (_d3d_format == D3DFMT_A8) { + // alloc buffer for explicit D3DFMT_A8L8 + USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth]; + if (!IS_VALID_PTR(temp_buffer)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; + goto exit_FillDDSurf; + } + using_temp_buffer = true; + + USHORT *out_pixels = temp_buffer; + BYTE *source_pixels = pixels + component_width - 1; + for (UINT z = 0; z < orig_depth; z++) { + for (UINT y = 0; y < orig_height; y++) { + for (UINT x = 0; + x < orig_width; + x++, source_pixels += component_width, out_pixels++) { + // add full white, which is our interpretation of alpha-only + // (similar to default adding full opaque alpha 0xFF to + // RGB-only textures) + *out_pixels = ((*source_pixels) << 8 ) | 0xFF; + } + } + } + + source_format = D3DFMT_A8L8; + source_row_byte_length = orig_width * sizeof(USHORT); + source_page_byte_length = orig_height * source_row_byte_length; + pixels = (BYTE*)temp_buffer; + + } else if (component_width != 1) { + // Convert from 16-bit per channel (or larger) format down to + // 8-bit per channel. This throws away precision in the + // original image, but dx8 doesn't support high-precision images + // anyway. + + int num_components = _texture->get_num_components(); + int num_pixels = orig_width * orig_height * orig_depth * num_components; + BYTE *temp_buffer = new BYTE[num_pixels]; + if (!IS_VALID_PTR(temp_buffer)) { + dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; + goto exit_FillDDSurf; + } + using_temp_buffer = true; + + BYTE *source_pixels = pixels + component_width - 1; + for (int i = 0; i < num_pixels; i++) { + temp_buffer[i] = *source_pixels; + source_pixels += component_width; + } + pixels = (BYTE*)temp_buffer; + } + + + // filtering may be done here if texture if targetsize != origsize +#ifdef DO_PSTATS + GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth); +#endif + hr = D3DXLoadVolumeFromMemory + (mip_level_0, (PALETTEENTRY*)NULL, (D3DBOX*)NULL, (LPCVOID)pixels, + source_format, source_row_byte_length, source_page_byte_length, + (PALETTEENTRY*)NULL, + &source_size, level_0_filter, (D3DCOLOR)0x0); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels failed for " << _texture->get_name() + << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr); + goto exit_FillDDSurf; + } + + if (_has_mipmaps) { + if (!dx_use_triangle_mipgen_filter) { + mip_filter_flags = D3DX_FILTER_BOX; + } else { + mip_filter_flags = D3DX_FILTER_TRIANGLE; + } + + // mip_filter_flags| = D3DX_FILTER_DITHER; + + hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, + mip_filter_flags); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "FillDDSurfaceTexturePixels failed for " << _texture->get_name() + << ", D3DXFilterTex failed" << D3DERRORSTRING(hr); + goto exit_FillDDSurf; + } + } + + exit_FillDDSurf: + if (using_temp_buffer) { + SAFE_DELETE_ARRAY(pixels); + } + RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE); + return hr; +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::down_to_power_2 +// Access: Private, Static +// Description: Returns the largest power of 2 less than or equal +// to value. +//////////////////////////////////////////////////////////////////// +int DXTextureContext9:: +down_to_power_2(int value) { + int x = 1; + while ((x << 1) <= value) { + x = (x << 1); + } + return x; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::get_bits_per_pixel +// Access: Private +// Description: Maps from the Texture's Format symbols to bpp. +// Returns # of alpha bits. Note: Texture's format +// indicates REQUESTED final format, not the stored +// format, which is indicated by pixelbuffer type +//////////////////////////////////////////////////////////////////// +unsigned int DXTextureContext9:: +get_bits_per_pixel(Texture::Format format, int *alphbits) { + *alphbits = 0; // assume no alpha bits + switch(format) { + case Texture::F_alpha: + *alphbits = 8; + case Texture::F_color_index: + case Texture::F_red: + case Texture::F_green: + case Texture::F_blue: + case Texture::F_rgb332: + return 8; + case Texture::F_luminance_alphamask: + *alphbits = 1; + return 16; + case Texture::F_luminance_alpha: + *alphbits = 8; + return 16; + case Texture::F_luminance: + return 8; + case Texture::F_rgba4: + *alphbits = 4; + return 16; + case Texture::F_rgba5: + *alphbits = 1; + return 16; + case Texture::F_depth_component: + case Texture::F_rgb5: + return 16; + case Texture::F_rgb8: + case Texture::F_rgb: + return 24; + case Texture::F_rgba8: + case Texture::F_rgba: + case Texture::F_rgbm: + if (format == Texture::F_rgbm) // does this make any sense? + *alphbits = 1; + else *alphbits = 8; + return 32; + case Texture::F_rgb12: + return 36; + case Texture::F_rgba12: + *alphbits = 12; + return 48; + } + return 8; } diff --git a/panda/src/dxgsg9/dxTextureContext9.h b/panda/src/dxgsg9/dxTextureContext9.h index 80d4cdcb43..30cba38951 100755 --- a/panda/src/dxgsg9/dxTextureContext9.h +++ b/panda/src/dxgsg9/dxTextureContext9.h @@ -1,10 +1,10 @@ -// Filename: dxTextureContext8.h -// Created by: masad (02Jan04) +// Filename: dxTextureContext9.h +// Created by: drose (07Oct99) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -23,38 +23,43 @@ #include "texture.h" #include "textureContext.h" -//#define DO_CUSTOM_CONVERSIONS - //////////////////////////////////////////////////////////////////// -// Class : DXTextureContext9 +// Class : DXTextureContext9 // Description : //////////////////////////////////////////////////////////////////// class EXPCL_PANDADX DXTextureContext9 : public TextureContext { - friend class DXGraphicsStateGuardian; - friend class wdxGraphicsWindow; - public: DXTextureContext9(Texture *tex); - ~DXTextureContext9(); + virtual ~DXTextureContext9(); - IDirect3DTexture9 *_pD3DTexture9; - Texture *_tex; // ptr to parent, primarily for access to namestr - IDirect3DTexture9 *CreateTexture(DXScreenData &scrn); + bool create_texture(DXScreenData &scrn); + void delete_texture(); - D3DFORMAT _PixBufD3DFmt; // the 'D3DFORMAT' the Panda TextureBuffer fmt corresponds to + INLINE bool has_mipmaps() const; + INLINE IDirect3DBaseTexture9 *get_d3d_texture() const; + INLINE IDirect3DTexture9 *get_d3d_2d_texture() const; + INLINE IDirect3DVolumeTexture9 *get_d3d_volume_texture() const; + INLINE IDirect3DCubeTexture9 *get_d3d_cube_texture() const; - bool _bHasMipMaps; + static HRESULT d3d_surface_to_texture(RECT &source_rect, + IDirect3DSurface9 *d3d_surface, + bool inverted, Texture *result, + int z); -#ifdef DO_CUSTOM_CONVERSIONS - DWORD _PixBufConversionType; // enum ConversionType -#endif +private: + HRESULT fill_d3d_texture_pixels(); + HRESULT fill_d3d_volume_texture_pixels(); + static int down_to_power_2(int value); + unsigned int get_bits_per_pixel(Texture::Format format, int *alphbits); - // must be public since called from global callback fns - void DeleteTexture(); - HRESULT FillDDSurfTexturePixels(); +private: + D3DFORMAT _d3d_format; // the 'D3DFORMAT' the Panda TextureBuffer fmt corresponds to + IDirect3DBaseTexture9 *_d3d_texture; + IDirect3DTexture9 *_d3d_2d_texture; + IDirect3DVolumeTexture9 *_d3d_volume_texture; + IDirect3DCubeTexture9 *_d3d_cube_texture; -protected: - unsigned int get_bits_per_pixel(Texture::Format format, int *alphbits); + bool _has_mipmaps; public: static TypeHandle get_class_type() { @@ -74,7 +79,6 @@ private: static TypeHandle _type_handle; }; -extern HRESULT ConvertD3DSurftoPixBuf(RECT &SrcRect,IDirect3DSurface9 *pD3DSurf9,Texture *pixbuf); +#include "dxTextureContext9.I" #endif - diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.I b/panda/src/dxgsg9/dxVertexBufferContext9.I new file mode 100755 index 0000000000..d137e27a3b --- /dev/null +++ b/panda/src/dxgsg9/dxVertexBufferContext9.I @@ -0,0 +1,17 @@ +// Filename: dxVertexBufferContext9.I +// Created by: drose (18Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.cxx b/panda/src/dxgsg9/dxVertexBufferContext9.cxx new file mode 100755 index 0000000000..95e7d47494 --- /dev/null +++ b/panda/src/dxgsg9/dxVertexBufferContext9.cxx @@ -0,0 +1,254 @@ +// Filename: dxVertexBufferContext9.cxx +// Created by: drose (18Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "dxVertexBufferContext9.h" +#include "geomVertexArrayData.h" +#include "geomVertexArrayFormat.h" +#include "graphicsStateGuardian.h" +#include "pStatTimer.h" +#include "internalName.h" +#include "config_dxgsg9.h" +#include + +TypeHandle DXVertexBufferContext9::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: DXVertexBufferContext9::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DXVertexBufferContext9:: +DXVertexBufferContext9(GeomVertexArrayData *data) : + VertexBufferContext(data), + _vbuffer(NULL) +{ + // Now fill in the FVF code. + const GeomVertexArrayFormat *array_format = data->get_array_format(); + + // We have to start with the vertex data, and work up from there in + // order, since that's the way the FVF is defined. + int n = 0; + int num_columns = array_format->get_num_columns(); + + _fvf = 0; + + if (n < num_columns && + array_format->get_column(n)->get_name() == InternalName::get_vertex()) { + ++n; + + int num_blend_values = 0; + + if (n < num_columns && + array_format->get_column(n)->get_name() == InternalName::get_transform_weight()) { + // We have hardware vertex animation. + num_blend_values = array_format->get_column(n)->get_num_values(); + ++n; + } + + if (n < num_columns && + array_format->get_column(n)->get_name() == InternalName::get_transform_index()) { + // Furthermore, it's indexed vertex animation. + _fvf |= D3DFVF_LASTBETA_UBYTE4; + ++num_blend_values; + ++n; + } + + switch (num_blend_values) { + case 0: + _fvf |= D3DFVF_XYZ; + break; + + case 1: + _fvf |= D3DFVF_XYZB1; + break; + + case 2: + _fvf |= D3DFVF_XYZB2; + break; + + case 3: + _fvf |= D3DFVF_XYZB3; + break; + + case 4: + _fvf |= D3DFVF_XYZB4; + break; + + case 5: + _fvf |= D3DFVF_XYZB5; + break; + } + } + + if (n < num_columns && + array_format->get_column(n)->get_name() == InternalName::get_normal()) { + _fvf |= D3DFVF_NORMAL; + ++n; + } + if (n < num_columns && + array_format->get_column(n)->get_name() == InternalName::get_color()) { + _fvf |= D3DFVF_DIFFUSE; + ++n; + } + + // Now look for all of the texcoord names and enable them in the + // same order they appear in the array. + int texcoord_index = 0; + while (n < num_columns && + array_format->get_column(n)->get_contents() == Geom::C_texcoord) { + const GeomVertexColumn *column = array_format->get_column(n); + switch (column->get_num_values()) { + case 1: + _fvf |= D3DFVF_TEXCOORDSIZE1(texcoord_index); + ++n; + break; + case 2: + _fvf |= D3DFVF_TEXCOORDSIZE2(texcoord_index); + ++n; + break; + case 3: + _fvf |= D3DFVF_TEXCOORDSIZE3(texcoord_index); + ++n; + break; + case 4: + _fvf |= D3DFVF_TEXCOORDSIZE4(texcoord_index); + ++n; + break; + } + ++texcoord_index; + } + + switch (texcoord_index) { + case 0: + break; + case 1: + _fvf |= D3DFVF_TEX1; + break; + case 2: + _fvf |= D3DFVF_TEX2; + break; + case 3: + _fvf |= D3DFVF_TEX3; + break; + case 4: + _fvf |= D3DFVF_TEX4; + break; + case 5: + _fvf |= D3DFVF_TEX5; + break; + case 6: + _fvf |= D3DFVF_TEX6; + break; + case 7: + _fvf |= D3DFVF_TEX7; + break; + case 8: + _fvf |= D3DFVF_TEX8; + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXVertexBufferContext9::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DXVertexBufferContext9:: +~DXVertexBufferContext9() { + if (_vbuffer != NULL) { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "deleting vertex buffer " << _vbuffer << "\n"; + } + + RELEASE(_vbuffer, dxgsg9, "vertex buffer", RELEASE_ONCE); + _vbuffer = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXVertexBufferContext9::create_vbuffer +// Access: Public +// Description: Creates a new vertex buffer (but does not upload data +// to it). +//////////////////////////////////////////////////////////////////// +void DXVertexBufferContext9:: +create_vbuffer(DXScreenData &scrn) { + if (_vbuffer != NULL) { + RELEASE(_vbuffer, dxgsg9, "vertex buffer", RELEASE_ONCE); + _vbuffer = NULL; + } + + PStatTimer timer(GraphicsStateGuardian::_create_vertex_buffer_pcollector); + + HRESULT hr = scrn._d3d_device->CreateVertexBuffer + +// (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY, +// _fvf, D3DPOOL_MANAGED, &_vbuffer, NULL); + (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, + _fvf, D3DPOOL_DEFAULT, &_vbuffer, NULL); + + if (FAILED(hr)) { + dxgsg9_cat.warning() + << "CreateVertexBuffer failed" << D3DERRORSTRING(hr); + _vbuffer = NULL; + } else { + if (dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "created vertex buffer " << _vbuffer << ": " + << get_data()->get_num_rows() << " vertices " + << *get_data()->get_array_format() << "\n"; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXVertexBufferContext9::upload_data +// Access: Public +// Description: Copies the latest data from the client store to +// DirectX. +//////////////////////////////////////////////////////////////////// +void DXVertexBufferContext9:: +upload_data() { + nassertv(_vbuffer != NULL); + PStatTimer timer(GraphicsStateGuardian::_load_vertex_buffer_pcollector); + + int data_size = get_data()->get_data_size_bytes(); + + if (dxgsg9_cat.is_spam()) { + dxgsg9_cat.spam() + << "copying " << data_size + << " bytes into vertex buffer " << _vbuffer << "\n"; + } + + BYTE *local_pointer; + +// HRESULT hr = _vbuffer->Lock(0, data_size, (void **) &local_pointer, 0); + HRESULT hr = _vbuffer->Lock(0, data_size, (void **) &local_pointer, D3DLOCK_DISCARD); + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr); + return; + } + + GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size); + memcpy(local_pointer, get_data()->get_data(), data_size); + + _vbuffer->Unlock(); +} diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.h b/panda/src/dxgsg9/dxVertexBufferContext9.h new file mode 100755 index 0000000000..94080a5587 --- /dev/null +++ b/panda/src/dxgsg9/dxVertexBufferContext9.h @@ -0,0 +1,62 @@ +// Filename: dxVertexBufferContext9.h +// Created by: drose (18Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DXVERTEXBUFFERCONTEXT9_H +#define DXVERTEXBUFFERCONTEXT9_H + +#include "pandabase.h" +#include "dxgsg9base.h" +#include "vertexBufferContext.h" + +//////////////////////////////////////////////////////////////////// +// Class : DXVertexBufferContext9 +// Description : Caches a GeomVertexArrayData in the DirectX device as +// a vertex buffer. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX DXVertexBufferContext9 : public VertexBufferContext { +public: + DXVertexBufferContext9(GeomVertexArrayData *data); + virtual ~DXVertexBufferContext9(); + + void create_vbuffer(DXScreenData &scrn); + void upload_data(); + + IDirect3DVertexBuffer9 *_vbuffer; + int _fvf; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + VertexBufferContext::init_type(); + register_type(_type_handle, "DXVertexBufferContext9", + VertexBufferContext::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "dxVertexBufferContext9.I" + +#endif diff --git a/panda/src/dxgsg9/dxgsg9_composite1.cxx b/panda/src/dxgsg9/dxgsg9_composite1.cxx index 3a35ad3a0c..969e0db020 100755 --- a/panda/src/dxgsg9/dxgsg9_composite1.cxx +++ b/panda/src/dxgsg9/dxgsg9_composite1.cxx @@ -1,7 +1,9 @@ #include "dxgsg9base.h" #include "config_dxgsg9.cxx" #include "dxTextureContext9.cxx" -#include "d3dfont9.cxx" +#include "dxVertexBufferContext9.cxx" +#include "dxIndexBufferContext9.cxx" +#include "dxGeomMunger9.cxx" #include "wdxGraphicsPipe9.cxx" #include "wdxGraphicsWindow9.cxx" #include "dxGraphicsDevice9.cxx" diff --git a/panda/src/dxgsg9/dxgsg9base.h b/panda/src/dxgsg9/dxgsg9base.h index 1f3a811e4b..8170c0f9a8 100755 --- a/panda/src/dxgsg9/dxgsg9base.h +++ b/panda/src/dxgsg9/dxgsg9base.h @@ -1,10 +1,10 @@ -// Filename: dxgsg8base.h -// Created by: masad (02Jan04) +// Filename: dxgsg9base.h +// Created by: georges (07Oct01) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -19,10 +19,9 @@ #ifndef DXGSG9BASE_H #define DXGSG9BASE_H -// include win32 defns for everything up to WinServer2003, and assume I'm smart enough to -// use GetProcAddress for backward compat on newer fns -// Note DX9 cannot be installed on w95, so OK to assume base of win98 -#define _WIN32_WINNT 0x0502 +#include "pandabase.h" +#include "graphicsWindow.h" +#include "pmap.h" #define WIN32_LEAN_AND_MEAN // get rid of mfc win32 hdr stuff #ifndef STRICT @@ -38,20 +37,19 @@ #include #undef WIN32_LEAN_AND_MEAN -#include "pandabase.h" -#include "graphicsWindow.h" - -#if D3D_SDK_VERSION < 31 -#error you have DX 8.0/8.1 headers, not DX 9, you need to install DX 9 SDK! +/* ***** DX9 +#if D3D_SDK_VERSION != 220 +#error you have DX 8.0 headers, not DX 8.1, you need to install DX 8.1 SDK! #endif #if DIRECT3D_VERSION != 0x0900 -#error DX9 headers not available, you need to install newer MS Platform SDK! +#error DX8.1 headers not available, you need to install newer MS Platform SDK! #endif #ifndef D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD #error you have pre-release DX8.1 headers, you need to install final DX 8.1 SDK! #endif +*/ #ifndef D3DERRORSTRING #ifdef NDEBUG @@ -78,7 +76,7 @@ typedef DWORD DXShaderHandle; type var; \ ZeroMemory(&var, sizeof(type)); \ var.dwSize = sizeof(type); - + #define SAFE_DELSHADER(TYPE,HANDLE,PDEVICE) \ if((HANDLE!=NULL)&&IS_VALID_PTR(PDEVICE)) { PDEVICE->Delete##TYPE##Shader(HANDLE); HANDLE=NULL; } @@ -94,7 +92,7 @@ typedef DWORD DXShaderHandle; #define RELEASE_ONCE false -// uncomment to add refcnt debug output +// uncomment to add refcnt debug output #define DEBUG_RELEASES #ifdef DEBUG_RELEASES @@ -116,7 +114,7 @@ typedef DWORD DXShaderHandle; #define PRINT_REFCNT(MODULE,p) { ULONG refcnt; (p)->AddRef(); refcnt=(p)->Release(); \ MODULE##_cat.debug() << #p << " has refcnt = " << refcnt << " at " << __FILE__ << ":" << __LINE__ << endl; } - + #else #define RELEASE(OBJECT,MODULE,DBGSTR,bDoDownToZero) { \ ULONG refcnt; \ @@ -132,7 +130,7 @@ typedef DWORD DXShaderHandle; }} #define PRINT_REFCNT(MODULE,p) -#endif +#endif #ifdef DO_PSTATS #define DO_PSTATS_STUFF(XX) XX; @@ -156,7 +154,7 @@ typedef enum { A8_FLAG = FLG(8), A8R3G3B2_FLAG = FLG(9), X4R4G4B4_FLAG = FLG(10), - A2R10G10B10_FLAG = FLG(11), + A2B10G10R10_FLAG = FLG(11), G16R16_FLAG = FLG(12), A8P8_FLAG = FLG(13), P8_FLAG = FLG(14), @@ -189,34 +187,33 @@ typedef enum { #define RECT_XSIZE(REC) (REC.right-REC.left) #define RECT_YSIZE(REC) (REC.bottom-REC.top) -typedef struct { - LPDIRECT3DDEVICE9 pD3DDevice; - IDirect3DSwapChain9 *pSwapChain; - LPDIRECT3D9 pD3D9; // copied from DXGraphicsPipe9 for convenience - HWND hWnd; - HMONITOR hMon; - DWORD MaxAvailVidMem; - ushort CardIDNum; // adapter ID - ushort depth_buffer_bitdepth; //GetSurfaceDesc is not reliable so must store this explicitly - bool bCanDirectDisableColorWrites; // if true, dont need blending for this - bool bIsLowVidMemCard; - bool bIsTNLDevice; - bool bCanUseHWVertexShaders; - bool bCanUsePixelShaders; - bool bIsDX9; - UINT SupportedScreenDepthsMask; - UINT SupportedTexFmtsMask; - D3DCAPS9 d3dcaps; - D3DDISPLAYMODE DisplayMode; - D3DPRESENT_PARAMETERS PresParams; // not redundant with DisplayMode since width/height must be 0 for windowed mode - D3DADAPTER_IDENTIFIER9 DXDeviceID; -} DXScreenData; +struct DXScreenData { + LPDIRECT3DDEVICE9 _d3d_device; + IDirect3DSwapChain9 *_swap_chain; + LPDIRECT3D9 _d3d9; // copied from DXGraphicsPipe9 for convenience + HWND _window; + HMONITOR _monitor; + DWORD _max_available_video_memory; + ushort _card_id; // adapter ID + ushort _depth_buffer_bitdepth; //GetSurfaceDesc is not reliable so must store this explicitly + bool _can_direct_disable_color_writes; // if true, dont need blending for this + bool _is_low_memory_card; + bool _is_tnl_device; + bool _can_use_hw_vertex_shaders; + bool _can_use_pixel_shaders; + bool _is_dx9_1; + UINT _supported_screen_depths_mask; + UINT _supported_tex_formats_mask; + D3DCAPS9 _d3dcaps; + D3DDISPLAYMODE _display_mode; + D3DPRESENT_PARAMETERS _presentation_params; // not redundant with _display_mode since width/height must be 0 for windowed mode + D3DADAPTER_IDENTIFIER9 _dx_device_id; +}; //utility stuff -extern map g_D3DFORMATmap; +extern pmap g_D3DFORMATmap; extern void Init_D3DFORMAT_map(); extern const char *D3DFormatStr(D3DFORMAT fmt); #endif - diff --git a/panda/src/dxgsg9/wdxGraphicsPipe9.I b/panda/src/dxgsg9/wdxGraphicsPipe9.I index eaafc45db5..3308a3a6ae 100755 --- a/panda/src/dxgsg9/wdxGraphicsPipe9.I +++ b/panda/src/dxgsg9/wdxGraphicsPipe9.I @@ -1,10 +1,10 @@ -// Filename: wdxGraphicsPipe8.I -// Created by: masad (02Jan04) +// Filename: wdxGraphicsPipe9.I +// Created by: drose (20Dec02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -14,4 +14,4 @@ // To contact the maintainers of this program write to // panda3d-general@lists.sourceforge.net . // -//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/panda/src/dxgsg9/wdxGraphicsPipe9.cxx b/panda/src/dxgsg9/wdxGraphicsPipe9.cxx index 2bf5819869..00449dc275 100755 --- a/panda/src/dxgsg9/wdxGraphicsPipe9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsPipe9.cxx @@ -1,10 +1,10 @@ // Filename: wdxGraphicsPipe9.cxx -// Created by: masad (05Jan04) +// Created by: drose (20Dec02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -23,7 +23,6 @@ TypeHandle wdxGraphicsPipe9::_type_handle; -// #define LOWVIDMEMTHRESHOLD 3500000 #define LOWVIDMEMTHRESHOLD 5700000 // 4MB cards should fall below this #define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000 // if # is > 1MB, card is lying and I cant tell what it is #define UNKNOWN_VIDMEM_SIZE 0xFFFFFFFF @@ -31,25 +30,24 @@ TypeHandle wdxGraphicsPipe9::_type_handle; //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsPipe9::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// wdxGraphicsPipe9:: wdxGraphicsPipe9() { _hDDrawDLL = NULL; _hD3D9_DLL = NULL; - _pD3D9 = NULL; + __d3d9 = NULL; _is_valid = init(); } //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsPipe9::Destructor // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// wdxGraphicsPipe9:: ~wdxGraphicsPipe9() { - - RELEASE(_pD3D9,wdxdisplay9,"ID3D9",RELEASE_DOWN_TO_ZERO); + RELEASE(__d3d9, wdxdisplay9, "ID3D9", RELEASE_DOWN_TO_ZERO); SAFE_FREELIB(_hD3D9_DLL); SAFE_FREELIB(_hDDrawDLL); } @@ -92,8 +90,10 @@ make_window(GraphicsStateGuardian *gsg, const string &name) { return NULL; } - // thanks to the dumb threading requirements this constructor actually does nothing but create an empty c++ object - // no windows are really opened until wdxGraphicsWindow9->open_window() is called + // thanks to the dumb threading requirements this constructor + // actually does nothing but create an empty c++ object. no windows + // are really opened until wdxGraphicsWindow9->open_window() is + // called return new wdxGraphicsWindow9(this, gsg, name); } @@ -108,45 +108,35 @@ make_window(GraphicsStateGuardian *gsg, const string &name) { //////////////////////////////////////////////////////////////////// bool wdxGraphicsPipe9:: init() { - if(!MyLoadLib(_hDDrawDLL,"ddraw.dll")) { - goto error; + if (!MyLoadLib(_hDDrawDLL, "ddraw.dll")) { + goto error; } - if(!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawCreateEx, "DirectDrawCreateEx")) { - goto error; + if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawCreateEx, "DirectDrawCreateEx")) { + goto error; } - if(!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawEnumerateExA, "DirectDrawEnumerateExA")) { - goto error; + if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawEnumerateExA, "DirectDrawEnumerateExA")) { + goto error; } - if(!MyLoadLib(_hD3D9_DLL,"d3d9.dll")) { - goto error; + if (!MyLoadLib(_hD3D9_DLL, "d3d9.dll")) { + goto error; } - if(!MyGetProcAddr(_hD3D9_DLL, (FARPROC*)&_Direct3DCreate9, "Direct3DCreate9")) { - goto error; + if (!MyGetProcAddr(_hD3D9_DLL, (FARPROC*)&_Direct3DCreate9, "Direct3DCreate9")) { + goto error; } -/* - wdxGraphicsPipe9 *dxpipe; - DCAST_INTO_V(dxpipe, _pipe); - - nassertv(_gsg == (GraphicsStateGuardian *)NULL); - _dxgsg = new DXGraphicsStateGuardian9(this); - _gsg = _dxgsg; - - // Tell the associated dxGSG about the window handle. - _dxgsg->scrn.hWnd = _hWnd; - */ // Create a Direct3D object. - // these were taken from the 9.0 and 9.0b d3d9.h SDK headers - #define D3D_SDK_VERSION_9_a 31 - //#define D3D_SDK_VERSION_9_b don't know yet + // these were taken from the 8.0 and 8.1 d3d8.h SDK headers + __is_dx9_1 = false; - /* - // are we using 9.0 or 9.0b? +#define D3D_SDK_VERSION_9_0 D3D_SDK_VERSION +#define D3D_SDK_VERSION_9_1 D3D_SDK_VERSION + + // are we using 9.0 or 9.1? WIN32_FIND_DATA TempFindData; HANDLE hFind; char tmppath[_MAX_PATH + 128]; @@ -155,22 +145,14 @@ init() { hFind = FindFirstFile (tmppath, &TempFindData); if (hFind != INVALID_HANDLE_VALUE) { FindClose(hFind); - _bIsDX9 = true; - _pD3D9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9); + __is_dx9_1 = true; + __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_1); } else { - _bIsDX91 = false; - _pD3D9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9); + __is_dx9_1 = false; + __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_0); } - */ - - // I think a simpler check is to look in your d3d9.h for version - if (D3D_SDK_VERSION == 31) { - _bIsDX9 = true; - _pD3D9 = (*_Direct3DCreate9)(D3D_SDK_VERSION); - } - - if (_pD3D9 == NULL) { - wdxdisplay9_cat.error() << "Direct3DCreate9(9." << (_bIsDX9 ? "1" : "0") << ") failed!, error=" << GetLastError() << endl; + if (__d3d9 == NULL) { + wdxdisplay9_cat.error() << "Direct3DCreate9(9." << (__is_dx9_1 ? "1" : "0") << ") failed!, error = " << GetLastError() << endl; //release_gsg(); goto error; } @@ -179,9 +161,8 @@ init() { return find_all_card_memavails(); - error: - // wdxdisplay9_cat.error() << ", error=" << GetLastError << endl; - return false; + error: + return false; } //////////////////////////////////////////////////////////////////// @@ -195,7 +176,7 @@ bool wdxGraphicsPipe9:: find_all_card_memavails() { HRESULT hr; - hr = (*_DirectDrawEnumerateExA)(dx7_driver_enum_callback, this, + hr = (*_DirectDrawEnumerateExA)(dx7_driver_enum_callback, this, DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES); if (FAILED(hr)) { wdxdisplay9_cat.fatal() @@ -219,18 +200,18 @@ find_all_card_memavails() { _card_ids.erase(_card_ids.begin()); } - for (UINT i=0; i < _card_ids.size(); i++) { + for (UINT i = 0; i < _card_ids.size(); i++) { LPDIRECTDRAW7 pDD; BYTE ddd_space[sizeof(DDDEVICEIDENTIFIER2)+4]; //bug in DX7 requires 4 extra bytes for GetDeviceID - DDDEVICEIDENTIFIER2 *pDX7DeviceID=(DDDEVICEIDENTIFIER2 *)&ddd_space[0]; - GUID *pGUID= &(_card_ids[i].DX7_DeviceGUID); + DDDEVICEIDENTIFIER2 *pDX7DeviceID = (DDDEVICEIDENTIFIER2 *)&ddd_space[0]; + GUID *pGUID = &(_card_ids[i].DX7_DeviceGUID); if (IsEqualGUID(*pGUID, ZeroGUID)) { - pGUID=NULL; + pGUID = NULL; } // Create the Direct Draw Object - hr = (*_DirectDrawCreateEx)(pGUID,(void **)&pDD, IID_IDirectDraw7, NULL); + hr = (*_DirectDrawCreateEx)(pGUID, (void **)&pDD, IID_IDirectDraw7, NULL); if (FAILED(hr)) { wdxdisplay9_cat.error() << "DirectDrawCreateEx failed for device (" << i @@ -243,7 +224,7 @@ find_all_card_memavails() { hr = pDD->GetDeviceIdentifier(pDX7DeviceID, 0x0); if (FAILED(hr)) { wdxdisplay9_cat.error() - << "GetDeviceID failed for device ("<< i << ")" << D3DERRORSTRING(hr); + << "GetDeviceID failed for device (" << i << ")" << D3DERRORSTRING(hr); continue; } @@ -256,8 +237,8 @@ find_all_card_memavails() { // fullscreen more than once due to the annoying monitor flicker, // so try to figure out optimal mode using this estimate DDSCAPS2 ddsGAVMCaps; - DWORD dwVidMemTotal,dwVidMemFree; - dwVidMemTotal=dwVidMemFree=0; + DWORD dwVidMemTotal, dwVidMemFree; + dwVidMemTotal = dwVidMemFree = 0; { // print out total INCLUDING AGP just for information purposes // and future use. The real value I'm interested in for @@ -269,7 +250,7 @@ find_all_card_memavails() { hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree); if (FAILED(hr)) { wdxdisplay9_cat.error() - << "GetAvailableVidMem failed for device #" << i + << "GetAvailableVidMem failed for device #" << i << D3DERRORSTRING(hr); //goto skip_device; //exit(1); // probably want to exit, since it may be my fault @@ -277,7 +258,7 @@ find_all_card_memavails() { } wdxdisplay9_cat.info() - << "GetAvailableVidMem (including AGP) returns Total: " + << "DX 9.0c GetAvailableVidMem (including AGP) returns Total: " << dwVidMemTotal <<", Free: " << dwVidMemFree << " for device #" << i << endl; @@ -288,24 +269,24 @@ find_all_card_memavails() { hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree); if (FAILED(hr)) { - wdxdisplay9_cat.error() << "GetAvailableVidMem failed for device #"<< i<< D3DERRORSTRING(hr); - // sometimes GetAvailableVidMem fails with hr=DDERR_NODIRECTDRAWHW for some unknown reason (bad drivers?) - // see bugs: 15327,18122, others. is it because D3D8 object has already been created? - if(hr==DDERR_NODIRECTDRAWHW) - continue; + wdxdisplay9_cat.error() << "GetAvailableVidMem failed for device #" << i<< D3DERRORSTRING(hr); + // sometimes GetAvailableVidMem fails with hr = DDERR_NODIRECTDRAWHW for some unknown reason (bad drivers?) + // see bugs: 15327, 18122, others. is it because D3D9 object has already been created? + if (hr == DDERR_NODIRECTDRAWHW) + continue; exit(1); // probably want to exit, since it may be my fault } wdxdisplay9_cat.info() << "GetAvailableVidMem (no AGP) returns Total: " << dwVidMemTotal - << ", Free: " << dwVidMemFree << " for device #"<< i<< endl; + << ", Free: " << dwVidMemFree << " for device #" << i<< endl; pDD->Release(); // release DD obj, since this is all we needed it for if (!dx_do_vidmemsize_check) { // still calling the DD stuff to get deviceID, etc. is this necessary? - _card_ids[i].MaxAvailVidMem = UNKNOWN_VIDMEM_SIZE; - _card_ids[i].bIsLowVidMemCard = false; + _card_ids[i]._max_available_video_memory = UNKNOWN_VIDMEM_SIZE; + _card_ids[i]._is_low_memory_card = false; continue; } @@ -315,7 +296,7 @@ find_all_card_memavails() { if (!ISPOW2(dwVidMemTotal)) { // assume they wont return a proper max value, so // round up to next pow of 2 - UINT count=0; + UINT count = 0; while ((dwVidMemTotal >> count) != 0x0) { count++; } @@ -323,11 +304,11 @@ find_all_card_memavails() { } } - // after SetDisplayMode, GetAvailVidMem totalmem seems to go down + // after Set_display_mode, GetAvailVidMem totalmem seems to go down // by 1.2 meg (contradicting above comment and what I think would // be correct behavior (shouldnt FS mode release the desktop // vidmem?), so this is the true value - _card_ids[i].MaxAvailVidMem = dwVidMemTotal; + _card_ids[i]._max_available_video_memory = dwVidMemTotal; // I can never get this stuff to work reliably, so I'm just // rounding up to nearest pow2. Could try to get @@ -337,46 +318,43 @@ find_all_card_memavails() { // assume buggy drivers (this means you, FireGL2) may return zero // (or small amts) for dwVidMemTotal, so ignore value if its < CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD - bool bLowVidMemFlag = - ((dwVidMemTotal > CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) && + bool bLowVidMemFlag = + ((dwVidMemTotal > CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) && (dwVidMemTotal< LOWVIDMEMTHRESHOLD)); - _card_ids[i].bIsLowVidMemCard = bLowVidMemFlag; - wdxdisplay9_cat.info() + _card_ids[i]._is_low_memory_card = bLowVidMemFlag; + wdxdisplay9_cat.info() << "SetLowVidMem flag to " << bLowVidMemFlag << " based on adjusted VidMemTotal: " << dwVidMemTotal << endl; } - return true; } //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsPipe9::dx7_driver_enum_callback // Access: Private, Static -// Description: +// Description: //////////////////////////////////////////////////////////////////// BOOL WINAPI wdxGraphicsPipe9:: dx7_driver_enum_callback(GUID *pGUID, TCHAR *strDesc, TCHAR *strName, VOID *argptr, HMONITOR hm) { - // #define PRNT(XX) ((XX!=NULL) ? XX : "NULL") - // cout << "strDesc: "<< PRNT(strDesc) << " strName: "<< PRNT(strName)<_card_ids.push_back(card_id); @@ -386,83 +364,80 @@ dx7_driver_enum_callback(GUID *pGUID, TCHAR *strDesc, TCHAR *strName, ////////////////////////////////////////////////////////////////// // Function: wdxGraphicsWindow9::find_best_depth_format // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// bool wdxGraphicsPipe9:: -find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &TestDisplayMode, +find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &Test_display_mode, D3DFORMAT *pBestFmt, bool bWantStencil, bool bForce16bpp, bool bVerboseMode) const { // list fmts in order of preference #define NUM_TEST_ZFMTS 3 - static D3DFORMAT NoStencilPrefList[NUM_TEST_ZFMTS]={D3DFMT_D32,D3DFMT_D24X8,D3DFMT_D16}; - static D3DFORMAT StencilPrefList[NUM_TEST_ZFMTS]={D3DFMT_D24S8,D3DFMT_D24X4S4,D3DFMT_D15S1}; + static D3DFORMAT NoStencilPrefList[NUM_TEST_ZFMTS] = {D3DFMT_D32, D3DFMT_D24X8, D3DFMT_D16}; + static D3DFORMAT StencilPrefList[NUM_TEST_ZFMTS] = {D3DFMT_D24S8, D3DFMT_D24X4S4, D3DFMT_D15S1}; - // do not use Display.DisplayMode since that is probably not set yet, use TestDisplayMode instead - - // int want_color_bits = _props._want_color_bits; - // int want_depth_bits = _props._want_depth_bits; should we pay attn to these so panda user can select bitdepth? + // do not use Display._display_mode since that is probably not set yet, use Test_display_mode instead *pBestFmt = D3DFMT_UNKNOWN; HRESULT hr; - // nvidia likes zbuf depth to match rendertarget depth + // nvidia likes zbuf depth to match rendertarget depth bool bOnlySelect16bpp = (bForce16bpp || - (IS_NVIDIA(Display.DXDeviceID) && IS_16BPP_DISPLAY_FORMAT(TestDisplayMode.Format))); + (IS_NVIDIA(Display._dx_device_id) && IS_16BPP_DISPLAY_FORMAT(Test_display_mode.Format))); if (bVerboseMode) { wdxdisplay9_cat.info() << "FindBestDepthFmt: bSelectOnly16bpp: " << bOnlySelect16bpp << endl; } - for (int i=0; i < NUM_TEST_ZFMTS; i++) { - D3DFORMAT TestDepthFmt = + for (int i = 0; i < NUM_TEST_ZFMTS; i++) { + D3DFORMAT TestDepthFmt = (bWantStencil ? StencilPrefList[i] : NoStencilPrefList[i]); if (bOnlySelect16bpp && !IS_16BPP_ZBUFFER(TestDepthFmt)) { continue; } - hr = Display.pD3D9->CheckDeviceFormat(Display.CardIDNum, + hr = Display._d3d9->CheckDeviceFormat(Display._card_id, D3DDEVTYPE_HAL, - TestDisplayMode.Format, + Test_display_mode.Format, D3DUSAGE_DEPTHSTENCIL, - D3DRTYPE_SURFACE,TestDepthFmt); + D3DRTYPE_SURFACE, TestDepthFmt); if (FAILED(hr)) { if (hr == D3DERR_NOTAVAILABLE) { if (bVerboseMode) - wdxdisplay9_cat.info() - << "FindBestDepthFmt: ChkDevFmt returns NotAvail for " + wdxdisplay9_cat.info() + << "FindBestDepthFmt: ChkDevFmt returns NotAvail for " << D3DFormatStr(TestDepthFmt) << endl; continue; } wdxdisplay9_cat.error() - << "unexpected CheckDeviceFormat failure" << D3DERRORSTRING(hr) + << "unexpected CheckDeviceFormat failure" << D3DERRORSTRING(hr) << endl; exit(1); } - hr = Display.pD3D9->CheckDepthStencilMatch(Display.CardIDNum, + hr = Display._d3d9->CheckDepthStencilMatch(Display._card_id, D3DDEVTYPE_HAL, - TestDisplayMode.Format, // adapter format - TestDisplayMode.Format, // backbuffer fmt (should be the same in my apps) + Test_display_mode.Format, // adapter format + Test_display_mode.Format, // backbuffer fmt (should be the same in my apps) TestDepthFmt); if (SUCCEEDED(hr)) { *pBestFmt = TestDepthFmt; break; } else { - if (hr==D3DERR_NOTAVAILABLE) { + if (hr == D3DERR_NOTAVAILABLE) { if (bVerboseMode) { wdxdisplay9_cat.info() << "FindBestDepthFmt: ChkDepMatch returns NotAvail for " - << D3DFormatStr(TestDisplayMode.Format) << ", " + << D3DFormatStr(Test_display_mode.Format) << ", " << D3DFormatStr(TestDepthFmt) << endl; } } else { wdxdisplay9_cat.error() << "unexpected CheckDepthStencilMatch failure for " - << D3DFormatStr(TestDisplayMode.Format) << ", " + << D3DFormatStr(Test_display_mode.Format) << ", " << D3DFormatStr(TestDepthFmt) << endl; exit(1); } @@ -485,28 +460,22 @@ find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &TestDisplayMode, // cases //////////////////////////////////////////////////////////////////// bool wdxGraphicsPipe9:: -special_check_fullscreen_resolution(DXScreenData &scrn,UINT x_size,UINT y_size) { - DWORD VendorId = scrn.DXDeviceID.VendorId; - DWORD DeviceId = scrn.DXDeviceID.DeviceId; +special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size) { + DWORD VendorId = scrn._dx_device_id.VendorId; + DWORD DeviceId = scrn._dx_device_id.DeviceId; switch (VendorId) { - case 0x8086: // Intel - /*for now, just validate all the intel cards at these resolutions. - I dont have a complete list of intel deviceIDs (missing 82830, 845, etc) - // Intel i810,i815,82810 - if ((DeviceId==0x7121)||(DeviceId==0x7123)||(DeviceId==0x7125)|| - (DeviceId==0x1132)) - */ - if ((x_size == 640) && (y_size == 480)) { - return true; - } - if ((x_size == 800) && (y_size == 600)) { - return true; - } - if ((x_size == 1024) && (y_size == 768)) { - return true; - } - break; + case 0x8086: // Intel + if ((x_size == 640) && (y_size == 480)) { + return true; + } + if ((x_size == 800) && (y_size == 600)) { + return true; + } + if ((x_size == 1024) && (y_size == 768)) { + return true; + } + break; } return false; @@ -522,261 +491,250 @@ void wdxGraphicsPipe9:: search_for_valid_displaymode(DXScreenData &scrn, UINT RequestedX_Size, UINT RequestedY_Size, bool bWantZBuffer, bool bWantStencil, - UINT *pSupportedScreenDepthsMask, + UINT *p_supported_screen_depths_mask, bool *pCouldntFindAnyValidZBuf, D3DFORMAT *pSuggestedPixFmt, bool bForce16bppZBuffer, bool bVerboseMode) { - // Use this list of format modes when trying to find a valid graphics - // format for the card. Formats are scanned in the order listed. - /* - Format Back buffer Display - A2R10G10B10 x x (full-screen mode only) - A8R8G8B8 x - X8R8G8B8 x x - A1R5G5B5 x - X1R5G5B5 x x - R5G6B5 x x - */ - static D3DFORMAT valid_formats[] = { - D3DFMT_X8R8G8B8, - D3DFMT_A2R10G10B10, - D3DFMT_R5G6B5, - D3DFMT_X1R5G5B5, - }; - static const int num_valid_formats = (sizeof(valid_formats) / sizeof(D3DFORMAT)); - - assert(IS_VALID_PTR(scrn.pD3D9)); + assert(IS_VALID_PTR(scrn._d3d9)); + + UINT adapter; HRESULT hr; *pSuggestedPixFmt = D3DFMT_UNKNOWN; - *pSupportedScreenDepthsMask = 0x0; + *p_supported_screen_depths_mask = 0x0; *pCouldntFindAnyValidZBuf = false; - wdxdisplay9_cat.info() - << "searching for valid display modes at res: (" - << RequestedX_Size << "," << RequestedY_Size - << ")" << endl; + adapter = D3DADAPTER_DEFAULT; - // iterate through all the formats we might support, and check the - // card for each one. - for (int fi = 0; fi < num_valid_formats; ++fi) { - int cNumModes = scrn.pD3D9->GetAdapterModeCount(scrn.CardIDNum, valid_formats[fi]); - D3DDISPLAYMODE BestDispMode; - ZeroMemory(&BestDispMode,sizeof(BestDispMode)); + int cNumModes = scrn._d3d9->GetAdapterModeCount(adapter, (D3DFORMAT) scrn._card_id); + D3DDISPLAYMODE BestDispMode; + ZeroMemory(&BestDispMode, sizeof(BestDispMode)); - if (bVerboseMode || wdxdisplay9_cat.is_spam()) { - wdxdisplay9_cat.info() - << "TotalModes with format " << D3DFormatStr(valid_formats[fi]) - << ": " << cNumModes << endl; + if (bVerboseMode) { + wdxdisplay9_cat.info() + << "searching for valid display modes at res: (" + << RequestedX_Size << ", " << RequestedY_Size + << "), TotalModes: " << cNumModes << endl; + } + + // ignore memory based checks for min res 640x480. some cards just + // dont give accurate memavails. (should I do the check anyway for + // 640x480 32bpp?) + bool bDoMemBasedChecks = + ((!((RequestedX_Size == 640)&&(RequestedY_Size == 480))) && + (scrn._max_available_video_memory != UNKNOWN_VIDMEM_SIZE) && + (!special_check_fullscreen_resolution(scrn, RequestedX_Size, RequestedY_Size))); + + if (bVerboseMode || wdxdisplay9_cat.is_spam()) { + wdxdisplay9_cat.info() + << "DoMemBasedChecks = " << bDoMemBasedChecks << endl; + } + + D3DFORMAT d3d_format; + +/* ***** DX9 ??? d3d_format */ + d3d_format = D3DFMT_X8R8G8B8; + + for (int i = 0; i < cNumModes; i++) { + D3DDISPLAYMODE dispmode; + hr = scrn._d3d9->EnumAdapterModes(scrn._card_id, d3d_format, i, &dispmode); + if (FAILED(hr)) { + wdxdisplay9_cat.error() + << "EnumAdapter_display_mode failed for device #" + << scrn._card_id << D3DERRORSTRING(hr); + continue; } - // ignore memory based checks for min res 640x480. some cards just - // dont give accurate memavails. (should I do the check anyway for - // 640x480 32bpp?) - bool bDoMemBasedChecks = - ((!((RequestedX_Size==640)&&(RequestedY_Size==480))) && - (scrn.MaxAvailVidMem!=UNKNOWN_VIDMEM_SIZE) && - (!special_check_fullscreen_resolution(scrn,RequestedX_Size,RequestedY_Size))); - - if (bVerboseMode || wdxdisplay9_cat.is_spam()) { - wdxdisplay9_cat.info() - << "DoMemBasedChecks = " << bDoMemBasedChecks << endl; + if ((dispmode.Width != RequestedX_Size) || + (dispmode.Height != RequestedY_Size)) { + if (bVerboseMode) { + wdxdisplay9_cat.info() + << "Mode dimension " << dispmode.Width << "x" << dispmode.Height + << "; format " << D3DFormatStr(dispmode.Format) + << ": onto next mode\n"; + } + continue; } - for (int i=0; i < cNumModes; i++) { - D3DDISPLAYMODE dispmode; - hr = scrn.pD3D9->EnumAdapterModes(scrn.CardIDNum,valid_formats[fi],i,&dispmode); - if (FAILED(hr)) { + if ((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) { + // dont want refresh rates under 60Hz, but 0 or 1 might indicate + // a default refresh rate, which is usually > = 60 + if (bVerboseMode) { + wdxdisplay9_cat.info() + << "skipping mode[" << i << "], bad refresh rate: " + << dispmode.RefreshRate << endl; + } + continue; + } + + // Note no attempt is made to verify if format will work at + // requested size, so even if this call succeeds, could still get + // an out-of-video-mem error + + hr = scrn._d3d9->CheckDeviceFormat(scrn._card_id, D3DDEVTYPE_HAL, dispmode.Format, + D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, + dispmode.Format); + if (FAILED(hr)) { + if (hr == D3DERR_NOTAVAILABLE) { + if (bVerboseMode) { + wdxdisplay9_cat.info() + << "skipping mode[" << i + << "], CheckDevFmt returns NotAvail for fmt: " + << D3DFormatStr(dispmode.Format) << endl; + } + continue; + } else { wdxdisplay9_cat.error() - << "EnumAdapterDisplayMode failed for device #" - << scrn.CardIDNum << D3DERRORSTRING(hr); + << "CheckDeviceFormat failed for device #" + << scrn._card_id << D3DERRORSTRING(hr); continue; } + } - if ((dispmode.Width!=RequestedX_Size) || - (dispmode.Height!=RequestedY_Size)) { - if (bVerboseMode) { - wdxdisplay9_cat.info() - << "Mode dimension found " << dispmode.Width << "x" << dispmode.Height - << ": continuing onto next mode\n"; - } - continue; - } + bool bIs16bppRenderTgt = IS_16BPP_DISPLAY_FORMAT(dispmode.Format); + float RendTgtMinMemReqmt; - if ((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) { - // dont want refresh rates under 60Hz, but 0 or 1 might indicate - // a default refresh rate, which is usually >=60 - if (bVerboseMode) { - wdxdisplay9_cat.info() - << "skipping mode[" << i << "], bad refresh rate: " - << dispmode.RefreshRate << endl; - } - continue; - } + // if we have a valid memavail value, try to determine if we have + // enough space + if (bDoMemBasedChecks) { + // assume user is testing fullscreen, not windowed, so use the + // dwTotal value see if 3 scrnbufs (front/back/z)at 16bpp at + // x_size*y_size will fit with a few extra megs for texmem - // Note no attempt is made to verify if format will work at - // requested size, so even if this call succeeds, could still get - // an out-of-video-mem error - - hr = scrn.pD3D9->CheckDeviceFormat(scrn.CardIDNum, D3DDEVTYPE_HAL, dispmode.Format, - D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, - dispmode.Format); - if (FAILED(hr)) { - if (hr==D3DERR_NOTAVAILABLE) { - if (bVerboseMode) { - wdxdisplay9_cat.info() - << "skipping mode[" << i - << "], CheckDevFmt returns NotAvail for fmt: " - << D3DFormatStr(dispmode.Format) << endl; - } - continue; - } else { - wdxdisplay9_cat.error() - << "CheckDeviceFormat failed for device #" - << scrn.CardIDNum << D3DERRORSTRING(hr); - continue; - } - } - - bool bIs16bppRenderTgt = IS_16BPP_DISPLAY_FORMAT(dispmode.Format); - float RendTgtMinMemReqmt; - - // if we have a valid memavail value, try to determine if we have - // enough space - if (bDoMemBasedChecks) { - // assume user is testing fullscreen, not windowed, so use the - // dwTotal value see if 3 scrnbufs (front/back/z)at 16bpp at - // x_size*y_size will fit with a few extra megs for texmem - - // 8MB Rage Pro says it has 6.8 megs Total free and will run at - // 1024x768, so formula makes it so that is OK + // 8MB Rage Pro says it has 6.8 megs Total free and will run at + // 1024x768, so formula makes it so that is OK #define REQD_TEXMEM 1800000 - float bytes_per_pixel = (bIs16bppRenderTgt ? 2 : 4); - - // cant do this check yet since gsg doesnt exist! - // assert((_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_double_buffer) != 0); + float bytes_per_pixel = (bIs16bppRenderTgt ? 2 : 4); - // *2 for double buffer + // *2 for double buffer - RendTgtMinMemReqmt = - ((float)RequestedX_Size) * ((float)RequestedY_Size) * - bytes_per_pixel * 2 + REQD_TEXMEM; - - if (bVerboseMode || wdxdisplay9_cat.is_spam()) - wdxdisplay9_cat.info() - << "Testing Mode (" < scrn.MaxAvailVidMem) { - if (bVerboseMode || wdxdisplay9_cat.is_debug()) - wdxdisplay9_cat.info() - << "not enough VidMem for render tgt, skipping display fmt " - << D3DFormatStr(dispmode.Format) << " (" - << (int)RendTgtMinMemReqmt << " > " - << scrn.MaxAvailVidMem << ")\n"; - continue; - } - } - - if (bWantZBuffer) { - D3DFORMAT zformat; - if (!find_best_depth_format(scrn,dispmode, &zformat, - bWantStencil, bForce16bppZBuffer)) { - *pCouldntFindAnyValidZBuf=true; - continue; - } - - float MinMemReqmt = 0.0f; - - if (bDoMemBasedChecks) { - // test memory again, this time including zbuf size - float zbytes_per_pixel = (IS_16BPP_ZBUFFER(zformat) ? 2 : 4); - float MinMemReqmt = RendTgtMinMemReqmt + ((float)RequestedX_Size)*((float)RequestedY_Size)*zbytes_per_pixel; - - if (bVerboseMode || wdxdisplay9_cat.is_spam()) - wdxdisplay9_cat.info() - << "Testing Mode w/Z (" << RequestedX_Size << "x" - << RequestedY_Size << "," << D3DFormatStr(dispmode.Format) - << ")\nReqdVidMem: "<< (int)MinMemReqmt << " AvailVidMem: " - << scrn.MaxAvailVidMem << endl; - - if (MinMemReqmt > scrn.MaxAvailVidMem) { - if (bVerboseMode || wdxdisplay9_cat.is_debug()) - wdxdisplay9_cat.info() - << "not enough VidMem for RendTgt+zbuf, skipping display fmt " - << D3DFormatStr(dispmode.Format) << " (" << (int)MinMemReqmt - << " > " << scrn.MaxAvailVidMem << ")\n"; - continue; - } - } - - if ((!bDoMemBasedChecks) || (MinMemReqmt scrn._max_available_video_memory) { + if (bVerboseMode || wdxdisplay9_cat.is_debug()) + wdxdisplay9_cat.info() + << "not enough VidMem for render tgt, skipping display fmt " + << D3DFormatStr(dispmode.Format) << " (" + << (int)RendTgtMinMemReqmt << " > " + << scrn._max_available_video_memory << ")\n"; + continue; + } + } + + if (bWantZBuffer) { + D3DFORMAT zformat; + if (!find_best_depth_format(scrn, dispmode, &zformat, + bWantStencil, bForce16bppZBuffer)) { + *pCouldntFindAnyValidZBuf = true; + continue; } - switch (dispmode.Format) { - case D3DFMT_X8R8G8B8: - *pSupportedScreenDepthsMask |= X8R8G8B8_FLAG; - break; - case D3DFMT_A2R10G10B10: - *pSupportedScreenDepthsMask |= A2R10G10B10_FLAG; - break; - case D3DFMT_R5G6B5: - *pSupportedScreenDepthsMask |= R5G6B5_FLAG; - break; - case D3DFMT_X1R5G5B5: - *pSupportedScreenDepthsMask |= X1R5G5B5_FLAG; - break; + float MinMemReqmt = 0.0f; - default: - // Render target formats should be only one of valid_formats, - // above. - wdxdisplay9_cat.error() - << "unrecognized supported fmt "<< D3DFormatStr(dispmode.Format) - << " returned by EnumAdapterDisplayModes!\n"; + if (bDoMemBasedChecks) { + // test memory again, this time including zbuf size + float zbytes_per_pixel = (IS_16BPP_ZBUFFER(zformat) ? 2 : 4); + float MinMemReqmt = RendTgtMinMemReqmt + ((float)RequestedX_Size)*((float)RequestedY_Size)*zbytes_per_pixel; + + if (bVerboseMode || wdxdisplay9_cat.is_spam()) + wdxdisplay9_cat.info() + << "Testing Mode w/Z (" << RequestedX_Size << "x" + << RequestedY_Size << ", " << D3DFormatStr(dispmode.Format) + << ")\nReqdVidMem: " << (int)MinMemReqmt << " AvailVidMem: " + << scrn._max_available_video_memory << endl; + + if (MinMemReqmt > scrn._max_available_video_memory) { + if (bVerboseMode || wdxdisplay9_cat.is_debug()) + wdxdisplay9_cat.info() + << "not enough VidMem for RendTgt+zbuf, skipping display fmt " + << D3DFormatStr(dispmode.Format) << " (" << (int)MinMemReqmt + << " > " << scrn._max_available_video_memory << ")\n"; + continue; + } } + + if ((!bDoMemBasedChecks) || (MinMemReqmt_Scrn, scrn, sizeof(device->_Scrn)); - device->_pD3DDevice = device->_Scrn.pD3DDevice; + device->_d3d_device = device->_Scrn._d3d_device; _device = device; wdxdisplay9_cat.info() << "walla: device" << device << "\n"; return device.p(); - -/* - nassertv(_gsg == (GraphicsStateGuardian *)NULL); - _dxgsg = new DXGraphicsStateGuardian9(this); - _gsg = _dxgsg; - - // Tell the associated dxGSG about the window handle. - _dxgsg->scrn.hWnd = _hWnd; - - if (pD3D9 == NULL) { - wdxdisplay9_cat.error() - << "Direct3DCreate9 failed!\n"; - release_gsg(); - return; - } - - if (!choose_adapter(pD3D9)) { - wdxdisplay9_cat.error() - << "Unable to find suitable rendering device.\n"; - release_gsg(); - return; - } - - create_screen_buffers_and_device(_dxgsg->scrn, dx_force_16bpp_zbuffer); - */ } + //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsPipew9::make_gsg // Access: Public, Virtual @@ -847,80 +778,56 @@ make_gsg(const FrameBufferProperties &properties, // put here because of GLX multithreading requirement PT(DXGraphicsStateGuardian9) gsg = new DXGraphicsStateGuardian9(properties); return gsg.p(); - -/* - nassertv(_gsg == (GraphicsStateGuardian *)NULL); - _dxgsg = new DXGraphicsStateGuardian9(this); - _gsg = _dxgsg; - - // Tell the associated dxGSG about the window handle. - _dxgsg->scrn.hWnd = _hWnd; - - if (pD3D9 == NULL) { - wdxdisplay9_cat.error() - << "Direct3DCreate9 failed!\n"; - release_gsg(); - return; - } - - if (!choose_adapter(pD3D9)) { - wdxdisplay9_cat.error() - << "Unable to find suitable rendering device.\n"; - release_gsg(); - return; - } - - create_screen_buffers_and_device(_dxgsg->scrn, dx_force_16bpp_zbuffer); - */ } -map g_D3DFORMATmap; +pmap g_D3DFORMATmap; void Init_D3DFORMAT_map() { - if(g_D3DFORMATmap.size()!=0) + if (g_D3DFORMATmap.size() != 0) return; - #define INSERT_ELEM(XX) g_D3DFORMATmap[XX##_FLAG] = D3DFMT_##XX; +#define INSERT_ELEM(XX) g_D3DFORMATmap[XX##_FLAG] = D3DFMT_##XX; - INSERT_ELEM(R8G8B8); - INSERT_ELEM(A8R8G8B8); - INSERT_ELEM(X8R8G8B8); - INSERT_ELEM(R5G6B5); - INSERT_ELEM(X1R5G5B5); - INSERT_ELEM(A1R5G5B5); - INSERT_ELEM(A4R4G4B4); - INSERT_ELEM(R3G3B2); - INSERT_ELEM(A8); - INSERT_ELEM(A8R3G3B2); - INSERT_ELEM(X4R4G4B4); - INSERT_ELEM(A2R10G10B10); - INSERT_ELEM(G16R16); - INSERT_ELEM(A8P8); - INSERT_ELEM(P8); - INSERT_ELEM(L8); - INSERT_ELEM(A8L8); - INSERT_ELEM(A4L4); - INSERT_ELEM(V8U8); - INSERT_ELEM(L6V5U5); - INSERT_ELEM(X8L8V8U8); - INSERT_ELEM(Q8W8V8U8); - INSERT_ELEM(V16U16); - //INSERT_ELEM(W11V11U10); - INSERT_ELEM(A2W10V10U10); - INSERT_ELEM(UYVY); - INSERT_ELEM(YUY2); - INSERT_ELEM(DXT1); - INSERT_ELEM(DXT2); - INSERT_ELEM(DXT3); - INSERT_ELEM(DXT4); - INSERT_ELEM(DXT5); + INSERT_ELEM(R8G8B8); + INSERT_ELEM(A8R8G8B8); + INSERT_ELEM(X8R8G8B8); + INSERT_ELEM(R5G6B5); + INSERT_ELEM(X1R5G5B5); + INSERT_ELEM(A1R5G5B5); + INSERT_ELEM(A4R4G4B4); + INSERT_ELEM(R3G3B2); + INSERT_ELEM(A8); + INSERT_ELEM(A8R3G3B2); + INSERT_ELEM(X4R4G4B4); + INSERT_ELEM(A2B10G10R10); + INSERT_ELEM(G16R16); + INSERT_ELEM(A8P8); + INSERT_ELEM(P8); + INSERT_ELEM(L8); + INSERT_ELEM(A8L8); + INSERT_ELEM(A4L4); + INSERT_ELEM(V8U8); + INSERT_ELEM(L6V5U5); + INSERT_ELEM(X8L8V8U8); + INSERT_ELEM(Q8W8V8U8); + INSERT_ELEM(V16U16); +// NOT IN DX9 +// INSERT_ELEM(W11V11U10); + INSERT_ELEM(A2W10V10U10); + INSERT_ELEM(UYVY); + INSERT_ELEM(YUY2); + INSERT_ELEM(DXT1); + INSERT_ELEM(DXT2); + INSERT_ELEM(DXT3); + INSERT_ELEM(DXT4); + INSERT_ELEM(DXT5); } + const char *D3DFormatStr(D3DFORMAT fmt) { #define CASESTR(XX) case XX: return #XX; - switch(fmt) { CASESTR(D3DFMT_UNKNOWN); CASESTR(D3DFMT_R8G8B8); @@ -934,7 +841,7 @@ const char *D3DFormatStr(D3DFORMAT fmt) { CASESTR(D3DFMT_A8); CASESTR(D3DFMT_A8R3G3B2); CASESTR(D3DFMT_X4R4G4B4); - CASESTR(D3DFMT_A2R10G10B10); + CASESTR(D3DFMT_A2B10G10R10); CASESTR(D3DFMT_G16R16); CASESTR(D3DFMT_A8P8); CASESTR(D3DFMT_P8); @@ -946,7 +853,8 @@ const char *D3DFormatStr(D3DFORMAT fmt) { CASESTR(D3DFMT_X8L8V8U8); CASESTR(D3DFMT_Q8W8V8U8); CASESTR(D3DFMT_V16U16); - //CASESTR(D3DFMT_W11V11U10); +// NOT IN DX9 +// CASESTR(D3DFMT_W11V11U10); CASESTR(D3DFMT_A2W10V10U10); CASESTR(D3DFMT_UYVY); CASESTR(D3DFMT_YUY2); @@ -969,4 +877,3 @@ const char *D3DFormatStr(D3DFORMAT fmt) { return "Invalid D3DFORMAT"; } - diff --git a/panda/src/dxgsg9/wdxGraphicsPipe9.h b/panda/src/dxgsg9/wdxGraphicsPipe9.h index 8f90cce15a..07b046f888 100755 --- a/panda/src/dxgsg9/wdxGraphicsPipe9.h +++ b/panda/src/dxgsg9/wdxGraphicsPipe9.h @@ -1,10 +1,10 @@ -// Filename: wdxGraphicsPipe8.h -// Created by: masad (02Jan04) +// Filename: wdxGraphicsPipe9.h +// Created by: drose (20Dec02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -25,20 +25,10 @@ #include "dxgsg9base.h" #include -typedef struct { - UINT cardID; - char szDriver[MAX_DEVICE_IDENTIFIER_STRING]; - char szDescription[MAX_DEVICE_IDENTIFIER_STRING]; - GUID guidDeviceIdentifier; - DWORD VendorID, DeviceID; - HMONITOR hMon; -} DXDeviceInfo; -typedef pvector DXDeviceInfoVec; - //////////////////////////////////////////////////////////////////// // Class : wdxGraphicsPipe9 // Description : This graphics pipe represents the interface for -// creating DirectX graphics windows. +// creating DirectX9 graphics windows. //////////////////////////////////////////////////////////////////// class EXPCL_PANDADX wdxGraphicsPipe9 : public WinGraphicsPipe { public: @@ -52,18 +42,18 @@ public: GraphicsStateGuardian *share_with); virtual PT(GraphicsDevice) make_device(void *scrn); - bool find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &TestDisplayMode, - D3DFORMAT *pBestFmt, bool bWantStencil, - bool bForce16bpp, bool bVerboseMode = false) const; + bool find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &Test_display_mode, + D3DFORMAT *pBestFmt, bool bWantStencil, + bool bForce16bpp, bool bVerboseMode = false) const; void search_for_valid_displaymode(DXScreenData &scrn, - UINT RequestedX_Size, UINT RequestedY_Size, - bool bWantZBuffer, bool bWantStencil, - UINT *pSupportedScreenDepthsMask, - bool *pCouldntFindAnyValidZBuf, - D3DFORMAT *pSuggestedPixFmt, - bool bForce16bppZBuffer, - bool bVerboseMode = false); + UINT RequestedX_Size, UINT RequestedY_Size, + bool bWantZBuffer, bool bWantStencil, + UINT *p_supported_screen_depths_mask, + bool *pCouldntFindAnyValidZBuf, + D3DFORMAT *pSuggestedPixFmt, + bool bForce16bppZBuffer, + bool bVerboseMode = false); bool special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size,UINT y_size); @@ -81,7 +71,7 @@ private: private: HINSTANCE _hDDrawDLL; HINSTANCE _hD3D9_DLL; - LPDIRECT3D9 _pD3D9; + LPDIRECT3D9 __d3d9; typedef LPDIRECT3D9 (WINAPI *Direct3DCreate9_ProcPtr)(UINT SDKVersion); @@ -91,20 +81,19 @@ private: LPDIRECTDRAWENUMERATEEX _DirectDrawEnumerateExA; Direct3DCreate9_ProcPtr _Direct3DCreate9; - // CardID is used in DX7 lowmem card-classification pass so DX9 can + // CardID is used in DX7 lowmem card-classification pass so DX8 can // establish correspondence b/w DX7 mem info & DX8 device struct CardID { - HMONITOR hMon; - DWORD MaxAvailVidMem; - bool bIsLowVidMemCard; + HMONITOR _monitor; + DWORD _max_available_video_memory; + bool _is_low_memory_card; GUID DX7_DeviceGUID; DWORD VendorID, DeviceID; - // char szDriver[MAX_DEVICE_IDENTIFIER_STRING]; }; - + typedef pvector CardIDs; CardIDs _card_ids; - bool _bIsDX9; + bool __is_dx9_1; public: static TypeHandle get_class_type() { diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.I b/panda/src/dxgsg9/wdxGraphicsWindow9.I index 64fdefdce8..a07c7bc8bb 100755 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.I +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.I @@ -1,10 +1,10 @@ -// Filename: wdxGraphicsWindow8.I -// Created by: masad (02Jan04) +// Filename: wdxGraphicsWindow9.I +// Created by: drose (20Dec02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -15,3 +15,4 @@ // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// + \ No newline at end of file diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx index 6f30d67448..4f3d3093f7 100755 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx @@ -1,10 +1,10 @@ -// Filename: wdxGraphicsWindow8.cxx -// Created by: masad (05Jan04) +// Filename: wdxGraphicsWindow9.cxx +// Created by: mike (09Jan00) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE -// Copyright (c) 2004, Disney Enterprises, Inc. All rights reserved +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license @@ -16,56 +16,23 @@ // //////////////////////////////////////////////////////////////////// -#include -#include -#include -#include #include "wdxGraphicsPipe9.h" #include "wdxGraphicsWindow9.h" #include "config_dxgsg9.h" #include "config_display.h" - #include "keyboardButton.h" #include "mouseButton.h" #include "throw_event.h" #include "pStatTimer.h" - - +#include "pmap.h" #include -#include +#include +#include +#include +#include TypeHandle wdxGraphicsWindow9::_type_handle; -#define WDX_WINDOWCLASSNAME "wdxDisplay" -#define WDX_WINDOWCLASSNAME_NOCURSOR WDX_WINDOWCLASSNAME "_NoCursor" -#define DEFAULT_CURSOR IDC_ARROW - -// define this to enable debug testing of dinput joystick -//#define DINPUT_DEBUG_POLL - -typedef map HWND_PANDAWIN_MAP; - -HWND_PANDAWIN_MAP hwnd_pandawin_map; -wdxGraphicsWindow9* global_wdxwinptr = NULL; // need this for temporary windproc - -#define MAX_DISPLAYS 20 - -#define PAUSED_TIMER_ID 7 // completely arbitrary choice -#define JOYSTICK_POLL_TIMER_ID 8 -#define DX_IS_READY ((_dxgsg!=NULL)&&(_dxgsg->GetDXReady())) - -LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam,LPARAM lparam); - -/* -// because we dont have access to ModifierButtons, as a hack just synchronize state of these -// keys on get/lose keybd focus -#define NUM_MODIFIER_KEYS 16 -unsigned int hardcoded_modifier_buttons[NUM_MODIFIER_KEYS]={VK_SHIFT,VK_MENU,VK_CONTROL,VK_SPACE,VK_TAB, - VK_UP,VK_DOWN,VK_LEFT,VK_RIGHT,VK_PRIOR,VK_NEXT,VK_HOME,VK_END, - VK_INSERT,VK_DELETE,VK_ESCAPE}; -*/ -//#define UNKNOWN_VIDMEM_SIZE 0xFFFFFFFF - //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsWindow9::Constructor // Access: Public @@ -74,15 +41,17 @@ unsigned int hardcoded_modifier_buttons[NUM_MODIFIER_KEYS]={VK_SHIFT,VK_MENU,VK_ wdxGraphicsWindow9:: wdxGraphicsWindow9(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, const string &name) : - WinGraphicsWindow(pipe, gsg, name) + WinGraphicsWindow(pipe, gsg, name) { - // dont actually create the window in the constructor. reason: multi-threading requires - // panda C++ window object to exist in separate thread from actual API window + // dont actually create the window in the constructor. reason: + // multi-threading requires panda C++ window object to exist in + // separate thread from actual API window _dxgsg = DCAST(DXGraphicsStateGuardian9, gsg); + _buffer_mask = 0; _depth_buffer_bpp = 0; _awaiting_restore = false; - ZeroMemory(&_wcontext,sizeof(_wcontext)); + ZeroMemory(&_wcontext, sizeof(_wcontext)); } //////////////////////////////////////////////////////////////////// @@ -94,124 +63,30 @@ wdxGraphicsWindow9:: ~wdxGraphicsWindow9() { } +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow9::make_current +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// void wdxGraphicsWindow9:: make_current() { PStatTimer timer(_make_current_pcollector); DXGraphicsStateGuardian9 *dxgsg; DCAST_INTO_V(dxgsg, _gsg); - //wglMakeCurrent(_hdc, wdxgsg->_context); dxgsg->set_context(&_wcontext); // Now that we have made the context current to a window, we can // reset the GSG state if this is the first time it has been used. // (We can't just call reset() when we construct the GSG, because // reset() requires having a current context.) - dxgsg->reset_if_new(); - - //wdxdisplay9_cat.debug() << "this is " << this << "\n"; -} - -/* BUGBUG: need to reinstate these methods ASAP. they were incorrectly moved from the GraphicsWindow to the GSG - apps need to know the framebuffer format so they can create texture/rendertgt with same fmt -int wdxGraphicsWindow9:: -get_depth_bitwidth() { - assert(_dxgsg!=NULL); - if(_dxgsg->scrn.PresParams.EnableAutoDepthStencil) - return _dxgsg->scrn.depth_buffer_bitdepth; - else return 0; - -// GetSurfaceDesc is not reliable, on GF2, GetSurfDesc returns 32bpp when you created a 24bpp zbuf -// instead store the depth used at creation time - -// DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); -// _dxgsg->_zbuf->GetSurfaceDesc(&ddsd); -// return ddsd.ddpfPixelFormat.dwRGBBitCount; -} - -void wdxGraphicsWindow9:: -get_framebuffer_format(PixelBuffer::Type &fb_type, PixelBuffer::Format &fb_format) { - assert(_dxgsg!=NULL); - - fb_type = PixelBuffer::T_unsigned_byte; - // this is sortof incorrect, since for F_rgb5 it's really 5 bits per channel - //would have to change a lot of texture stuff to make this correct though - - if(IS_16BPP_DISPLAY_FORMAT(_dxgsg->scrn.PresParams.BackBufferFormat)) - fb_format = PixelBuffer::F_rgb5; - else fb_format = PixelBuffer::F_rgb; -} -*/ - -//////////////////////////////////////////////////////////////////// -// Function: wdxGraphicsWindow9::verify_window_sizes -// Access: Public, Virtual -// Description: Determines which of the indicated window sizes are -// supported by available hardware (e.g. in fullscreen -// mode). -// -// On entry, dimen is an array containing contiguous x,y -// pairs specifying possible display sizes; it is -// numsizes*2 words long. The function will zero out -// any invalid x,y size pairs. The return value is the -// number of valid sizes that were found. -//////////////////////////////////////////////////////////////////// -int wdxGraphicsWindow9:: -verify_window_sizes(int numsizes, int *dimen) { - // unfortunately this only works AFTER you make the window - // initially, so its really mostly useful for resizes only - assert(IS_VALID_PTR(_dxgsg)); - - int num_valid_modes = 0; - - wdxGraphicsPipe9 *dxpipe; - DCAST_INTO_R(dxpipe, _pipe, 0); - - // not requesting same refresh rate since changing res might not - // support same refresh rate at new size - - int *pCurDim = dimen; - - for (int i=0; i < numsizes; i++, pCurDim += 2) { - int x_size = pCurDim[0]; - int y_size = pCurDim[1]; - - bool bIsGoodMode = false; - bool CouldntFindAnyValidZBuf; - D3DFORMAT newPixFmt = D3DFMT_UNKNOWN; - - if (dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) { - // bypass the test below for certain cards we know have valid modes - bIsGoodMode=true; - - } else { - if (_wcontext.bIsLowVidMemCard) { - bIsGoodMode = ((x_size == 640) && (y_size == 480)); - } else { - dxpipe->search_for_valid_displaymode(_wcontext, x_size, y_size, _wcontext.PresParams.EnableAutoDepthStencil != false, - IS_STENCIL_FORMAT(_wcontext.PresParams.AutoDepthStencilFormat), - &_wcontext.SupportedScreenDepthsMask, - &CouldntFindAnyValidZBuf, &newPixFmt, dx_force_16bpp_zbuffer); - bIsGoodMode = (newPixFmt != D3DFMT_UNKNOWN); - } - } - - if (bIsGoodMode) { - num_valid_modes++; - } else { - // tell caller the mode is invalid - pCurDim[0] = 0; - pCurDim[1] = 0; - } - - if (wdxdisplay9_cat.is_spam()) { - wdxdisplay9_cat.spam() - << "Fullscrn Mode (" << x_size << "," << y_size << ")\t" - << (bIsGoodMode ? "V" : "Inv") <<"alid\n"; - } + if (dxgsg->reset_if_new()) { + // We should also fill in the buffer mask at this time, which adds + // support for depth buffer or stencil buffer if the window + // supports it. This assumes that the gsg will not be shared by + // other windows with a different buffer mask. + dxgsg->_buffer_mask |= _buffer_mask; } - - return num_valid_modes; } //////////////////////////////////////////////////////////////////// @@ -228,7 +103,7 @@ begin_frame() { if (_awaiting_restore) { // The fullscreen window was recently restored; we can't continue // until the GSG says we can. - if (!_dxgsg->CheckCooperativeLevel()) { + if (!_dxgsg->check_cooperative_level()) { // Keep waiting. return false; } @@ -255,12 +130,202 @@ begin_frame() { void wdxGraphicsWindow9:: end_flip() { if (_dxgsg != (DXGraphicsStateGuardian9 *)NULL && is_active()) { - //wdxdisplay9_cat.debug() << "current swapchain from end_flip is " << _wcontext.pSwapChain << "\n"; _dxgsg->show_frame(); } GraphicsWindow::end_flip(); } +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow9::verify_window_sizes +// Access: Public, Virtual +// Description: Determines which of the indicated window sizes are +// supported by available hardware (e.g. in fullscreen +// mode). +// +// On entry, dimen is an array containing contiguous x, y +// pairs specifying possible display sizes; it is +// numsizes*2 words long. The function will zero out +// any invalid x, y size pairs. The return value is the +// number of valid sizes that were found. +//////////////////////////////////////////////////////////////////// +int wdxGraphicsWindow9:: +verify_window_sizes(int numsizes, int *dimen) { + // unfortunately this only works AFTER you make the window + // initially, so its really mostly useful for resizes only + nassertr(IS_VALID_PTR(_dxgsg), 0); + + int num_valid_modes = 0; + + wdxGraphicsPipe9 *dxpipe; + DCAST_INTO_R(dxpipe, _pipe, 0); + + // not requesting same refresh rate since changing res might not + // support same refresh rate at new size + + int *pCurDim = dimen; + + for (int i = 0; i < numsizes; i++, pCurDim += 2) { + int x_size = pCurDim[0]; + int y_size = pCurDim[1]; + + bool bIsGoodMode = false; + bool CouldntFindAnyValidZBuf; + D3DFORMAT newPixFmt = D3DFMT_UNKNOWN; + + if (dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) { + // bypass the test below for certain cards we know have valid modes + bIsGoodMode = true; + + } else { + if (_wcontext._is_low_memory_card) { + bIsGoodMode = ((x_size == 640) && (y_size == 480)); + } else { + dxpipe->search_for_valid_displaymode + (_wcontext, x_size, y_size, _wcontext._presentation_params.EnableAutoDepthStencil != false, + IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat), + &_wcontext._supported_screen_depths_mask, + &CouldntFindAnyValidZBuf, &newPixFmt, dx_force_16bpp_zbuffer); + bIsGoodMode = (newPixFmt != D3DFMT_UNKNOWN); + } + } + + if (bIsGoodMode) { + num_valid_modes++; + } else { + // tell caller the mode is invalid + pCurDim[0] = 0; + pCurDim[1] = 0; + } + + if (wdxdisplay9_cat.is_spam()) { + wdxdisplay9_cat.spam() + << "Fullscrn Mode (" << x_size << ", " << y_size << ")\t" + << (bIsGoodMode ? "V" : "Inv") << "alid\n"; + } + } + + return num_valid_modes; +} + +////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow::close_window +// Access: Public +// Description: Some cleanup is necessary for directx closeup of window. +// Handle close window events for this particular +// window. +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow9:: +close_window() { + wdxdisplay9_cat.debug() << "wdx closed window\n"; + _dxgsg->release_swap_chain(&_wcontext); + WinGraphicsWindow::close_window(); +} + +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow9::open_window +// Access: Protected, Virtual +// Description: Opens the window right now. Called from the window +// thread. Returns true if the window is successfully +// opened, or false if there was a problem. +//////////////////////////////////////////////////////////////////// +bool wdxGraphicsWindow9:: +open_window() { + PT(DXGraphicsDevice9) dxdev; + DXGraphicsStateGuardian9 *dxgsg; + DCAST_INTO_R(dxgsg, _gsg, false); + WindowProperties props; + bool discard_device = false; + + if (!choose_device()) { + return false; + } + + wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n"; + if (!WinGraphicsWindow::open_window()) { + return false; + } + _wcontext._window = _hWnd; + + wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n"; + + // Here check if a device already exists. If so, then this open_window + // call may be an extension to create multiple windows on same device + // In that case just create an additional swapchain for this window + + while (true) { + if (dxgsg->get_pipe()->get_device() == NULL || discard_device) { + wdxdisplay9_cat.debug() << "device is null or fullscreen\n"; + + // If device exists, free it + if (dxgsg->get_pipe()->get_device()) { + dxgsg->dx_cleanup(); + } + + wdxdisplay9_cat.debug() << "device width " << _wcontext._display_mode.Width << "\n"; + if (!create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer)) { + // just crash here + wdxdisplay9_cat.error() << "fatal: must be trying to create two fullscreen windows: not supported\n"; + return false; + } + dxgsg->get_pipe()->make_device((void*)(&_wcontext)); + dxgsg->copy_pres_reset(&_wcontext); + dxgsg->create_swap_chain(&_wcontext); + break; + + } else { + // fill in the DXScreenData from dxdevice here and change the + // reference to _window. + wdxdisplay9_cat.debug() << "device is not null\n"; + + dxdev = (DXGraphicsDevice9*)dxgsg->get_pipe()->get_device(); + props = get_properties(); + memcpy(&_wcontext, &dxdev->_Scrn, sizeof(DXScreenData)); + + _wcontext._presentation_params.Windowed = !is_fullscreen(); + _wcontext._presentation_params.hDeviceWindow = _wcontext._window = _hWnd; + _wcontext._presentation_params.BackBufferWidth = _wcontext._display_mode.Width = props.get_x_size(); + _wcontext._presentation_params.BackBufferHeight = _wcontext._display_mode.Height = props.get_y_size(); + + wdxdisplay9_cat.debug() << "device width " << _wcontext._presentation_params.BackBufferWidth << "\n"; + if (!dxgsg->create_swap_chain(&_wcontext)) { + discard_device = true; + continue; // try again + } + init_resized_window(); + break; + } + } + wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n"; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow9::reset_window +// Access: Public, Virtual +// Description: Resets the window framebuffer right now. Called +// from graphicsEngine. It releases the current swap +// chain / creates a new one. If this is the initial +// window and swapchain is false, then it calls reset_ +// main_device to Reset the device. +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow9:: +reset_window(bool swapchain) { + DXGraphicsStateGuardian9 *dxgsg; + DCAST_INTO_V(dxgsg, _gsg); + if (swapchain) { + if (_wcontext._swap_chain) { + dxgsg->create_swap_chain(&_wcontext); + wdxdisplay9_cat.debug() << "created swapchain " << _wcontext._swap_chain << "\n"; + } + } + else { + if (_wcontext._swap_chain) { + dxgsg->release_swap_chain(&_wcontext); + wdxdisplay9_cat.debug() << "released swapchain " << _wcontext._swap_chain << "\n"; + } + } +} + //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsWindow9::fullscreen_restored // Access: Protected, Virtual @@ -272,7 +337,7 @@ end_flip() { //////////////////////////////////////////////////////////////////// void wdxGraphicsWindow9:: fullscreen_restored(WindowProperties &properties) { - // In DX9, unlike DX7, for some reason we can't immediately start + // In DX8, unlike DX7, for some reason we can't immediately start // rendering as soon as the window is restored, even though // BeginScene() says we can. Instead, we have to wait until // TestCooperativeLevel() lets us in. We need to set a flag so we @@ -299,21 +364,24 @@ handle_reshape() { WindowProperties props = get_properties(); int x_size = props.get_x_size(); int y_size = props.get_y_size(); - bool resize_succeeded = reset_device_resize_window(x_size, y_size); - if (!resize_succeeded) { + + if (_wcontext._presentation_params.BackBufferWidth != x_size || + _wcontext._presentation_params.BackBufferHeight != y_size) { + bool resize_succeeded = reset_device_resize_window(x_size, y_size); + if (wdxdisplay9_cat.is_debug()) { - wdxdisplay9_cat.debug() - << "windowed_resize to size: (" << x_size << "," << y_size - << ") failed due to out-of-memory\n"; - } else { - if (wdxdisplay9_cat.is_debug()) { - int x_origin = props.get_x_origin(); - int y_origin = props.get_y_origin(); - wdxdisplay9_cat.debug() - << "windowed_resize to origin: (" << x_origin << "," - << y_origin << "), size: (" << x_size - << "," << y_size << ")\n"; - } + if (!resize_succeeded) { + wdxdisplay9_cat.debug() + << "windowed_resize to size: (" << x_size << ", " << y_size + << ") failed due to out-of-memory\n"; + } else { + int x_origin = props.get_x_origin(); + int y_origin = props.get_y_origin(); + wdxdisplay9_cat.debug() + << "windowed_resize to origin: (" << x_origin << ", " + << y_origin << "), size: (" << x_size + << ", " << y_size << ")\n"; + } } } } @@ -329,310 +397,69 @@ bool wdxGraphicsWindow9:: do_fullscreen_resize(int x_size, int y_size) { bool bCouldntFindValidZBuf; D3DFORMAT pixFmt; - bool bNeedZBuffer = (_wcontext.PresParams.EnableAutoDepthStencil!=false); - bool bNeedStencilBuffer = IS_STENCIL_FORMAT(_wcontext.PresParams.AutoDepthStencilFormat); + bool bNeedZBuffer = (_wcontext._presentation_params.EnableAutoDepthStencil != false); + bool bNeedStencilBuffer = IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat); wdxGraphicsPipe9 *dxpipe; DCAST_INTO_R(dxpipe, _pipe, false); - bool bIsGoodMode=false; - bool bResizeSucceeded=false; + bool bIsGoodMode = false; + bool bResizeSucceeded = false; - if (!dxpipe->special_check_fullscreen_resolution(_wcontext, x_size,y_size)) { + if (!dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) { // bypass the lowvidmem test below for certain "lowmem" cards we know have valid modes - // wdxdisplay9_cat.info() << "1111111 lowvidmemcard="<< _wcontext.bIsLowVidMemCard << endl; - if (_wcontext.bIsLowVidMemCard && (!((x_size==640) && (y_size==480)))) { - wdxdisplay9_cat.error() << "resize() failed: will not try to resize low vidmem device #" << _wcontext.CardIDNum << " to non-640x480!\n"; - goto Error_Return; + if (_wcontext._is_low_memory_card && (!((x_size == 640) && (y_size == 480)))) { + wdxdisplay9_cat.error() << "resize() failed: will not try to resize low vidmem device #" << _wcontext._card_id << " to non-640x480!\n"; + return bResizeSucceeded; } } // must ALWAYS use search_for_valid_displaymode even if we know // a-priori that res is valid so we can get a valid pixfmt - dxpipe->search_for_valid_displaymode(_wcontext, x_size, y_size, - bNeedZBuffer, bNeedStencilBuffer, - &_wcontext.SupportedScreenDepthsMask, - &bCouldntFindValidZBuf, - &pixFmt, dx_force_16bpp_zbuffer); - bIsGoodMode=(pixFmt!=D3DFMT_UNKNOWN); + dxpipe->search_for_valid_displaymode(_wcontext, x_size, y_size, + bNeedZBuffer, bNeedStencilBuffer, + &_wcontext._supported_screen_depths_mask, + &bCouldntFindValidZBuf, + &pixFmt, dx_force_16bpp_zbuffer); + bIsGoodMode = (pixFmt != D3DFMT_UNKNOWN); if (!bIsGoodMode) { wdxdisplay9_cat.error() << "resize() failed: " - << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") - << " at " << x_size << "x" << y_size << " for device #" << _wcontext.CardIDNum <16bpp, fallback to 16bpp buffers - _wcontext.DisplayMode.Format = ((_wcontext.SupportedScreenDepthsMask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); - dx_force_16bpp_zbuffer=true; + _wcontext._display_mode.Format = ((_wcontext._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); + dx_force_16bpp_zbuffer = true; if (wdxdisplay9_cat.info()) - wdxdisplay9_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #"<< _wcontext.CardIDNum << endl; + wdxdisplay9_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #" << _wcontext._card_id << endl; - bResizeSucceeded= reset_device_resize_window(x_size, y_size); // create the new resized rendertargets + bResizeSucceeded = reset_device_resize_window(x_size, y_size); // create the new resized rendertargets } } - Error_Return: - - if (wdxdisplay9_cat.is_debug()) - wdxdisplay9_cat.debug() << "fullscrn resize("<support_overlay_window(flag); - } -} -////////////////////////////////////////////////////////////////// -// Function: wdxGraphicsWindow::close_window -// Access: Public -// Description: Some cleanup is necessary for directx closeup of window. -// Handle close window events for this particular -// window. -//////////////////////////////////////////////////////////////////// -void wdxGraphicsWindow9:: -close_window() { - wdxdisplay9_cat.debug() << "wdx closed window\n"; - _dxgsg->release_swap_chain(&_wcontext); - WinGraphicsWindow::close_window(); -} - -#if 1 -////////////////////////////////////////////////////////////////// -// Function: WinGraphicsWindow::window_proc -// Access: Private -// Description: This is the nonstatic window_proc function. It is -// called to handle window events for this particular -// window. -//////////////////////////////////////////////////////////////////// -LONG wdxGraphicsWindow9:: -window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - return WinGraphicsWindow::window_proc(hwnd,msg,wparam,lparam); -} - -#else - -//////////////////////////////////////////////////////////////////// -// Function: window_proc -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -LONG wdxGraphicsWindow9:: -window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - int button = -1; - int x, y, width, height; - - switch(msg) { - case WM_PAINT: { - // primarily seen when app window is 'uncovered' - if((_WindowAdjustingType != NotAdjusting) || (!DX_IS_READY)) { - // let DefWndProc do WM_ERASEBKGND & just draw black, - // rather than forcing Present to stretchblt the old window contents - // into the new size - break; - } - - PAINTSTRUCT ps; - BeginPaint(hwnd, &ps); - if(DX_IS_READY) { - _dxgsg->show_frame(true); // 'true' since just want to show the last rendered backbuf, if any - } - EndPaint(hwnd, &ps); - return 0; - } - - case WM_ENTERSIZEMOVE: - if(_dxgsg!=NULL) - _dxgsg->SetDXReady(false); // dont see pic during resize - _WindowAdjustingType = MovingOrResizing; - break; - - case WM_EXITSIZEMOVE: { - #ifdef _DEBUG - wdxdisplay_cat.spam() << "WM_EXITSIZEMOVE received" << endl; - #endif - - if(_WindowAdjustingType==Resizing) { - bool bSucceeded=handle_windowed_resize(hwnd,true); - - if(!bSucceeded) { - #if 0 - bugbug need to fix this stuff - SetWindowPos(hwnd,NULL,0,0,lastxsize,lastysize,SWP_NOMOVE | - #endif - } - } - - _WindowAdjustingType = NotAdjusting; - _dxgsg->SetDXReady(true); - return 0; - } - - case WM_SIZE: { - - #ifdef _DEBUG - { - width = LOWORD(lparam); height = HIWORD(lparam); - wdxdisplay_cat.spam() << "WM_SIZE received with width:" << width << " height: " << height << " flags: " << - ((wparam == SIZE_MAXHIDE)? "SIZE_MAXHIDE " : "") << ((wparam == SIZE_MAXSHOW)? "SIZE_MAXSHOW " : "") << - ((wparam == SIZE_MINIMIZED)? "SIZE_MINIMIZED " : "") << ((wparam == SIZE_RESTORED)? "SIZE_RESTORED " : "") << - ((wparam == SIZE_MAXIMIZED)? "SIZE_MAXIMIZED " : "") << endl; - } - #endif - // old comment -- added SIZE_RESTORED to handle 3dfx case - if(_props._fullscreen || ((_dxgsg==NULL) || (_dxgsg->scrn.hWnd==NULL)) || ((wparam != SIZE_RESTORED) && (wparam != SIZE_MAXIMIZED))) - break; - - width = LOWORD(lparam); height = HIWORD(lparam); - - if((_props._xsize != width) || (_props._ysize != height)) { - _WindowAdjustingType = Resizing; - - // for maximized,unmaximize, need to call resize code artificially - // since no WM_EXITSIZEMOVE is generated. - if(wparam==SIZE_MAXIMIZED) { - _bSizeIsMaximized=TRUE; - window_proc(hwnd, WM_EXITSIZEMOVE, 0x0,0x0); - } else if((wparam==SIZE_RESTORED) && _bSizeIsMaximized) { - _bSizeIsMaximized=FALSE; // only want to reinit dx if restoring from maximized state - window_proc(hwnd, WM_EXITSIZEMOVE, 0x0,0x0); - } - } - - break; - } - - case WM_ERASEBKGND: { - // WM_ERASEBKGND will be ignored during resizing, because - // we dont want WM_PAINT's generated as user is manually resizing window. - - // for the intermediate resizing images that WM_PAINT would show to be useful, - // the panda window parameters need to be reset on every - // WM_SIZE event and that isnt happening yet - - if(_WindowAdjustingType) - break; - return 0; // dont let GDI waste time redrawing the deflt background - } - - case WM_TIMER: - // 2 cases of app deactivation: - // - // 1) user has switched out of fullscreen mode - // this is first signalled when ACTIVATEAPP returns false - // for this case, we dont wake up until WM_SIZE returns restore or maximize - // and WM_TIMER just periodically reawakens app for idle processing - - // unfortunately this doesnt seem to work because RestoreAllSurfaces doesn't - // seem to think we're back in the original displaymode even after I've received - // the WM_DISPLAYCHANGE msg, and returns WRONGMODE error. So the only way I can - // think of to make this work is to have the timer periodically check for restored - // coop level, as it does in case 2) - - // - // 2) windowed app has lost access to dx because another app has taken dx exclusive mode - // here we rely on WM_TIMER to periodically check if it is ok to reawaken app. - // windowed apps currently run regardless of if its window is in the foreground - // so we cannot rely on window messages to reawaken app - - if((wparam==_PandaPausedTimer) && ((!_window_active)||_active_minimized_fullscreen)) { - assert(_dxgsg!=NULL); - _dxgsg->CheckCooperativeLevel(DO_REACTIVATE_WINDOW); - - // wdxdisplay_cat.spam() << "periodic return of control to app\n"; - _return_control_to_app = true; - // throw_event("PandaPaused"); - // do we still need to do this since I return control to app periodically using timer msgs? - // does app need to know to avoid major computation? - } - - #ifdef DINPUT_DEBUG_POLL - // probably want to get rid of this in favor of event-based input - if(dx_use_joystick && (wparam==_pParentWindowGroup->_pDInputInfo->_JoystickPollTimer)) { - DIJOYSTATE2 js; - ZeroMemory(&js,sizeof(js)); - if(_pParentWindowGroup->_pDInputInfo->ReadJoystick(0,js)) { - // for now just print stuff out to make sure it works - wdxdisplay_cat.debug() << "joyPos (X: " << js.lX << ",Y: " << js.lY << ",Z: " << js.lZ << ")\n"; - for(int i=0;i<128;i++) { - if(js.rgbButtons[i]!=0) - wdxdisplay_cat.debug() << "joyButton "<< i << " pressed\n"; - } - } else { - wdxdisplay_cat.error() << "read of Joystick failed!\n"; - exit(1); - } - } - #endif - return 0; - - case WM_CLOSE: - #ifdef _DEBUG - wdxdisplay_cat.spam() << "WM_CLOSE received\n"; - #endif - // close_window(); - delete _pParentWindowGroup; - - // BUGBUG: right now there is no way to tell the panda app the graphics window is invalid or - // has been closed by the user, to prevent further methods from being called on the window. - // this needs to be added to panda for multiple windows to work. in the meantime, just - // trigger an exit here if # windows==0, since that is the expected behavior when all - // windows are closed (should be done by the app though, and it assumes you only make this - // type of panda gfx window) - - if(hwnd_pandawin_map.size()==0) { - exit(0); - } - return 0; - - case WM_ACTIVATEAPP: { - #ifdef _DEBUG - wdxdisplay_cat.spam() << "WM_ACTIVATEAPP(" << (bool)(wparam!=0) <<") received\n"; - #endif - - if((!wparam) && _props._fullscreen) { - deactivate_window(); - return 0; - } // dont want to reactivate until window is actually un-minimized (see WM_SIZE) - break; - } - } - - return WinGraphicsWindow::window_proc(hwnd,msg,wparam,lparam); -} -#endif - //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsWindow9::create_screen_buffers_and_device // Access: Private @@ -642,33 +469,36 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // Sets _depth_buffer_bpp appropriately. //////////////////////////////////////////////////////////////////// bool wdxGraphicsWindow9:: -create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer) { +create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer) { wdxGraphicsPipe9 *dxpipe; DCAST_INTO_R(dxpipe, _pipe, false); - // only want dx_pick_best_screenres to apply to initial startup, and - // since the initial res has already been picked, dont use auto-res-select in any future init sequence. + // only want dx_pick_best_screenres to apply to initial startup, and + // since the initial res has already been picked, dont use + // auto-res-select in any future init sequence. dx_pick_best_screenres = false; - DWORD dwRenderWidth=Display.DisplayMode.Width; - DWORD dwRenderHeight=Display.DisplayMode.Height; - DWORD dwBehaviorFlags=0x0; - LPDIRECT3D9 pD3D9=Display.pD3D9; - D3DCAPS9 *pD3DCaps = &Display.d3dcaps; - D3DPRESENT_PARAMETERS* pPresParams = &Display.PresParams; + DWORD dwRenderWidth = display._display_mode.Width; + DWORD dwRenderHeight = display._display_mode.Height; + DWORD dwBehaviorFlags = 0x0; + LPDIRECT3D9 _d3d9 = display._d3d9; + D3DCAPS9 *pD3DCaps = &display._d3dcaps; + D3DPRESENT_PARAMETERS* presentation_params = &display._presentation_params; RECT view_rect; HRESULT hr; + wdxdisplay9_cat.debug() << "Display Width " << dwRenderWidth << " and PresParam Width " << _wcontext._presentation_params.BackBufferWidth << "\n"; + // BUGBUG: need to change panda to put frame buffer properties with GraphicsWindow, not GSG!! int frame_buffer_mode = _gsg->get_properties().get_frame_buffer_mode(); bool bWantStencil = ((frame_buffer_mode & FrameBufferProperties::FM_stencil) != 0); - PRINT_REFCNT(wdxdisplay9,pD3D9); + PRINT_REFCNT(wdxdisplay9, _d3d9); - assert(pD3D9!=NULL); + assert(_d3d9 != NULL); assert(pD3DCaps->DevCaps & D3DDEVCAPS_HWRASTERIZATION); - pPresParams->BackBufferFormat = Display.DisplayMode.Format; // dont need dest alpha, so just use adapter format + presentation_params->BackBufferFormat = display._display_mode.Format; // dont need dest alpha, so just use adapter format bool do_sync = sync_video; @@ -679,111 +509,102 @@ create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer } // verify the rendertarget fmt one last time - if (FAILED(pD3D9->CheckDeviceFormat(Display.CardIDNum, D3DDEVTYPE_HAL, Display.DisplayMode.Format,D3DUSAGE_RENDERTARGET, - D3DRTYPE_SURFACE, pPresParams->BackBufferFormat))) { - wdxdisplay9_cat.error() << "device #"<BackBufferFormat) << endl; + if (FAILED(_d3d9->CheckDeviceFormat(display._card_id, D3DDEVTYPE_HAL, display._display_mode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_SURFACE, presentation_params->BackBufferFormat))) { + wdxdisplay9_cat.error() << "device #" << display._card_id << " CheckDeviceFmt failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl; goto Fallback_to_16bpp_buffers; } - if (FAILED(pD3D9->CheckDeviceType(Display.CardIDNum,D3DDEVTYPE_HAL, Display.DisplayMode.Format,pPresParams->BackBufferFormat, - is_fullscreen()))) { - wdxdisplay9_cat.error() << "device #"<BackBufferFormat) << endl; + if (FAILED(_d3d9->CheckDeviceType(display._card_id, D3DDEVTYPE_HAL, display._display_mode.Format, presentation_params->BackBufferFormat, + is_fullscreen()))) { + wdxdisplay9_cat.error() << "device #" << display._card_id << " CheckDeviceType failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl; goto Fallback_to_16bpp_buffers; } - if (Display.PresParams.EnableAutoDepthStencil) { - if (!dxpipe->find_best_depth_format(Display, Display.DisplayMode, - &Display.PresParams.AutoDepthStencilFormat, - bWantStencil, false)) { + if (display._presentation_params.EnableAutoDepthStencil) { + if (!dxpipe->find_best_depth_format(display, display._display_mode, + &display._presentation_params.AutoDepthStencilFormat, + bWantStencil, false)) { wdxdisplay9_cat.error() << "find_best_depth_format failed in CreateScreenBuffers for device #" - << Display.CardIDNum << endl; + << display._card_id << endl; goto Fallback_to_16bpp_buffers; } - _depth_buffer_bpp = D3DFMT_to_DepthBits(Display.PresParams.AutoDepthStencilFormat); + _depth_buffer_bpp = D3DFMT_to_DepthBits(display._presentation_params.AutoDepthStencilFormat); } else { _depth_buffer_bpp = 0; } - pPresParams->Windowed = !is_fullscreen(); + presentation_params->Windowed = !is_fullscreen(); if (dx_multisample_antialiasing_level>1) { // need to check both rendertarget and zbuffer fmts - hr = pD3D9->CheckDeviceMultiSampleType(Display.CardIDNum, D3DDEVTYPE_HAL, Display.DisplayMode.Format, + hr = _d3d9->CheckDeviceMultiSampleType(display._card_id, D3DDEVTYPE_HAL, display._display_mode.Format, is_fullscreen(), D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level.get_value()), NULL); if (FAILED(hr)) { - wdxdisplay9_cat.fatal() << "device #"<CheckDeviceMultiSampleType(Display.CardIDNum, D3DDEVTYPE_HAL, Display.PresParams.AutoDepthStencilFormat, + if (display._presentation_params.EnableAutoDepthStencil) { + hr = _d3d9->CheckDeviceMultiSampleType(display._card_id, D3DDEVTYPE_HAL, display._presentation_params.AutoDepthStencilFormat, is_fullscreen(), D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level.get_value()), NULL); if (FAILED(hr)) { - wdxdisplay9_cat.fatal() << "device #"<MultiSampleType = D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level.get_value()); + presentation_params->MultiSampleType = D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level.get_value()); if (wdxdisplay9_cat.is_info()) - wdxdisplay9_cat.info() << "device #"<BackBufferCount = 1; - pPresParams->Flags = 0x0; - pPresParams->hDeviceWindow = Display.hWnd; - pPresParams->BackBufferWidth = Display.DisplayMode.Width; - pPresParams->BackBufferHeight = Display.DisplayMode.Height; + presentation_params->BackBufferCount = 1; + presentation_params->Flags = 0x0; + presentation_params->hDeviceWindow = display._window; + presentation_params->BackBufferWidth = display._display_mode.Width; + presentation_params->BackBufferHeight = display._display_mode.Height; -#if 0 - GetClientRect(GetDesktopWindow(), &view_rect); - pPresParams->BackBufferWidth = view_rect.right; - pPresParams->BackBufferHeight = view_rect.bottom; - wdxdisplay9_cat.debug()<<"width "<SwapEffect = D3DSWAPEFFECT_DISCARD; // we dont care about preserving contents of old frame - pPresParams->PresentationInterval = (do_sync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE); - pPresParams->FullScreen_RefreshRateInHz = Display.DisplayMode.RefreshRate; + // CREATE FULLSCREEN BUFFERS -#ifdef _DEBUG - if (pPresParams->MultiSampleType != D3DMULTISAMPLE_NONE) - assert(pPresParams->SwapEffect == D3DSWAPEFFECT_DISCARD); // only valid effect for multisample -#endif + presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; // we dont care about preserving contents of old frame + presentation_params->PresentationInterval = (do_sync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE); + presentation_params->FullScreen_RefreshRateInHz = display._display_mode.RefreshRate; - ClearToBlack(Display.hWnd, get_properties()); + ClearToBlack(display._window, get_properties()); - hr = pD3D9->CreateDevice(Display.CardIDNum, D3DDEVTYPE_HAL, _hWnd, - dwBehaviorFlags, pPresParams, &Display.pD3DDevice); + hr = _d3d9->CreateDevice(display._card_id, D3DDEVTYPE_HAL, _hWnd, + dwBehaviorFlags, presentation_params, &display._d3d_device); if (FAILED(hr)) { - wdxdisplay9_cat.fatal() << "D3D CreateDevice failed for device #" << Display.CardIDNum << ", " << D3DERRORSTRING(hr); + wdxdisplay9_cat.fatal() << "D3D CreateDevice failed for device #" << display._card_id << ", " << D3DERRORSTRING(hr); if (hr == D3DERR_OUTOFVIDEOMEMORY) goto Fallback_to_16bpp_buffers; @@ -792,72 +613,67 @@ create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer } SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight); - } // end create full screen buffers - else { // CREATE WINDOWED BUFFERS - - /* not necessary anymore...all cards can do this now a days - if (!(pD3DCaps->Caps2 & D3DCAPS2_CANRENDERWINDOWED)) { - wdxdisplay9_cat.fatal() << "the 3D HW cannot render windowed, exiting..." << endl; - exit(1); - } - */ + } else { + // CREATE WINDOWED BUFFERS D3DDISPLAYMODE dispmode; - hr = Display.pD3D9->GetAdapterDisplayMode(Display.CardIDNum, &dispmode); + hr = display._d3d9->GetAdapterDisplayMode(display._card_id, &dispmode); if (FAILED(hr)) { - wdxdisplay9_cat.fatal() << "GetAdapterDisplayMode failed" << D3DERRORSTRING(hr); - //exit(1); + wdxdisplay9_cat.fatal() + << "GetAdapterDisplayMode failed" << D3DERRORSTRING(hr); return false; } if (dispmode.Format == D3DFMT_P8) { - wdxdisplay9_cat.fatal() << "Can't run windowed in an 8-bit or less display mode" << endl; - //exit(1); + wdxdisplay9_cat.fatal() + << "Can't run windowed in an 8-bit or less display mode" << endl; return false; } - pPresParams->PresentationInterval = 0; + presentation_params->PresentationInterval = 0; if (dx_multisample_antialiasing_level<2) { if (do_sync) { - pPresParams->SwapEffect = D3DSWAPEFFECT_COPY; + // It turns out that COPY_VSYNC has real performance problems + // on many nVidia cards--it syncs at some random interval, + // possibly skipping over several video syncs. Screw it, + // we'll effectively disable sync-video with windowed mode + // using DirectX8. + //presentation_params->SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; + presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; } else { - pPresParams->SwapEffect = D3DSWAPEFFECT_DISCARD; //D3DSWAPEFFECT_COPY; does this make any difference? + presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; } } else { - pPresParams->SwapEffect = D3DSWAPEFFECT_DISCARD; + presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; } - // assert((dwRenderWidth==pPresParams->BackBufferWidth)&&(dwRenderHeight==pPresParams->BackBufferHeight)); + //assert((dwRenderWidth == presentation_params->BackBufferWidth)&&(dwRenderHeight == presentation_params->BackBufferHeight)); - hr = pD3D9->CreateDevice(Display.CardIDNum, D3DDEVTYPE_HAL, _hWnd, - dwBehaviorFlags, pPresParams, &Display.pD3DDevice); + hr = _d3d9->CreateDevice(display._card_id, D3DDEVTYPE_HAL, _hWnd, + dwBehaviorFlags, presentation_params, &display._d3d_device); if (FAILED(hr)) { - wdxdisplay9_cat.warning() << "pPresParams->BackBufferWidth : " << pPresParams->BackBufferWidth << endl; - wdxdisplay9_cat.warning() << "pPresParams->BackBufferHeight : " << pPresParams->BackBufferHeight << endl; - wdxdisplay9_cat.warning() << "pPresParams->BackBufferFormat : " << pPresParams->BackBufferFormat << endl; - wdxdisplay9_cat.warning() << "pPresParams->BackBufferCount : " << pPresParams->BackBufferCount << endl; - wdxdisplay9_cat.warning() << "D3D CreateDevice failed for device #" << Display.CardIDNum << D3DERRORSTRING(hr); + wdxdisplay9_cat.warning() << "presentation_params->BackBufferWidth : " << presentation_params->BackBufferWidth << endl; + wdxdisplay9_cat.warning() << "presentation_params->BackBufferHeight : " << presentation_params->BackBufferHeight << endl; + wdxdisplay9_cat.warning() << "presentation_params->BackBufferFormat : " << presentation_params->BackBufferFormat << endl; + wdxdisplay9_cat.warning() << "presentation_params->BackBufferCount : " << presentation_params->BackBufferCount << endl; + wdxdisplay9_cat.warning() << "D3D CreateDevice failed for device #" << display._card_id << D3DERRORSTRING(hr); goto Fallback_to_16bpp_buffers; } } // end create windowed buffers -#if 0 - pPresParams->BackBufferWidth = Display.DisplayMode.Width; - pPresParams->BackBufferHeight = Display.DisplayMode.Height; -#endif - // ======================================================== - PRINT_REFCNT(wdxdisplay9,_wcontext.pD3DDevice); + PRINT_REFCNT(wdxdisplay9, _wcontext._d3d_device); - if (pPresParams->EnableAutoDepthStencil) { - _dxgsg->_buffer_mask |= RenderBuffer::T_depth; - if (IS_STENCIL_FORMAT(pPresParams->AutoDepthStencilFormat)) - _dxgsg->_buffer_mask |= RenderBuffer::T_stencil; + if (presentation_params->EnableAutoDepthStencil) { + _buffer_mask |= RenderBuffer::T_depth; + if (IS_STENCIL_FORMAT(presentation_params->AutoDepthStencilFormat)) { + _buffer_mask |= RenderBuffer::T_stencil; + } } init_resized_window(); @@ -866,33 +682,32 @@ create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer Fallback_to_16bpp_buffers: - if ((!IS_16BPP_DISPLAY_FORMAT(pPresParams->BackBufferFormat)) && - (Display.SupportedScreenDepthsMask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) { + if ((!IS_16BPP_DISPLAY_FORMAT(presentation_params->BackBufferFormat)) && + (display._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) { // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers - Display.DisplayMode.Format = ((Display.SupportedScreenDepthsMask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); + display._display_mode.Format = ((display._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); if (wdxdisplay9_cat.info()) { wdxdisplay9_cat.info() << "CreateDevice failed with out-of-vidmem or invalid BackBufferFormat, retrying w/16bpp buffers on device #" - << Display.CardIDNum << endl; + << display._card_id << endl; } - return create_screen_buffers_and_device(Display, true); + return create_screen_buffers_and_device(display, true); //return; - } else if (!((dwRenderWidth==640)&&(dwRenderHeight==480))) { + } else if (!((dwRenderWidth == 640)&&(dwRenderHeight == 480))) { if (wdxdisplay9_cat.info()) - wdxdisplay9_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on device #"<< Display.CardIDNum << endl; + wdxdisplay9_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on device #" << display._card_id << endl; // try final fallback to 640x480x16 - Display.DisplayMode.Width=640; - Display.DisplayMode.Height=480; - return create_screen_buffers_and_device(Display, true); + display._display_mode.Width = 640; + display._display_mode.Height = 480; + return create_screen_buffers_and_device(display, true); //return; } else { - wdxdisplay9_cat.fatal() + wdxdisplay9_cat.fatal() << "Can't create any screen buffers, bailing out.\n"; - //exit(1); return false; } } @@ -912,34 +727,34 @@ choose_device() { wdxGraphicsPipe9 *dxpipe; DCAST_INTO_R(dxpipe, _pipe, false); - int num_adapters = dxpipe->_pD3D9->GetAdapterCount(); + int num_adapters = dxpipe->__d3d9->GetAdapterCount(); DXDeviceInfoVec device_infos; for (int i = 0; i < num_adapters; i++) { D3DADAPTER_IDENTIFIER9 adapter_info; ZeroMemory(&adapter_info, sizeof(D3DADAPTER_IDENTIFIER9)); - hr = dxpipe->_pD3D9->GetAdapterIdentifier(i, 0, &adapter_info); + hr = dxpipe->__d3d9->GetAdapterIdentifier(i, 0, &adapter_info); if (FAILED(hr)) { wdxdisplay9_cat.fatal() << "D3D GetAdapterID(" << i << ") failed: " << D3DERRORSTRING(hr) << endl; continue; } - + LARGE_INTEGER *DrvVer = &adapter_info.DriverVersion; wdxdisplay9_cat.info() - << "D3D9." << (dxpipe->_bIsDX9 ?"a":"b") << " Adapter[" << i << "]: " << adapter_info.Description + << "D3D9." << (dxpipe->__is_dx9_1 ?"1":"0") << " Adapter[" << i << "]: " << adapter_info.Description << ", Driver: " << adapter_info.Driver << ", DriverVersion: (" << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "." << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart) - << ")\nVendorID: 0x" << (void*) adapter_info.VendorId + << ")\nVendorID: 0x" << (void*) adapter_info.VendorId << " DeviceID: 0x" << (void*) adapter_info.DeviceId << " SubsysID: 0x" << (void*) adapter_info.SubSysId << " Revision: 0x" << (void*) adapter_info.Revision << endl; - - HMONITOR hMon = dxpipe->_pD3D9->GetAdapterMonitor(i); - if (hMon == NULL) { + + HMONITOR _monitor = dxpipe->__d3d9->GetAdapterMonitor(i); + if (_monitor == NULL) { wdxdisplay9_cat.info() << "D3D9 Adapter[" << i << "]: seems to be disabled, skipping it\n"; continue; @@ -947,7 +762,7 @@ choose_device() { DXDeviceInfo devinfo; ZeroMemory(&devinfo, sizeof(devinfo)); - memcpy(&devinfo.guidDeviceIdentifier, &adapter_info.DeviceIdentifier, + memcpy(&devinfo.guidDeviceIdentifier, &adapter_info.DeviceIdentifier, sizeof(GUID)); strncpy(devinfo.szDescription, adapter_info.Description, MAX_DEVICE_IDENTIFIER_STRING); @@ -955,7 +770,7 @@ choose_device() { MAX_DEVICE_IDENTIFIER_STRING); devinfo.VendorID = adapter_info.VendorId; devinfo.DeviceID = adapter_info.DeviceId; - devinfo.hMon = hMon; + devinfo._monitor = _monitor; devinfo.cardID = i; device_infos.push_back(devinfo); @@ -980,241 +795,27 @@ choose_device() { if (dx_preferred_device_id != -1) { if (dx_preferred_device_id < 0 || dx_preferred_device_id >= num_adapters) { wdxdisplay9_cat.error() - << "invalid 'dx-preferred-device-id', valid values are 0-" + << "invalid 'dx-preferred-device-id', valid values are 0-" << num_adapters - 1 << ", using default adapter instead.\n"; } else { adapter_num = dx_preferred_device_id; } } - UINT good_device_count=0; - for(UINT devnum=0;devnum0); - _hOldForegroundWindow=GetForegroundWindow(); - _bClosingAllWindows= false; - - UINT num_windows=_windows.size(); - - #define D3D9_NAME "d3d9.dll" - #define D3DCREATE9 "Direct3DCreate9" - - _hD3D9_DLL = LoadLibrary(D3D9_NAME); - if(_hD3D9_DLL == 0) { - wdxdisplay_cat.fatal() << "PandaDX9 requires DX9, can't locate " << D3D9_NAME <<"!\n"; - exit(1); - } - - _hMouseCursor = NULL; - _bLoadedCustomCursor = false; - - _pDInputInfo = NULL; - - // can only get multimon HW acceleration in fullscrn on DX7 - - UINT numMonitors = GetSystemMetrics(SM_CMONITORS); - - if(numMonitors < num_windows) { - if(numMonitors==0) { - numMonitors=1; //win95 system will fail this call - } else { - wdxdisplay_cat.fatal() << "system has only " << numMonitors << " monitors attached, couldn't find enough devices to meet multi window reqmt of " << num_windows << endl; - exit(1); - } - } - - // Do all DX7 stuff first - // find_all_card_memavails(); - - LPDIRECT3D9 pD3D9; - - typedef LPDIRECT3D9 (WINAPI *Direct3DCreate9_ProcPtr)(UINT SDKVersion); - - // dont want to statically link to possibly non-existent d3d9 dll, so must call D3DCr9 indirectly - Direct3DCreate9_ProcPtr D3DCreate9_Ptr = - (Direct3DCreate9_ProcPtr) GetProcAddress(_hD3D9_DLL, D3DCREATE9); - - if(D3DCreate9_Ptr == NULL) { - wdxdisplay_cat.fatal() << "GetProcAddress for "<< D3DCREATE9 << "failed!" << endl; - exit(1); - } - -// these were taken from the 8.0 and 8.1 d3d8.h SDK headers -#define D3D_SDK_VERSION_8_0 120 -#define D3D_SDK_VERSION_8_1 220 - - // are we using 8.0 or 8.1? - WIN32_FIND_DATA TempFindData; - HANDLE hFind; - char tmppath[MAX_PATH]; - GetSystemDirectory(tmppath,MAX_PATH); - strcat(tmppath,"\\dpnhpast.dll"); - hFind = FindFirstFile ( tmppath,&TempFindData ); - if(hFind != INVALID_HANDLE_VALUE) { - FindClose(hFind); - _bIsDX81=true; - pD3D8 = (*D3DCreate8_Ptr)(D3D_SDK_VERSION_8_1); - } else { - _bIsDX81=false; - pD3D8 = (*D3DCreate8_Ptr)(D3D_SDK_VERSION_8_0); - } - - if(pD3D8==NULL) { - wdxdisplay_cat.fatal() << D3DCREATE8 << " failed!\n"; - exit(1); - } - - _numAdapters = pD3D8->GetAdapterCount(); - if(_numAdapters < num_windows) { - wdxdisplay_cat.fatal() << "couldn't find enough devices attached to meet multi window reqmt of " << num_windows << endl; - exit(1); - } - - for(UINT i=0;i<_numAdapters;i++) { - D3DADAPTER_IDENTIFIER8 adapter_info; - ZeroMemory(&adapter_info,sizeof(D3DADAPTER_IDENTIFIER8)); - hr = pD3D8->GetAdapterIdentifier(i,D3DENUM_NO_WHQL_LEVEL,&adapter_info); - if(FAILED(hr)) { - wdxdisplay_cat.fatal() << "D3D GetAdapterID failed" << D3DERRORSTRING(hr); - } - - LARGE_INTEGER *DrvVer=&adapter_info.DriverVersion; - - wdxdisplay_cat.info() << "D3D8 Adapter[" << i << "]: " << adapter_info.Description << - ", Driver: " << adapter_info.Driver << ", DriverVersion: (" - << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "." - << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart) << ")\nVendorID: 0x" - << (void*) adapter_info.VendorId << " DeviceID: 0x" << (void*) adapter_info.DeviceId - << " SubsysID: 0x" << (void*) adapter_info.SubSysId << " Revision: 0x" - << (void*) adapter_info.Revision << endl; - - HMONITOR hMon=pD3D8->GetAdapterMonitor(i); - if(hMon==NULL) { - wdxdisplay_cat.info() << "D3D8 Adapter[" << i << "]: seems to be disabled, skipping it\n"; - continue; - } - - DXDeviceInfo devinfo; - ZeroMemory(&devinfo,sizeof(devinfo)); - memcpy(&devinfo.guidDeviceIdentifier,&adapter_info.DeviceIdentifier,sizeof(GUID)); - strncpy(devinfo.szDescription,adapter_info.Description,MAX_DEVICE_IDENTIFIER_STRING); - strncpy(devinfo.szDriver,adapter_info.Driver,MAX_DEVICE_IDENTIFIER_STRING); - devinfo.VendorID=adapter_info.VendorId; - devinfo.DeviceID=adapter_info.DeviceId; - devinfo.hMon=hMon; - devinfo.cardID=i; - - _DeviceInfoVec.push_back(devinfo); - } - - for(UINT i=0;iconfig_window(this); - } - - UINT good_device_count=0; - - if(num_windows==1) { - UINT D3DAdapterNum = D3DADAPTER_DEFAULT; - - if(dx_preferred_deviceID!=-1) { - if(dx_preferred_deviceID>=(int)_numAdapters) { - wdxdisplay_cat.fatal() << "invalid 'dx-preferred-device-id', valid values are 0-" << _numAdapters-1 << ", using default adapter 0 instead\n"; - } else D3DAdapterNum=dx_preferred_deviceID; - } - if(_windows[0]->search_for_device(pD3D8,&(_DeviceInfoVec[D3DAdapterNum]))) - good_device_count=1; - } else { - for(UINT devnum=0;devnum<_DeviceInfoVec.size() && (good_device_count < num_windows);devnum++) { - if(_windows[devnum]->search_for_device(pD3D8,&(_DeviceInfoVec[devnum]))) - good_device_count++; - } - } - - if(good_device_count < num_windows) { - if(good_device_count==0) - wdxdisplay_cat.fatal() << "no usable display devices, exiting...\n"; - else wdxdisplay_cat.fatal() << "multi-device request for " << num_windows << "devices, found only "<< good_device_count << " usable ones, exiting!"; - exit(1); - } - - _DeviceInfoVec.clear(); // dont need this anymore - - if(wdxdisplay_cat.is_debug() && (g_pCardIDVec!=NULL)) { - // print out the MaxAvailVidMems - for(UINT i=0;i<_windows.size();i++) { - D3DADAPTER_IDENTIFIER8 adapter_info; - pD3D8->GetAdapterIdentifier(_windows[i]->_wcontext.CardIDNum,D3DENUM_NO_WHQL_LEVEL,&adapter_info); - wdxdisplay_cat.info() << "D3D8 Adapter[" << i << "]: " << adapter_info.Description - << ", MaxAvailVideoMem: " << _windows[i]->_wcontext.MaxAvailVidMem - << ", IsLowVidMemCard: " << (_windows[i]->_wcontext.bIsLowVidMemCard ? "true" : "false") << endl; - } - } - - CreateWindows(); // creates win32 windows (need to do this before Setting coopLvls and display modes, - // but after we have all the monitor handles needed by CreateWindow() - -// SetCoopLevelsAndDisplayModes(); - - for(UINT i=0;iCreateScreenBuffersAndDevice(_windows[i]->_wcontext); - } - - for(UINT i=0;ifinish_window_setup(); - } - - SAFE_DELETE(g_pCardIDVec); // dont need this anymore - - for(UINT i=0;i_dxgsg->SetDXReady(true); - } - - dx_pick_best_screenres = false; // only want to do this on startup, not resize - - #ifdef DINPUT_DEBUG_POLL - if(dx_use_joystick) { - _pDInputInfo = new DInput8Info; - assert(_pDInputInfo !=NULL); - if(!_pDInputInfo->InitDirectInput()) { - wdxdisplay_cat.error() << "InitDirectInput failed!\n"; - exit(1); - } - - if(!_pDInputInfo->CreateJoystickOrPad(_hParentWindow)) { // associate w/parent window of group for now - wdxdisplay_cat.error() << "CreateJoystickOrPad failed!\n"; - exit(1); - } - - // for now, just set up a WM_TIMER to poll the joystick. - // could configure it to do event-based input, and that is default w/action mapping - // which would be better, less processor intensive - - #define POLL_FREQUENCY_HZ 3 - _pDInputInfo->_JoystickPollTimer = SetTimer(_hParentWindow, JOYSTICK_POLL_TIMER_ID, 1000/POLL_FREQUENCY_HZ, NULL); - if(_pDInputInfo->_JoystickPollTimer!=JOYSTICK_POLL_TIMER_ID) { - wdxdisplay_cat.error() << "Error in joystick SetTimer!\n"; - } - } - #endif -} -*/ - //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsWindow9::search_for_device // Access: Private @@ -1224,36 +825,36 @@ void wdxGraphicsWindow9Group::initWindowGroup() { bool wdxGraphicsWindow9:: search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { - assert(dxpipe != NULL); + assert(dxpipe != NULL); WindowProperties properties = get_properties(); DWORD dwRenderWidth = properties.get_x_size(); DWORD dwRenderHeight = properties.get_y_size(); HRESULT hr; - LPDIRECT3D9 pD3D9 = dxpipe->_pD3D9; + LPDIRECT3D9 _d3d9 = dxpipe->__d3d9; - assert(_dxgsg != NULL); - _wcontext.pD3D9 = pD3D9; - _wcontext.bIsDX9 = dxpipe->_bIsDX9; - _wcontext.CardIDNum = device_info->cardID; // could this change by end? + assert(_dxgsg != NULL); + _wcontext._d3d9 = _d3d9; + _wcontext._is_dx9_1 = dxpipe->__is_dx9_1; + _wcontext._card_id = device_info->cardID; // could this change by end? int frame_buffer_mode = _gsg->get_properties().get_frame_buffer_mode(); bool bWantStencil = ((frame_buffer_mode & FrameBufferProperties::FM_stencil) != 0); - - hr = pD3D9->GetAdapterIdentifier(device_info->cardID, 0, - &_wcontext.DXDeviceID); + + hr = _d3d9->GetAdapterIdentifier(device_info->cardID, 0, + &_wcontext._dx_device_id); if (FAILED(hr)) { wdxdisplay9_cat.error() << "D3D GetAdapterID failed" << D3DERRORSTRING(hr); return false; } - - D3DCAPS9 d3dcaps; - hr = pD3D9->GetDeviceCaps(device_info->cardID,D3DDEVTYPE_HAL,&d3dcaps); + + D3DCAPS9 _d3dcaps; + hr = _d3d9->GetDeviceCaps(device_info->cardID, D3DDEVTYPE_HAL, &_d3dcaps); if (FAILED(hr)) { - if ((hr==D3DERR_INVALIDDEVICE)||(hr==D3DERR_NOTAVAILABLE)) { + if ((hr == D3DERR_INVALIDDEVICE)||(hr == D3DERR_NOTAVAILABLE)) { wdxdisplay9_cat.error() << "No DirectX 9 D3D-capable 3D hardware detected for device # " - << device_info->cardID << " (" <szDescription + << device_info->cardID << " (" << device_info->szDescription << ")!\n"; } else { wdxdisplay9_cat.error() @@ -1261,54 +862,46 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { } return false; } - + //search_for_valid_displaymode needs these to be set - memcpy(&_wcontext.d3dcaps, &d3dcaps,sizeof(D3DCAPS9)); - _wcontext.CardIDNum = device_info->cardID; - - _wcontext.MaxAvailVidMem = UNKNOWN_VIDMEM_SIZE; - _wcontext.bIsLowVidMemCard = false; - + memcpy(&_wcontext._d3dcaps, &_d3dcaps, sizeof(D3DCAPS9)); + _wcontext._card_id = device_info->cardID; + + _wcontext._max_available_video_memory = UNKNOWN_VIDMEM_SIZE; + _wcontext._is_low_memory_card = false; + // bugbug: wouldnt we like to do GetAVailVidMem so we can do - // upper-limit memory computation for dx9 cards too? otherwise + // upper-limit memory computation for dx8 cards too? otherwise // verify_window_sizes cant do much - if ((d3dcaps.MaxStreams==0) || dx_pick_best_screenres) { + if ((_d3dcaps.MaxStreams == 0) || dx_pick_best_screenres) { if (wdxdisplay9_cat.is_debug()) { wdxdisplay9_cat.debug() << "checking vidmem size\n"; } - // assert(IS_VALID_PTR(_pParentWindowGroup)); - - // look for low memory video cards - // _pParentWindowGroup->find_all_card_memavails(); - + UINT IDnum; - - // simple linear search to match DX7 card info w/DX9 card ID - for (IDnum=0; IDnum < dxpipe->_card_ids.size(); IDnum++) { - // wdxdisplay9_cat.info() - // << "comparing '" << dxpipe->_card_ids[IDnum].Driver - // << "' to '" << _wcontext.DXDeviceID.Driver << "'\n"; - if (//(stricmp(dxpipe->_card_ids[IDnum].szDriver,device_info->szDriver)==0) && - (device_info->VendorID==dxpipe->_card_ids[IDnum].VendorID) && - (device_info->DeviceID==dxpipe->_card_ids[IDnum].DeviceID) && - (device_info->hMon==dxpipe->_card_ids[IDnum].hMon)) + + // simple linear search to match DX7 card info w/DX8 card ID + for (IDnum = 0; IDnum < dxpipe->_card_ids.size(); IDnum++) { + if ((device_info->VendorID == dxpipe->_card_ids[IDnum].VendorID) && + (device_info->DeviceID == dxpipe->_card_ids[IDnum].DeviceID) && + (device_info->_monitor == dxpipe->_card_ids[IDnum]._monitor)) break; } - + if (IDnum < dxpipe->_card_ids.size()) { - _wcontext.MaxAvailVidMem = dxpipe->_card_ids[IDnum].MaxAvailVidMem; - _wcontext.bIsLowVidMemCard = dxpipe->_card_ids[IDnum].bIsLowVidMemCard; + _wcontext._max_available_video_memory = dxpipe->_card_ids[IDnum]._max_available_video_memory; + _wcontext._is_low_memory_card = dxpipe->_card_ids[IDnum]._is_low_memory_card; } else { wdxdisplay9_cat.error() << "Error: couldnt find a CardID match in DX7 info, assuming card is not a lowmem card\n"; } } - if ((bWantStencil) && (d3dcaps.StencilCaps==0x0)) { + if ((bWantStencil) && (_d3dcaps.StencilCaps == 0x0)) { wdxdisplay9_cat.fatal() << "Stencil ability requested, but device #" << device_info->cardID - << " (" << _wcontext.DXDeviceID.Description + << " (" << _wcontext._dx_device_id.Description << "), has no stencil capability!\n"; return false; } @@ -1317,70 +910,67 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { // supported in HW (see GF2) for this case, you probably want MIXED // processing to use HW for fixed-fn vertex processing and SW for // vtx shaders - _wcontext.bIsTNLDevice = - ((d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0); - _wcontext.bCanUseHWVertexShaders = - (d3dcaps.VertexShaderVersion >= D3DVS_VERSION(1, 0)); - _wcontext.bCanUsePixelShaders = - (d3dcaps.PixelShaderVersion >= D3DPS_VERSION(1, 0)); + _wcontext._is_tnl_device = + ((_d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0); + _wcontext._can_use_hw_vertex_shaders = + (_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(1, 0)); + _wcontext._can_use_pixel_shaders = + (_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(1, 0)); - bool bNeedZBuffer = - ((!(d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) && + bool bNeedZBuffer = + ((!(_d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) && ((frame_buffer_mode & FrameBufferProperties::FM_depth) != 0)); - _wcontext.PresParams.EnableAutoDepthStencil = bNeedZBuffer; + _wcontext._presentation_params.EnableAutoDepthStencil = bNeedZBuffer; D3DFORMAT pixFmt = D3DFMT_UNKNOWN; if (is_fullscreen()) { bool bCouldntFindValidZBuf; - if (!_wcontext.bIsLowVidMemCard) { + if (!_wcontext._is_low_memory_card) { bool bUseDefaultSize = dx_pick_best_screenres && - ((_wcontext.MaxAvailVidMem == UNKNOWN_VIDMEM_SIZE) || - is_badvidmem_card(&_wcontext.DXDeviceID)); + ((_wcontext._max_available_video_memory == UNKNOWN_VIDMEM_SIZE) || + is_badvidmem_card(&_wcontext._dx_device_id)); if (dx_pick_best_screenres && !bUseDefaultSize) { typedef struct { UINT memlimit; - DWORD scrnX,scrnY; + DWORD scrnX, scrnY; } Memlimres; const Memlimres MemRes[] = { { 0, 640, 480}, { 8000000, 800, 600}, -#if 0 - {16000000, 1024, 768}, - {32000000, 1280,1024}, // 32MB+ cards will choose this -#else + // unfortunately the 32MB card perf varies greatly (TNT2-GF2), // so we need to be conservative since frame rate difference // can change from 15->30fps when going from 1280x1024->800x600 // on low-end 32mb cards {16000000, 800, 600}, {32000000, 800, 600}, // 32MB+ cards will choose this -#endif + // some monitors have trouble w/1600x1200, so dont pick this by deflt, - // even though 64MB cards should handle it - {64000000, 1280,1024} // 64MB+ cards will choose this + // even though 64MB cards should handle it + {64000000, 1280, 1024} // 64MB+ cards will choose this }; const NumResLims = (sizeof(MemRes)/sizeof(Memlimres)); for(int i = NumResLims - 1; i >= 0; i--) { // find biggest slot card can handle - if (_wcontext.MaxAvailVidMem > MemRes[i].memlimit) { + if (_wcontext._max_available_video_memory > MemRes[i].memlimit) { dwRenderWidth = MemRes[i].scrnX; dwRenderHeight = MemRes[i].scrnY; wdxdisplay9_cat.info() - << "pick_best_screenres: trying " << dwRenderWidth + << "pick_best_screenres: trying " << dwRenderWidth << "x" << dwRenderHeight << " based on " - << _wcontext.MaxAvailVidMem << " bytes avail\n"; + << _wcontext._max_available_video_memory << " bytes avail\n"; - dxpipe->search_for_valid_displaymode(_wcontext,dwRenderWidth, dwRenderHeight, - bNeedZBuffer, bWantStencil, - &_wcontext.SupportedScreenDepthsMask, - &bCouldntFindValidZBuf, - &pixFmt, dx_force_16bpp_zbuffer); + dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight, + bNeedZBuffer, bWantStencil, + &_wcontext._supported_screen_depths_mask, + &bCouldntFindValidZBuf, + &pixFmt, dx_force_16bpp_zbuffer); // note I'm not saving refresh rate, will just use adapter // default at given res for now @@ -1393,7 +983,7 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { << "skipping scrnres; " << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") << " at " << dwRenderWidth << "x" << dwRenderHeight - << " for device #" << _wcontext.CardIDNum << endl; + << " for device #" << _wcontext._card_id << endl; } } // otherwise just go with whatever was specified (we probably shouldve marked this card as lowmem if it gets to end of loop w/o breaking @@ -1403,15 +993,15 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { if (bUseDefaultSize) { wdxdisplay9_cat.info() << "pick_best_screenres: defaulted 800x600 based on no reliable vidmem size\n"; - dwRenderWidth=800; - dwRenderHeight=600; + dwRenderWidth = 800; + dwRenderHeight = 600; } dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight, - bNeedZBuffer, bWantStencil, - &_wcontext.SupportedScreenDepthsMask, - &bCouldntFindValidZBuf, - &pixFmt, dx_force_16bpp_zbuffer); + bNeedZBuffer, bWantStencil, + &_wcontext._supported_screen_depths_mask, + &bCouldntFindValidZBuf, + &pixFmt, dx_force_16bpp_zbuffer); // note I'm not saving refresh rate, will just use adapter // default at given res for now @@ -1419,21 +1009,21 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { if (pixFmt == D3DFMT_UNKNOWN) { wdxdisplay9_cat.error() << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") - << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _wcontext.CardIDNum <search_for_valid_displaymode(_wcontext,dwRenderWidth, dwRenderHeight, - bNeedZBuffer, bWantStencil, - &_wcontext.SupportedScreenDepthsMask, - &bCouldntFindValidZBuf, - &pixFmt, dx_force_16bpp_zbuffer, true); + dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight, + bNeedZBuffer, bWantStencil, + &_wcontext._supported_screen_depths_mask, + &bCouldntFindValidZBuf, + &pixFmt, dx_force_16bpp_zbuffer, true); // if still D3DFMT_UNKNOWN return false if (pixFmt == D3DFMT_UNKNOWN) @@ -1442,46 +1032,47 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { } } else { // Low Memory card - dwRenderWidth=640; - dwRenderHeight=480; + dwRenderWidth = 640; + dwRenderHeight = 480; dx_force_16bpptextures = true; - // need to autoforce 16bpp zbuf? or let user use that extra mem for textures/framebuf res/etc? - // most lowmem cards only do 16bpp Z anyway, but we wont force it for now + // need to autoforce 16bpp zbuf? or let user use that extra mem + // for textures/framebuf res/etc? most lowmem cards only do + // 16bpp Z anyway, but we wont force it for now - dxpipe->search_for_valid_displaymode(_wcontext,dwRenderWidth, dwRenderHeight, - bNeedZBuffer, bWantStencil, - &_wcontext.SupportedScreenDepthsMask, - &bCouldntFindValidZBuf, - &pixFmt, dx_force_16bpp_zbuffer); + dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight, + bNeedZBuffer, bWantStencil, + &_wcontext._supported_screen_depths_mask, + &bCouldntFindValidZBuf, + &pixFmt, dx_force_16bpp_zbuffer); // hack: figuring out exactly what res to use is tricky, instead I will // just use 640x480 if we have < 3 meg avail - if (_wcontext.SupportedScreenDepthsMask & R5G6B5_FLAG) { + if (_wcontext._supported_screen_depths_mask & R5G6B5_FLAG) { pixFmt = D3DFMT_R5G6B5; - } else if (_wcontext.SupportedScreenDepthsMask & X1R5G5B5_FLAG) { + } else if (_wcontext._supported_screen_depths_mask & X1R5G5B5_FLAG) { pixFmt = D3DFMT_X1R5G5B5; } else { wdxdisplay9_cat.fatal() << "Low Memory VidCard has no supported FullScreen 16bpp resolutions at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" - << device_info->cardID << " (" - << _wcontext.DXDeviceID.Description << "), skipping device...\n"; + << device_info->cardID << " (" + << _wcontext._dx_device_id.Description << "), skipping device...\n"; // run it again in verbose mode to get more dbg info to log dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight, - bNeedZBuffer, bWantStencil, - &_wcontext.SupportedScreenDepthsMask, - &bCouldntFindValidZBuf, - &pixFmt, dx_force_16bpp_zbuffer, - true /* verbose mode on*/); + bNeedZBuffer, bWantStencil, + &_wcontext._supported_screen_depths_mask, + &bCouldntFindValidZBuf, + &pixFmt, dx_force_16bpp_zbuffer, + true /* verbose mode on*/); return false; } if (wdxdisplay9_cat.is_info()) { wdxdisplay9_cat.info() - << "Available VidMem (" << _wcontext.MaxAvailVidMem + << "Available VidMem (" << _wcontext._max_available_video_memory << ") is under threshold, using 640x480 16bpp rendertargets to save tex vidmem.\n"; } } @@ -1489,7 +1080,7 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { // Windowed Mode D3DDISPLAYMODE dispmode; - hr = pD3D9->GetAdapterDisplayMode(device_info->cardID,&dispmode); + hr = _d3d9->GetAdapterDisplayMode(device_info->cardID, &dispmode); if (FAILED(hr)) { wdxdisplay9_cat.error() << "GetAdapterDisplayMode(" << device_info->cardID @@ -1499,11 +1090,11 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { pixFmt = dispmode.Format; } - _wcontext.DisplayMode.Width = dwRenderWidth; - _wcontext.DisplayMode.Height = dwRenderHeight; - _wcontext.DisplayMode.Format = pixFmt; - _wcontext.DisplayMode.RefreshRate = D3DPRESENT_RATE_DEFAULT; - _wcontext.hMon = device_info->hMon; + _wcontext._display_mode.Width = dwRenderWidth; + _wcontext._display_mode.Height = dwRenderHeight; + _wcontext._display_mode.Format = pixFmt; + _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT; + _wcontext._monitor = device_info->_monitor; if (dwRenderWidth != properties.get_x_size() || dwRenderHeight != properties.get_y_size()) { @@ -1537,47 +1128,54 @@ search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { //////////////////////////////////////////////////////////////////// bool wdxGraphicsWindow9:: reset_device_resize_window(UINT new_xsize, UINT new_ysize) { - assert((new_xsize > 0) && (new_ysize > 0)); - bool bRetval = true; + nassertr((new_xsize > 0) && (new_ysize > 0), false); + bool retval = true; - DXScreenData *pScrn; + DXScreenData *screen = NULL; D3DPRESENT_PARAMETERS d3dpp; - memcpy(&d3dpp, &_wcontext.PresParams, sizeof(D3DPRESENT_PARAMETERS)); - _wcontext.PresParams.BackBufferWidth = new_xsize; - _wcontext.PresParams.BackBufferHeight = new_ysize; + memcpy(&d3dpp, &_wcontext._presentation_params, sizeof(D3DPRESENT_PARAMETERS)); + _wcontext._presentation_params.BackBufferWidth = new_xsize; + _wcontext._presentation_params.BackBufferHeight = new_ysize; make_current(); - HRESULT hr = _dxgsg->reset_d3d_device(&_wcontext.PresParams, &pScrn); - + HRESULT hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen); + if (FAILED(hr)) { - bRetval = false; + retval = false; wdxdisplay9_cat.error() << "reset_device_resize_window Reset() failed" << D3DERRORSTRING(hr); if (hr == D3DERR_OUTOFVIDEOMEMORY) { - memcpy(&_wcontext.PresParams, &d3dpp, sizeof(D3DPRESENT_PARAMETERS)); - hr = _dxgsg->reset_d3d_device(&_wcontext.PresParams, &pScrn); + memcpy(&_wcontext._presentation_params, &d3dpp, sizeof(D3DPRESENT_PARAMETERS)); + hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen); if (FAILED(hr)) { wdxdisplay9_cat.error() << "reset_device_resize_window Reset() failed OutOfVidmem, then failed again doing Reset w/original params:" << D3DERRORSTRING(hr); - exit(1); + throw_event("panda3d-render-error"); + return false; + } else { - if (wdxdisplay9_cat.is_info()) + if (wdxdisplay9_cat.is_info()) { wdxdisplay9_cat.info() - << "reset of original size (" << _wcontext.PresParams.BackBufferWidth - << "," << _wcontext.PresParams.BackBufferHeight << ") succeeded\n"; + << "reset of original size (" << _wcontext._presentation_params.BackBufferWidth + << ", " << _wcontext._presentation_params.BackBufferHeight << ") succeeded\n"; + } } } else { - wdxdisplay9_cat.fatal() + wdxdisplay9_cat.fatal() << "Can't reset device, bailing out.\n"; - exit(1); + throw_event("panda3d-render-error"); + return false; } } // before you init_resized_window you need to copy certain changes to _wcontext - if (pScrn) - _wcontext.pSwapChain = pScrn->pSwapChain; - wdxdisplay9_cat.debug() << "swapchain is " << _wcontext.pSwapChain << "\n"; + if (screen) { + _wcontext._swap_chain = screen->_swap_chain; + } + wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n"; + _gsg->mark_new(); init_resized_window(); - return bRetval; + return retval; } + //////////////////////////////////////////////////////////////////// // Function: wdxGraphicsWindow9::init_resized_window // Access: Private @@ -1586,76 +1184,51 @@ reset_device_resize_window(UINT new_xsize, UINT new_ysize) { // // Assumes CreateDevice or Device->Reset() has just been // called, and the new size is specified in -// _wcontext.PresParams. +// _wcontext._presentation_params. //////////////////////////////////////////////////////////////////// void wdxGraphicsWindow9:: init_resized_window() { HRESULT hr; - DWORD newWidth = _wcontext.PresParams.BackBufferWidth; - DWORD newHeight = _wcontext.PresParams.BackBufferHeight; + DWORD newWidth = _wcontext._presentation_params.BackBufferWidth; + DWORD newHeight = _wcontext._presentation_params.BackBufferHeight; - assert((newWidth!=0) && (newHeight!=0)); - assert(_wcontext.hWnd!=NULL); + assert((newWidth != 0) && (newHeight != 0)); + assert(_wcontext._window != NULL); - if (_wcontext.PresParams.Windowed) { - POINT ul,lr; + if (_wcontext._presentation_params.Windowed) { + POINT ul, lr; RECT client_rect; - // need to figure out x,y origin offset of window client area on screen + // need to figure out x, y origin offset of window client area on screen // (we already know the client area size) - GetClientRect(_wcontext.hWnd, &client_rect); + GetClientRect(_wcontext._window, &client_rect); ul.x = client_rect.left; ul.y = client_rect.top; lr.x = client_rect.right; - lr.y=client_rect.bottom; - ClientToScreen(_wcontext.hWnd, &ul); - ClientToScreen(_wcontext.hWnd, &lr); + lr.y = client_rect.bottom; + ClientToScreen(_wcontext._window, &ul); + ClientToScreen(_wcontext._window, &lr); client_rect.left = ul.x; client_rect.top = ul.y; client_rect.right = lr.x; client_rect.bottom = lr.y; - // _props._xorg = client_rect.left; // _props should reflect view rectangle - // _props._yorg = client_rect.top; - - /* -#ifdef _DEBUG - // try to make sure GDI and DX agree on window client area size - // but client rect will not include any offscreen areas, so dont - // do check if window was bigger than screen (there are other bad - // cases too, like when window is positioned partly offscreen, - // or if window trim border make size bigger than screen) - - RECT desktop_rect; - GetClientRect(GetDesktopWindow(), &desktop_rect); - int x_size = get_properties().get_x_size(); - int y_size = get_properties().get_y_size(); - if ((x_size < RECT_X_SIZE(desktop_rect)) && - (y_size < RECT_Y_SIZE(desktop_rect))) - assert((RECT_X_SIZE(client_rect) == newWidth) && - (RECT_Y_SIZE(client_rect) == newHeight)); -#endif - */ } - // resized(newWidth, newHeight); // update panda channel/display rgn info, _props.x_size, _props.y_size - // clear window to black ASAP - assert(_wcontext.hWnd!=NULL); - ClearToBlack(_wcontext.hWnd, get_properties()); + assert(_wcontext._window != NULL); + ClearToBlack(_wcontext._window, get_properties()); // clear textures and VB's out of video&AGP mem, so cache is reset - hr = _wcontext.pD3DDevice->EvictManagedResources(); + hr = _wcontext._d3d_device->EvictManagedResources ( ); if (FAILED(hr)) { wdxdisplay9_cat.error() - << "EvictManagedResources failed for device #" - << _wcontext.CardIDNum << D3DERRORSTRING(hr); + << "EvictManagedResources failed for device #" + << _wcontext._card_id << D3DERRORSTRING(hr); } - _dxgsg->set_context(&_wcontext); - // Note: dx_init will fill in additional fields in _wcontext, like supportedtexfmts - _dxgsg->dx_init(); + make_current(); } //////////////////////////////////////////////////////////////////// @@ -1705,114 +1278,3 @@ is_badvidmem_card(D3DADAPTER_IDENTIFIER9 *pDevID) { return false; } -//////////////////////////////////////////////////////////////////// -// Function: wdxGraphicsWindow9::reset_window -// Access: Public, Virtual -// Description: Resets the window framebuffer right now. Called -// from graphicsEngine. It releases the current swap -// chain / creates a new one. If this is the initial -// window and swapchain is false, then it calls reset_ -// main_device to Reset the device. -//////////////////////////////////////////////////////////////////// -void wdxGraphicsWindow9:: -reset_window(bool swapchain) { - DXGraphicsStateGuardian9 *dxgsg; - DCAST_INTO_V(dxgsg,_gsg); - if (swapchain) { - if (_wcontext.pSwapChain) { - dxgsg->create_swap_chain(&_wcontext); - wdxdisplay9_cat.debug() << "created swapchain " << _wcontext.pSwapChain << "\n"; - } - } - else { - if (_wcontext.pSwapChain) { - dxgsg->release_swap_chain(&_wcontext); - wdxdisplay9_cat.debug() << "released swapchain " << _wcontext.pSwapChain << "\n"; - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: wdxGraphicsWindow9::open_window -// Access: Protected, Virtual -// Description: Opens the window right now. Called from the window -// thread. Returns true if the window is successfully -// opened, or false if there was a problem. -//////////////////////////////////////////////////////////////////// -bool wdxGraphicsWindow9:: -open_window() { - PT(DXGraphicsDevice9) dxdev; - DXGraphicsStateGuardian9 *dxgsg; - DCAST_INTO_R(dxgsg,_gsg,false); - WindowProperties props; - bool discard_device = false; - - if(!choose_device()) { - return false; - } - - wdxdisplay9_cat.debug() << "_wcontext.hWnd is " << _wcontext.hWnd << "\n"; - if (!WinGraphicsWindow::open_window()) { - return false; - } - _wcontext.hWnd = _hWnd; - - wdxdisplay9_cat.debug() << "_wcontext.hWnd is " << _wcontext.hWnd << "\n"; - - // Here check if a device already exists. If so, then this open_window - // call may be an extension to create multiple windows on same device - // In that case just create an additional swapchain for this window - - while(1) { - if (dxgsg->get_pipe()->get_device() == NULL || discard_device) { - wdxdisplay9_cat.debug() << "device is null or fullscreen\n"; - - // If device exists, free it - if (dxgsg->get_pipe()->get_device()) { - dxgsg->dx_cleanup(false, true); - } - - wdxdisplay9_cat.debug()<<"device width "<<_wcontext.DisplayMode.Width<<"\n"; - if (!create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer)) { - // just crash here - wdxdisplay9_cat.error() << "fatal: must be trying to create two fullscreen windows: not supported\n"; - exit(1);//return false; - } - dxgsg->get_pipe()->make_device((void*)(&_wcontext)); - dxgsg->copy_pres_reset(&_wcontext); - dxgsg->create_swap_chain(&_wcontext); - break; - - } else { - // fill in the DXScreenData from dxdevice here and change the - // reference to hWnd. - wdxdisplay9_cat.debug() << "device is not null\n"; - - dxdev = (DXGraphicsDevice9*)dxgsg->get_pipe()->get_device(); - props = get_properties(); - memcpy(&_wcontext,&dxdev->_Scrn,sizeof(DXScreenData)); - - _wcontext.PresParams.Windowed = !is_fullscreen(); - _wcontext.PresParams.hDeviceWindow = _wcontext.hWnd = _hWnd; - _wcontext.PresParams.BackBufferWidth = _wcontext.DisplayMode.Width = props.get_x_size(); - _wcontext.PresParams.BackBufferHeight = _wcontext.DisplayMode.Height = props.get_y_size(); - - wdxdisplay9_cat.debug()<<"device width "<<_wcontext.PresParams.BackBufferWidth<<"\n"; - //wdxdisplay9_cat.debug()<<"debug pSwapChain "<<_wcontext.pSwapChain<<"\n"; - if (!dxgsg->create_swap_chain(&_wcontext)) { - discard_device = true; - continue; //try again - } - init_resized_window(); - break; - } - } - wdxdisplay9_cat.debug() << "swapchain is " << _wcontext.pSwapChain << "\n"; - return true; -} - -bool wdxGraphicsWindow9:: -handle_mouse_motion(int x, int y) { - () WinGraphicsWindow::handle_mouse_motion(x,y); - return false; -} diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.h b/panda/src/dxgsg9/wdxGraphicsWindow9.h index 8aaf5211b4..c62266d606 100755 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.h +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.h @@ -1,5 +1,5 @@ -// Filename: wdxGraphicsWindow8.h -// Created by: masad (02Jan04) +// Filename: wdxGraphicsWindow9.h +// Created by: mike (09Jan97) // //////////////////////////////////////////////////////////////////// // @@ -16,8 +16,8 @@ // //////////////////////////////////////////////////////////////////// -#ifndef wdxGraphicsWindow9_H -#define wdxGraphicsWindow9_H +#ifndef WDXGRAPHICSWINDOW9_H +#define WDXGRAPHICSWINDOW9_H #include "pandabase.h" #include "winGraphicsWindow.h" @@ -27,11 +27,6 @@ class wdxGraphicsPipe9; -static const int WDXWIN_CONFIGURE = 4; -static const int WDXWIN_EVENT = 8; - -//#define FIND_CARD_MEMAVAILS - //////////////////////////////////////////////////////////////////// // Class : wdxGraphicsWindow9 // Description : A single graphics window for rendering DirectX under @@ -42,40 +37,40 @@ public: wdxGraphicsWindow9(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, const string &name); virtual ~wdxGraphicsWindow9(); - virtual bool open_window(); - virtual void close_window(); - virtual void reset_window(bool swapchain); - virtual int verify_window_sizes(int numsizes, int *dimen); + virtual void make_current(); virtual bool begin_frame(); virtual void end_flip(); - virtual LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - virtual bool handle_mouse_motion(int x, int y); + + virtual int verify_window_sizes(int numsizes, int *dimen); protected: + virtual void close_window(); + virtual bool open_window(); + virtual void reset_window(bool swapchain); + virtual void fullscreen_restored(WindowProperties &properties); virtual void handle_reshape(); virtual bool do_fullscreen_resize(int x_size, int y_size); - virtual void support_overlay_window(bool flag); private: - // bool set_to_temp_rendertarget(); - bool create_screen_buffers_and_device(DXScreenData &Display, + struct DXDeviceInfo { + UINT cardID; + char szDriver[MAX_DEVICE_IDENTIFIER_STRING]; + char szDescription[MAX_DEVICE_IDENTIFIER_STRING]; + GUID guidDeviceIdentifier; + DWORD VendorID, DeviceID; + HMONITOR _monitor; + }; + typedef pvector DXDeviceInfoVec; + + bool create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer); bool choose_device(); bool search_for_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info); - // void set_coop_levels_and_display_modes(); -/* - void search_for_valid_displaymode(UINT RequestedX_Size, UINT RequestedY_Size, - bool bWantZBuffer, bool bWantStencil, - UINT *pSupportedScreenDepthsMask, - bool *pCouldntFindAnyValidZBuf, - D3DFORMAT *pSuggestedPixFmt, - bool bVerboseMode = false); -*/ bool reset_device_resize_window(UINT new_xsize, UINT new_ysize); void init_resized_window(); static int D3DFMT_to_DepthBits(D3DFORMAT fmt); @@ -84,6 +79,7 @@ private: DXGraphicsStateGuardian9 *_dxgsg; DXScreenData _wcontext; + int _buffer_mask; int _depth_buffer_bpp; bool _awaiting_restore; @@ -100,15 +96,13 @@ public: return get_class_type(); } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - virtual void make_current(); private: static TypeHandle _type_handle; friend class wdxGraphicsPipe9; }; -//extern bool is_badvidmem_card(D3DADAPTER_IDENTIFIER9 *pDevID); #include "wdxGraphicsWindow9.I" -#endif +#endif \ No newline at end of file