From f4a3d7d340a0b8923480a70854ffc0703615dabc Mon Sep 17 00:00:00 2001 From: cxgeorge <> Date: Wed, 5 Dec 2001 01:40:31 +0000 Subject: [PATCH] dx8 dxgsg --- panda/metalibs/pandadx8/Sources.pp | 23 + panda/metalibs/pandadx8/pandadx8.cxx | 23 + panda/metalibs/pandadx8/pandadx8.h | 13 + panda/src/dxgsg8/Sources.pp | 31 + panda/src/dxgsg8/config_dxgsg8.cxx | 138 + panda/src/dxgsg8/config_dxgsg8.h | 64 + panda/src/dxgsg8/dxGeomNodeContext8.I | 31 + panda/src/dxgsg8/dxGeomNodeContext8.cxx | 33 + panda/src/dxgsg8/dxGeomNodeContext8.h | 94 + panda/src/dxgsg8/dxGraphicsStateGuardian8.I | 398 + panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 7301 +++++++++++++++++ panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 494 ++ panda/src/dxgsg8/dxSavedFrameBuffer8.I | 39 + panda/src/dxgsg8/dxSavedFrameBuffer8.cxx | 21 + panda/src/dxgsg8/dxSavedFrameBuffer8.h | 64 + panda/src/dxgsg8/dxTextureContext8.cxx | 1915 +++++ panda/src/dxgsg8/dxTextureContext8.h | 89 + panda/src/dxgsg8/dxgsg8_composite1.cxx | 4 + panda/src/wdxdisplay8/Sources.pp | 20 + panda/src/wdxdisplay8/config_wdxdisplay8.cxx | 80 + panda/src/wdxdisplay8/config_wdxdisplay8.h | 36 + panda/src/wdxdisplay8/wdxGraphicsPipe8.cxx | 1603 ++++ panda/src/wdxdisplay8/wdxGraphicsPipe8.h | 82 + panda/src/wdxdisplay8/wdxGraphicsWindow8.cxx | 2371 ++++++ panda/src/wdxdisplay8/wdxGraphicsWindow8.h | 144 + .../wdxdisplay8/wdxdisplay8_composite1.cxx | 4 + 26 files changed, 15115 insertions(+) create mode 100644 panda/metalibs/pandadx8/Sources.pp create mode 100644 panda/metalibs/pandadx8/pandadx8.cxx create mode 100644 panda/metalibs/pandadx8/pandadx8.h create mode 100644 panda/src/dxgsg8/Sources.pp create mode 100644 panda/src/dxgsg8/config_dxgsg8.cxx create mode 100644 panda/src/dxgsg8/config_dxgsg8.h create mode 100644 panda/src/dxgsg8/dxGeomNodeContext8.I create mode 100644 panda/src/dxgsg8/dxGeomNodeContext8.cxx create mode 100644 panda/src/dxgsg8/dxGeomNodeContext8.h create mode 100644 panda/src/dxgsg8/dxGraphicsStateGuardian8.I create mode 100644 panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx create mode 100644 panda/src/dxgsg8/dxGraphicsStateGuardian8.h create mode 100644 panda/src/dxgsg8/dxSavedFrameBuffer8.I create mode 100644 panda/src/dxgsg8/dxSavedFrameBuffer8.cxx create mode 100644 panda/src/dxgsg8/dxSavedFrameBuffer8.h create mode 100644 panda/src/dxgsg8/dxTextureContext8.cxx create mode 100644 panda/src/dxgsg8/dxTextureContext8.h create mode 100644 panda/src/dxgsg8/dxgsg8_composite1.cxx create mode 100644 panda/src/wdxdisplay8/Sources.pp create mode 100644 panda/src/wdxdisplay8/config_wdxdisplay8.cxx create mode 100644 panda/src/wdxdisplay8/config_wdxdisplay8.h create mode 100644 panda/src/wdxdisplay8/wdxGraphicsPipe8.cxx create mode 100644 panda/src/wdxdisplay8/wdxGraphicsPipe8.h create mode 100644 panda/src/wdxdisplay8/wdxGraphicsWindow8.cxx create mode 100644 panda/src/wdxdisplay8/wdxGraphicsWindow8.h create mode 100644 panda/src/wdxdisplay8/wdxdisplay8_composite1.cxx diff --git a/panda/metalibs/pandadx8/Sources.pp b/panda/metalibs/pandadx8/Sources.pp new file mode 100644 index 0000000000..a031891c20 --- /dev/null +++ b/panda/metalibs/pandadx8/Sources.pp @@ -0,0 +1,23 @@ +#define DIRECTORY_IF_DX yes + +// DIR_TYPE "metalib" indicates we are building a shared library that +// consists mostly of references to other shared libraries. Under +// Windows, this directly produces a DLL (as opposed to the regular +// src libraries, which don't produce anything but a pile of OBJ files +// under Windows). + +#define DIR_TYPE metalib +#define BUILDING_DLL BUILDING_PANDADX + +#define COMPONENT_LIBS \ + dxgsg8 wdxdisplay8 +#define LOCAL_LIBS gsgbase display express gobj +#define OTHER_LIBS dtoolconfig dtool + +#if $[BUILD_DX8] +#begin metalib_target + #define TARGET pandadx8 + + #define SOURCES pandadx8.cxx +#end metalib_target +#endif diff --git a/panda/metalibs/pandadx8/pandadx8.cxx b/panda/metalibs/pandadx8/pandadx8.cxx new file mode 100644 index 0000000000..7110dd62b0 --- /dev/null +++ b/panda/metalibs/pandadx8/pandadx8.cxx @@ -0,0 +1,23 @@ +// Filename: pandadx.cxx +// Created by: drose (15May00) +// +//////////////////////////////////////////////////////////////////// + +#include "pandadx8.h" + +#include +#include + +//////////////////////////////////////////////////////////////////// +// Function: init_libpandadx +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void +init_libpandadx8() { + init_libdxgsg8(); + init_libwdxdisplay8(); +} diff --git a/panda/metalibs/pandadx8/pandadx8.h b/panda/metalibs/pandadx8/pandadx8.h new file mode 100644 index 0000000000..ede7adfb1e --- /dev/null +++ b/panda/metalibs/pandadx8/pandadx8.h @@ -0,0 +1,13 @@ +// Filename: pandadx.h +// Created by: drose (2Jan01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef PANDADX8_H +#define PANDADX8_H + +#include + +EXPCL_PANDADX void init_libpandadx8(); + +#endif diff --git a/panda/src/dxgsg8/Sources.pp b/panda/src/dxgsg8/Sources.pp new file mode 100644 index 0000000000..15c07c39f5 --- /dev/null +++ b/panda/src/dxgsg8/Sources.pp @@ -0,0 +1,31 @@ +#define DIRECTORY_IF_DX yes + +#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ + dtoolutil:c dtoolbase:c dtool:m +#define USE_DX yes + +#if $[BUILD_DX8] +#begin lib_target + + #define TARGET dxgsg8 + #define LOCAL_LIBS \ + cull gsgmisc gsgbase gobj sgattrib sgraphutil graph display light \ + putil linmath sgraph mathutil pnmimage event + + #define COMBINED_SOURCES $[TARGET]_composite1.cxx + + #define SOURCES \ + config_dxgsg8.h dxGraphicsStateGuardian8.I \ + dxGraphicsStateGuardian8.cxx dxGraphicsStateGuardian8.h \ + dxSavedFrameBuffer8.I dxSavedFrameBuffer8.h \ + dxTextureContext8.h dxGeomNodeContext8.h dxGeomNodeContext8.I + + #define INCLUDED_SOURCES \ + config_dxgsg8.cxx dxSavedFrameBuffer8.cxx dxTextureContext8.cxx dxGeomNodeContext8.cxx + + #define INSTALL_HEADERS \ + dxGraphicsStateGuardian8.I dxGraphicsStateGuardian8.h \ + dxSavedFrameBuffer8.I dxSavedFrameBuffer8.h dxTextureContext8.h + +#end lib_target +#endif diff --git a/panda/src/dxgsg8/config_dxgsg8.cxx b/panda/src/dxgsg8/config_dxgsg8.cxx new file mode 100644 index 0000000000..1305921f5a --- /dev/null +++ b/panda/src/dxgsg8/config_dxgsg8.cxx @@ -0,0 +1,138 @@ +// Filename: config_dxgsg.cxx +// Created by: drose (06Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "config_dxgsg8.h" +#include "dxGraphicsStateGuardian8.h" +#include "dxSavedFrameBuffer8.h" +#include "dxTextureContext8.h" + +#include + +Configure(config_dxgsg); +NotifyCategoryDef(dxgsg, ":display:gsg"); + +// Configure this variable true to cause the DXGSG to show each +// transform space it renders by drawing a little unit axis. This +// cannot be enabled when the player is compiled in NDEBUG mode. +bool dx_show_transforms = config_dxgsg.GetBool("dx-show-transforms", false); + +// Configure this to TRUE if you want DirectX to control the entire screen, +// If false, it will just blit into a window. +bool dx_full_screen = config_dxgsg.GetBool("dx-full-screen", false); + +// Configure this true to force the rendering to sync to the video +// refresh, or false to let your frame rate go as high as it can, +// irrespective of the video refresh. +bool dx_sync_video = config_dxgsg.GetBool("sync-video", true); + +// enable this to turn on full-screen anti-aliasing, if the HW supports it +// this var is also used in wdxGraphicsWindows.cxx +bool dx_full_screen_antialiasing = config_dxgsg.GetBool("dx-antialias", false); + +// Configure this true to perform a cull traversal over the geometry +// by default, false otherwise. The cull traversal provides support +// for state-sorting, z-sorting, and binning. +bool dx_cull_traversal = config_dxgsg.GetBool("dx-cull-traversal", true); + +// if true, if card only supports per-vertex fog, it will be treated as no-HW fog capability +bool dx_no_vertex_fog = config_dxgsg.GetBool("dx-no-vertex-fog", false); + +// Configure this true to cause all lighting normals to automatically +// be normalized by the CPU before rendering. This is +// necessary if you intend to render things under scale transforms and +// expect lighting to work correctly. Maybe one day there will be +// another way to set this at runtime, instead of only as a configure +// variable +bool dx_auto_normalize_lighting = config_dxgsg.GetBool("auto-normalize-lighting", false); + +bool dx_show_fps_meter = config_dxgsg.GetBool("show-fps-meter", false); +float dx_fps_meter_update_interval = max(0.5,config_dxgsg.GetFloat("fps-meter-update-interval", 1.7)); + +#ifndef NDEBUG +// debugging flag +// values are same as D3DCULL enumtype, 0 - no force, 1 - force none, 2 - force CW, 3 - force CCW +int dx_force_backface_culling = config_dxgsg.GetInt("dx-force-backface-culling", 0); +#endif + +bool dx_mipmap_everything = config_dxgsg.GetBool("dx-mipmap-everything", false); +bool dx_ignore_mipmaps = config_dxgsg.GetBool("dx-ignore-mipmaps", false); + +// if this is set, more accurate but more expensive fog computations are performed +bool dx_use_rangebased_fog = config_dxgsg.GetBool("dx-use-rangebased-fog", false); + +#ifdef _DEBUG +float dx_global_miplevel_bias = config_dxgsg.GetFloat("dx-global-miplevel-bias", 0.0); +bool dx_debug_view_mipmaps = config_dxgsg.GetBool("dx-debug-view-mipmaps", false); +bool dx_force_16bpptextures = config_dxgsg.GetBool("dx-force-16bpptextures", false); +bool dx_force_anisotropic_filtering = config_dxgsg.GetBool("dx-force-anisotropic-filtering", false); +//int dx_print_texstats = config_dxgsg.GetBool("dx-print-texstats", 0); +#endif + +// set 'retained-mode #t' and this to have prepare_geom concatenate all tristrips within a geom +// together using degenerate tris +const bool link_tristrips = config_dxgsg.GetBool("link-tristrips", false); + +// note: offset currently disabled since it wasnt working properly +DXDecalType dx_decal_type = GDT_offset; + +static DXDecalType +parse_decal_type(const string &type) { + if (type == "mask") { + return GDT_mask; + } else if (type == "blend") { + return GDT_blend; + } else if (type == "offset") { + return GDT_offset; + } + dxgsg_cat.error() << "Invalid dx-decal-type: " << type << "\n"; + return GDT_offset; +} + +ConfigureFn(config_dxgsg) { + init_libdxgsg8(); +} + +//////////////////////////////////////////////////////////////////// +// Function: init_libdxgsg +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void init_libdxgsg8() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + + string decal_type = config_dxgsg.GetString("dx-decal-type", ""); + if (!decal_type.empty()) { + dx_decal_type = parse_decal_type(decal_type); + } + + DXGraphicsStateGuardian::init_type(); + DXSavedFrameBuffer::init_type(); + DXTextureContext::init_type(); + DXGeomNodeContext::init_type(); + + GraphicsStateGuardian::get_factory().register_factory + (DXGraphicsStateGuardian::get_class_type(), + DXGraphicsStateGuardian::make_DXGraphicsStateGuardian); +} diff --git a/panda/src/dxgsg8/config_dxgsg8.h b/panda/src/dxgsg8/config_dxgsg8.h new file mode 100644 index 0000000000..39d2442421 --- /dev/null +++ b/panda/src/dxgsg8/config_dxgsg8.h @@ -0,0 +1,64 @@ +// Filename: config_dxgsg.h +// Created by: drose (06Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONFIG_DXGSG_H +#define CONFIG_DXGSG_H + +#include +#include + +NotifyCategoryDecl(dxgsg, EXPCL_PANDADX, EXPTP_PANDADX); + +extern bool dx_full_screen; +extern bool dx_sync_video; +extern bool dx_cull_traversal; +extern bool dx_show_fps_meter; +extern bool dx_no_vertex_fog; +extern bool dx_full_screen_antialiasing; +extern float dx_fps_meter_update_interval; +extern bool dx_auto_normalize_lighting; +extern bool dx_use_rangebased_fog; +extern const bool link_tristrips; + +// debug flags +extern bool dx_ignore_mipmaps; +extern bool dx_mipmap_everything; +extern bool dx_show_transforms; + +#ifndef NDEBUG +extern int dx_force_backface_culling; +#endif + +#ifdef _DEBUG +extern float dx_global_miplevel_bias; +extern bool dx_debug_view_mipmaps; +extern bool dx_force_16bpptextures; +extern bool dx_force_anisotropic_filtering; +#endif + +// Ways to implement decals. +enum DXDecalType { + GDT_mask, // GL 1.0 style, involving three steps and double-draw of polygon + GDT_blend, // As above, but slower; use blending to disable colorbuffer writes + GDT_offset // The fastest, using GL 1.1 style glPolygonOffset +}; +extern DXDecalType dx_decal_type; + +extern EXPCL_PANDADX void init_libdxgsg8(); + +#endif diff --git a/panda/src/dxgsg8/dxGeomNodeContext8.I b/panda/src/dxgsg8/dxGeomNodeContext8.I new file mode 100644 index 0000000000..8d30be3c3b --- /dev/null +++ b/panda/src/dxgsg8/dxGeomNodeContext8.I @@ -0,0 +1,31 @@ +// Filename: dxGeomNodeContext.I +// Created by: drose (12Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: dxGeomNodeContext::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE DXGeomNodeContext:: +DXGeomNodeContext(GeomNode *node) : GeomNodeContext(node) +{ + _num_verts = 0; + _pVB = NULL; + _pXformed_VB = NULL; +} diff --git a/panda/src/dxgsg8/dxGeomNodeContext8.cxx b/panda/src/dxgsg8/dxGeomNodeContext8.cxx new file mode 100644 index 0000000000..fc77d6723f --- /dev/null +++ b/panda/src/dxgsg8/dxGeomNodeContext8.cxx @@ -0,0 +1,33 @@ +// Filename: dxGeomNodeContext.cxx +// Created by: drose (12Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "dxGeomNodeContext8.h" + +TypeHandle DXGeomNodeContext::_type_handle; + +DXGeomNodeContext::~DXGeomNodeContext() +{ + if(_pXformed_VB!=NULL) + _pXformed_VB->Release(); + _pXformed_VB=NULL; + + if(_pVB!=NULL) + _pVB->Release(); + _pVB=NULL; +} + diff --git a/panda/src/dxgsg8/dxGeomNodeContext8.h b/panda/src/dxgsg8/dxGeomNodeContext8.h new file mode 100644 index 0000000000..4680e7d497 --- /dev/null +++ b/panda/src/dxgsg8/dxGeomNodeContext8.h @@ -0,0 +1,94 @@ +// Filename: dxGeomNodeContext.h +// Created by: drose (12Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DXGEOMNODECONTEXT_H +#define DXGEOMNODECONTEXT_H + +#include + +#ifdef WIN32_VC +// Must include windows.h before dx.h on NT +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#endif + +#include +#include +#include "pvector.h" + +#define D3D_OVERLOADS // get D3DVECTOR '+' operator, etc from d3dtypes.h +#include + +typedef struct { + DWORD nVerts; + D3DPRIMITIVETYPE primtype; +} DPInfo; + +//////////////////////////////////////////////////////////////////// +// Class : DXGeomNodeContext +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX DXGeomNodeContext : public GeomNodeContext { +public: + INLINE DXGeomNodeContext(GeomNode *node); + ~DXGeomNodeContext(); + + // A list of the dynamic Geoms within the GeomNode; these aren't + // part of the above display list and must be drawn separately + typedef pvector Geoms; + Geoms _cached_geoms,_other_geoms; + + // VB's are already reference-counted by D3D, no need to make separate panda object to do that + // but we will want a way to know if VB has already been xformed by ProcessVerts this frame + // if multiple geomnodes share VBs + + LPDIRECT3DVERTEXBUFFER7 _pVB; + LPDIRECT3DVERTEXBUFFER7 _pXformed_VB; + + int _start_index; // starting offset of this geom's verts within the VB + int _num_verts; // number of verts used by this geomcontext within the VB + + BYTE *_pEndofVertData; // ptr to end of current vert data in VB (note: only used/valid during setup) + + // for multiple geoms per VB, either will have to regen lengths based on per* flags, or store + // per geom vector of perprim vectors lengths + vector _PrimInfo; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + GeomNodeContext::init_type(); + register_type(_type_handle, "DXGeomNodeContext", + GeomNodeContext::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 "dxGeomNodeContext8.I" + +#endif + diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.I b/panda/src/dxgsg8/dxGraphicsStateGuardian8.I new file mode 100644 index 0000000000..7ccbddc6fc --- /dev/null +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.I @@ -0,0 +1,398 @@ +// Filename: dxGraphicsStateGuardian.I +// Created by: mike (02Feb99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "config_dxgsg8.h" +#include + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_line_smooth +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_line_smooth(bool val) { + if(_line_smooth_enabled != val) { + _line_smooth_enabled = val; + #ifdef NDEBUG + { + if(val && (_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES)) + dxgsg_cat.error() << "no HW support for line smoothing!!\n"; + } + #endif + + _d3dDevice->SetRenderState(D3DRENDERSTATE_EDGEANTIALIAS, (DWORD)val); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_lighting +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_lighting(bool val) { + if (_lighting_enabled != val) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, (DWORD)val); + if(_lighting_enabled = val) + _lighting_enabled_this_frame = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_dither +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_dither(bool val) { + if (_dither_enabled != val) { + + #ifdef _DEBUG + { + if(val && !(_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_DITHER)) + dxgsg_cat.error() << "no HW support for color dithering!!\n"; + return; + } + #endif + + _dither_enabled = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, (DWORD)val); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_stencil_test +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_stencil_test(bool val) { + if (_stencil_test_enabled != val) { + _stencil_test_enabled = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, (DWORD)val); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_color_material +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_color_material(bool val) { + if (_color_material_enabled != val) { + _color_material_enabled = val; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_clip_plane +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_clip_plane(int clip_plane, bool val) +{ + if (_clip_plane_enabled[clip_plane] != val) + { + _clip_plane_enabled[clip_plane] = val; + DWORD ClipPlaneBits; + _d3dDevice->GetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE , &ClipPlaneBits); + if (val) + ClipPlaneBits |= 1 << clip_plane; + else + ClipPlaneBits &= ~(1 << clip_plane); + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE , ClipPlaneBits); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_blend +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_blend(bool val) { + if (_blend_enabled != val) { + _blend_enabled = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, (DWORD)val); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_blend +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +set_shademode(D3DSHADEMODE val) { + if (_CurShadeMode != val) { + _CurShadeMode = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, (DWORD)val); + } +} + +INLINE void DXGraphicsStateGuardian:: +enable_primitive_clipping(bool val) { + if (_clipping_enabled != val) { + _clipping_enabled = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, (DWORD)val); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_fog +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_fog(bool val) { + if ((_fog_enabled != val) && (_doFogType!=None)) { + _fog_enabled = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, (DWORD)val); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_alpha_test +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_alpha_test(bool val ) +{ + if (_alpha_test_enabled != val) { + _alpha_test_enabled = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, (DWORD)val); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::call_dxLightModelAmbient +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +call_dxLightModelAmbient( const Colorf& color) +{ + if (_lmodel_ambient != color) { + _lmodel_ambient = color; +#ifdef GSG_VERBOSE + dxgsg_cat.debug() << "dxLightModel(LIGHT_MODEL_AMBIENT, " << color << ")" << endl; +#endif + _d3dDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, + D3DRGBA(color[0], color[1], color[2], color[3])); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::call_glAlphaFunc +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +call_dxAlphaFunc(D3DCMPFUNC func, DWORD ref) +{ + if (_alpha_func != func || _alpha_func_ref != ref) { + _alpha_func = func; + _alpha_func_ref = ref; +#ifdef GSG_VERBOSE + dxgsg_cat.debug() << "dxAlphaFunc("; + switch (func) { + case D3DCMP_NEVER: + dxgsg_cat.debug(false) << "D3DCMP_NEVER, "; + break; + case D3DCMP_LESS: + dxgsg_cat.debug(false) << "D3DCMP_LESS, "; + break; + case D3DCMP_EQUAL: + dxgsg_cat.debug(false) << "D3DCMP_EQUAL, "; + break; + case D3DCMP_LEQUAL: + dxgsg_cat.debug(false) << "D3DCMP_LEQUAL, "; + break; + case D3DCMP_GREATER: + dxgsg_cat.debug(false) << "D3DCMP_GREATER, "; + break; + case D3DCMP_NOTEQUAL: + dxgsg_cat.debug(false) << "D3DCMP_NOTEQUAL, "; + break; + case D3DCMP_GEQUAL: + dxgsg_cat.debug(false) << "D3DCMP_GEQUAL, "; + break; + case D3DCMP_ALWAYS: + dxgsg_cat.debug(false) << "D3DCMP_ALWAYS, "; + break; + } + dxgsg_cat.debug() << ref << ")" << endl; +#endif + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, func); + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, ref); + } +} + + +INLINE void DXGraphicsStateGuardian:: +call_dxBlendFunc(D3DBLEND sfunc, D3DBLEND dfunc ) +{ + if (_blend_source_func != sfunc) + { + _blend_source_func = sfunc; + _d3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, sfunc); +#ifdef GSG_VERBOSE + dxgsg_cat.debug() << "dxSrcBlendFunc("; + switch (sfunc) + { + case D3DBLEND_ZERO: + dxgsg_cat.debug(false) << "ZERO, "; + break; + case D3DBLEND_ONE: + dxgsg_cat.debug(false) << "ONE, "; + break; + case D3DBLEND_DESTCOLOR: + dxgsg_cat.debug(false) << "DESTCOLOR, "; + break; + case D3DBLEND_INVDESTCOLOR: + dxgsg_cat.debug(false) << "INVDESTCOLOR, "; + break; + case D3DBLEND_SRCALPHA: + dxgsg_cat.debug(false) << "SRCALPHA, "; + break; + case D3DBLEND_INVSRCALPHA: + dxgsg_cat.debug(false) << "INVSRCALPHA, "; + break; + case D3DBLEND_DESTALPHA: + dxgsg_cat.debug(false) << "DESTALPHA, "; + break; + case D3DBLEND_INVDESTALPHA: + dxgsg_cat.debug(false) << "INVDESTALPHA, "; + break; + case D3DBLEND_SRCALPHASAT: + dxgsg_cat.debug(false) << "SRCALPHASAT, "; + break; + default: + dxgsg_cat.debug(false) << "unknown, "; + break; + } + dxgsg_cat.debug(false) << endl; +#endif + } + if ( _blend_dest_func != dfunc) + { + _blend_dest_func = dfunc; + _d3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, dfunc); +#ifdef GSG_VERBOSE + dxgsg_cat.debug() << "dxDstBlendFunc("; + switch (dfunc) + { + case D3DBLEND_ZERO: + dxgsg_cat.debug(false) << "ZERO, "; + break; + case D3DBLEND_ONE: + dxgsg_cat.debug(false) << "ONE, "; + break; + case D3DBLEND_DESTCOLOR: + dxgsg_cat.debug(false) << "DESTCOLOR, "; + break; + case D3DBLEND_INVDESTCOLOR: + dxgsg_cat.debug(false) << "INVDESTCOLOR, "; + break; + case D3DBLEND_SRCALPHA: + dxgsg_cat.debug(false) << "SRCALPHA, "; + break; + case D3DBLEND_INVSRCALPHA: + dxgsg_cat.debug(false) << "INVSRCALPHA, "; + break; + case D3DBLEND_DESTALPHA: + dxgsg_cat.debug(false) << "DESTALPHA, "; + break; + case D3DBLEND_INVDESTALPHA: + dxgsg_cat.debug(false) << "INVDESTALPHA, "; + break; + case D3DBLEND_SRCALPHASAT: + dxgsg_cat.debug(false) << "SRCALPHASAT, "; + break; + } + dxgsg_cat.debug(false) << endl; +#endif + } +} + +INLINE void DXGraphicsStateGuardian:: +enable_zwritemask(bool val) { + if (_depth_write_enabled != val) { + _depth_write_enabled = val; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, val); + } +} + +/** unimplemented + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_multisample +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_multisample(bool val) { + _multisample_enabled = val; + #ifdef NDEBUG + dxgsg_cat.error() << "dx multisample unimplemented!!\n"; + #endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_multisample_alpha_one +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_multisample_alpha_one(bool val) { + if (_multisample_alpha_one_enabled != val) { + _multisample_alpha_one_enabled = val; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_multisample_alpha_mask +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_multisample_alpha_mask(bool val) { + if (_multisample_alpha_mask_enabled != val) { + _multisample_alpha_mask_enabled = val; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_point_smooth +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_point_smooth(bool val) { + // _point_smooth_enabled = val; + + #ifdef NDEBUG + dxgsg_cat.error() << "dx point smoothing unimplemented!!\n"; + #endif +} +*/ + diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx new file mode 100644 index 0000000000..bb37745014 --- /dev/null +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -0,0 +1,7301 @@ +// Filename: dxGraphicsStateGuardian.cxx +// Created by: mike (02Feb99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DO_PSTATS +#include +#include +#endif + +#include "config_dxgsg8.h" +#include "dxGraphicsStateGuardian8.h" + +// disable nameless struct 'warning' +#pragma warning (disable : 4201) + +#include + +// print out simple drawprim stats every few secs +//#define COUNT_DRAWPRIMS + +//#define PRINT_TEXSTATS +// #define MAKE_FPSMETER_TRANSPARENT + +//#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 + +// test non-optimized general geom pipe for all models +// apparently DPStrided faults for some color G_OVERALL cases, so comment out for now +// not clear that it is actually faster in practice, it may even be slightly slower +#define DONT_USE_DRAWPRIMSTRIDED + +//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); + +// if defined, pandadx only handles 1 panda display region +// note multiple region code doesnt work now (see prepare_display_region,set_clipper) +#define NO_MULTIPLE_DISPLAY_REGIONS + +TypeHandle DXGraphicsStateGuardian::_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; + +#define PER_NORMAL NormalOnly +#define PER_COLOR ColorOnly +#define PER_TEXCOORD TexCoordOnly + +// technically DX7's front-end has no limit on the number of lights, but it's simpler for +// this implementation to set a small GL-like limit to make the light array traversals short +// and so I dont have to write code that reallocs light arrays +#define DXGSG_MAX_LIGHTS 8 + +static D3DMATRIX matIdentity; + +#ifdef COUNT_DRAWPRIMS +// you should just use Intel GPT instead of this stuff + +static DWORD cDPcount=0; +static DWORD cVertcount=0; +static DWORD cTricount=0; +static DWORD cGeomcount=0; + +static LPDIRECTDRAWSURFACE7 pLastTexture=NULL; +static DWORD cDP_noTexChangeCount=0; +static LPDIRECT3DDEVICE7 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) D3DRGBA(r,g,b,a)) + +#if defined(DO_PSTATS) || defined(PRINT_TEXSTATS) +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])) + +INLINE DWORD +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; + + // 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) + 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) + fistp tempcolorval + mov ebx,tempcolorval + shl ebx, 8 + or eax,ebx + + fld DWORD PTR [ecx+8] ;blue + fmul ST(0),ST(1) + fistp tempcolorval + or eax,tempcolorval + + fld DWORD PTR [ecx+12] ;alpha + 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 + shl ebx, 24 + or eax,ebx + mov d3dcolor,eax + pop ecx + pop ebx + } + + // dxgsg_cat.debug() << (void*)d3dcolor << endl; + return d3dcolor; +#else //!_X86_ + return MY_D3DRGBA(cColorf[0], cColorf[1], cColorf[2], cColorf[3]); +#endif //!_X86_ +} + +void DXGraphicsStateGuardian:: +set_color_clear_value(const Colorf& value) { + _color_clear_value = value; + _d3dcolor_clear_value = Colorf_to_D3DCOLOR(value); +} + +void DXGraphicsStateGuardian::SetFPSMeterPosition(RECT &view_rect) { + if(_fpsmeter_verts==NULL) + return; + + DWORD renderWid = view_rect.right - view_rect.left; + DWORD renderHt = view_rect.bottom - view_rect.top; + + // adjust these to match fontsize (these are hacks for default font, probably should get char width from win32) + #define FPSMETER_NUMFONTLETTERS 11 // need 11 letters [0-9.] + #define NUM_FPSMETER_LETTERS 6 // field width used for display + #define FPSMETER_LETTER_WIDTH 9 + #define FPSMETER_LETTER_HEIGHT 12 + + #define FPSMETER_SUFFIX " FPS" + #define FPSMETER_SUFFIXLEN 4 + + float top_offset,left_offset; + float letter_width=FPSMETER_LETTER_WIDTH; + float z = 0.1f; // shouldnt matter since I turn off zfunc and clipping. these values are written into zbuf, but shouldnt matter since its endofframe + float rhw=1.0f; + + top_offset=0.05f * renderHt; + + left_offset = 0.99f*renderWid-letter_width*(NUM_FPSMETER_LETTERS+FPSMETER_SUFFIXLEN); + if(left_offset<0.0f) + left_offset=0.0f; + + float *fltptr= (float*)_fpsmeter_verts; + + // poly color should be irrelevant since fps texblend throws it away + D3DCOLOR fpscolr = (D3DCOLOR) 0xFFFFFFFF; //MY_D3DRGBA(1.0f,1.0f,1.0f,1.0f); + + #define WRITE_FPSMETER_VERT(x,y,z,w,colr,u,v) { *fltptr = x; fltptr++; \ + *fltptr = y; fltptr++; \ + *fltptr = z; fltptr++; \ + *fltptr = w; fltptr++; \ + (*((DWORD*)fltptr)) = colr; fltptr++; \ + *fltptr = u; fltptr++; \ + *fltptr = v; fltptr++; } + + float u_letter_width = _fps_u_usedwidth/(float)FPSMETER_NUMFONTLETTERS; + float height = FPSMETER_LETTER_HEIGHT; + float cur_xoffset=left_offset; + + // fmt is 3.2, need 12 tris. cant share verts since texcoords differ + + #define WRITE_FPS_SQUARE(x1,y1,x2,y2,u1,v1,u2,v2) \ + float *firstvertptr = fltptr; \ + WRITE_FPSMETER_VERT(x1,y1,z,rhw,fpscolr,u1,v1); \ + WRITE_FPSMETER_VERT(x1,y2,z,rhw,fpscolr,u1,v2); \ + float *thirdvertptr=fltptr; \ + WRITE_FPSMETER_VERT(x2,y2,z,rhw,fpscolr,u2,v2); \ + memcpy(fltptr,thirdvertptr,_fps_vertexsize); \ + fltptr = (float*) (((BYTE*)fltptr) + _fps_vertexsize); \ + WRITE_FPSMETER_VERT(x2,y1,z,rhw,fpscolr,u2,v1); \ + memcpy(fltptr,firstvertptr,_fps_vertexsize); \ + fltptr = (float*) (((BYTE*)fltptr) + _fps_vertexsize); + + for(int i=0;iGetSurfaceDesc(&ddsd); + + // init it to transparent black + if(FAILED( hr = _fpsmeter_font_surf->Lock( NULL, &ddsd, DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL ))) { + dxgsg_cat.error() << "fps meter creation failed, Lock() failed on texture! hr = " << ConvD3DErrorToString(hr) << "\n"; + dx_show_fps_meter = false; + return; + } + ZeroMemory(ddsd.lpSurface,ddsd.dwWidth*ddsd.dwHeight*2); + _fpsmeter_font_surf->Unlock(NULL); + + // draw FPS text using GDI + HDC hDC; + if(FAILED( hr = _fpsmeter_font_surf->GetDC(&hDC))) { + dxgsg_cat.error() << "fps meter creation failed, GetDC failed on fps font surface! hr = " << ConvD3DErrorToString(hr) << "\n"; + dx_show_fps_meter = false; + return; + } + + HFONT hfnt = (HFONT) GetStockObject(ANSI_FIXED_FONT); + (void) SelectObject(hDC, hfnt); + + SetTextColor(hDC, RGB(255,255,128) ); + SetBkMode(hDC, TRANSPARENT ); + + char tstr[2] = {'\0','\0'}; + RECT Rect; + Rect.top = 0; Rect.bottom = FPSMETER_LETTER_HEIGHT-1; + Rect.left = 0; Rect.right = FPSMETER_LETTER_WIDTH; + + for(int i=0;iReleaseDC(hDC); + + // GDI writes 0x00 for alpha, have to make letter pixels opaque again + if(FAILED( hr = _fpsmeter_font_surf->Lock( NULL, &ddsd, DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL ))) { + dxgsg_cat.error() << "fps meter creation failed, Lock() failed on texture! hr = " << ConvD3DErrorToString(hr) << "\n"; + dx_show_fps_meter = false; + return; + } + + DWORD numpixels=ddsd.dwWidth*ddsd.dwHeight; + + #ifdef MAKE_FPSMETER_TRANSPARENT + WORD *pPixel=(WORD*)ddsd.lpSurface; + for(int ii=numpixels;ii>0;ii--) { + WORD wPixel=*pPixel; + if(wPixel & 0x0FFF) { + *pPixel |= 0xF000; // make written pixels opaque + }/* else { + *pPixel = 0x700F; // otherwise background is translucent blue + }*/ + pPixel++; + } + #endif + _fpsmeter_font_surf->Unlock(NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DXGraphicsStateGuardian:: +DXGraphicsStateGuardian(GraphicsWindow *win) : GraphicsStateGuardian(win) { + // allocate local buffers used during rendering + + GraphicsStateGuardian::reset(); + + _pCurFvfBufPtr = NULL; + _pFvfBufBasePtr = new char[VERT_BUFFER_SIZE]; // allocate storage for vertex info. + _index_buf = new WORD[D3DMAXNUMVERTICES]; // allocate storage for vertex index info. + _fpsmeter_verts=NULL; + _fpsmeter_font_surf=NULL; + _dx_ready = false; + + _pri = _zbuf = _back = NULL; + _pDD = NULL; + _d3dDevice = NULL; + + // 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 + + ZeroMemory(&matIdentity,sizeof(D3DMATRIX)); + matIdentity._11 = matIdentity._22 = matIdentity._33 = matIdentity._44 = 1.0f; + + // Create a default RenderTraverser. + if (dx_cull_traversal) { + _render_traverser = new CullTraverser(this, RenderRelation::get_class_type()); + } else { + _render_traverser = new DirectRenderTraverser(this, RenderRelation::get_class_type()); + } + + // All implementations have the following buffers. + _buffer_mask = (RenderBuffer::T_color | + RenderBuffer::T_depth | + RenderBuffer::T_back +// RenderBuffer::T_stencil | +// RenderBuffer::T_accum + ); + + // this is incorrect for general mono displays, need both right and left flags set. + // stereo has not been handled yet for dx + // _buffer_mask &= ~RenderBuffer::T_right; + + _cur_read_pixel_buffer=RenderBuffer::T_front; + + set_color_clear_value(_color_clear_value); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DXGraphicsStateGuardian:: +~DXGraphicsStateGuardian() { + if (_d3dDevice != NULL) + _d3dDevice->SetTexture(0, NULL); // this frees reference to the old texture + _pCurTexContext = NULL; + + free_pointers(); + delete [] _pFvfBufBasePtr; + delete [] _index_buf; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::reset +// Access: Public, Virtual +// Description: Resets all internal state as if the gsg were newly +// created. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +reset(void) { + GraphicsStateGuardian::reset(); + dxgsg_cat.error() << "DXGSG reset() not implemented properly yet!\n"; + // delete all the objs too, right? + //dx_init(); +} + +// recreate dx objects without modifying gsg state, other than clearing state cache +void DXGraphicsStateGuardian:: +free_dxgsg_objects(void) { + ULONG refcnt; + + free_pointers(); + + // dont want a full reset of gsg, just a state clear + GraphicsStateGuardian::clear_cached_state(); // want gsg to pass all state settings through + + _dx_ready = false; + + if (_d3dDevice!=NULL) { + _d3dDevice->SetTexture(0,NULL); // should release this stuff internally anyway + RELEASE(_d3dDevice,dxgsg,"d3dDevice",RELEASE_DOWN_TO_ZERO); + } + + DeleteAllVideoSurfaces(); + + // Release the DDraw and D3D objects used by the app + RELEASE(_zbuf,dxgsg,"zbuffer",false); + RELEASE(_back,dxgsg,"backbuffer",false); + RELEASE(_pri,dxgsg,"primary surface",false); +} + +HRESULT CALLBACK EnumTexFmtsCallback( LPDDPIXELFORMAT pddpf, VOID* param ) { + // wont build if its a member fn, so had to do this stuff + DXGraphicsStateGuardian *mystate = (DXGraphicsStateGuardian *) param; + assert(mystate->_cNumTexPixFmts < MAX_DX_TEXPIXFMTS); + memcpy( &(mystate->_pTexPixFmts[mystate->_cNumTexPixFmts]), pddpf, sizeof(DDPIXELFORMAT) ); + mystate->_cNumTexPixFmts++; + return DDENUMRET_OK; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::reset +// Access: Public, Virtual +// Description: Handles initialization which assumes that DX has already been +// set up. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +dx_init( LPDIRECTDRAW7 context, + LPDIRECTDRAWSURFACE7 pri, + LPDIRECTDRAWSURFACE7 back, + LPDIRECTDRAWSURFACE7 zbuf, + LPDIRECT3D7 pD3D, + LPDIRECT3DDEVICE7 pDevice, + RECT viewrect) { + _pDD = context; + _pri = pri; + _back = back; + _zbuf = zbuf; + _d3d = pD3D; + _d3dDevice = pDevice; + _view_rect = viewrect; + + ZeroMemory(&_lmodel_ambient,sizeof(Colorf)); + _d3dDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, 0x0); + + _light_enabled = (bool *)NULL; + _cur_light_enabled = (bool *)NULL; + _clip_plane_enabled = (bool *)NULL; + _cur_clip_plane_enabled = (bool *)NULL; + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE , 0x0); + + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, true); + _clipping_enabled = true; + + _CurShadeMode = D3DSHADE_FLAT; + _d3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, _CurShadeMode); + + _depth_test_enabled = true; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, _depth_test_enabled); + + // need to free these properly + _cNumTexPixFmts = 0; + _pTexPixFmts = NULL; + _pCurTexContext = NULL; + + //Color and alpha transform variables + _color_transform_enabled = false; + _alpha_transform_enabled = false; + _color_transform_required = _color_transform_enabled || _alpha_transform_enabled; + + _current_color_mat = LMatrix4f::ident_mat(); + _current_alpha_offset = 0; + _current_alpha_scale = 1; + + // none of these are implemented + //_multisample_enabled = false; + //_point_smooth_enabled = false; + + _line_smooth_enabled = false; + _d3dDevice->SetRenderState(D3DRENDERSTATE_EDGEANTIALIAS, false); + + _color_material_enabled = false; + _normals_enabled = false; + + _depth_test_enabled = D3DZB_FALSE; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); + + _blend_enabled = false; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, (DWORD)_blend_enabled); + + _d3dDevice->GetRenderState(D3DRENDERSTATE_SRCBLEND, (DWORD*)&_blend_source_func); + _d3dDevice->GetRenderState(D3DRENDERSTATE_DESTBLEND, (DWORD*)&_blend_dest_func); + + _fog_enabled = false; + _d3dDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, _fog_enabled); + + _decal_level = 0; + _current_projection_mat = LMatrix4f::ident_mat(); + _projection_mat_stack_count = 0; + _issued_color_enabled = false; + _enable_all_color = true; + +// GL stuff that hasnt been translated to DX +// _scissor_enabled = false; +// _multisample_alpha_one_enabled = false; +// _multisample_alpha_mask_enabled = false; +// _line_width = 1.0f; +// _point_size = 1.0f; + + assert(_back!=NULL); // dxgsg is always double-buffered right now + +#ifdef COUNT_DRAWPRIMS + global_pD3DDevice = pDevice; +#endif + _pCurrentGeomContext = NULL; + _bDrawPrimDoSetupVertexBuffer = false; + + _last_testcooplevel_result = S_OK; + + // only 1 channel on dx currently + _panda_gfx_channel = _win->get_channel(0); + + HRESULT hr; + + _pTexPixFmts = new DDPIXELFORMAT[MAX_DX_TEXPIXFMTS]; + _cNumTexPixFmts = 0; + + assert(_pTexPixFmts!=NULL); + + if (pDevice->EnumTextureFormats(EnumTexFmtsCallback, this) != S_OK) { + dxgsg_cat.error() << "EnumTextureFormats failed!!\n"; + } + + if (FAILED(hr = pDevice->GetCaps(&_D3DDevDesc))) { + dxgsg_cat.fatal() << "GetCaps failed on D3D Device\n"; + exit(1); + } + + DX_DECLARE_CLEAN(DDCAPS,ddCaps); + if (FAILED(hr = _pDD->GetCaps(&ddCaps,NULL))) { + dxgsg_cat.fatal() << "GetCaps failed on DDraw\n"; + exit(1); + } + + _bIsTNLDevice = (IsEqualGUID(_D3DDevDesc.deviceGUID,IID_IDirect3DTnLHalDevice)!=0); + + if ((dx_decal_type==GDT_offset) && !(_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBIAS)) { +#ifdef _DEBUG + // dx7 doesnt support PLANEMASK renderstate +#if(DIRECT3D_VERSION < 0x700) + dxgsg_cat.debug() << "dx-decal-type 'offset' not supported by hardware, switching to decal masking\n"; +#else + dxgsg_cat.debug() << "dx-decal-type 'offset' not supported by hardware, switching to decal double-draw blend-based masking\n"; +#endif +#endif +#if(DIRECT3D_VERSION < 0x700) + dx_decal_type = GDT_mask; +#else + dx_decal_type = GDT_blend; +#endif + } + +#ifdef DISABLE_POLYGON_OFFSET_DECALING +#ifdef _DEBUG + dxgsg_cat.spam() << "polygon-offset decaling disabled in dxgsg, switching to double-draw decaling\n"; +#endif + +#if(DIRECT3D_VERSION < 0x700) + dx_decal_type = GDT_mask; +#else + dx_decal_type = GDT_blend; +#endif +#endif + + if ((dx_decal_type==GDT_mask) && !(_D3DDevDesc.dpcTriCaps.dwMiscCaps & D3DPMISCCAPS_MASKPLANES)) { +#ifdef _DEBUG + dxgsg_cat.debug() << "No hardware support for colorwrite disabling, switching to dx-decal-type 'mask' to 'blend'\n"; +#endif + dx_decal_type = GDT_blend; + } + + if (((dx_decal_type==GDT_blend)||(dx_decal_type==GDT_mask)) && !(_D3DDevDesc.dpcTriCaps.dwMiscCaps & D3DPMISCCAPS_MASKZ)) { + dxgsg_cat.error() << "dx-decal-type mask impossible to implement, no hardware support for Z-masking, decals will not appear correctly!\n"; + } + +//#define REQUIRED_BLENDCAPS (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE|D3DPBLENDCAPS_SRCCOLOR|D3DPBLENDCAPS_INVSRCCOLOR| \ +// D3DPBLENDCAPS_SRCALPHA|D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA|D3DPBLENDCAPS_INVDESTALPHA|D3DPBLENDCAPS_DESTCOLOR|D3DPBLENDCAPS_INVDESTCOLOR) +// voodoo3 doesnt support commented out ones, & we dont need them now + +#define REQUIRED_BLENDCAPS (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE| /*D3DPBLENDCAPS_SRCCOLOR|D3DPBLENDCAPS_INVSRCCOLOR| */ \ + D3DPBLENDCAPS_SRCALPHA|D3DPBLENDCAPS_INVSRCALPHA /* | D3DPBLENDCAPS_DESTALPHA|D3DPBLENDCAPS_INVDESTALPHA|D3DPBLENDCAPS_DESTCOLOR|D3DPBLENDCAPS_INVDESTCOLOR*/) + + if (((_D3DDevDesc.dpcTriCaps.dwSrcBlendCaps & REQUIRED_BLENDCAPS)!=REQUIRED_BLENDCAPS) || + ((_D3DDevDesc.dpcTriCaps.dwDestBlendCaps & REQUIRED_BLENDCAPS)!=REQUIRED_BLENDCAPS)) { + dxgsg_cat.error() << "device is missing alpha blending capabilities, blending may not work correctly: SrcBlendCaps: 0x"<< (void*) _D3DDevDesc.dpcTriCaps.dwSrcBlendCaps << " DestBlendCaps: "<< (void*) _D3DDevDesc.dpcTriCaps.dwDestBlendCaps << endl; + } + + if (!(_D3DDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_TRANSPARENCY)) { + dxgsg_cat.error() << "device is missing texture transparency capability, transparency may not work correctly! TextureCaps: 0x"<< (void*) _D3DDevDesc.dpcTriCaps.dwTextureCaps << endl; + } + + // just require trilinear. if it can do that, it can probably do all the lesser point-sampling variations too +#define REQUIRED_TEXFILTERCAPS (D3DPTFILTERCAPS_MAGFLINEAR | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_LINEAR) + if ((_D3DDevDesc.dpcTriCaps.dwTextureFilterCaps & REQUIRED_TEXFILTERCAPS)!=REQUIRED_TEXFILTERCAPS) { + dxgsg_cat.error() << "device is missing texture bilinear filtering capability, textures may appear blocky! TextureFilterCaps: 0x"<< (void*) _D3DDevDesc.dpcTriCaps.dwTextureFilterCaps << endl; + } +#define REQUIRED_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR) + + if (!(ddCaps.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) { + dxgsg_cat.debug() << "device does not have mipmap texturing filtering capability! TextureFilterCaps: 0x"<< (void*) _D3DDevDesc.dpcTriCaps.dwTextureFilterCaps << endl; + dx_ignore_mipmaps = TRUE; + } else if ((_D3DDevDesc.dpcTriCaps.dwTextureFilterCaps & REQUIRED_MIPMAP_TEXFILTERCAPS)!=REQUIRED_MIPMAP_TEXFILTERCAPS) { + dxgsg_cat.debug() << "device is missing tri-linear mipmap filtering capability, texture mipmaps may not supported! TextureFilterCaps: 0x"<< (void*) _D3DDevDesc.dpcTriCaps.dwTextureFilterCaps << endl; + } + +#define REQUIRED_TEXBLENDCAPS (D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2) + if ((_D3DDevDesc.dwTextureOpCaps & REQUIRED_TEXBLENDCAPS)!=REQUIRED_TEXBLENDCAPS) { + dxgsg_cat.error() << "device is missing some required texture blending capabilities, texture blending may not work properly! TextureOpCaps: 0x"<< (void*) _D3DDevDesc.dwTextureOpCaps << endl; + } + + if(_D3DDevDesc.dpcTriCaps.dwRasterCaps & 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((_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGVERTEX )!=0); + + // vtx 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) { + _doFogType = None; + } else { + _doFogType = PerVertexFog; + + // range-based fog only works with vertex fog in dx7/8 + if(dx_use_rangebased_fog && (_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGRANGE)) + _d3dDevice->SetRenderState(D3DRENDERSTATE_RANGEFOGENABLE, true); + } + } + + SetRect(&clip_rect, 0,0,0,0); // no clip rect set + + // Lighting, let's turn it off by default + _lighting_enabled = false; + _d3dDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, _lighting_enabled); + + // turn on dithering if the rendertarget is < 8bits/color channel + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_back); + _back->GetSurfaceDesc(&ddsd_back); + _dither_enabled = ((ddsd_back.ddpfPixelFormat.dwRGBBitCount < 24) && + (_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_DITHER)); + _d3dDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, _dither_enabled); + + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING,true); + + // Stencil test is off by default + _stencil_test_enabled = false; + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, _stencil_test_enabled); + + // Antialiasing. + enable_line_smooth(false); +// enable_multisample(true); + + _current_fill_mode = RenderModeProperty::M_filled; + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); + + _d3dDevice->SetRenderState(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1); + + // technically DX7's front-end has no limit on the number of lights, but it's simpler for + // this implementation to set a small GL-like limit to make the light array traversals short + // and so I dont have to write code that reallocs light arrays + assert((_D3DDevDesc.dwMaxActiveLights==0) || // 0 means infinite lights + (DXGSG_MAX_LIGHTS <= _D3DDevDesc.dwMaxActiveLights)); + + _max_lights = DXGSG_MAX_LIGHTS; + + _available_light_ids = PTA(Light*)::empty_array(_max_lights); + _light_enabled = new bool[_max_lights]; + _cur_light_enabled = new bool[_max_lights]; + + int i; + for (i = 0; i < _max_lights; i++) { + _available_light_ids[i] = NULL; + _light_enabled[i] = false; + } + + if(dx_auto_normalize_lighting) + _d3dDevice->SetRenderState(D3DRENDERSTATE_NORMALIZENORMALS, true); + + // Set up the clip plane id map + _max_clip_planes = D3DMAXUSERCLIPPLANES; + _available_clip_plane_ids = PTA(PlaneNode*)::empty_array(_max_clip_planes); + _clip_plane_enabled = new bool[_max_clip_planes]; + _cur_clip_plane_enabled = new bool[_max_clip_planes]; + for (i = 0; i < _max_clip_planes; i++) { + _available_clip_plane_ids[i] = NULL; + _clip_plane_enabled[i] = false; + } + + // initial clip rect + SetRect(&clip_rect, 0,0,0,0); // no clip rect set + + // 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 = TextureApplyProperty::M_modulate; + SetTextureBlendMode(_CurTexBlendMode,FALSE); + _texturing_enabled = false; + _d3dDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE); // disables texturing + + // Init more Texture State + _CurTexMagFilter=_CurTexMinFilter=Texture::FT_nearest; + _CurTexWrapModeU=_CurTexWrapModeV=Texture::WM_clamp; + _CurTexAnisoDegree=1; + + // this code must match apply_texture() code for states above + // so DX TSS renderstate matches dxgsg state + + _d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT); + _d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFP_POINT); + _d3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_NONE); + _d3dDevice->SetTextureStageState(0, D3DTSS_MAXANISOTROPY,_CurTexAnisoDegree); + _d3dDevice->SetTextureStageState(0, D3DTSS_ADDRESSU,get_texture_wrap_mode(_CurTexWrapModeU)); + _d3dDevice->SetTextureStageState(0, D3DTSS_ADDRESSV,get_texture_wrap_mode(_CurTexWrapModeV)); + +#ifdef _DEBUG + if ((_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) && + (dx_global_miplevel_bias!=0.0f)) { + _d3dDevice->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((LPDWORD) (&dx_global_miplevel_bias)) ); + } +#endif + + if(dx_full_screen_antialiasing) { + if(_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_ANTIALIAS,D3DANTIALIAS_SORTINDEPENDENT); + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "enabling full-screen anti-aliasing\n"; + } else { + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "device doesnt support full-screen anti-aliasing\n"; + } + } + +#ifndef NDEBUG + if(dx_force_backface_culling!=0) { + if((dx_force_backface_culling > 0) && + (dx_force_backface_culling < D3DCULL_FORCE_DWORD)) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, dx_force_backface_culling); + } else { + dx_force_backface_culling=0; + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "error, invalid value for dx-force-backface-culling\n"; + } + } + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, dx_force_backface_culling); +#else + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); +#endif + + _alpha_func = D3DCMP_ALWAYS; + _alpha_func_ref = 0; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, _alpha_func); + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, _alpha_func_ref); + _alpha_test_enabled = false; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, _alpha_test_enabled); + + // need to release this better, so dx_init can be called multiple times + + if(dx_show_fps_meter) { + _start_time = timeGetTime(); + _current_fps = 0.0f; + _start_frame_count = _cur_frame_count = 0; + + // create the fpsmeter font texture + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT ; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTSTATIC; + + ddsd.dwTextureStage=0; + ddsd.dwFlags |= DDSD_TEXTURESTAGE; + ddsd.dwMipMapCount = 1; + + // note GDI cant draw to 4-4-4-4 fmt DDSURF on win9x (GetDC will fail) + + DDPIXELFORMAT *pCurPixFmt; + for(i=0,pCurPixFmt=&_pTexPixFmts[_cNumTexPixFmts-1];i<_cNumTexPixFmts;i++,pCurPixFmt--) { + if((pCurPixFmt->dwRGBBitCount==16) && + #ifdef MAKE_FPSMETER_TRANSPARENT + (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) && + (pCurPixFmt->dwRGBAlphaBitMask==0x8000) + #else + ((pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)==0) && + (pCurPixFmt->dwBBitMask==0x001F) + #endif + ) // emacs gets confused if we don't match parens accurately. + break; + } + + if(i>=_cNumTexPixFmts) { + // if this fails, no 4-4-4-4 fmt, need code to use 5-5-5-1 + dxgsg_cat.error() << "couldnt find 4-4-4-4 tex fmt for fpsmeter font!\n"; + dx_show_fps_meter = false; + return; + } + + memcpy(&ddsd.ddpfPixelFormat,pCurPixFmt,sizeof(DDPIXELFORMAT)); + + DWORD fontareaHeight = FPSMETER_LETTER_HEIGHT; + DWORD fontareaWidth = FPSMETER_LETTER_WIDTH * (FPSMETER_NUMFONTLETTERS + FPSMETER_SUFFIXLEN); + + // this is just the area used for the letters, not the suffix + DWORD letterfontareaWidth = FPSMETER_LETTER_WIDTH * FPSMETER_NUMFONTLETTERS; + + DWORD texdim_x = fontareaWidth; + DWORD texdim_y = fontareaHeight; + + #define ROUND_UP_TO_POW2(val) if(!ISPOW2(val)) { \ + for(int i=31;i>=0;i--) { \ + if(((1< texdim_x) + texdim_x = texdim_y; + texdim_y = texdim_x; + } + + ddsd.dwWidth = texdim_x; + ddsd.dwHeight = texdim_y; + + if(_fpsmeter_font_surf!=NULL) { + ULONG refcnt; + RELEASE(_fpsmeter_font_surf,dxgsg,"fpsmeter fontsurf",false); + } + + PRINTREFCNT(_pDD,"pre-fpsmeter-font-create IDirectDraw7"); + + // Create a new surface for the texture + if(FAILED( hr = _pDD->CreateSurface( &ddsd, &_fpsmeter_font_surf, NULL ) )) { + dxgsg_cat.error() << "CreateSurface() failed for fpsmeter font! hr = " << ConvD3DErrorToString(hr) << "\n"; + dx_show_fps_meter = false; + return; + } + + PRINTREFCNT(_pDD,"post-fpsmeter-font-create IDirectDraw7"); + + FillFPSMeterTexture(); + + // make buffer for fps meter tri data + + _fps_vertexsize = sizeof(D3DVALUE) * 4 + sizeof(D3DCOLOR) + sizeof(float) * 2; + _fpsmeter_fvfflags = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); + + int numverts=(NUM_FPSMETER_LETTERS+1)*2*3; // +1 for square to hold suffix + + if(_fpsmeter_verts == NULL) + _fpsmeter_verts = (DWORD *) new BYTE[_fps_vertexsize*numverts]; + + _fps_u_usedwidth = letterfontareaWidth/(float)texdim_x; + _fps_v_usedheight = fontareaHeight/(float)texdim_y; + + SetFPSMeterPosition(_view_rect); + } + + // Make sure the DX state matches all of our initial attribute states. + PT(DepthTestTransition) dta = new DepthTestTransition; + PT(DepthWriteTransition) dwa = new DepthWriteTransition; + PT(CullFaceTransition) cfa = new CullFaceTransition; + PT(LightTransition) la = new LightTransition; + PT(TextureTransition) ta = new TextureTransition; + + dta->issue(this); + dwa->issue(this); + cfa->issue(this); + la->issue(this); + ta->issue(this); // no curtextcontext, this does nothing. dx should already be properly inited above anyway +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::clear +// Access: Public, Virtual +// Description: Clears all of the indicated buffers to their assigned +// colors. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +clear(const RenderBuffer &buffer) { + DO_PSTATS_STUFF(PStatTimer timer(_win->_clear_pcollector)); + + nassertv(buffer._gsg == this); + int buffer_type = buffer._buffer_type; + + int flags = 0; + + if (buffer_type & RenderBuffer::T_depth) + flags |= D3DCLEAR_ZBUFFER; + if (buffer_type & RenderBuffer::T_back) //set appropriate flags + flags |= D3DCLEAR_TARGET; + if (buffer_type & RenderBuffer::T_stencil) + flags |= D3DCLEAR_STENCIL; + + HRESULT hr = _d3dDevice->Clear(0, NULL, flags, _d3dcolor_clear_value, + (D3DVALUE) _depth_clear_value, (DWORD)_stencil_clear_value); + if (hr != DD_OK) + dxgsg_cat.error() << "clear_buffer failed: Clear returned " << ConvD3DErrorToString(hr) << endl; + /* 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; + */ +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::clear +// Access: Public, Virtual +// Description: Clears all of the indicated buffers to their assigned +// colors. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +clear(const RenderBuffer &buffer, const DisplayRegion *region) { + DisplayRegionStack old_dr = push_display_region(region); + prepare_display_region(); + clear(buffer); + pop_display_region(old_dr); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_light +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian:: +enable_light(int light, bool val) { + if (_light_enabled[light] != val) { + _light_enabled[light] = val; + HRESULT res = _d3dDevice->LightEnable( light, val ); + +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "LightEnable(" << light << "=" << val << ")" << endl; +#endif + + return(res == DD_OK); + } + return TRUE; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::prepare_display_region +// Access: Public, Virtual +// Description: Prepare a display region for rendering (set up +// scissor region and viewport) +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +prepare_display_region() { + if (_current_display_region == (DisplayRegion*)0L) { + dxgsg_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; + +#ifndef NO_MULTIPLE_DISPLAY_REGIONS + int l, b, w, h; + _actual_display_region->get_region_pixels(l, b, w, h); + GLint x = GLint(l); + GLint y = GLint(b); + GLsizei width = GLsizei(w); + GLsizei height = GLsizei(h); +#ifdef WBD_GL_MODE +// call_glScissor( x, y, width, height ); +// call_glViewport( x, y, width, height ); +#else + if ( _scissor_x != x || _scissor_y != y || + _scissor_width != width || _scissor_height != height ) + { + _scissor_x = x; _scissor_y = y; + _scissor_width = width; _scissor_height = height; + RECT cliprect; + SetRect(&cliprect, x, y, x+width, y+height ); + set_clipper(cliprect); + } +#endif //WBD_GL_MODE +#endif + } +} + +#ifndef NO_MULTIPLE_DISPLAY_REGIONS +//////////////////////////////////////////////////////////////////// +// Function: set_clipper +// Access: +// Description: Useless in DX at the present time +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::set_clipper(RECT cliprect) { + + LPDIRECTDRAWCLIPPER Clipper; + HRESULT result; + + // For windowed mode, the clip region is associated with the window, + // and DirectX does not allow you to create clip regions. + if (dx_full_screen) return; + + /* The cliprect we receive is normalized so that (0,0) means the upper left of + the client portion of the window. + At least, I think that's true, and the following code assumes that. + So we must adjust the clip region by offsetting it to the origin of the + view rectangle. + */ + clip_rect = cliprect; // store the normalized clip rect + cliprect.left += _view_rect.left; + cliprect.right += _view_rect.left; + cliprect.top += _view_rect.top; + cliprect.bottom += _view_rect.top; + RGNDATA *rgn_data = (RGNDATA *)malloc(sizeof(RGNDATAHEADER) + sizeof(RECT)); + HRGN hrgn = CreateRectRgn(cliprect.left, cliprect.top, cliprect.right, cliprect.bottom); + GetRegionData(hrgn, sizeof(RGNDATAHEADER) + sizeof(RECT), rgn_data); + + if (_pri->GetClipper(&Clipper) != DD_OK) { + result = _pDD->CreateClipper(0, &Clipper, NULL); + result = Clipper->SetClipList(rgn_data, 0); + result = _pri->SetClipper(Clipper); + } else { + result = Clipper->SetClipList(rgn_data, 0 ); + if (result == DDERR_CLIPPERISUSINGHWND) { + result = _pri->SetClipper(NULL); + result = _pDD->CreateClipper(0, &Clipper, NULL); + result = Clipper->SetClipList(rgn_data, 0 ) ; + result = _pri->SetClipper(Clipper); + } + } + free(rgn_data); + DeleteObject(hrgn); +} +#endif + +#if defined(_DEBUG) || defined(COUNT_DRAWPRIMS) +typedef enum {DrawPrim,DrawIndexedPrim,DrawPrimStrided} DP_Type; +static const char *DP_Type_Strs[3] = {"DrawPrimitive","DrawIndexedPrimitive","DrawPrimitiveStrided"}; + +void INLINE TestDrawPrimFailure(DP_Type dptype,HRESULT hr,LPDIRECTDRAW7 pDD,DWORD nVerts,DWORD nTris) { + if(FAILED(hr)) { + // loss of exclusive mode is not a real DrawPrim problem, ignore it + HRESULT testcooplvl_hr = pDD->TestCooperativeLevel(); + if((testcooplvl_hr != DDERR_NOEXCLUSIVEMODE)||(testcooplvl_hr != DDERR_EXCLUSIVEMODEALREADYSET)) { + dxgsg_cat.fatal() << DP_Type_Strs[dptype] << "() failed: result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + + CountDPs(nVerts,nTris); +} +#else +#define TestDrawPrimFailure(a,b,c,nVerts,nTris) CountDPs(nVerts,nTris); +#endif + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::render_frame +// Access: Public, Virtual +// Description: Renders an entire frame, including all display +// regions within the frame, and includes any necessary +// pre- and post-processing like swapping buffers. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +render_frame() { + if (!_dx_ready) + return; + + _win->begin_frame(); + _lighting_enabled_this_frame = false; + +#ifdef DO_PSTATS + // For Pstats to track our current texture memory usage, we have to + // reset the set of current textures each frame. + init_frame_pstats(); + + // But since we don't get sent a new issue_texture() unless our + // texture state has changed, we have to be sure to clear the + // current texture state now. A bit unfortunate, but probably not + // measurably expensive. + NodeTransitions state; + state.set_transition(new TextureTransition); + modify_state(state); +#endif + + HRESULT hr = _d3dDevice->BeginScene(); + + if(FAILED(hr)) { + if((hr==DDERR_SURFACELOST)||(hr==DDERR_SURFACEBUSY)) { + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "BeginScene returns " << ConvD3DErrorToString(hr) << endl; + + CheckCooperativeLevel(); + } else { + dxgsg_cat.error() << "BeginScene failed, unhandled error hr == " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + return; + } + +/* _d3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &matIdentity); */ + +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "begin frame --------------------------------------------" << endl; +#endif + + _decal_level = 0; + + if (_clear_buffer_type != 0) { + // First, clear the entire window. + #ifndef NO_MULTIPLE_DISPLAY_REGIONS + PT(DisplayRegion) win_dr = _win->make_scratch_display_region(_win->get_width(), _win->get_height()); + clear(get_render_buffer(_clear_buffer_type), win_dr); + #else + clear(get_render_buffer(_clear_buffer_type)); + #endif + } + +#if 0 + int max_channel_index = _win->get_max_channel_index(); + for (int c = 0; c < max_channel_index; c++) { + if (_win->is_channel_defined(c)) { +#endif + + // only 1 channel on dx currently + assert(_win->get_max_channel_index()==1); + assert(_win->is_channel_defined(0)); + + if(_panda_gfx_channel->is_active()) { + // Now render each of our layers in order. + + int num_layers = _panda_gfx_channel->get_num_layers(); + for (int l = 0; l < num_layers; l++) { + GraphicsLayer *layer = _panda_gfx_channel->get_layer(l); + if (layer->is_active()) { + int num_drs = layer->get_num_drs(); + for (int d = 0; d < num_drs; d++) { + DisplayRegion *dr = layer->get_dr(d); + Camera *cam = dr->get_camera(); + + // For each display region, render from the camera's view. + if (dr->is_active() && cam != (Camera *)NULL && + cam->is_active() && cam->get_scene() != (Node *)NULL) { + DisplayRegionStack old_dr = push_display_region(dr); + prepare_display_region(); + render_scene(cam->get_scene(), cam); + pop_display_region(old_dr); + } + } + } // if (layer->is_active()) + } + } // if (chan->is_active()) +#if 0 + } + } // for (int c = 0; c < max_channel_index; c++) +#endif + + // draw new tri-based FPS meter + + if(dx_show_fps_meter) { + DO_PSTATS_STUFF(PStatTimer timer(_win->_show_fps_pcollector)); + // compute and write new texture indices here + + char fps_msg[15]; + sprintf(fps_msg, "%6.02f fps", _current_fps); // 6 == NUM_FPSMETER_LETTERS + + #define WRITE_FPS_UV(u,v) {*fltptr=(u); fltptr[1]=(v); fltptr= (float*)(((BYTE*)fltptr)+_fps_vertexsize);} + float u_FPSMETER_LETTER_WIDTH = _fps_u_usedwidth/(float)FPSMETER_NUMFONTLETTERS; + + // write out texcoords + float *fltptr = (float*)_fpsmeter_verts; + fltptr+=5; // skip over 1st XYZ,RHW, and colr (5 DWORDs) + + for(DWORD c=0;c'9'))) { + uval1=0.0f; uval2=0.0f; vval2=0.0f; + } + + WRITE_FPS_UV(uval1,0.0f); + WRITE_FPS_UV(uval1,vval2); + WRITE_FPS_UV(uval2,vval2); + + WRITE_FPS_UV(uval2,vval2); + WRITE_FPS_UV(uval2,0.0f); + WRITE_FPS_UV(uval1,0.0f); + } + + // is this blending fn expensive? if so, can just overwrite everything + + // could a state-block be used here instead? definitely to set up, but to restore? + #ifdef MAKE_FPSMETER_TRANSPARENT + call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + if(!_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, true); + #else + if(_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, false); + #endif + + if (_CurShadeMode != D3DSHADE_FLAT) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT); + } + + DWORD saved_zfunc; + _d3dDevice->GetRenderState(D3DRENDERSTATE_ZFUNC,&saved_zfunc); + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZFUNC,D3DCMP_ALWAYS); + + DWORD saved_fill_state; + if(_current_fill_mode != RenderModeProperty::M_filled) { + _d3dDevice->GetRenderState(D3DRENDERSTATE_FILLMODE, &saved_fill_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); + } + + + DWORD saved_clipping_state,saved_cull_state; + _d3dDevice->GetRenderState(D3DRENDERSTATE_CULLMODE, &saved_cull_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + + _d3dDevice->GetRenderState(D3DRENDERSTATE_CLIPPING, &saved_clipping_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, false); + + // ignore lighting state since verts are post-xform + + DWORD saved_magfilter,saved_minfilter,saved_mipfilter; + DWORD saved_colorop,saved_alphaop,saved_colorarg1,saved_alphaarg1; + LPDIRECTDRAWSURFACE7 saved_tex_surf=NULL; + + _d3dDevice->GetTextureStageState(0, D3DTSS_MAGFILTER, &saved_magfilter); + _d3dDevice->GetTextureStageState(0, D3DTSS_MINFILTER, &saved_minfilter); + _d3dDevice->GetTextureStageState(0, D3DTSS_MIPFILTER, &saved_mipfilter); + _d3dDevice->GetTextureStageState( 0, D3DTSS_COLOROP, &saved_colorop); + _d3dDevice->GetTextureStageState( 0, D3DTSS_COLORARG1, &saved_colorarg1); + _d3dDevice->GetTextureStageState( 0, D3DTSS_ALPHAOP, &saved_alphaop); + _d3dDevice->GetTextureStageState( 0, D3DTSS_ALPHAARG1, &saved_alphaarg1); + + if(saved_mipfilter!= D3DTFP_NONE) + _d3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_NONE); + + #define FPS_TEXFILTER(X) D3D##X##_POINT + + if(saved_minfilter!=FPS_TEXFILTER(TFN)) + _d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, FPS_TEXFILTER(TFN)); + if(saved_magfilter!= FPS_TEXFILTER(TFG)) + _d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, FPS_TEXFILTER(TFG)); + + if(saved_colorop!=D3DTOP_SELECTARG1) + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + if(saved_colorarg1!=D3DTA_TEXTURE) + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + if(saved_alphaop!=D3DTOP_SELECTARG1) + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + if(saved_alphaarg1!=D3DTA_TEXTURE) + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + + hr = _d3dDevice->SetTexture(0, _fpsmeter_font_surf); + if(FAILED(hr)) { + dxgsg_cat.error() << "SetTexture failed in draw fps meter, result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + DWORD nVerts = (NUM_FPSMETER_LETTERS+1)*2*3; // +1 for suffix square + HRESULT hr = _d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, _fpsmeter_fvfflags, _fpsmeter_verts, nVerts, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,NUM_FPSMETER_LETTERS*2,0); + + #ifdef MAKE_FPSMETER_TRANSPARENT + if(!_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, false); + #else + if(_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, true); + #endif + + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, saved_zfunc); + + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, saved_clipping_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, saved_cull_state); + + _d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, saved_magfilter); + _d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, saved_minfilter); + _d3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, saved_mipfilter); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, saved_colorop); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, saved_colorarg1); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, saved_alphaop); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, saved_alphaarg1); + + if (_CurShadeMode != D3DSHADE_FLAT) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, _CurShadeMode); + } + + if(_current_fill_mode != RenderModeProperty::M_filled) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, saved_fill_state); + } + + _d3dDevice->SetTexture(0, ((_pCurTexContext != NULL) ? _pCurTexContext->_surface : NULL)); + } + + hr = _d3dDevice->EndScene(); + + // any GDI operations MUST occur after EndScene + + // Now we're done with the frame processing. Clean up. + if (_lighting_enabled_this_frame) { + // Let's turn off all the lights we had on, and clear the light + // cache--to force the lights to be reissued next frame, in case + // their parameters or positions have changed between frames. + + for (int i = 0; i < _max_lights; i++) { + enable_light(i, false); + _available_light_ids[i] = NULL; + } + + // Also force the lighting state to unlit, so that issue_light() + // will be guaranteed to be called next frame even if we have the + // same set of light pointers we had this frame. + NodeTransitions state; + state.set_transition(new LightTransition); + modify_state(state); + + // All this work to undo the lighting state each frame doesn't seem + // ideal--there may be a better way. Maybe if the lights were just + // more aware of whether their parameters or positions have changed + // at all? + } + + if(FAILED(hr)) { + if((hr==DDERR_SURFACELOST)||(hr==DDERR_SURFACEBUSY)) { + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "EndScene returns " << ConvD3DErrorToString(hr) << endl; + + CheckCooperativeLevel(); + } else { + dxgsg_cat.error() << "EndScene failed, unhandled error hr == " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + return; + } + + if(dx_show_fps_meter) { + DO_PSTATS_STUFF(PStatTimer timer(_win->_show_fps_pcollector)); + + DWORD now = timeGetTime(); // this is win32 fn + + float time_delta = (now - _start_time) * 0.001f; + + if(time_delta > dx_fps_meter_update_interval) { + // didnt use global clock object, it wasnt working properly when I tried, + // its probably slower due to cache faults, and I can easily track all the + // info I need in dxgsg + DWORD num_frames = _cur_frame_count - _start_frame_count; + + _current_fps = num_frames / time_delta; + _start_time = now; + _start_frame_count = _cur_frame_count; + } + + _cur_frame_count++; // only used by fps meter right now + } + + _win->end_frame(); + + show_frame(); + +#ifdef COUNT_DRAWPRIMS + { + #define FRAMES_PER_DPINFO 90 + static DWORD LastDPInfoFrame=0; + static DWORD LastTickCount=0; + + if (_cur_frame_count-LastDPInfoFrame > FRAMES_PER_DPINFO) { + DWORD CurTickCount=GetTickCount(); + float delta_secs=(CurTickCount-LastTickCount)/1000.0f; + + 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; + + dxgsg_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_TEXSTATS) +#ifndef PRINT_TEXSTATS + 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 + +#ifdef GSG_VERBOSE + dxgsg_cat.debug() << "end frame ----------------------------------------------" << endl; +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::report_texmgr_stats +// Access: Protected +// Description: Reports the DX texture manager's activity to PStats. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +report_texmgr_stats() { + +#if defined(DO_PSTATS)||defined(PRINT_TEXSTATS) + + HRESULT hr; + DWORD dwTexTotal,dwTexFree,dwVidTotal,dwVidFree; + +#ifndef PRINT_TEXSTATS + if (_total_texmem_pcollector.is_active()) +#endif + { + DDSCAPS2 ddsCaps; + + ZeroMemory(&ddsCaps,sizeof(ddsCaps)); + + ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + if(FAILED( hr = _pDD->GetAvailableVidMem(&ddsCaps,&dwVidTotal,&dwVidFree))) { + dxgsg_cat.debug() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + ddsCaps.dwCaps = DDSCAPS_TEXTURE; + if(FAILED( hr = _pDD->GetAvailableVidMem(&ddsCaps,&dwTexTotal,&dwTexFree))) { + dxgsg_cat.debug() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + + D3DDEVINFO_TEXTUREMANAGER tminfo; + ZeroMemory(&tminfo,sizeof(D3DDEVINFO_TEXTUREMANAGER)); + + if(!bTexStatsRetrievalImpossible) { + hr = _d3dDevice->GetInfo(D3DDEVINFOID_TEXTUREMANAGER,&tminfo,sizeof(D3DDEVINFO_TEXTUREMANAGER)); + if (hr!=D3D_OK) { + if (hr==S_FALSE) { + static int PrintedMsg=2; + if(PrintedMsg>0) { + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << " ************ texstats GetInfo() requires debug DX DLLs to be installed!! ***********\n"; + ZeroMemory(&tminfo,sizeof(D3DDEVINFO_TEXTUREMANAGER)); + bTexStatsRetrievalImpossible=true; + } + } else { + dxgsg_cat.error() << "d3ddev->GetInfo(TEXTUREMANAGER) failed to get tex stats: result = " << ConvD3DErrorToString(hr) << endl; + return; + } + } + } + +#ifdef PRINT_TEXSTATS + 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); + dxgsg_cat.debug() << "\nAvailableVidMem for RenderSurfs: (megs) total: " << tmpstr1 << " free: " << tmpstr2 + << "\nAvailableVidMem for Textures: (megs) total: " << tmpstr3 << " free: " << tmpstr4 << endl; + + if(!bTexStatsRetrievalImpossible) { + dxgsg_cat.spam() + << "\n bThrashing:\t" << tminfo.bThrashing + << "\n NumEvicts:\t" << tminfo.dwNumEvicts + << "\n NumVidCreates:\t" << tminfo.dwNumVidCreates + << "\n NumTexturesUsed:\t" << tminfo.dwNumTexturesUsed + << "\n NumUsedTexInVid:\t" << tminfo.dwNumUsedTexInVid + << "\n WorkingSet:\t" << tminfo.dwWorkingSet + << "\n WorkingSetBytes:\t" << tminfo.dwWorkingSetBytes + << "\n TotalManaged:\t" << tminfo.dwTotalManaged + << "\n TotalBytes:\t" << tminfo.dwTotalBytes + << "\n LastPri:\t" << tminfo.dwLastPri << endl; + + D3DDEVINFO_TEXTURING texappinfo; + ZeroMemory(&texappinfo,sizeof(D3DDEVINFO_TEXTURING)); + hr = _d3dDevice->GetInfo(D3DDEVINFOID_TEXTURING,&texappinfo,sizeof(D3DDEVINFO_TEXTURING)); + if (hr!=D3D_OK) { + dxgsg_cat.error() << "GetInfo(TEXTURING) failed : result = " << ConvD3DErrorToString(hr) << endl; + return; + } else { + dxgsg_cat.spam() + << "\n NumTexLoads:\t" << texappinfo.dwNumLoads + << "\n ApproxBytesLoaded:\t" << texappinfo.dwApproxBytesLoaded + << "\n NumPreLoads:\t" << texappinfo.dwNumPreLoads + << "\n NumSet:\t" << texappinfo.dwNumSet + << "\n NumCreates:\t" << texappinfo.dwNumCreates + << "\n NumDestroys:\t" << texappinfo.dwNumDestroys + << "\n NumSetPriorities:\t" << texappinfo.dwNumSetPriorities + << "\n NumSetLODs:\t" << texappinfo.dwNumSetLODs + << "\n NumLocks:\t" << texappinfo.dwNumLocks + << "\n NumGetDCs:\t" << texappinfo.dwNumGetDCs << 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(tminfo.dwTotalBytes); + _texmgrmem_resident_pcollector.set_level(tminfo.dwWorkingSetBytes); + } + + if (_total_texmem_pcollector.is_active()) { + _total_texmem_pcollector.set_level(dwTexTotal); + _used_texmem_pcollector.set_level(dwTexTotal - dwTexFree); + } +#endif + +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::render_scene +// Access: Public, Virtual +// Description: Renders an entire scene, from the root node of the +// scene graph, as seen from a particular ProjectionNode +// and with a given initial state. This initial state +// may be modified during rendering. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +render_scene(Node *root, ProjectionNode *projnode) { +#ifdef GSG_VERBOSE + _pass_number = 0; + dxgsg_cat.debug() + << "begin scene - - - - - - - - - - - - - - - - - - - - - - - - -" + << endl; +#endif + _current_root_node = root; + + render_subgraph(_render_traverser, root, projnode, + AllTransitionsWrapper()); + +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "done scene - - - - - - - - - - - - - - - - - - - - - - - - -" + << endl; +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::render_subgraph +// Access: Public, Virtual +// Description: Renders a subgraph of the scene graph as seen from a +// given projection node, and with a particular initial +// state. This state may be modified by the render +// process. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +render_subgraph(RenderTraverser *traverser, + Node *subgraph, ProjectionNode *projnode, + const AllTransitionsWrapper &net_trans) { + ProjectionNode *old_projection_node = _current_projection_node; + _current_projection_node = projnode; + LMatrix4f old_projection_mat = _current_projection_mat; + + // d3d is left-handed coord system + LMatrix4f projection_mat = projnode->get_projection()->get_projection_mat(CS_yup_left); + +#if 0 + dxgsg_cat.spam() << "cur projection matrix: " << projection_mat <<"\n"; +#endif + + _current_projection_mat = projection_mat; + _projection_mat_stack_count++; + +#ifdef _DEBUG + { + static bool bPrintedMsg=false; + + if((!bPrintedMsg) && !IS_NEARLY_EQUAL(projection_mat(2,3),1.0f)) { + bPrintedMsg=true; + dxgsg_cat.debug() << "non w-compliant render_subgraph projection matrix [2][3] should be 1.0, instead is: " << projection_mat(2,3) << endl; + dxgsg_cat.debug() << "cur projection matrix: " << projection_mat << endl; + } + + // note: a projection matrix that does not have a [3][4] value of 1.0f is + // not w-compliant and could cause problems with fog + + } +#endif + + HRESULT hr; + + // We load the projection matrix directly. + hr = _d3dDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, + (LPD3DMATRIX) _current_projection_mat.get_data()); + + // We infer the modelview matrix by doing a wrt on the projection + // node. + LMatrix4f modelview_mat; + get_rel_mat(subgraph, _current_projection_node, modelview_mat); //needs reversal from glgsg, probably due D3D LH coordsys +// get_rel_mat(_current_projection_node, subgraph, modelview_mat); + + if (_coordinate_system != CS_yup_left) { + // Now we build the coordinate system conversion into the + // modelview matrix (as described in the paragraph above). + modelview_mat = modelview_mat * + LMatrix4f::convert_mat(_coordinate_system, CS_yup_left); + } + + // The modelview matrix will be loaded as each geometry is + // encountered. So we set the supplied modelview matrix as an + // initial value instead of loading it now. + AllTransitionsWrapper sub_trans = net_trans; + sub_trans.set_transition(new TransformTransition(modelview_mat)); + + render_subgraph(traverser, subgraph, sub_trans); + + _current_projection_node = old_projection_node; + _current_projection_mat = old_projection_mat; + _projection_mat_stack_count--; + + + // We must now restore the projection matrix from before. We could + // do a push/pop matrix if we were using D3DX + if (_projection_mat_stack_count > 0) + hr =_d3dDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, + (LPD3DMATRIX) _current_projection_mat.get_data()); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::render_subgraph +// Access: Public, Virtual +// Description: Renders a subgraph of the scene graph as seen from the +// current projection node, and with a particular +// initial state. This state may be modified during the +// render process. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +render_subgraph(RenderTraverser *traverser, Node *subgraph, + const AllTransitionsWrapper &net_trans) { +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "begin subgraph (pass " << ++_pass_number + << ") - - - - - - - - - - - - - - - - - - - - - - - - -" << endl; +#endif + + nassertv(traverser != (RenderTraverser *)NULL); + traverser->traverse(subgraph, net_trans); + +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "end subgraph (pass " << _pass_number + << ") - - - - - - - - - - - - - - - - - - - - - - - - -" + << endl; +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::add_to_FVFBuf +// Access: Private +// Description: This adds data to the flexible vertex format +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +add_to_FVFBuf(void *data, size_t bytes) { + memcpy(_pCurFvfBufPtr, data, bytes); + _pCurFvfBufPtr += bytes; +} + +// generates slightly fewer instrs +#define add_DWORD_to_FVFBuf(data) { *((DWORD *)_pCurFvfBufPtr) = (DWORD) data; _pCurFvfBufPtr += sizeof(DWORD);} + +typedef enum { + FlatVerts,IndexedVerts,MixedFmtVerts +} GeomVertFormat; + +#define COPYVERTDATA_2_VERTEXBUFFER(PrimType,NumVertices) { \ + DWORD numVertBytes=_pCurFvfBufPtr-_pFvfBufBasePtr; \ + memcpy(_pCurrentGeomContext->_pEndofVertData,_pFvfBufBasePtr,numVertBytes); \ + DPInfo dpInfo; \ + dpInfo.nVerts=NumVertices; \ + dpInfo.primtype=PrimType; \ + _pCurrentGeomContext->_PrimInfo.push_back(dpInfo); \ + _pCurrentGeomContext->_num_verts+=dpInfo.nVerts; \ + _pCurrentGeomContext->_pEndofVertData+=numVertBytes; } + + +INLINE void DXGraphicsStateGuardian:: +transform_color(Colorf &InColor,D3DCOLOR &OutRGBAColor) { + // To be truly general, we really need a 5x5 matrix to transform a + // 4-component color. Rather than messing with that, we instead + // treat the color as a 3-component RGB, which can be transformed by + // the ordinary 4x4 matrix, and a separate alpha value, which can be + // scaled and offsetted. + + LPoint4f temp_pnt(InColor[0], InColor[1], InColor[2], 1.0f); + Colorf out_color = temp_pnt * _current_color_mat; // maybe expand this out for efficiency + out_color[3] = (InColor[3] * _current_alpha_scale) + _current_alpha_offset; + OutRGBAColor = Colorf_to_D3DCOLOR(out_color); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::wants_colors +// Access: Public, Virtual +// Description: Returns true if the GSG should issue geometry color +// commands, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool DXGraphicsStateGuardian:: +wants_colors() const { + // If we have scene graph color enabled, return false to indicate we + // shouldn't bother issuing geometry color commands. + + const ColorTransition *catt; + if (!get_attribute_into(catt, this)) { + // No scene graph color at all. + return true; + } + + // We should issue geometry colors only if the scene graph color is off. + if (catt->is_off() || (!catt->is_real())) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_prim_setup +// Access: Private +// Description: This adds data to the flexible vertex format +//////////////////////////////////////////////////////////////////// +size_t DXGraphicsStateGuardian:: +draw_prim_setup(const Geom *geom) { + // Set the flags for the flexible vertex format and compute the bytes + // required to store a single vertex. + + #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_transform_required) { \ + _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(); + _curFVFflags = D3DFVF_XYZ; + size_t vertex_size = sizeof(D3DVALUE) * 3; + + GeomBindType ColorBinding=geom->get_binding(G_COLOR); + bool bDoColor=(ColorBinding != G_OFF); + + if (_enable_all_color && (bDoColor || _issued_color_enabled)) { + ci = geom->make_color_iterator(); + _curFVFflags |= D3DFVF_DIFFUSE; + vertex_size += sizeof(D3DCOLOR); + + if (_issued_color_enabled) { + _curD3Dcolor = _issued_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(); + _curFVFflags |= D3DFVF_NORMAL; + vertex_size += sizeof(D3DVALUE) * 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) { + // 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(); + _curFVFflags |= (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 + + D3DSHADEMODE needed_shademode = + (((_perVertex & (PER_COLOR | (wants_normals() ? PER_NORMAL : 0))) || _fog_enabled) ? + D3DSHADE_GOURAUD : D3DSHADE_FLAT); + + set_shademode(needed_shademode); + + return vertex_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_prim_inner_loop +// Access: Private +// Description: This adds data to the flexible vertex format with a check +// for component normals and color +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +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, sizeof(D3DVECTOR)); + + 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 (_curFVFflags & D3DFVF_NORMAL) + add_to_FVFBuf((void *)&p_normal, sizeof(D3DVECTOR)); + if (_curFVFflags & D3DFVF_DIFFUSE) + add_DWORD_to_FVFBuf(_curD3Dcolor); + if (_curFVFflags & D3DFVF_TEXCOUNT_MASK) + add_to_FVFBuf((void *)&p_texcoord, sizeof(TexCoordf)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_prim_inner_loop_coordtexonly +// Access: Private +// Description: FastPath loop used by animated character data +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_prim_inner_loop_coordtexonly(int nVerts, const Geom *geom) { + // assumes coord and texcoord data is per-vertex, color is not per-vert, 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 + + Vertexf *pCurCoord = _pCurCoord; + ushort *pCurCoordIndex = _pCurCoordIndex; + TexCoordf *pCurTexCoord = _pCurTexCoord; + ushort *pCurTexCoordIndex = _pCurTexCoordIndex; + + char *LocalFvfBufPtr = _pCurFvfBufPtr; + DWORD cur_color = _curD3Dcolor; + bool bDoIndexedTexCoords = (_texcoordindex_array != NULL); + bool bDoIndexedCoords = (_coordindex_array != NULL); + + for(;nVerts>0;nVerts--) { + if(bDoIndexedCoords) { + memcpy(LocalFvfBufPtr,(void*)&_coord_array[*pCurCoordIndex],sizeof(D3DVECTOR)); + pCurCoordIndex++; + } else { + memcpy(LocalFvfBufPtr,(void*)pCurCoord,sizeof(D3DVECTOR)); + pCurCoord++; + } + + LocalFvfBufPtr+=sizeof(D3DVECTOR); + + *((DWORD *)LocalFvfBufPtr) = cur_color; + LocalFvfBufPtr += sizeof(DWORD); + + if(bDoIndexedTexCoords) { + memcpy(LocalFvfBufPtr,(void*)&_texcoord_array[*pCurTexCoordIndex],sizeof(TexCoordf)); + pCurTexCoordIndex++; + } else { + memcpy(LocalFvfBufPtr,(void*)pCurTexCoord,sizeof(TexCoordf)); + pCurTexCoord++; + } + LocalFvfBufPtr+=sizeof(TexCoordf); + } + + _pCurFvfBufPtr=LocalFvfBufPtr; + _pCurCoord = pCurCoord; + _pCurCoordIndex = pCurCoordIndex; + _pCurTexCoord = pCurTexCoord; + _pCurTexCoordIndex = pCurTexCoordIndex; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_point +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_point(GeomPoint *geom, GeomContext *gc) { + +#ifdef GSG_VERBOSE + dxgsg_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) { + dxgsg_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; + dxgsg_cat.warning() << "D3D does not support drawing points of non-unit size, setting point size to 1.0f!\n"; + } +#endif + + nassertv(nPrims < D3DMAXNUMVERTICES ); + + 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); + + GeomVertFormat GeomVrtFmt=FlatVerts; + + // first determine if we're indexed or non-indexed + + if ((vindexes!=NULL)&&(cindexes!=NULL)&&(tindexes!=NULL)&&(nindexes!=NULL)) { + GeomVrtFmt=IndexedVerts; + } else if (!((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL))) + GeomVrtFmt=MixedFmtVerts; + +#ifdef DONT_USE_DRAWPRIMSTRIDED + GeomVrtFmt=MixedFmtVerts; +#else + if(_bDrawPrimDoSetupVertexBuffer) { + GeomVrtFmt=MixedFmtVerts; + } +#endif + + // 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) + if (GeomVrtFmt!=FlatVerts) { + + _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); + + if(!_bDrawPrimDoSetupVertexBuffer) { + HRESULT hr = _d3dDevice->DrawPrimitive(D3DPT_POINTLIST, _curFVFflags, _pFvfBufBasePtr, nPrims, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,nPrims,0); + } else { + COPYVERTDATA_2_VERTEXBUFFER(D3DPT_POINTLIST,nPrims); + } + } else { // setup for strided + + size_t vertex_size = draw_prim_setup(geom); + + // new code only handles non-indexed pointlists (is this enough?) + nassertv((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL)); + + D3DDRAWPRIMITIVESTRIDEDDATA dps_data; + memset(&dps_data,0,sizeof(D3DDRAWPRIMITIVESTRIDEDDATA)); + + dps_data.position.lpvData = (VOID*)coords; + dps_data.position.dwStride = sizeof(D3DVECTOR); + + if (_curFVFflags & D3DFVF_NORMAL) { + dps_data.normal.lpvData = (VOID*)norms; + dps_data.normal.dwStride = sizeof(D3DVECTOR); + } + + if (_curFVFflags & D3DFVF_DIFFUSE) { + _pCurFvfBufPtr=_pFvfBufBasePtr; + + dps_data.diffuse.lpvData = (VOID*)_pFvfBufBasePtr; + dps_data.diffuse.dwStride = sizeof(D3DCOLOR); + + // Geom nodes store floats for colors, drawprim requires ARGB dwords + // BUGBUG: eventually this hack every-frame all-colors conversion needs + // to be done only once as part of a vertex buffer + + if(_color_transform_required) { + for (int i=0;iDrawPrimitiveStrided(D3DPT_POINTLIST, _curFVFflags, &dps_data, nPrims, NULL); + TestDrawPrimFailure(DrawPrimStrided,hr,_pDD,nPrims,0); + } + + _pCurFvfBufPtr = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_line +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_line(GeomLine* geom, GeomContext *gc) { + +#ifdef GSG_VERBOSE + dxgsg_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; + dxgsg_cat.warning() << "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) { + dxgsg_cat.warning() << "draw_line() called with ZERO vertices!!" << endl; + return; + } + + assert(geom->get_binding(G_COORD) == G_PER_VERTEX); + _perVertex = 0x0; + _perPrim = _perComp = 0x0; + + 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; + } + + 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; + } + + size_t vertex_size = draw_prim_setup(geom); + + char *_tmp_fvf = 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_fvf = new char[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 vertCount = nPrims<<1; + + if(!_bDrawPrimDoSetupVertexBuffer) { + if (_tmp_fvf == NULL) + hr = _d3dDevice->DrawPrimitive(D3DPT_LINELIST, _curFVFflags, _pFvfBufBasePtr, vertCount, NULL); + else { + hr = _d3dDevice->DrawPrimitive(D3DPT_LINELIST, _curFVFflags, _tmp_fvf, vertCount, NULL); + delete [] _tmp_fvf; + } + TestDrawPrimFailure(DrawPrim,hr,_pDD,vertCount,0); + } else { + COPYVERTDATA_2_VERTEXBUFFER(D3DPT_LINELIST,vertCount); + } + + _pCurFvfBufPtr = NULL; +} + +void DXGraphicsStateGuardian:: +draw_linestrip(GeomLinestrip* geom, GeomContext *gc) { + +#ifdef _DEBUG + static BOOL bPrintedMsg=FALSE; + + if (!bPrintedMsg && (geom->get_width()!=1.0f)) { + bPrintedMsg=TRUE; + dxgsg_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: DXGraphicsStateGuardian::draw_linestrip +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_linestrip_base(Geom* geom, GeomContext *gc, bool bConnectEnds) { + +#ifdef GSG_VERBOSE + dxgsg_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 *plen = geom->get_lengths(); + + if (nPrims==0) { + dxgsg_cat.warning() << "draw_linestrip() called with ZERO vertices!!" << endl; + return; + } + + assert(geom->get_binding(G_COORD) == G_PER_VERTEX); + _perVertex = 0x0; + + _perPrim = _perComp = 0; + 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; + } + + 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; + } + + size_t vertex_size = draw_prim_setup(geom); + ushort perFlags = _perVertex | _perComp; + + for (int i = 0; i < nPrims; i++) { + if (_perPrim & PER_COLOR) { + GET_NEXT_COLOR(); + } + + int nVerts; + + if(plen!=NULL) { + nVerts= *(plen++); + nassertv(nVerts >= 2); + } else { + nVerts=4; // we've been called by draw_quad, which has no lengths array + } + + 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++; + } + + if(!_bDrawPrimDoSetupVertexBuffer) { + HRESULT hr = _d3dDevice->DrawPrimitive(D3DPT_LINESTRIP, _curFVFflags, _pFvfBufBasePtr, nVerts, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,nVerts,0); + } else { + COPYVERTDATA_2_VERTEXBUFFER(D3DPT_LINESTRIP,nVerts); + } + + _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: DXGraphicsStateGuardian::draw_sprite +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +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 DX8, try to use the PointSprite primitive instead of doing all the stuff below + +#ifdef GSG_VERBOSE + dxgsg_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; + _d3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &OldD3DWorldMatrix); + + bool bReEnableDither=false; + + _d3dDevice->GetTransform(D3DTRANSFORMSTATE_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 + NodeTransitions state; + + // this sets up texturing. Could just set the renderstates directly, but this is a little cleaner + TextureTransition *ta = new TextureTransition(tex); + state.set_transition(ta); + + TextureApplyTransition *taa = new TextureApplyTransition(TextureApplyProperty::M_modulate); + state.set_transition(taa); + + modify_state(state); + + tex_xsize = tex->_pbuffer->get_xsize(); + tex_ysize = tex->_pbuffer->get_ysize(); + } + + // save the modelview matrix + LMatrix4f modelview_mat; + + const TransformTransition *ctatt; + if (!get_attribute_into(ctatt, this)) + modelview_mat = LMatrix4f::ident_mat(); + else + modelview_mat = ctatt->get_matrix(); + + // get the camera information + float aspect_ratio; + aspect_ratio = _actual_display_region->get_camera()->get_aspect(); + + // null the world xform, so sprites are orthog to scrn (but not necessarily camera pnt unless they lie along z-axis) + _d3dDevice->SetTransform(D3DTRANSFORMSTATE_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 TransparencyTransition *ctratt; + if (get_attribute_into(ctratt, this)) + alpha = (ctratt->get_mode() != TransparencyProperty::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 * aspect_ratio; + 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) { + dxgsg_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; + + #if 0 + // not going to attempt this bDoColor optimization to use default white color in flat-shaded + // mode anymore, it just make the logic confusing below. from now on, always have color in FVF + + _curFVFflags = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) ; + DWORD vertex_size = sizeof(float) * 2 + sizeof(D3DVALUE) * 3; + + bool bDoColor=true; + + if (color_overall) { + GET_NEXT_COLOR(); + CurColor = _curD3Dcolor; + bDoColor = (_curD3Dcolor != ~0); // dont need to add color if it's all white + } + + if (bDoColor) { + _curFVFflags |= D3DFVF_DIFFUSE; + vertex_size+=sizeof(D3DCOLOR); + } + #else + _curFVFflags = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) | D3DFVF_DIFFUSE; + DWORD vertex_size = sizeof(float) * 2 + sizeof(D3DVALUE) * 3 + sizeof(D3DCOLOR); + + if (color_overall) { + GET_NEXT_COLOR(); + CurColor = _curD3Dcolor; + } + #endif + + // see note on fog in draw_prim_setup + bool bUseGouraudShadedColor=_fog_enabled; + + set_shademode(!_fog_enabled ? D3DSHADE_FLAT: D3DSHADE_GOURAUD); + + #ifdef _DEBUG + nassertv(_pCurFvfBufPtr == NULL); // make sure the storage pointer is clean. + nassertv(nprims * 4 * vertex_size < VERT_BUFFER_SIZE); + nassertv(nprims * 6 < D3DMAXNUMVERTICES ); + #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 * aspect_ratio; + + // 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(), sizeof(D3DVECTOR)); + 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(), sizeof(D3DVECTOR)); + + // 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(), sizeof(D3DVECTOR)); + // 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(), sizeof(D3DVECTOR)); + add_DWORD_to_FVFBuf(CurColor); + add_to_FVFBuf((void *)TexCrdSets[3], sizeof(float)*2); + + for (int ii=0;iiDrawIndexedPrimitive(D3DPT_TRIANGLELIST, _curFVFflags, _pFvfBufBasePtr, 4*nprims, _index_buf,QUADVERTLISTLEN*nprims,NULL); + TestDrawPrimFailure(DrawIndexedPrim,hr,_pDD,QUADVERTLISTLEN*nprims,nprims); + + _pCurFvfBufPtr = NULL; + delete [] SpriteArray; + + // restore the matrices + _d3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &OldD3DWorldMatrix); + + if(bReEnableDither) + enable_dither(true); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_polygon +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_polygon(GeomPolygon *geom, GeomContext *gc) { + +#ifdef GSG_VERBOSE + dxgsg_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; + _d3dDevice->GetRenderState(D3DRENDERSTATE_FILLMODE, &rstate); + if(rstate==D3DFILL_WIREFRAME) { + draw_linestrip_base(geom,gc,true); + } else { + draw_multitri(geom, D3DPT_TRIANGLEFAN); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_quad +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_quad(GeomQuad *geom, GeomContext *gc) { + +#ifdef GSG_VERBOSE + dxgsg_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; + _d3dDevice->GetRenderState(D3DRENDERSTATE_FILLMODE, &rstate); + if(rstate==D3DFILL_WIREFRAME) { + draw_linestrip_base(geom,gc,true); + } else { + draw_multitri(geom, D3DPT_TRIANGLEFAN); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_tri +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_tri(GeomTri *geom, GeomContext *gc) { + +#ifdef GSG_VERBOSE + dxgsg_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) { + dxgsg_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); + + GeomVertFormat GeomVrtFmt=FlatVerts; + + // first determine if we're indexed or non-indexed + + if ((vindexes!=NULL)&&(cindexes!=NULL)&&(tindexes!=NULL)&&(nindexes!=NULL)) { + GeomVrtFmt=IndexedVerts; + //make sure array sizes are consistent, we can only pass 1 size to DrawIPrm +// nassertv(coords.size==norms.size); nassertv(coords.size==colors.size); nassertv(coords.size==texcoords.size); need to assert only if we have this w/same binding + // indexed mode requires all used norms,colors,texcoords,coords array be the same + // length, or 0 or 1 (dwStride==0), also requires all elements to use the same index array + } else if (!((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL))) + GeomVrtFmt=MixedFmtVerts; + +#ifdef DONT_USE_DRAWPRIMSTRIDED + GeomVrtFmt=MixedFmtVerts; +#else + if(_bDrawPrimDoSetupVertexBuffer) { + GeomVrtFmt=MixedFmtVerts; + } +#endif + + // 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) + if (GeomVrtFmt!=FlatVerts) { + // this is the old geom setup, it reformats every vtx into an output array passed to d3d + + _perVertex = 0x0; + _perPrim = 0x0; + + if(NormalBinding == G_PER_VERTEX) + _perVertex |= PER_NORMAL; + else if(NormalBinding == G_PER_PRIM) + _perPrim |= PER_NORMAL; + + if(ColorBinding == G_PER_PRIM) + _perPrim |= PER_COLOR; + else if(ColorBinding == G_PER_VERTEX) + _perVertex |= PER_COLOR; + + if (TexCoordBinding == G_PER_VERTEX) + _perVertex |= PER_TEXCOORD; + + size_t vertex_size = draw_prim_setup(geom); + + 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 (_perPrim & PER_COLOR) { + GET_NEXT_COLOR(); + } + + if (_perPrim & PER_NORMAL) + p_normal = geom->get_next_normal(ni); // set primitive normal if there is one. + + + if(_perVertex==TexCoordOnly) + draw_prim_inner_loop_coordtexonly(3, geom); + else draw_prim_inner_loop(3, geom, _perVertex); + } + + DWORD nVerts=nPrims*3; + + if(!_bDrawPrimDoSetupVertexBuffer) { + hr = _d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, _curFVFflags, _pFvfBufBasePtr, nVerts, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,nVerts,nPrims); + } else { + COPYVERTDATA_2_VERTEXBUFFER(D3DPT_TRIANGLELIST,nVerts); + } + + _pCurFvfBufPtr = NULL; + } else { + + // new geom setup that uses strided DP calls to avoid making an extra pass over the data + + D3DDRAWPRIMITIVESTRIDEDDATA dps_data; + memset(&dps_data,0,sizeof(D3DDRAWPRIMITIVESTRIDEDDATA)); + +#ifdef _DEBUG + nassertv(!geom->uses_components()); // code ignores lengths array + nassertv(geom->get_binding(G_COORD) == G_PER_VERTEX); +#endif + + D3DPRIMITIVETYPE primtype=D3DPT_TRIANGLELIST; + + DWORD fvf_flags = D3DFVF_XYZ; + dps_data.position.lpvData = (VOID*)coords; + dps_data.position.dwStride = sizeof(D3DVECTOR); + + // see fog comment in draw_prim_setup + D3DSHADEMODE NeededShadeMode = (_fog_enabled) ? D3DSHADE_GOURAUD : D3DSHADE_FLAT; + + const DWORD dwVertsperPrim=3; + + if ((NormalBinding != G_OFF) && wants_normals()) { + + dps_data.normal.lpvData = (VOID*)norms; + dps_data.normal.dwStride = sizeof(D3DVECTOR); + +#ifdef _DEBUG + nassertv(geom->get_num_vertices_per_prim()==3); + nassertv( nPrims*dwVertsperPrim*sizeof(D3DVECTOR) <= D3DMAXNUMVERTICES*sizeof(WORD)); + if (NormalBinding==G_PER_VERTEX) + nassertv(norms.size()>=nPrims*dwVertsperPrim); +#endif + + fvf_flags |= D3DFVF_NORMAL; + NeededShadeMode = D3DSHADE_GOURAUD; + + Normalf *pExpandedNormalArray = (Normalf *)_index_buf; // BUGBUG: need to use real permanent buffers for this conversion + if (NormalBinding==G_PER_PRIM) { + // must use tmp array to duplicate-expand per-prim norms to per-vert norms + Normalf *pOutVec = pExpandedNormalArray; + Normalf *pInVec=norms; + + nassertv(norms.size()>=nPrims); + + for (uint i=0;iis_real()) + bDoColor=FALSE; // this turns off any Geom colors + else { + ColorBinding=G_OVERALL; + bDoGlobalSceneGraphColor=TRUE; + } + } + + if (bDoColor || bDoGlobalSceneGraphColor) { + D3DCOLOR *pOutColor,*pConvertedColorArray; + Colorf *pInColor=colors; + pOutColor = pConvertedColorArray = (D3DCOLOR *)_pFvfBufBasePtr; + +#ifdef _DEBUG + nassertv( nPrims*dwVertsperPrim*sizeof(D3DCOLOR) <= VERT_BUFFER_SIZE); +#endif + + fvf_flags |= D3DFVF_DIFFUSE; + + dps_data.diffuse.lpvData = (VOID*)pConvertedColorArray; + dps_data.diffuse.dwStride = sizeof(D3DCOLOR); + + if (ColorBinding==G_PER_PRIM) { + // must use tmp array to expand per-prim info to per-vert info + + // Geom nodes store floats for colors, drawprim requires ARGB dwords + // BUGBUG: eventually this hack every-frame all-colors conversion needs + // to be done only once as part of a vertex buffer + + if (NeededShadeMode!=D3DSHADE_FLAT) { + // but if lighting enabled, we need to color every vert since shading will be GOURAUD + + if(!_color_transform_required) { + for (uint i=0;iget_color(); + *pConvertedColorArray = Colorf_to_D3DCOLOR(colr); + } else { + *pConvertedColorArray = Colorf_to_D3DCOLOR(*pInColor); + } + } else { + if (bDoGlobalSceneGraphColor) { + Colorf colr = catt->get_color(); + transform_color(colr,*pConvertedColorArray); + } else { + transform_color(*pInColor,*pConvertedColorArray); + } + } + + dps_data.diffuse.dwStride = 0; + } + } + + if ((TexCoordBinding != G_OFF) && _texturing_enabled) { + +#ifdef _DEBUG + nassertv(TexCoordBinding == G_PER_VERTEX); // only sensible choice for a tri +#endif + + dps_data.textureCoords[0].lpvData = (VOID*)texcoords; + dps_data.textureCoords[0].dwStride = sizeof(TexCoordf); + fvf_flags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); + } + + set_shademode(NeededShadeMode); + + DWORD nVerts = nPrims*dwVertsperPrim; + + hr = _d3dDevice->DrawPrimitiveStrided(primtype, fvf_flags, &dps_data, nVerts, NULL); + TestDrawPrimFailure(DrawPrimStrided,hr,_pDD,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 + }; + + _d3dDevice->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_BORDER); + _d3dDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_BORDER); + _d3dDevice->SetTextureStageState(0,D3DTSS_BORDERCOLOR,MY_D3DRGBA(0,0,0,0)); + + _curFVFflags = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) ; + HRESULT hr = _d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, _curFVFflags, vert_buf, nPrims*3, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,nPrims*3,nPrims); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_tristrip +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_tristrip(GeomTristrip *geom, GeomContext *gc) { + +#ifdef GSG_VERBOSE + dxgsg_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: DXGraphicsStateGuardian::draw_trifan +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_trifan(GeomTrifan *geom, GeomContext *gc) { + +#ifdef GSG_VERBOSE + dxgsg_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: DXGraphicsStateGuardian::draw_multitri +// Access: Public, Virtual +// Description: handles trifans and tristrips +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +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 + dxgsg_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); + + GeomVertFormat GeomVrtFmt; + +#ifdef DONT_USE_DRAWPRIMSTRIDED + GeomVrtFmt=MixedFmtVerts; +#else + GeomVrtFmt=FlatVerts; + + if(!geom->uses_components()) { + GeomVrtFmt=MixedFmtVerts; // dont need efficiency here, just use simpler codepath + } else { + // first determine if we're indexed or non-indexed + if((vindexes!=NULL)&&(cindexes!=NULL)&&(tindexes!=NULL)&&(nindexes!=NULL)) { + GeomVrtFmt=IndexedVerts; + //make sure array sizes are consistent, we can only pass 1 size to DrawIPrm + // nassertv(coords.size==norms.size); nassertv(coords.size==colors.size); nassertv(coords.size==texcoords.size); need to assert only if we have this w/same binding + // indexed mode requires all used norms,colors,texcoords,coords array be the same + // length, or 0 or 1 (dwStride==0), also requires all elements to use the same index array + } else if (!((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL))) + GeomVrtFmt=MixedFmtVerts; + } + + if(_bDrawPrimDoSetupVertexBuffer) { + GeomVrtFmt=MixedFmtVerts; + } +#endif + + // for Indexed Prims and mixed indexed/non-indexed prims, we will use old pipeline + // cant handle indexed prims because usually have different index arrays for different components, + // and DrIdxPrmStrd only accepts 1 index array for all components + if (GeomVrtFmt!=FlatVerts) { + + // this is the old geom setup, it reformats every vtx into an output array passed to d3d + _perVertex = 0x0; + _perPrim = _perComp = 0; + + switch (NormalBinding) { + case G_OFF: + break; + case G_PER_VERTEX: + _perVertex |= PER_NORMAL; + break; + case G_PER_PRIM: + _perPrim |= PER_NORMAL; + break; + case G_PER_COMPONENT: + _perComp |= PER_NORMAL; + break; + } + + 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; + } + + if (TexCoordBinding == G_PER_VERTEX) + _perVertex |= PER_TEXCOORD; + + size_t vertex_size = draw_prim_setup(geom); + + // iterate through the triangle primitives + + for (uint 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. + + int nVerts; + + if(pLengthArr!=NULL) { + nVerts = *(pLengthArr++); + } else { + // we've been called by draw_quad, which has no lengths array + nVerts=4; + } + +#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(_perVertex==TexCoordOnly) + draw_prim_inner_loop_coordtexonly(nVerts, geom); + else draw_prim_inner_loop(nVerts, geom, _perVertex); + } else { + if(trilisttype==D3DPT_TRIANGLESTRIP) { + // 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); + } + } + + if(!_bDrawPrimDoSetupVertexBuffer) { + hr = _d3dDevice->DrawPrimitive(trilisttype, _curFVFflags, _pFvfBufBasePtr, nVerts, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,nVerts,nVerts-2); + } else { + COPYVERTDATA_2_VERTEXBUFFER(trilisttype,nVerts); + } + + _pCurFvfBufPtr = NULL; + } + } else { + + // new geom setup that uses strided DP calls to avoid making an extra pass over the data + + D3DDRAWPRIMITIVESTRIDEDDATA dps_data; + memset(&dps_data,0,sizeof(D3DDRAWPRIMITIVESTRIDEDDATA)); + +#ifdef _DEBUG + nassertv(geom->uses_components()); + nassertv(geom->get_binding(G_COORD) == G_PER_VERTEX); +#endif + + DWORD fvf_flags = D3DFVF_XYZ; + dps_data.position.lpvData = (VOID*)coords; + dps_data.position.dwStride = sizeof(D3DVECTOR); + + D3DSHADEMODE NeededShadeMode = D3DSHADE_FLAT; + + DWORD cTotalVerts=0; + + for (uint i=0;iget_num_more_vertices_than_components()==2); + nassertv(NormalBinding!=G_PER_COMPONENT); // makes no sense, unimplementable for strips since normals always shared across tris + nassertv( cTotalVerts*sizeof(D3DVECTOR) <= D3DMAXNUMVERTICES*sizeof(WORD)); + if(NormalBinding==G_PER_VERTEX) + nassertv(norms.size()>=cTotalVerts); +#endif + fvf_flags |= D3DFVF_NORMAL; + NeededShadeMode = D3DSHADE_GOURAUD; + + Normalf *pExpandedNormalArray = (Normalf *)_index_buf; // BUGBUG: need to use real permanent buffers instead of _indexbuf hack + + if(NormalBinding==G_PER_PRIM) { + // we have 1 normal per strip + // must use tmp array to duplicate-expand per-prim norms to per-vert norms + Normalf *pOutVec = pExpandedNormalArray; + Normalf *pInVec=norms; + const uint *pLengths=pLengthArr; + + nassertv(norms.size()>=nPrims); + + for (uint i=0;iis_real()) + bDoColor=FALSE; // this turns off any Geom colors + else { + ColorBinding=G_OVERALL; + bDoGlobalSceneGraphColor=TRUE; + } + } + + if (bDoColor || bDoGlobalSceneGraphColor) { + D3DCOLOR *pOutColor,*pConvertedColorArray; + Colorf *pInColor=colors; + pOutColor = pConvertedColorArray = (D3DCOLOR *)_pFvfBufBasePtr; + +#ifdef _DEBUG + nassertv( cTotalVerts*sizeof(D3DCOLOR) <= VERT_BUFFER_SIZE); +#endif + + fvf_flags |= D3DFVF_DIFFUSE; + + dps_data.diffuse.lpvData = (VOID*)pConvertedColorArray; + dps_data.diffuse.dwStride = sizeof(D3DCOLOR); + + if (ColorBinding==G_PER_VERTEX) { + NeededShadeMode = D3DSHADE_GOURAUD; + + if(!_color_transform_required) { + for (uint i=0;i= cTotalVerts-nPrims*cNumMoreVertsthanTris); + + #define MULTITRI_COLORCOPY_LOOP \ + DWORD cCurStripColorCnt=pLengthArr[j]-cNumMoreVertsthanTris; \ + for (uint i=0;iget_color(); + *pConvertedColorArray = Colorf_to_D3DCOLOR(colr); + } else { + *pConvertedColorArray = Colorf_to_D3DCOLOR(*pInColor); + } + } else { + if (bDoGlobalSceneGraphColor) { + Colorf colr = catt->get_color(); + transform_color(colr,*pConvertedColorArray); + } else { + transform_color(*pInColor,*pConvertedColorArray); + } + } + + dps_data.diffuse.dwStride = 0; + } + } + + if ((TexCoordBinding != G_OFF) && _texturing_enabled) { + +#ifdef _DEBUG + nassertv(TexCoordBinding == G_PER_VERTEX); // only sensible choice for a tri +#endif + + dps_data.textureCoords[0].lpvData = (VOID*)texcoords; + dps_data.textureCoords[0].dwStride = sizeof(TexCoordf); + fvf_flags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); + } + + set_shademode(NeededShadeMode); + + for (uint j=0;jDrawPrimitiveStrided(trilisttype, fvf_flags, &dps_data, cCurNumStripVerts, NULL); + TestDrawPrimFailure(DrawPrimStrided,hr,_pDD,cCurNumStripVerts,cCurNumStripVerts-2); + + dps_data.position.lpvData = (VOID*)(((char*) dps_data.position.lpvData) + cCurNumStripVerts*dps_data.position.dwStride); + dps_data.diffuse.lpvData = (VOID*)(((char*) dps_data.diffuse.lpvData) + cCurNumStripVerts*dps_data.diffuse.dwStride); + dps_data.normal.lpvData = (VOID*)(((char*) dps_data.normal.lpvData) + cCurNumStripVerts*dps_data.normal.dwStride); + dps_data.textureCoords[0].lpvData = (VOID*)(((char*) dps_data.textureCoords[0].lpvData) + cCurNumStripVerts*dps_data.textureCoords[0].dwStride); + } + + nassertv(_pCurFvfBufPtr == NULL); + } +} + +//----------------------------------------------------------------------------- +// Name: GenerateSphere() +// Desc: Makes vertex and index data for ellipsoid w/scaling factors sx,sy,sz +// tries to match gluSphere behavior +//----------------------------------------------------------------------------- + +void DXGraphicsStateGuardian:: +GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize, + void *pIndexSpace,DWORD dwIndexSpaceByteSize, + D3DVECTOR *pCenter, float fRadius, + DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz, + DWORD *pNumVertices,DWORD *pNumIndices,DWORD fvfFlags,DWORD dwVertSize) { + + float x, y, z, rsintheta; + D3DVECTOR 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 DOTEXTURING (fvfFlags & D3DFVF_TEXCOUNT_MASK) +#define DONORMAL (fvfFlags & D3DFVF_NORMAL) +#define DOCOLOR (fvfFlags & D3DFVF_DIFFUSE) + + if (DOTEXTURING) { + // 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 = *pNumIndices = dwNumTriangles*3; + + D3DVERTEX* pvVertices = (D3DVERTEX*) pVertexSpace; + WORD *pwIndices = (WORD *) pIndexSpace; + + nassertv(dwNumVertices*dwVertSize < VERT_BUFFER_SIZE); + nassertv(dwNumIndices < D3DMAXNUMVERTICES ); + + // Generate vertex at the top point + D3DVECTOR vTopPoint = *pCenter + D3DVECTOR( 0.0f, +sy*fRadius, 0.0f); + D3DVECTOR vBotPoint = *pCenter + D3DVECTOR( 0.0f, -sy*fRadius, 0.0f); + D3DVECTOR vNormal = D3DVECTOR( 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), sizeof(D3DVECTOR)); \ + if(fvfFlags & D3DFVF_NORMAL) \ + add_to_FVFBuf((void *)&vNormal, sizeof(D3DVECTOR)); \ + 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 (! DOTEXTURING) { + 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 (DOTEXTURING) { + // 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 (DOTEXTURING) { + 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 = *pCenter + D3DVECTOR( sx*x, sy*y, sz*z ); + + add_to_FVFBuf((void *)&vPoint, sizeof(D3DVECTOR)); + + if (DONORMAL) { + // this is wrong normal for the non-spherical case (i think you need to multiply by 1/scale factor per component) + vNormal = Normalize(D3DVECTOR( x*inv_radius, y*inv_radius, z*inv_radius )); + add_to_FVFBuf((void *)&vNormal, sizeof(D3DVECTOR)); + } + + if (DOCOLOR) + add_DWORD_to_FVFBuf(_curD3Dcolor); + + if (DOTEXTURING) { + texCoords[0] = 1.0f - phi*reciprocal_2PI; + add_to_FVFBuf((void *)texCoords, sizeof(TexCoordf)); + } + + phi += dphi; + } + theta += dtheta; + } + + if (! DOTEXTURING) { + // Generate bottom vertex + vNormal = D3DVECTOR( 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 (! DOTEXTURING) { + // 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) { + dxgsg_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,nIndices; + 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, D3DMAXNUMVERTICES, + (D3DVECTOR *)¢er, fRadius, + SPHERE_NUMSTACKS, SPHERE_NUMSLICES, + 1.0f, 1.0f, 1.0f, // no scaling factors, do a sphere not ellipsoid + &nVerts,&nIndices,_curFVFflags,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 = _d3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, _curFVFflags, _pFvfBufBasePtr, nVerts, _index_buf,nIndices,NULL); + TestDrawPrimFailure(DrawIndexedPrim,hr,_pDD,nVerts,(nIndices>>2)); + } + + _pCurFvfBufPtr = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::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 *DXGraphicsStateGuardian:: +prepare_texture(Texture *tex) { + + DXTextureContext *gtc = new DXTextureContext(tex); +#ifdef WBD_GL_MODE + glGenTextures(1, >c->_index); + + bind_texture(gtc); + glPrioritizeTextures(1, >c->_index, >c->_priority); + specify_texture(tex); + apply_texture_immediate(tex); +#else + if (gtc->CreateTexture(_d3dDevice,_cNumTexPixFmts,_pTexPixFmts) == NULL) { + delete gtc; + return NULL; + } +#endif // WBD_GL_MODE + + bool inserted = mark_prepared_texture(gtc); + + // If this assertion fails, the same texture was prepared twice, + // which shouldn't be possible, since the texture itself should + // detect this. + nassertr(inserted, NULL); + + return gtc; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::apply_texture +// Access: Public, Virtual +// Description: Makes the texture the currently available texture for +// rendering. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +apply_texture(TextureContext *tc) { + if (tc==NULL) { + return; // use enable_texturing to disable/enable + } + #ifdef DO_PSTATS + add_to_texture_record(tc); + #endif + +// bind_texture(tc); + +// specify_texture(tc->_texture); + // Note: if this code changes, make sure to change initialization SetTSS code in dx_init as well + // so DX TSS renderstate matches dxgsg state + + DXTextureContext *dtc = DCAST(DXTextureContext, 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) { + dxgsg_cat.warning() + << "Texture " << *dtc->_texture << " has changed mipmap state.\n"; + } + + dtc->DeleteTexture(); + if (dtc->CreateTexture(_d3dDevice,_cNumTexPixFmts,_pTexPixFmts) == NULL) { + // Oops, we can't re-create the texture for some reason. + dxgsg_cat.error() + << "Unable to re-create texture " << *dtc->_texture << endl; + + release_texture(dtc); + enable_texturing(false); + return; + } + } + dtc->clear_dirty_flags(); + } else { + if(_pCurTexContext == dtc) { + return; // tex already set (and possible problem in state-sorting?) + } + } + + Texture *tex = tc->_texture; + Texture::WrapMode wrapU,wrapV; + wrapU=tex->get_wrapu(); + wrapV=tex->get_wrapv(); + + if (wrapU!=_CurTexWrapModeU) { + _d3dDevice->SetTextureStageState(0,D3DTSS_ADDRESSU,get_texture_wrap_mode(wrapU)); + _CurTexWrapModeU = wrapU; + } + if (wrapV!=_CurTexWrapModeV) { + _d3dDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,get_texture_wrap_mode(wrapV)); + _CurTexWrapModeV = wrapV; + } + +/* +#ifdef _DEBUG + Texture::WrapMode wrapval; + _d3dDevice->GetTextureStageState(0,D3DTSS_ADDRESSU,(DWORD*)&wrapval); + assert(get_texture_wrap_mode(wrapU) == wrapval); + _d3dDevice->GetTextureStageState(0,D3DTSS_ADDRESSV,(DWORD*)&wrapval); + assert(get_texture_wrap_mode(wrapV) == wrapval); +#endif +*/ + + uint aniso_degree=tex->get_anisotropic_degree(); + Texture::FilterType ft=tex->get_magfilter(); + + if (aniso_degree<=1) { + if (_CurTexMagFilter!=ft) { + + _CurTexMagFilter = ft; + _d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER,(ft==Texture::FT_nearest)? D3DTFG_POINT : D3DTFG_LINEAR); +#ifdef _DEBUG + if((ft!=Texture::FT_linear)&&(ft!=Texture::FT_nearest)) { + dxgsg_cat.error() << "MipMap filter type setting for texture magfilter makes no sense, texture: " << tex->get_name() << "\n"; + } +#endif + } + } else { + if (aniso_degree!=_CurTexAnisoDegree) { + _CurTexAnisoDegree = aniso_degree; + _d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_ANISOTROPIC ); + _d3dDevice->SetTextureStageState(0, D3DTSS_MAXANISOTROPY,aniso_degree); + } + } + +#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, }; +*/ + static D3DTEXTUREMINFILTER PandaToD3DMinType[8] = + {D3DTFN_POINT,D3DTFN_LINEAR,D3DTFN_POINT,D3DTFN_LINEAR,D3DTFN_POINT,D3DTFN_LINEAR}; + static D3DTEXTUREMIPFILTER PandaToD3DMipType[8] = + {D3DTFP_NONE,D3DTFP_NONE,D3DTFP_POINT,D3DTFP_POINT,D3DTFP_LINEAR,D3DTFP_LINEAR}; + + ft=tex->get_minfilter(); + + if ((ft!=_CurTexMinFilter)||(aniso_degree!=_CurTexAnisoDegree)) { + +#ifdef _DEBUG + if(ft > Texture::FT_linear_mipmap_linear) { + dxgsg_cat.error() << "Unknown tex filter type for tex: " << tex->get_name() << " filter: "<<(DWORD)ft<<"\n"; + return; + } +#endif + + D3DTEXTUREMINFILTER minfilter = PandaToD3DMinType[(DWORD)ft]; + D3DTEXTUREMIPFILTER mipfilter = PandaToD3DMipType[(DWORD)ft]; + + #ifndef NDEBUG + extern char *PandaFilterNameStrs[]; + if((!(dtc->_bHasMipMaps))&&(mipfilter!=D3DTFP_NONE)) { + dxgsg_cat.error() << "Trying to set mipmap filtering for texture with no generated mipmaps!! texname[" << tex->get_name() << "], filter("<1) { + minfilter=D3DTFN_ANISOTROPIC; + } + + _d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, minfilter); + _d3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, mipfilter); + + _CurTexMinFilter = ft; + _CurTexAnisoDegree = aniso_degree; + } + + // bugbug: does this handle the case of untextured geometry? + // we dont see this bug cause we never mix textured/untextured + + _d3dDevice->SetTexture(0,dtc->_surface); + +#if 0 + if (dtc!=NULL) { + dxgsg_cat.spam() << "Setting active DX texture: " << dtc->_tex->get_name() << "\n"; + } +#endif + + _pCurTexContext = dtc; // enable_texturing needs this +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::release_texture +// Access: Public, Virtual +// Description: Frees the GL resources previously allocated for the +// texture. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +release_texture(TextureContext *tc) { + DXTextureContext *gtc = DCAST(DXTextureContext, tc); + Texture *tex = tc->_texture; + + gtc->DeleteTexture(); + bool erased = unmark_prepared_texture(gtc); + + // If this assertion fails, a texture was released that hadn't been + // prepared (or a texture was released twice). + nassertv(erased); + + tex->clear_gsg(this); + + delete gtc; +} + +#if 1 + +void DXGraphicsStateGuardian:: +copy_texture(TextureContext *tc, const DisplayRegion *dr) { + dxgsg_cat.fatal() << "DX copy_texture unimplemented!!!"; +} + +#else +static int logs[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, + 4096, 0}; + +// This function returns the smallest power of two greater than or +// equal to x. +static int binary_log_cap(const int x) { + int i = 0; + for (; (x > logs[i]) && (logs[i] != 0); ++i); + if (logs[i] == 0) + return 4096; + return logs[i]; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::copy_texture +// Access: Public, Virtual +// Description: Copy the pixel region indicated by the display +// region from the framebuffer into texture memory +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +copy_texture(TextureContext *tc, const DisplayRegion *dr) { + + nassertv(tc != NULL && dr != NULL); + + Texture *tex = tc->_texture; + + // Determine the size of the grab from the given display region + // If the requested region is not a power of two, grab a region that is + // a power of two that contains the requested region + int xo, yo, req_w, req_h; + dr->get_region_pixels(xo, yo, req_w, req_h); + int w = binary_log_cap(req_w); + int h = binary_log_cap(req_h); + if (w != req_w || h != req_h) { + tex->_requested_w = req_w; + tex->_requested_h = req_h; + tex->_has_requested_size = true; + } + + PixelBuffer *pb = tex->_pbuffer; + + pb->set_xorg(xo); + pb->set_yorg(yo); + pb->set_xsize(w); + pb->set_ysize(h); + + + bind_texture(tc); + glCopyTexImage2D( GL_TEXTURE_2D, tex->get_level(), + get_internal_image_format(pb->get_format()), + pb->get_xorg(), pb->get_yorg(), + pb->get_xsize(), pb->get_ysize(), pb->get_border() ); +} +#endif + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::copy_texture +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +copy_texture(TextureContext *tc, const DisplayRegion *dr, const RenderBuffer &rb) { + dxgsg_cat.fatal() << "DX copy_texture unimplemented!!!"; + return; + + set_read_buffer(rb); + copy_texture(tc, dr); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_texture +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_texture(TextureContext *tc, const DisplayRegion *dr) { + + dxgsg_cat.fatal() << "DXGSG draw_texture unimplemented!!!"; + return; + + nassertv(tc != NULL && dr != NULL); + +#ifdef WBD_GL_MODE + Texture *tex = tc->_texture; + + DisplayRegionStack old_dr = push_display_region(dr); + prepare_display_region(); + + NodeTransitions state; + CullFaceTransition *cfa = new CullFaceTransition(CullFaceProperty::M_cull_none); + DepthTestTransition *dta = new DepthTestTransition(DepthTestProperty::M_none); + DepthWriteTransition *dwa = new DepthWriteTransition(DepthWriteTransition::off()); + TextureTransition *ta = new TextureTransition(tex); + TextureApplyTransition *taa = new TextureApplyTransition(TextureApplyProperty::M_decal); + + state.set_transition(new LightTransition); + state.set_transition(new ColorMaskTransition); + state.set_transition(new RenderModeTransition); + state.set_transition(new TexMatrixTransition); + state.set_transition(new TransformTransition); + state.set_transition(new ColorBlendTransition); + state.set_transition(cfa); + state.set_transition(dta); + state.set_transition(dwa); + state.set_transition(ta); + state.set_transition(taa); + modify_state(state); + + // We set up an orthographic projection that defines our entire + // viewport to the range [0..1] in both dimensions. Then, when we + // create a unit square polygon below, it will exactly fill the + // viewport (and thus exactly fill the display region). + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0, 1, 0, 1); + + float txl, txr, tyt, tyb; + txl = tyb = 0.; + if (tex->_has_requested_size) { + txr = ((float)(tex->_requested_w)) / ((float)(tex->_pbuffer->get_xsize())); + tyt = ((float)(tex->_requested_h)) / ((float)(tex->_pbuffer->get_ysize())); + } else { + txr = tyt = 1.; + } + + // This two-triangle strip is actually a quad. But it's usually + // better to render quads as tristrips anyway. + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(txl, tyb); glVertex2i(0, 0); + glTexCoord2f(txr, tyb); glVertex2i(1, 0); + glTexCoord2f(txl, tyt); glVertex2i(0, 1); + glTexCoord2f(txr, tyt); glVertex2i(1, 1); + glEnd(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + pop_display_region(old_dr); +#endif // WBD_GL_MODE + +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_texture +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_texture(TextureContext *tc, const DisplayRegion *dr, const RenderBuffer &rb) { + dxgsg_cat.fatal() << "DXGSG draw_texture unimplemented!!!"; + return; + + set_draw_buffer(rb); + draw_texture(tc, dr); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::texture_to_pixel_buffer +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb) { + nassertv(tc != NULL && pb != NULL); + + Texture *tex = tc->_texture; + + int w = tex->_pbuffer->get_xsize(); + int h = tex->_pbuffer->get_ysize(); + + PT(DisplayRegion) dr = _win->make_scratch_display_region(w, h); + + FrameBufferStack old_fb = push_frame_buffer + (get_render_buffer(RenderBuffer::T_back | RenderBuffer::T_depth), + dr); + + texture_to_pixel_buffer(tc, pb, dr); + + pop_frame_buffer(old_fb); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::texture_to_pixel_buffer +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb, + const DisplayRegion *dr) { + nassertv(tc != NULL && pb != NULL && dr != NULL); + + Texture *tex = tc->_texture; + + // Do a deep copy to initialize the pixel buffer + pb->copy(tex->_pbuffer); + + // If the image was empty, we need to render the texture into the frame + // buffer and then copy the results into the pixel buffer's image + if (pb->_image.empty()) { + int w = pb->get_xsize(); + int h = pb->get_ysize(); + draw_texture(tc, dr); + pb->_image = PTA_uchar::empty_array(w * h * pb->get_num_components()); + copy_pixel_buffer(pb, dr); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::copy_pixel_buffer +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) { + + extern HRESULT ConvertDDSurftoPixBuf(PixelBuffer *pixbuf,LPDIRECTDRAWSURFACE7 pDDSurf); + + nassertv(pb != NULL && dr != NULL); + + int xo, yo, w, h; + dr->get_region_pixels(xo, yo, w, h); + + // only handled simple case + nassertv(xo==0); + nassertv(yo==0); + nassertv(w==pb->get_xsize()); + nassertv(h==pb->get_ysize()); + +/* + set_pack_alignment(1); + glReadPixels( pb->get_xorg() + xo, pb->get_yorg() + yo, + pb->get_xsize(), pb->get_ysize(), + get_external_image_format(pb->get_format()), + get_image_type(pb->get_image_type()), + pb->_image.p() ); +*/ + + + (void) ConvertDDSurftoPixBuf(pb,((_cur_read_pixel_buffer & RenderBuffer::T_back) ? _back : _pri)); + + nassertv(!pb->_image.empty()); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::copy_pixel_buffer +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr, + const RenderBuffer &rb) { + set_read_buffer(rb); + copy_pixel_buffer(pb, dr); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_pixel_buffer +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr, + const NodeTransitions& na) { + + dxgsg_cat.fatal() << "DXGSG draw_pixel_buffer unimplemented!!!"; + return; + +#ifdef WBD_GL_MODE + nassertv(pb != NULL && dr != NULL); + nassertv(!pb->_image.empty()); + + DisplayRegionStack old_dr = push_display_region(dr); + prepare_display_region(); + + NodeTransitions state(na); + state.set_transition(new LightTransition); + state.set_transition(new TextureTransition); + state.set_transition(new TransformTransition); + state.set_transition(new ColorBlendTransition); + state.set_transition(new StencilTransition); + + + switch (pb->get_format()) { + case PixelBuffer::F_depth_component: + { + ColorMaskTransition *cma = new ColorMaskTransition(0); + DepthTestTransition *dta = new DepthTestTransition(DepthTestProperty::M_always); + DepthWriteTransition *dwa = new DepthWriteTransition(DepthWriteTransition::off()); + state.set_transition(cma); + state.set_transition(dta); + state.set_transition(dwa); + } + break; + + case PixelBuffer::F_rgb: + case PixelBuffer::F_rgb5: + case PixelBuffer::F_rgb8: + case PixelBuffer::F_rgb12: + case PixelBuffer::F_rgba: + case PixelBuffer::F_rgba4: + case PixelBuffer::F_rgba8: + case PixelBuffer::F_rgba12: + { + ColorMaskTransition *cma = new ColorMaskTransition; + DepthTestTransition *dta = new DepthTestTransition(DepthTestProperty::M_none); + DepthWriteTransition *dwa = new DepthWriteTransition(DepthWriteTransition::off()); + state.set_transition(cma); + state.set_transition(dta); + state.set_transition(dwa); + } + break; + default: + dxgsg_cat.error() + << "draw_pixel_buffer(): unknown buffer format" << endl; + break; + } + + modify_state(state); + + enable_color_material(false); + set_unpack_alignment(1); + + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0, _win->get_width(), + 0, _win->get_height()); + +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "glDrawPixels(" << pb->get_xsize() << ", " << pb->get_ysize() + << ", "; + switch (get_external_image_format(pb->get_format())) { + case GL_DEPTH_COMPONENT: + dxgsg_cat.debug(false) << "GL_DEPTH_COMPONENT, "; + break; + case GL_RGB: + dxgsg_cat.debug(false) << "GL_RGB, "; + break; + case GL_RGBA: + dxgsg_cat.debug(false) << "GL_RGBA, "; + break; + default: + dxgsg_cat.debug(false) << "unknown, "; + break; + } + switch (get_image_type(pb->get_image_type())) { + case GL_UNSIGNED_BYTE: + dxgsg_cat.debug(false) << "GL_UNSIGNED_BYTE, "; + break; + case GL_float: + dxgsg_cat.debug(false) << "GL_float, "; + break; + default: + dxgsg_cat.debug(false) << "unknown, "; + break; + } + dxgsg_cat.debug(false) + << (void *)pb->_image.p() << ")" << endl; +#endif + + glRasterPos2i( pb->get_xorg(), pb->get_yorg() ); + glDrawPixels( pb->get_xsize(), pb->get_ysize(), + get_external_image_format(pb->get_format()), + get_image_type(pb->get_image_type()), + pb->_image.p() ); + + glMatrixMode( GL_PROJECTION ); + glPopMatrix(); + + pop_display_region(old_dr); +#endif // WBD_GL_MODE +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_pixel_buffer +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr, + const RenderBuffer &rb, const NodeTransitions& na) { + set_read_buffer(rb); + draw_pixel_buffer(pb, dr, na); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::apply_material +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::apply_material( const Material* material ) { + D3DMATERIAL7 cur_material; + cur_material.dcvDiffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data()); + cur_material.dcvAmbient = *(D3DCOLORVALUE *)(material->get_ambient().get_data()); + cur_material.dcvSpecular = *(D3DCOLORVALUE *)(material->get_specular().get_data()); + cur_material.dcvEmissive = *(D3DCOLORVALUE *)(material->get_emission().get_data()); + cur_material.dvPower = material->get_shininess(); + _d3dDevice->SetMaterial(&cur_material); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::apply_fog +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +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 + _d3dDevice->SetRenderState((D3DRENDERSTATETYPE)_doFogType, d3dfogmode); + + const Colorf &fog_colr = fog->get_color(); + _d3dDevice->SetRenderState(D3DRENDERSTATE_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: + { + // Linear fog may be world-relative or + // camera-relative. The fog object knows how to + // decode its parameters into camera-relative + // properties. + float fog_start, fog_end; + fog->compute_linear_range(fog_start, fog_end, + _current_projection_node, + _coordinate_system); + + _d3dDevice->SetRenderState( D3DRENDERSTATE_FOGSTART, + *((LPDWORD) (&fog_start)) ); + _d3dDevice->SetRenderState( D3DRENDERSTATE_FOGEND, + *((LPDWORD) (&fog_end)) ); + } + break; + case Fog::M_exponential: + case Fog::M_exponential_squared: + { + // Exponential fog is always camera-relative. + float fog_density = fog->get_exp_density(); + _d3dDevice->SetRenderState( D3DRENDERSTATE_FOGDENSITY, + *((LPDWORD) (&fog_density)) ); + } + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::apply_light +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::apply_light( PointLight* light ) { + // The light position will be relative to the current matrix, so + // we have to know what the current matrix is. Find a better + // solution later. + D3DCOLORVALUE black; + black.r = black.g = black.b = black.a = 0.0f; + D3DLIGHT7 alight; + alight.dltType = D3DLIGHT_POINT; + alight.dcvDiffuse = *(D3DCOLORVALUE *)(light->get_color().get_data()); + alight.dcvAmbient = black ; + alight.dcvSpecular = *(D3DCOLORVALUE *)(light->get_specular().get_data()); + + // Position needs to specify x, y, z, and w + // w == 1 implies non-infinite position + alight.dvPosition = *(D3DVECTOR *)(get_rel_pos( light, _current_root_node ).get_data()); + + alight.dvRange = D3DLIGHT_RANGE_MAX; + alight.dvFalloff = 1.0f; + + alight.dvAttenuation0 = (D3DVALUE)light->get_constant_attenuation(); + alight.dvAttenuation1 = (D3DVALUE)light->get_linear_attenuation(); + alight.dvAttenuation2 = (D3DVALUE)light->get_quadratic_attenuation(); + + HRESULT res = _d3dDevice->SetLight(_cur_light_id, &alight); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::apply_light +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::apply_light( DirectionalLight* light ) { + // The light position will be relative to the current matrix, so + // we have to know what the current matrix is. Find a better + // solution later. + D3DCOLORVALUE black; + black.r = black.g = black.b = black.a = 0.0f; + + D3DLIGHT7 alight; + ZeroMemory(&alight, sizeof(D3DLIGHT7)); + + alight.dltType = D3DLIGHT_DIRECTIONAL; + alight.dcvDiffuse = *(D3DCOLORVALUE *)(light->get_color().get_data()); + alight.dcvAmbient = black ; + alight.dcvSpecular = *(D3DCOLORVALUE *)(light->get_specular().get_data()); + + alight.dvDirection = *(D3DVECTOR *) + (get_rel_forward( light, _current_projection_node, CS_yup_left).get_data()); + + alight.dvRange = D3DLIGHT_RANGE_MAX; + alight.dvFalloff = 1.0f; + + alight.dvAttenuation0 = 1.0f; // constant + alight.dvAttenuation1 = 0.0f; // linear + alight.dvAttenuation2 = 0.0f; // quadratic + + HRESULT res = _d3dDevice->SetLight(_cur_light_id, &alight); +// _d3dDevice->LightEnable( _cur_light_id, TRUE ); +// _d3dDevice->SetRenderState( D3DRENDERSTATE_LIGHTING, TRUE ); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::apply_light +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::apply_light( Spotlight* light ) { + // The light position will be relative to the current matrix, so + // we have to know what the current matrix is. Find a better + // solution later. +#ifdef WBD_GL_MODE +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "glMatrixMode(GL_MODELVIEW)" << endl; + dxgsg_cat.debug() + << "glPushMatrix()" << endl; + dxgsg_cat.debug() + << "glLoadIdentity()" << endl; +#endif + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf(LMatrix4f::convert_mat(_coordinate_system, CS_yup_left) + .get_data()); + + GLenum id = get_light_id( _cur_light_id ); + Colorf black(0, 0, 0, 1); + glLightfv(id, GL_AMBIENT, black.get_data()); + glLightfv(id, GL_DIFFUSE, light->get_color().get_data()); + glLightfv(id, GL_SPECULAR, light->get_specular().get_data()); + + // Position needs to specify x, y, z, and w + // w == 1 implies non-infinite position + LPoint3f pos = get_rel_pos( light, _current_projection_node ); + LPoint4f fpos( pos[0], pos[1], pos[2], 1 ); + glLightfv( id, GL_POSITION, fpos.get_data() ); + + glLightfv( id, GL_SPOT_DIRECTION, + get_rel_forward( light, _current_projection_node, + _coordinate_system ).get_data() ); + glLightf( id, GL_SPOT_EXPONENT, light->get_exponent() ); + glLightf( id, GL_SPOT_CUTOFF, + light->get_cutoff_angle() ); + glLightf( id, GL_CONSTANT_ATTENUATION, + light->get_constant_attenuation() ); + glLightf( id, GL_LINEAR_ATTENUATION, + light->get_linear_attenuation() ); + glLightf( id, GL_QUADRATIC_ATTENUATION, + light->get_quadratic_attenuation() ); + + glPopMatrix(); +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "glPopMatrix()" << endl; +#endif +#else // DX Spotlight + D3DCOLORVALUE black; + black.r = black.g = black.b = black.a = 0.0f; + + D3DLIGHT7 alight; + ZeroMemory(&alight, sizeof(D3DLIGHT7)); + + alight.dltType = D3DLIGHT_SPOT; + alight.dcvAmbient = black ; + alight.dcvDiffuse = *(D3DCOLORVALUE *)(light->get_color().get_data()); + alight.dcvSpecular = *(D3DCOLORVALUE *)(light->get_specular().get_data()); + + alight.dvPosition = *(D3DVECTOR *) + (get_rel_pos( light, _current_root_node ).get_data()); + + alight.dvDirection = *(D3DVECTOR *) + (get_rel_forward( light, _current_root_node, _coordinate_system).get_data()); + + alight.dvRange = D3DLIGHT_RANGE_MAX; + alight.dvFalloff = 1.0f; + alight.dvTheta = 0.0f; + alight.dvPhi = light->get_cutoff_angle(); + + alight.dvAttenuation0 = (D3DVALUE)light->get_constant_attenuation(); // constant + alight.dvAttenuation1 = (D3DVALUE)light->get_linear_attenuation(); // linear + alight.dvAttenuation2 = (D3DVALUE)light->get_quadratic_attenuation();// quadratic + + HRESULT res = _d3dDevice->SetLight(_cur_light_id, &alight); + +#endif // WBD_GL_MODE +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::apply_light +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::apply_light( AmbientLight* light ) { + _cur_ambient_light = _cur_ambient_light + light->get_color(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_transform +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_transform(const TransformTransition *attrib) { +#ifndef NDEBUG + if (dx_show_transforms) { + + bool lighting_was_enabled = _lighting_enabled; + bool texturing_was_enabled = _texturing_enabled; + enable_lighting(false); + enable_texturing(false); + + typedef struct { + D3DVALUE x,y,z; // position + D3DVALUE nx,ny,nz; // normal + D3DCOLOR diff; // diffuse color + } VERTFORMAT; + + VERTFORMAT vert_buf[] = { + {0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, MY_D3DRGBA(1.0f, 0.0f, 0.0f, 1.0f)}, // red + {3.0, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, MY_D3DRGBA(1.0f, 0.0f, 0.0f, 1.0f)}, // red + {0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, MY_D3DRGBA(0.0f, 1.0f, 0.0f, 1.0f)}, // grn + {0.0f, 3.0, 0.0f, 0.0f, -1.0f, 0.0f, MY_D3DRGBA(0.0f, 1.0f, 0.0f, 1.0f)}, // grn + {0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, MY_D3DRGBA(0.0f, 0.0f, 1.0f, 1.0f)}, // blu + {0.0f, 0.0f, 3.0, 0.0f, -1.0f, 0.0f, MY_D3DRGBA(0.0f, 0.0f, 1.0f, 1.0f)}, // blu + }; + + HRESULT hr = _d3dDevice->DrawPrimitive(D3DPT_LINELIST, D3DFVF_DIFFUSE | D3DFVF_XYZ | D3DFVF_NORMAL, + vert_buf, 6, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,6,0); + + enable_lighting(lighting_was_enabled); + enable_texturing(texturing_was_enabled); + } +#endif + + _d3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD/*VIEW*/, + (LPD3DMATRIX) attrib->get_matrix().get_data()); + _bTransformIssued = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_matrix +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_tex_matrix(const TexMatrixTransition *attrib) { + dxgsg_cat.fatal() << "DXGSG issue_tex_matrix unimplemented!!!"; + return; + +#ifdef WBD_GL_MODE +#ifdef GSG_VERBOSE + dxgsg_cat.debug() + << "glLoadMatrix(GL_TEXTURE): " << attrib->get_matrix() << endl; +#endif + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(attrib->get_matrix().get_data()); +#else + _d3dDevice->SetTransform( D3DTRANSFORMSTATE_TEXTURE0, + (LPD3DMATRIX)attrib->get_matrix().get_data()); +#endif // WBD_GL_MODE +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_color +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_color(const ColorTransition *attrib) { + + bool bAttribOn=attrib->is_on(); + bool bIsReal = (bAttribOn ? attrib->is_real() : false); + + _issued_color_enabled = bAttribOn; + + // if an active unreal color is set, disable all color + _enable_all_color = !(bAttribOn && (!bIsReal)); + + if(bAttribOn && bIsReal) { + _issued_color = attrib->get_color(); + if(_color_transform_required) { + transform_color(_issued_color, _issued_color_D3DCOLOR); + } else { + _issued_color_D3DCOLOR = Colorf_to_D3DCOLOR(_issued_color); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_color_transform +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_color_transform(const ColorMatrixTransition *attrib) { + _current_color_mat = attrib->get_matrix(); + + // couldnt we compare a single ptr instead of doing full comparison? + // bugbug: the ColorMatrixTransition needs to be an On/Off transition + // so we dont have to do this comparison + if (_current_color_mat == LMatrix4f::ident_mat()) { + _color_transform_enabled = false; + if(_issued_color_enabled) { + _issued_color_D3DCOLOR = Colorf_to_D3DCOLOR(_issued_color); + } + } else { + _color_transform_enabled = true; + if(_issued_color_enabled) { + transform_color(_issued_color, _issued_color_D3DCOLOR); + } + } + _color_transform_required = _color_transform_enabled || _alpha_transform_enabled; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_alpha_transform +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_alpha_transform(const AlphaTransformTransition *attrib) { + _current_alpha_offset = attrib->get_offset(); + _current_alpha_scale = attrib->get_scale(); + + if ((_current_alpha_offset == 0.0f) && (_current_alpha_scale == 1.0f)) { + _alpha_transform_enabled = false; + if(_issued_color_enabled) { + _issued_color_D3DCOLOR = Colorf_to_D3DCOLOR(_issued_color); + } + } else { + _alpha_transform_enabled = true; + if(_issued_color_enabled) { + transform_color(_issued_color, _issued_color_D3DCOLOR); + } + } + _color_transform_required = _color_transform_enabled || _alpha_transform_enabled; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_texture +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_texture(const TextureTransition *attrib) { + if (attrib->is_on()) { + enable_texturing(true); + Texture *tex = attrib->get_texture(); + nassertv(tex != (Texture *)NULL); + tex->apply(this); + } else { + enable_texturing(false); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_tex_gen +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_tex_gen(const TexGenTransition *attrib) { + dxgsg_cat.fatal() << "DXGSG issue_tex_gen unimplemented!!!"; + return; +#ifdef WBD_GL_MODE + TexGenProperty::Mode mode = attrib->get_mode(); + + switch (mode) { + case TexGenProperty::M_none: + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_Q); + glDisable(GL_TEXTURE_GEN_R); + break; + + case TexGenProperty::M_texture_projector: + { + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glEnable(GL_TEXTURE_GEN_Q); + glEnable(GL_TEXTURE_GEN_R); + const LMatrix4f &plane = attrib->get_plane(); + glTexGenfv(GL_S, GL_OBJECT_PLANE, plane.get_row(0).get_data()); + glTexGenfv(GL_T, GL_OBJECT_PLANE, plane.get_row(1).get_data()); + glTexGenfv(GL_R, GL_OBJECT_PLANE, plane.get_row(2).get_data()); + glTexGenfv(GL_Q, GL_OBJECT_PLANE, plane.get_row(3).get_data()); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + } + break; + + case TexGenProperty::M_sphere_map: + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_Q); + glDisable(GL_TEXTURE_GEN_R); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + break; + + default: + dxgsg_cat.error() + << "Unknown texgen mode " << (int)mode << endl; + break; + } +#endif // WBD_GL_MODE +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_material +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_material(const MaterialTransition *attrib) { + if (attrib->is_on()) { + const Material *material = attrib->get_material(); + nassertv(material != (const Material *)NULL); + apply_material(material); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_fog +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_fog(const FogTransition *attrib) { + + if (attrib->is_on()) { + enable_fog(true); + Fog *fog = attrib->get_fog(); + nassertv(fog != (Fog *)NULL); + fog->apply(this); + } else { + enable_fog(false); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_render_mode +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_render_mode(const RenderModeTransition *attrib) { + + RenderModeProperty::Mode mode = attrib->get_mode(); + + if(mode==_current_fill_mode) + return; + + switch (mode) { + case RenderModeProperty::M_filled: + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); + break; + + case RenderModeProperty::M_wireframe: + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_WIREFRAME); + break; + + default: + dxgsg_cat.error() + << "Unknown render mode " << (int)mode << endl; + } + + _current_fill_mode = mode; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_light +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::issue_light(const LightTransition *attrib ) { + nassertv(attrib->get_default_dir() != TD_on); + + // Initialize the current ambient light total and currently enabled + // light list + _cur_ambient_light.set(0.0f, 0.0f, 0.0f, 1.0f); + int i; + for (i = 0; i < _max_lights; i++) + _cur_light_enabled[i] = false; + + int num_enabled = 0; + LightTransition::const_iterator li; + for (li = attrib->begin(); li != attrib->end(); ++li) { + Light *light = (*li).first; + nassertv(light != (Light *)NULL); + TransitionDirection dir = (*li).second; + + if (dir == TD_on) { + num_enabled++; + enable_lighting(true); + + _cur_light_id = -1; + + // Ambient lights don't require specific light ids + // Simply add in the ambient contribution to the current total + if (light->get_light_type() == AmbientLight::get_class_type()) { + light->apply(this); + // We need to indicate that no light id is necessary because + // it's an ambient light + _cur_light_id = -2; + } + + // Check to see if this light has already been bound to an id + for (i = 0; i < _max_lights; i++) { + if (_available_light_ids[i] == light) { + // Light has already been bound to an id, we only need + // to enable the light, not apply it + _cur_light_id = -2; + if (enable_light(i, true)) _cur_light_enabled[i] = true; + break; + } + } + + // See if there are any unbound light ids + if (_cur_light_id == -1) { + for (i = 0; i < _max_lights; i++) { + if (_available_light_ids[i] == NULL) { + _available_light_ids[i] = light; + _cur_light_id = i; + break; + } + } + } + + // If there were no unbound light ids, see if we can replace + // a currently unused but previously bound id + if (_cur_light_id == -1) { + for (i = 0; i < _max_lights; i++) { + if (attrib->is_off(_available_light_ids[i])) { + _available_light_ids[i] = light; + _cur_light_id = i; + break; + } + } + } + + if (_cur_light_id >= 0) { + if (enable_light(_cur_light_id, true)) _cur_light_enabled[_cur_light_id] = true; + + // We need to do something different for each type of light + light->apply(this); + } else if (_cur_light_id == -1) { + dxgsg_cat.error() + << "issue_light() - failed to bind light to id" << endl; + } + } + } + + // Disable all unused lights + for (i = 0; i < _max_lights; i++) { + if (!_cur_light_enabled[i]) + enable_light(i, false); + } + + // If no lights were enabled, disable lighting + if (num_enabled == 0) { + enable_lighting(false); + enable_color_material(false); + } else { + call_dxLightModelAmbient(_cur_ambient_light); + enable_color_material(true); + } +} + +/* +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::reset_ambient +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +reset_ambient() { + _lmodel_ambient += 2.0f; +} +*/ + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_color_blend // +// Access: Public, Virtual // +// Description: // +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_color_blend(const ColorBlendTransition *attrib) { + + ColorBlendProperty::Mode mode = attrib->get_mode(); + + switch (mode) { + case ColorBlendProperty::M_none: + enable_blend(false); + break; + case ColorBlendProperty::M_multiply: + enable_blend(true); + call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ZERO); + break; + case ColorBlendProperty::M_add: + enable_blend(true); + call_dxBlendFunc(D3DBLEND_ONE, D3DBLEND_ONE); + break; + case ColorBlendProperty::M_multiply_add: + enable_blend(true); + call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ONE); + break; + case ColorBlendProperty::M_alpha: + enable_blend(true); + call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + break; + default: + dxgsg_cat.error() + << "Unknown color blend mode " << (int)mode << endl; + break; + } +} + +void DXGraphicsStateGuardian::SetTextureBlendMode(TextureApplyProperty::Mode TexBlendMode,bool bCanJustEnable) { + +/*class TextureApplyProperty { + enum Mode { + M_modulate,M_decal,M_blend,M_replace,M_add}; +*/ + static D3DTEXTUREOP TexBlendColorOp1[/* TextureApplyProperty::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 + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] ); + return; + } + + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] ); + + switch (TexBlendMode) { + + case TextureApplyProperty::M_modulate: + // emulates GL_MODULATE glTexEnv mode + // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv) + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + + break; + case TextureApplyProperty::M_decal: + // emulates GL_DECAL glTexEnv mode + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + + break; + case TextureApplyProperty::M_replace: + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + break; + case TextureApplyProperty::M_add: + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + + // since I'm making up 'add' mode, use modulate. "adding" alpha never makes sense right? + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + + break; + case TextureApplyProperty::M_blend: + dxgsg_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 + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + + need to SetTexture(1,tex) also + _d3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); wrong + _d3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + _d3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR ); + + _d3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + _d3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT ); +*/ + + + break; + default: + dxgsg_cat.error() << "Unknown texture blend mode " << (int) TexBlendMode << endl; + break; + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::enable_texturing +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DXGraphicsStateGuardian:: +enable_texturing(bool val) { +// if (_texturing_enabled == val) { // this check is mostly for internal gsg calls, panda already screens out redundant state changes +// return; +// } + + _texturing_enabled = val; + +// assert(_pCurTexContext!=NULL); we're definitely called with it NULL for both true and false +// I'm going to allow enabling texturing even if no tex has been set yet, seems to cause no probs + + if (val == FALSE) { + _d3dDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE); + } else { + SetTextureBlendMode(_CurTexBlendMode,TRUE); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_texture_apply +// Access: Public, Virtual +// Description: handles texture transition (i.e. filter modes, etc) changes +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_texture_apply(const TextureApplyTransition *attrib) { + + _CurTexBlendMode = attrib->get_mode(); + + if (!_texturing_enabled) { + return; + } + + SetTextureBlendMode(_CurTexBlendMode,FALSE); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_color_mask +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_color_mask(const ColorMaskTransition *attrib) { + dxgsg_cat.fatal() << "DXGSG issue_color_mask unimplemented (not implementable on DX7, need DX8)!!!"; + // because PLANEMASK renderstate has inconsistent to poor driver support on dx6 and before, and is + // explicitly disabled on dx7 + return; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_depth_test +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_depth_test(const DepthTestTransition *attrib) { + + + DepthTestProperty::Mode mode = attrib->get_mode(); + + if (mode == DepthTestProperty::M_none) { + _depth_test_enabled = false; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); + } else { + _depth_test_enabled = true; + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_TRUE); + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, get_depth_func_type(mode)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_stencil +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_stencil(const StencilTransition *attrib) { + + StencilProperty::Mode mode = attrib->get_mode(); + + if (mode == StencilProperty::M_none) { + enable_stencil_test(false); + } else { + enable_stencil_test(true); + D3DSTENCILOP pass_op = get_stencil_action_type(attrib->get_pass_action()); + D3DSTENCILOP fail_op = get_stencil_action_type(attrib->get_fail_action()); + D3DSTENCILOP zfail_op = get_stencil_action_type(attrib->get_zfail_action()); + + #ifdef _DEBUG + if(!(_D3DDevDesc.dwStencilCaps & (1<<(pass_op-1)))) { + dxgsg_cat.warning() << "driver doesnt support pass stencil operation: " << pass_op << endl; + } + if(!(_D3DDevDesc.dwStencilCaps & (1<<(fail_op-1)))) { + dxgsg_cat.warning() << "driver doesnt support fail stencil operation: " << fail_op << endl; + } + if(!(_D3DDevDesc.dwStencilCaps & (1<<(zfail_op-1)))) { + dxgsg_cat.warning() << "driver doesnt support zfail stencil operation: " << zfail_op << endl; + } + #endif + // TODO: need to cache all these + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILFUNC, get_stencil_func_type(mode)); + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILPASS, pass_op); + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILFAIL, fail_op); + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILZFAIL, zfail_op); + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILREF, attrib->get_reference_value()); + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILMASK, attrib->get_func_mask()); + _d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILWRITEMASK, attrib->get_write_mask()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_cull_transition +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_cull_face(const CullFaceTransition *attrib) { + +#ifndef NDEBUG + if(dx_force_backface_culling!=0) { + return; // leave as initially set + } +#endif + + CullFaceProperty::Mode mode = attrib->get_mode(); + + switch (mode) { + case CullFaceProperty::M_cull_none: + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + break; + case CullFaceProperty::M_cull_clockwise: + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CW); + break; + case CullFaceProperty::M_cull_counter_clockwise: + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW); + break; + case CullFaceProperty::M_cull_all: + dxgsg_cat.warning() << "M_cull_all is invalid for DX GSG renderer, using CULL_CCW \n"; + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW); + break; + default: + dxgsg_cat.error() + << "invalid cull face mode " << (int)mode << endl; + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_clip_plane +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_clip_plane(const ClipPlaneTransition *attrib) { + nassertv(attrib->get_default_dir() != TD_on); + + // Initialize the currently enabled clip plane list + int i; + for (i = 0; i < _max_clip_planes; i++) + _cur_clip_plane_enabled[i] = false; + + int num_enabled = 0; + ClipPlaneTransition::const_iterator pi; + for (pi = attrib->begin(); pi != attrib->end(); ++pi) { + PlaneNode *plane_node; + DCAST_INTO_V(plane_node, (*pi).first); + nassertv(plane_node != (PlaneNode *)NULL); + TransitionDirection dir = (*pi).second; + + if (dir == TD_on) { + _cur_clip_plane_id = -1; + num_enabled++; + + // Check to see if this clip plane has already been bound to an id + for (i = 0; i < _max_clip_planes; i++) { + if (_available_clip_plane_ids[i] == plane_node) { + // Clip plane has already been bound to an id, we only need + // to enable the clip plane, not apply it + _cur_clip_plane_id = -2; + enable_clip_plane(i, true); + _cur_clip_plane_enabled[i] = true; + break; + } + } + + // See if there are any unbound clip plane ids + if (_cur_clip_plane_id == -1) { + for (i = 0; i < _max_clip_planes; i++) { + if (_available_clip_plane_ids[i] == NULL) { + _available_clip_plane_ids[i] = plane_node; + _cur_clip_plane_id = i; + break; + } + } + } + + // If there were no unbound clip plane ids, see if we can replace + // a currently unused but previously bound id + if (_cur_clip_plane_id == -1) { + for (i = 0; i < _max_clip_planes; i++) { + if (attrib->is_off(_available_clip_plane_ids[i])) { + _available_clip_plane_ids[i] = plane_node; + _cur_clip_plane_id = i; + break; + } + } + } + + if (_cur_clip_plane_id >= 0) { + enable_clip_plane(_cur_clip_plane_id, true); + _cur_clip_plane_enabled[_cur_clip_plane_id] = true; + const Planef clip_plane = plane_node->get_plane(); + + D3DVALUE equation[4]; + equation[0] = clip_plane._a; + equation[1] = clip_plane._b; + equation[2] = clip_plane._c; + equation[3] = clip_plane._d; + _d3dDevice->SetClipPlane(_cur_clip_plane_id, equation); + + } else if (_cur_clip_plane_id == -1) { + dxgsg_cat.error() + << "issue_clip_plane() - failed to bind clip plane to id" << endl; + } + } + } + + // Disable all unused clip planes + for (i = 0; i < _max_clip_planes; i++) { + if (!_cur_clip_plane_enabled[i]) + enable_clip_plane(i, false); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_transparency +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_transparency(const TransparencyTransition *attrib ) { + + TransparencyProperty::Mode mode = attrib->get_mode(); + + switch (mode) { + case TransparencyProperty::M_none: +// enable_multisample_alpha_one(false); +// enable_multisample_alpha_mask(false); + enable_blend(false); + enable_alpha_test(false); + break; + case TransparencyProperty::M_alpha: + case TransparencyProperty::M_alpha_sorted: + // Should we really have an "alpha" and an "alpha_sorted" mode, + // like Performer does? (The difference is that "alpha" is with + // the write to the depth buffer disabled.) Or should we just use + // the separate depth write transition to control this? Doing it + // implicitly requires a bit more logic here and in the state + // management; for now we require the user to explicitly turn off + // the depth write. +// enable_multisample_alpha_one(false); +// enable_multisample_alpha_mask(false); + enable_blend(true); + enable_alpha_test(false); + call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + break; + case TransparencyProperty::M_multisample: +// enable_multisample_alpha_one(true); +// enable_multisample_alpha_mask(true); + enable_blend(false); + enable_alpha_test(false); + break; + case TransparencyProperty::M_multisample_mask: +// enable_multisample_alpha_one(false); +// enable_multisample_alpha_mask(true); + enable_blend(false); + enable_alpha_test(false); + break; + case TransparencyProperty::M_binary: +// enable_multisample_alpha_one(false); +// enable_multisample_alpha_mask(false); + enable_blend(false); + enable_alpha_test(true); + call_dxAlphaFunc(D3DCMP_EQUAL, 1); + break; + default: + dxgsg_cat.error() + << "invalid transparency mode " << (int)mode << endl; + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_linesmooth +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_linesmooth(const LinesmoothTransition *attrib) { + enable_line_smooth(attrib->is_on()); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::wants_normals +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool DXGraphicsStateGuardian:: +wants_normals() const { + return (_lighting_enabled || _normals_enabled); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::wants_texcoords +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool DXGraphicsStateGuardian:: +wants_texcoords() const { + return _texturing_enabled; +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::issue_depth_write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +issue_depth_write(const DepthWriteTransition *attrib) { + enable_zwritemask(attrib->is_on()); +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::begin_decal +// Access: Public, Virtual +// Description: This will be called to initiate decaling mode. It is +// passed the pointer to the GeomNode that will be the +// destination of the decals, which it is expected that +// the GSG will render normally; subsequent geometry +// rendered up until the next call of end_decal() should +// be rendered as decals of the base_geom. +// +// The transitions wrapper is the current state as of the +// base geometry node. It may or may not be modified by +// the GSG to reflect whatever rendering state is +// necessary to render the decals properly. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +begin_decal(GeomNode *base_geom, AllTransitionsWrapper &attrib) { + nassertv(base_geom != (GeomNode *)NULL); + + assert(_decal_level>=0); + + _decal_level++; + +#ifndef DISABLE_DECALING + + #ifndef DISABLE_POLYGON_OFFSET_DECALING + if (dx_decal_type == GDT_offset) { + #define POLYGON_OFFSET_MULTIPLIER 2 + + // note: zbias seems inconsitently supported. may be possible to fake it by + // adding (delta * element[4,3]) to element [3,3] of a regular matrix + // need to test this and see if to offers perf improvement over blend-based decaling + + nassertv(POLYGON_OFFSET_MULTIPLIER*_decal_level < 16); // 16 is the max allowed zbias + + // Just draw the base geometry normally. + base_geom->draw(this); + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, POLYGON_OFFSET_MULTIPLIER * _decal_level); // _decal_level better not be higher than 8! + } else + #endif + + { + if (_decal_level > 1) { + base_geom->draw(this); // If we're already decaling, just draw the geometry. + } else { + // need to save current xform matrix in case it is changed during subrendering, so subsequent decal draws use same xform + _bTransformIssued = false; + _d3dDevice->GetTransform( D3DTRANSFORMSTATE_WORLD, &_SavedTransform); + + // First turn off writing the depth buffer to render the base geometry. + enable_zwritemask(false); + + // It is also important to update the current state to + // indicate the depth buffer write is off, so that future + // geometry will render correctly. + DepthWriteTransition *dwa = new DepthWriteTransition(DepthWriteTransition::off()); + attrib.set_transition(dwa); + + // Now render the base geometry. + base_geom->draw(this); + + // Render all of the decal geometry, too. We'll keep the depth + // buffer write off during this. + } + } +#else + base_geom->draw(this); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::end_decal +// Access: Public, Virtual +// Description: This will be called to terminate decaling mode. It +// is passed the same base_geom that was passed to +// begin_decal(). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +end_decal(GeomNode *base_geom) { + _decal_level--; + + assert(_decal_level>=0); + +#ifdef DISABLE_DECALING + return; +#endif + + nassertv(base_geom != (GeomNode *)NULL); +// nassertv(_decal_level >= 1); + +#ifndef DISABLE_POLYGON_OFFSET_DECALING + if (dx_decal_type == GDT_offset) { + // Restore the Zbias offset. + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, POLYGON_OFFSET_MULTIPLIER * _decal_level); // _decal_level better not be higher than 8! + } else +#endif + { // for GDT_mask + if (_decal_level == 0) { + // Now we need to re-render the base geometry with the depth write + // on and the color mask off, so we update the depth buffer + // properly. + bool was_textured = _texturing_enabled; + bool was_blend = _blend_enabled; + D3DBLEND old_blend_source_func = _blend_source_func; + D3DBLEND old_blend_dest_func = _blend_dest_func; + + // Enable the writing to the depth buffer. + enable_zwritemask(true); + + // Disable the writing to the color buffer, however we have to + // do this. (I don't think this is possible in DX without blending.) + if (dx_decal_type == GDT_blend) { + // Expensive. + enable_blend(true); + call_dxBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE); + } + +#if(DIRECT3D_VERSION < 0x700) + else { // dx7 doesn't support planemask rstate + // note: not saving current planemask val, assumes this is always all 1's. should be ok + _d3dDevice->SetRenderState(D3DRENDERSTATE_PLANEMASK,0x0); // note PLANEMASK is supposedly obsolete for DX7 + } +#endif + // Note: For DX8, use D3DRS_COLORWRITEENABLE (check D3DPMISCCAPS_COLORWRITEENABLE first) + + // No need to have texturing on for this. + enable_texturing(false); + + // if current xform has changed, reset to saved xform + if(_bTransformIssued) + _d3dDevice->SetTransform( D3DTRANSFORMSTATE_WORLD, &_SavedTransform); + + base_geom->draw(this); + + // Finally, restore the depth write and color mask states to the + // way they're supposed to be. + + if (dx_decal_type == GDT_blend) { + enable_blend(was_blend); + if (was_blend) + call_dxBlendFunc(old_blend_source_func, old_blend_dest_func); + } +#if(DIRECT3D_VERSION < 0x700) + else { + _d3dDevice->SetRenderState(D3DRENDERSTATE_PLANEMASK,0xFFFFFFFF); // this is unlikely to work due to poor driver support + } +#endif + enable_texturing(was_textured); + + // Finally, restore the depth write state to the + // way they're supposed to be. + + // could we do this faster by saving last issued depth writemask? + DepthWriteTransition *depth_write; + if (get_attribute_into(depth_write, this)) { + issue_depth_write(depth_write); + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::compute_distance_to +// Access: Public, Virtual +// Description: This function may only be called during a render +// traversal; it will compute the distance to the +// indicated point, assumed to be in modelview +// coordinates, from the camera plane. +//////////////////////////////////////////////////////////////////// +INLINE float DXGraphicsStateGuardian:: +compute_distance_to(const LPoint3f &point) const { + // In the case of a DXGraphicsStateGuardian, we know that the + // modelview matrix already includes the relative transform from the + // camera, as well as a to-y-up conversion. Thus, the distance to + // the camera plane is simply the +z distance. (negative of gl compute_distance_to, + // since d3d uses left-hand coords) + + return point[2]; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::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 DXGraphicsStateGuardian:: +set_draw_buffer(const RenderBuffer &rb) { + dxgsg_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: DXGraphicsStateGuardian::set_read_buffer +// Access: Protected +// Description: Vestigial analog of glReadBuffer +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +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 { + dxgsg_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n"; + } + return; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::get_texture_wrap_mode +// Access: Protected +// Description: Maps from the Texture's internal wrap mode symbols to +// GL's. +//////////////////////////////////////////////////////////////////// +INLINE D3DTEXTUREADDRESS DXGraphicsStateGuardian:: +get_texture_wrap_mode(Texture::WrapMode wm) const { + + if (wm == Texture::WM_clamp) + return D3DTADDRESS_CLAMP; + else if (wm != Texture::WM_repeat) { +#ifdef _DEBUG + dxgsg_cat.error() << "Invalid or Unimplemented Texture::WrapMode value!\n"; +#endif + } + + return D3DTADDRESS_WRAP; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::get_depth_func_type +// Access: Protected +// Description: Maps from the depth func modes to gl version +//////////////////////////////////////////////////////////////////// +INLINE D3DCMPFUNC DXGraphicsStateGuardian:: +get_depth_func_type(DepthTestProperty::Mode m) const { + switch (m) { + case DepthTestProperty::M_never: return D3DCMP_NEVER; + case DepthTestProperty::M_less: return D3DCMP_LESS; + case DepthTestProperty::M_equal: return D3DCMP_EQUAL; + case DepthTestProperty::M_less_equal: return D3DCMP_LESSEQUAL; + case DepthTestProperty::M_greater: return D3DCMP_GREATER; + case DepthTestProperty::M_not_equal: return D3DCMP_NOTEQUAL; + case DepthTestProperty::M_greater_equal: return D3DCMP_GREATEREQUAL; + case DepthTestProperty::M_always: return D3DCMP_ALWAYS; + } + dxgsg_cat.error() + << "Invalid DepthTestProperty::Mode value" << endl; + return D3DCMP_LESS; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::get_stencil_func_type +// Access: Protected +// Description: Maps from the stencil func modes to dx version +//////////////////////////////////////////////////////////////////// +INLINE D3DCMPFUNC DXGraphicsStateGuardian:: +get_stencil_func_type(StencilProperty::Mode m) const { + switch (m) { + case StencilProperty::M_never: return D3DCMP_NEVER; + case StencilProperty::M_less: return D3DCMP_LESS; + case StencilProperty::M_equal: return D3DCMP_EQUAL; + case StencilProperty::M_less_equal: return D3DCMP_LESSEQUAL; + case StencilProperty::M_greater: return D3DCMP_GREATER; + case StencilProperty::M_not_equal: return D3DCMP_NOTEQUAL; + case StencilProperty::M_greater_equal: return D3DCMP_GREATEREQUAL; + case StencilProperty::M_always: return D3DCMP_ALWAYS; + } + dxgsg_cat.error() << "Invalid StencilProperty::Mode value" << endl; + return D3DCMP_LESS; +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::get_stencil_action_type +// Access: Protected +// Description: Maps from the stencil action modes to dx version +//////////////////////////////////////////////////////////////////// +INLINE D3DSTENCILOP DXGraphicsStateGuardian:: +get_stencil_action_type(StencilProperty::Action a) const { + switch (a) { + case StencilProperty::A_keep: return D3DSTENCILOP_KEEP; + case StencilProperty::A_zero: return D3DSTENCILOP_ZERO; + case StencilProperty::A_replace: return D3DSTENCILOP_REPLACE; + case StencilProperty::A_increment: return D3DSTENCILOP_INCR; + case StencilProperty::A_decrement: return D3DSTENCILOP_DECR; + case StencilProperty::A_invert: return D3DSTENCILOP_INVERT; + } + dxgsg_cat.error() << "Invalid StencilProperty::Action value" << endl; + return D3DSTENCILOP_KEEP; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::get_fog_mode_type +// Access: Protected +// Description: Maps from the fog types to gl version +//////////////////////////////////////////////////////////////////// +INLINE D3DFOGMODE DXGraphicsStateGuardian:: +get_fog_mode_type(Fog::Mode m) const { + switch (m) { + case Fog::M_linear: return D3DFOG_LINEAR; + case Fog::M_exponential: return D3DFOG_EXP; + case Fog::M_exponential_squared: return D3DFOG_EXP2; + } + dxgsg_cat.error() << "Invalid Fog::Mode value" << endl; + return D3DFOG_EXP; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::free_pointers +// Access: Public +// Description: Frees some memory that was explicitly allocated +// within the dxgsg. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +free_pointers() { + if (_light_enabled != (bool *)NULL) { + delete[] _light_enabled; + _light_enabled = (bool *)NULL; + } + if (_cur_light_enabled != (bool *)NULL) { + delete[] _cur_light_enabled; + _cur_light_enabled = (bool *)NULL; + } + if (_clip_plane_enabled != (bool *)NULL) { + delete[] _clip_plane_enabled; + _clip_plane_enabled = (bool *)NULL; + } + if (_cur_clip_plane_enabled != (bool *)NULL) { + delete[] _cur_clip_plane_enabled; + _cur_clip_plane_enabled = (bool *)NULL; + } + + if (_pTexPixFmts != NULL) { + delete [] _pTexPixFmts; + _pTexPixFmts = NULL; + } + + if(_fpsmeter_verts!=NULL) { + delete [] _fpsmeter_verts; + _fpsmeter_verts = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::save_frame_buffer +// Access: Public +// Description: Saves the indicated planes of the frame buffer +// (within the indicated display region) and returns it +// in some meaningful form that can be restored later +// via restore_frame_buffer(). This is a helper +// function for push_frame_buffer() and +// pop_frame_buffer(). +//////////////////////////////////////////////////////////////////// +PT(SavedFrameBuffer) DXGraphicsStateGuardian:: +save_frame_buffer(const RenderBuffer &buffer, + CPT(DisplayRegion) dr) { + + dxgsg_cat.error() << "save_frame_buffer unimplemented!!\n"; + return NULL; + +#if 0 + DXSavedFrameBuffer *sfb = new DXSavedFrameBuffer(buffer, dr); + + if (buffer._buffer_type & RenderBuffer::T_depth) { + // Save the depth buffer. + sfb->_depth = + new PixelBuffer(PixelBuffer::depth_buffer(dr->get_pixel_width(), + dr->get_pixel_height())); + copy_pixel_buffer(sfb->_depth, dr, buffer); + } + + if (buffer._buffer_type & RenderBuffer::T_back) { + // Save the color buffer. + sfb->_back_rgba = new Texture; + copy_texture(sfb->_back_rgba->prepare(this), dr, buffer); + } + + return sfb; +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::restore_frame_buffer +// Access: Public +// Description: Restores the frame buffer that was previously saved. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +restore_frame_buffer(SavedFrameBuffer *frame_buffer) { + + dxgsg_cat.error() << "restore_frame_buffer unimplemented!!\n"; + return; + +#if 0 + DXSavedFrameBuffer *sfb = DCAST(DXSavedFrameBuffer, frame_buffer); + + if (sfb->_back_rgba != (Texture *)NULL && + (sfb->_buffer._buffer_type & RenderBuffer::T_back) != 0) { + // Restore the color buffer. + draw_texture(sfb->_back_rgba->prepare(this), + sfb->_display_region, sfb->_buffer); + } + + if (sfb->_depth != (PixelBuffer *)NULL && + (sfb->_buffer._buffer_type & RenderBuffer::T_depth) != 0) { + // Restore the depth buffer. + draw_pixel_buffer(sfb->_depth, sfb->_display_region, sfb->_buffer); + } +#endif +} + +// factory and type stuff + +GraphicsStateGuardian *DXGraphicsStateGuardian:: +make_DXGraphicsStateGuardian(const FactoryParams ¶ms) { + GraphicsStateGuardian::GsgWindow *win_param; + if (!get_param_into(win_param, params)) { + dxgsg_cat.error() + << "No window specified for gsg creation!" << endl; + return NULL; + } + + GraphicsWindow *win = win_param->get_window(); + return new DXGraphicsStateGuardian(win); +} + +TypeHandle DXGraphicsStateGuardian::get_type(void) const { + return get_class_type(); +} + +TypeHandle DXGraphicsStateGuardian::get_class_type(void) { + return _type_handle; +} + +void DXGraphicsStateGuardian::init_type(void) { + GraphicsStateGuardian::init_type(); + register_type(_type_handle, "DXGraphicsStateGuardian", + GraphicsStateGuardian::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: dx_cleanup +// Description: Clean up the DirectX environment. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) { + static bool bAtExitFnEverCalled=false; + + if(dxgsg_cat.is_spam()) { + dxgsg_cat.spam() << "dx_cleanup called, bAtExitFnCalled=" << bAtExitFnCalled << ", bAtExitFnEverCalled=" << bAtExitFnEverCalled << endl; + } + + bAtExitFnEverCalled = (bAtExitFnEverCalled || bAtExitFnCalled); + + // 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; + + ULONG refcnt; + + // unsafe to do the D3D releases after exit() called, since DLL_PROCESS_DETACH + // msg already delivered to d3d.dll and it's unloaded itself + if(!bAtExitFnEverCalled) { + + PRINTREFCNT(_pDD,"exit start IDirectDraw7"); + + // these 2 calls release ddraw surfaces and vbuffers. unsafe unless not on exit + release_all_textures(); + release_all_geoms(); + + PRINTREFCNT(_pDD,"after release_all_textures IDirectDraw7"); + + // Do a safe check for releasing the D3DDEVICE. RefCount should be zero. + // if we're called from exit(), _d3dDevice may already have been released + if (_d3dDevice!=NULL) { + _d3dDevice->SetTexture(0,NULL); // should release this stuff internally anyway + RELEASE(_d3dDevice,dxgsg,"d3dDevice",RELEASE_DOWN_TO_ZERO); + } + + PRINTREFCNT(_pDD,"after d3ddevice release IDirectDraw7"); + + RELEASE(_fpsmeter_font_surf,dxgsg,"fpsmeter fontsurf",false); + + PRINTREFCNT(_pDD,"after fpsfont release IDirectDraw7"); + + if((_back!=NULL)&&(_zbuf!=NULL)) + _back->DeleteAttachedSurface(0x0,_zbuf); + + // Release the DDraw and D3D objects used by the app + RELEASE(_zbuf,dxgsg,"zbuffer",false); + + PRINTREFCNT(_pDD,"before releasing d3d obj, IDirectDraw7"); + RELEASE(_d3d,dxgsg,"IDirect3D7 _d3d",false); //RELEASE_DOWN_TO_ZERO); + PRINTREFCNT(_pDD,"after releasing d3d obj, IDirectDraw7"); + + RELEASE(_back,dxgsg,"backbuffer",false); + RELEASE(_pri,dxgsg,"primary surface",false); + + PRINTREFCNT(_pDD,"after releasing all surfs, IDirectDraw7"); + } + + // for some reason, DLL_PROCESS_DETACH has not yet been sent to ddraw, so we can still call its fns + + // Do a safe check for releasing DDRAW. RefCount should be zero. + if (_pDD!=NULL) { + if(bRestoreDisplayMode) { + HRESULT hr = _pDD->RestoreDisplayMode(); + if(dxgsg_cat.is_spam()) + dxgsg_cat.spam() << "dx_cleanup - Restoring original desktop DisplayMode\n"; + if(FAILED(hr)) { + dxgsg_cat.error() << "dx_cleanup - RestoreDisplayMode failed, hr = " << ConvD3DErrorToString(hr) << endl; + } + } + + if(bAtExitFnCalled) { + // if exit() called, there is definitely no more need for the IDDraw object, + // so we can make sure it's fully released + // note currently this is never called + RELEASE(_pDD,dxgsg,"IDirectDraw7 _pDD", RELEASE_DOWN_TO_ZERO); + } else { + // seems wrong to release to zero, since it might be being used somewhere else? + + RELEASE(_pDD,dxgsg,"IDirectDraw7 _pDD", false); + if(refcnt>0) { + if(dxgsg_cat.is_spam()) + dxgsg_cat.debug() << "dx_cleanup - warning IDDraw7 refcnt = " << refcnt << ", should be zero!\n"; + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: dx_setup_after_resize +// Description: Recreate the back buffer and zbuffers at the new size +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +dx_setup_after_resize(RECT viewrect, HWND mwindow) { + if (_back == NULL) // nothing created yet + return; + + // for safety, need some better error-cleanup here + assert((_pri!=NULL) && (_back!=NULL) && (_zbuf!=NULL)); + + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_back); + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_zbuf); + + _back->GetSurfaceDesc(&ddsd_back); + _zbuf->GetSurfaceDesc(&ddsd_zbuf); + + ULONG refcnt; + + if((_back!=NULL)&&(_zbuf!=NULL)) + _back->DeleteAttachedSurface(0x0,_zbuf); + + RELEASE(_zbuf,dxgsg,"zbuffer",false); + RELEASE(_back,dxgsg,"backbuffer",false); + RELEASE(_pri,dxgsg,"primary surface",false); + + assert((_pri == NULL) && (_back == NULL) && (_zbuf == NULL)); + _view_rect = viewrect; + + DWORD renderWid = _view_rect.right - _view_rect.left; + DWORD renderHt = _view_rect.bottom - _view_rect.top; + + ddsd_back.dwWidth = ddsd_zbuf.dwWidth = renderWid; + ddsd_back.dwHeight = ddsd_zbuf.dwHeight = renderHt; + + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); + + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + ddsd.dwFlags = DDSD_CAPS; + + PRINTVIDMEM(_pDD,&ddsd.ddsCaps,"resize primary surf"); + HRESULT hr; + + if (FAILED(hr = _pDD->CreateSurface( &ddsd, &_pri, NULL ))) { + dxgsg_cat.fatal() << "resize() - CreateSurface failed for primary : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(!dx_full_screen) { + // Create a clipper object which handles all our clipping for cases when + // our window is partially obscured by other windows. + LPDIRECTDRAWCLIPPER Clipper; + + if (FAILED(hr = _pDD->CreateClipper( 0, &Clipper, NULL ))) { + dxgsg_cat.fatal() + << "CreateClipper after resize failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + // Associate the clipper with our window. Note that, afterwards, the + // clipper is internally referenced by the primary surface, so it is safe + // to release our local reference to it. + Clipper->SetHWnd( 0, mwindow ); + _pri->SetClipper( Clipper ); + Clipper->Release(); + } + + // Recreate the backbuffer. (might want to handle failure due to running out of video memory) + + ddsd_back.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; // just to make sure + ddsd_back.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + + PRINTVIDMEM(_pDD,&ddsd_back.ddsCaps,"resize backbuffer surf"); + + if (FAILED(hr = _pDD->CreateSurface( &ddsd_back, &_back, NULL ))) { + dxgsg_cat.fatal() << "resize() - CreateSurface failed for backbuffer : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + PRINTVIDMEM(_pDD,&ddsd_back.ddsCaps,"resize zbuffer surf"); + + // Recreate and attach a z-buffer. + if (FAILED(hr = _pDD->CreateSurface( &ddsd_zbuf, &_zbuf, NULL ))) { + dxgsg_cat.fatal() << "resize() - CreateSurface failed for Z buffer: result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Attach the z-buffer to the back buffer. + if ((hr = _back->AddAttachedSurface( _zbuf ) ) != DD_OK) { + dxgsg_cat.fatal() << "resize() - AddAttachedSurface failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if ((hr = _d3dDevice->SetRenderTarget(_back,0x0) ) != DD_OK) { + dxgsg_cat.fatal() << "resize() - SetRenderTarget failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Create the viewport + D3DVIEWPORT7 vp = { 0, 0, renderWid, renderHt, 0.0f, 1.0f}; + hr = _d3dDevice->SetViewport( &vp ); + if (hr != DD_OK) { + dxgsg_cat.fatal() + << "SetViewport failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(dx_show_fps_meter) + SetFPSMeterPosition(_view_rect); +} + +bool refill_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) { + DXTextureContext *dtc = DCAST(DXTextureContext, tc); +// DXGraphicsStateGuardian *dxgsg = (DXGraphicsStateGuardian *)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) { + DXTextureContext *dtc = DCAST(DXTextureContext, tc); + + // release DDSurf (but not the texture context) + dtc->DeleteTexture(); + return true; +} + +bool recreate_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) { + DXTextureContext *dtc = DCAST(DXTextureContext, tc); + DXGraphicsStateGuardian *dxgsg = (DXGraphicsStateGuardian *)void_dxgsg_ptr; + + // Re-fill the contents of textures and vertex buffers + // which just got restored now. + + LPDIRECTDRAWSURFACE7 ddtex = dtc->CreateTexture(dxgsg->_d3dDevice, + dxgsg->_cNumTexPixFmts,dxgsg->_pTexPixFmts); + return ddtex!=NULL; +} + +// release all textures and vertex/index buffers +HRESULT DXGraphicsStateGuardian::DeleteAllVideoSurfaces(void) { + // 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(delete_tex_callback,this); + + ULONG refcnt; + + if(dx_show_fps_meter) + RELEASE(_fpsmeter_font_surf,dxgsg,"fpsmeter fontsurf",false); + + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "release of all textures complete\n"; + return S_OK; +} + +// recreate all textures and vertex/index buffers +HRESULT DXGraphicsStateGuardian::RecreateAllVideoSurfaces(void) { + // 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(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "recreation of all textures complete\n"; + return S_OK; +} + +HRESULT DXGraphicsStateGuardian::RestoreAllVideoSurfaces(void) { + // BUGBUG: this should also restore vertex buffer contents when they are implemented + // You will need to destroy and recreate + // optimized vertex buffers however, restoring is not enough. + + HRESULT hr; + + // note: could go through and just restore surfs that return IsLost() true + // apparently that isnt as reliable w/some drivers tho + if (FAILED(hr = _pDD->RestoreAllSurfaces() )) { + dxgsg_cat.fatal() << "RestoreAllSurfs failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it + traverse_prepared_textures(refill_tex_callback,this); + + if(dx_show_fps_meter) + FillFPSMeterTexture(); + + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "restore and refill of video surfaces complete...\n"; + return S_OK; +} + + +//////////////////////////////////////////////////////////////////// +// Function: show_frame +// Access: +// Description: Repaint primary buffer from back buffer +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::show_frame(void) { + if(_pri==NULL) + return; + + 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 + + if(dx_full_screen) { + show_full_screen_frame(); + } else { + show_windowed_frame(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: show_full_screen_frame +// Access: +// Description: Repaint primary buffer from back buffer +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::show_full_screen_frame(void) { + HRESULT hr; + + // Flip the front and back buffers, to make what we just rendered + // visible. + + DWORD dwFlipFlags = DDFLIP_WAIT; + + if (!dx_sync_video) { + // If the user indicated via Config that we shouldn't wait for + // video sync, then don't wait (if the hardware supports this). + // This will introduce visible artifacts like tearing, and may + // cause the frame rate to grow excessively (and pointlessly) + // high, starving out other processes. + dwFlipFlags |= DDFLIP_NOVSYNC; +// dwFlipFlags = DDFLIP_DONOTWAIT | DDFLIP_NOVSYNC; + } + + // bugbug: dont we want triple buffering instead of wasting time + // waiting for vsync? + hr = _pri->Flip( NULL, dwFlipFlags); + + if(FAILED(hr)) { + if((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) { + CheckCooperativeLevel(); + } else { + dxgsg_cat.error() << "show_frame() - Flip failed w/unexpected error code: " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + +} + +//////////////////////////////////////////////////////////////////// +// Function: show_windowed_frame +// Access: Public +// Description: Repaint primary buffer from back buffer (windowed +// mode only) +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::show_windowed_frame(void) { + HRESULT hr; + + DX_DECLARE_CLEAN(DDBLTFX, bltfx); + + if (dx_sync_video) { + // Wait for the video refresh *before* we blt the rendered image + // onto the window. This will (a) prevent the "tearing" of the + // image that would occur if only part of the image happened to be + // copied into the window before the video refresh occurred, and + // (b) prevent our frame rate from going excessively (and + // pointlessly) higher than our video refresh rate, starving out + // other processes. + + // Unfortunately, when the system is even lightly loaded, this + // wait call sometimes appears to wait through multiple frames + // before returning, causing our frame rate to be unreasonably low + // and erratic. There doesn't appear to be any way to prevent + // this behavior; thus, we allow the user to avoid this wait, + // based on the Config settings. + + bltfx.dwDDFX |= DDBLTFX_NOTEARING; // hmm, does any driver actually recognize this flag? + } + + hr = _pri->Blt( &_view_rect, _back, NULL, DDBLT_DDFX | DDBLT_WAIT, &bltfx ); + + if (dx_sync_video) { + HRESULT hr = _pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); + if(hr != DD_OK) { + dxgsg_cat.error() << "WaitForVerticalBlank() failed : " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + + if(FAILED(hr)) { + if((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) { + CheckCooperativeLevel(); + } else { + dxgsg_cat.error() << "show_frame() - Blt failed : " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + +} + +bool DXGraphicsStateGuardian::CheckCooperativeLevel(bool bDoReactivateWindow) { + + HRESULT hr = _pDD->TestCooperativeLevel(); + + if(SUCCEEDED(_last_testcooplevel_result)) { + if(SUCCEEDED(hr)) // this means this was just a safety check, dont need to restore surfs + return true; + + // otherwise something just went wrong + + HRESULT hr; + + // TestCooperativeLevel returns DD_OK: If the current mode is same as the one which the App set. + // The following error is returned only for exclusivemode apps. + // DDERR_NOEXCLUSIVEMODE: Some other app took exclusive mode. + + hr = _pDD->TestCooperativeLevel(); + + HRESULT expected_error = (dx_full_screen ? DDERR_NOEXCLUSIVEMODE : DDERR_EXCLUSIVEMODEALREADYSET); + + if(hr == expected_error) { + // This means that mode changes had taken place, surfaces + // were lost but still we are in the original mode, so we + // simply restore all surfaces and keep going. + + if(dxgsg_cat.is_debug()) { + if(dx_full_screen) + dxgsg_cat.debug() << "Lost access to DDRAW exclusive mode, waiting to regain it...\n"; + else dxgsg_cat.debug() << "Another app has DDRAW exclusive mode, waiting...\n"; + } + + if(_dx_ready) { + _win->deactivate_window(); + _dx_ready = FALSE; + } + } else if(hr==DDERR_WRONGMODE) { + // This means that the desktop mode has changed + // need to destroy all of dx stuff and recreate everything + // back again, which is a big hit + dxgsg_cat.error() << "detected display mode change in TestCoopLevel, must recreate all DDraw surfaces, D3D devices, this is not handled yet. hr == " << ConvD3DErrorToString(hr) << endl; + exit(1); + } else if(FAILED(hr)) { + dxgsg_cat.error() << "unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } else { + // testcooplvl was failing, handle case where it now succeeds + + if(SUCCEEDED(hr)) { + if(_last_testcooplevel_result == DDERR_EXCLUSIVEMODEALREADYSET) { + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "other app relinquished exclusive mode, refilling surfs...\n"; + } else if(_last_testcooplevel_result == DDERR_NOEXCLUSIVEMODE) { + if(dxgsg_cat.is_debug()) + dxgsg_cat.debug() << "regained exclusive mode, refilling surfs...\n"; + } + + if(bDoReactivateWindow) + _win->reactivate_window(); //must reactivate window before you can restore surfaces (otherwise you are in WRONGVIDEOMODE, and DDraw RestoreAllSurfaces fails) + + RestoreAllVideoSurfaces(); + + _dx_ready = TRUE; + + } else if(hr==DDERR_WRONGMODE) { + // This means that the desktop mode has changed + // need to destroy all of dx stuff and recreate everything + // back again, which is a big hit + dxgsg_cat.error() << "detected desktop display mode change in TestCoopLevel, must recreate all DDraw surfaces & D3D devices, this is not handled yet. " << ConvD3DErrorToString(hr) << endl; + _win->close_window(); + exit(1); + } else if((hr!=DDERR_NOEXCLUSIVEMODE) && (hr!=DDERR_EXCLUSIVEMODEALREADYSET)) { + dxgsg_cat.error() << "unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + + _last_testcooplevel_result = hr; + return SUCCEEDED(hr); +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_window_move +// Access: +// Description: we receive the new x and y position of the client +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::adjust_view_rect(int x, int y) { + if (_view_rect.left != x || _view_rect.top != y) { + _view_rect.right = x + _view_rect.right - _view_rect.left; + _view_rect.left = x; + _view_rect.bottom = y + _view_rect.bottom - _view_rect.top; + _view_rect.top = y; + +// set_clipper(clip_rect); + } +} + +#if 0 + +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::save_mipmap_images +// Access: Protected +// Description: Saves out each mipmap level of the indicated texture +// (which must also be the currently active texture in +// the GL state) as a separate image file to disk. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian::read_mipmap_images(Texture *tex) { + Filename filename = tex->get_name(); + string name; + if (filename.empty()) { + static index = 0; + name = "texture" + format_string(index); + index++; + } else { + name = filename.get_basename_wo_extension(); + } + + PixelBuffer *pb = tex->get_ram_image(); + nassertv(pb != (PixelBuffer *)NULL); + + GLenum external_format = get_external_image_format(pb->get_format()); + GLenum type = get_image_type(pb->get_image_type()); + + int xsize = pb->get_xsize(); + int ysize = pb->get_ysize(); + + // Specify byte-alignment for the pixels on output. + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + int mipmap_level = 0; + do { + xsize = max(xsize, 1); + ysize = max(ysize, 1); + + PT(PixelBuffer) mpb = + new PixelBuffer(xsize, ysize, pb->get_num_components(), + pb->get_component_width(), pb->get_image_type(), + pb->get_format()); + glGetTexImage(GL_TEXTURE_2D, mipmap_level, external_format, + type, mpb->_image); + Filename mipmap_filename = name + "_" + format_string(mipmap_level) + ".pnm"; + nout << "Writing mipmap level " << mipmap_level + << " (" << xsize << " by " << ysize << ") " + << mipmap_filename << "\n"; + mpb->write(mipmap_filename); + + xsize >>= 1; + ysize >>= 1; + mipmap_level++; + } while (xsize > 0 && ysize > 0); +} +#endif + + +#if 0 +//----------------------------------------------------------------------------- +// Name: SetViewMatrix() +// Desc: Given an eye point, a lookat point, and an up vector, this +// function builds a 4x4 view matrix. +//----------------------------------------------------------------------------- +HRESULT SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, D3DVECTOR& vAt, + D3DVECTOR& vWorldUp ) { + // Get the z basis vector, which points straight ahead. This is the + // difference from the eyepoint to the lookat point. + D3DVECTOR vView = vAt - vFrom; + + float fLength = Magnitude( vView ); + if (fLength < 1e-6f) + return E_INVALIDARG; + + // Normalize the z basis vector + vView /= fLength; + + // Get the dot product, and calculate the projection of the z basis + // vector onto the up vector. The projection is the y basis vector. + float fDotProduct = DotProduct( vWorldUp, vView ); + + D3DVECTOR vUp = vWorldUp - fDotProduct * vView; + + // If this vector has near-zero length because the input specified a + // bogus up vector, let's try a default up vector + if (1e-6f > ( fLength = Magnitude( vUp ) )) { + vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView; + + // If we still have near-zero length, resort to a different axis. + if (1e-6f > ( fLength = Magnitude( vUp ) )) { + vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView; + + if (1e-6f > ( fLength = Magnitude( vUp ) )) + return E_INVALIDARG; + } + } + + // Normalize the y basis vector + vUp /= fLength; + + // The x basis vector is found simply with the cross product of the y + // and z basis vectors + D3DVECTOR vRight = CrossProduct( vUp, vView ); + + // Start building the matrix. The first three rows contains the basis + // vectors used to rotate the view to point at the lookat point + mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x; mat._14 = 0.0f; + mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y; mat._24 = 0.0f; + mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z; mat._34 = 0.0f; + + // Do the translation values (rotations are still about the eyepoint) + mat._41 = - DotProduct( vFrom, vRight ); + mat._42 = - DotProduct( vFrom, vUp ); + mat._43 = - DotProduct( vFrom, vView ); + mat._44 = 1.0f; + + return S_OK; +} + +#endif + + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::prepare_geom_node +// Access: Public, Virtual +// Description: Prepares the indicated GeomNode for retained-mode +// rendering. If this function returns non-NULL, the +// value returned will be passed back to a future call +// to draw_geom_node(), which is expected to draw the +// contents of the node. +//////////////////////////////////////////////////////////////////// +GeomNodeContext *DXGraphicsStateGuardian:: +prepare_geom_node(GeomNode *node) { + + + if(link_tristrips) { + for(int iGeom=0;iGeomget_num_geoms();iGeom++) { + dDrawable *drawable1 = node->get_geom(iGeom); + + if(!drawable1->is_of_type(Geom::get_class_type())) + continue; + + Geom *geomptr=DCAST(Geom, drawable1); + assert(geomptr!=NULL); + + if(!geomptr->is_of_type(GeomTristrip::get_class_type())) + continue; + + GeomTristrip *me = DCAST(GeomTristrip, geomptr); + assert(me!=NULL); + + int nPrims=me->get_num_prims(); + if(nPrims==1) + continue; + + if(dxgsg_cat.is_debug()) { + static bool bPrintedMsg=false; + if(!bPrintedMsg) { + dxgsg_cat.debug() << "linking tristrips together with degenerate tris\n"; + bPrintedMsg=true; + } + } + + bool bStripReversalNeeded; + unsigned int nOrigTotalVerts=0; + PTA_int new_lengths; + int p; + + // sum things up so can reserve space for new vecs + for(p=0;pget_length(p); + } + + // could compute it exactly if I wanted to reproduce all the cTotalVertsOutputSoFar logic in the loop below + // might save on memory reallocations. try to overestimate using *3. + int cEstimatedTotalVerts=nOrigTotalVerts+nPrims*3-2; + + #define INIT_ATTRVARS(ATTRNAME,PTA_TYPENAME) \ + PTA_##PTA_TYPENAME old_##ATTRNAME##s,new_##ATTRNAME##s; \ + PTA_ushort old_##ATTRNAME##_indices,new_##ATTRNAME##_indices; \ + GeomBindType ATTRNAME##binding; \ + me->get_##ATTRNAME##s(old_##ATTRNAME##s, ATTRNAME##binding, old_##ATTRNAME##_indices); \ + \ + PTA_##PTA_TYPENAME::iterator old_##ATTRNAME##_iter=old_##ATTRNAME##s.begin(); \ + PTA_ushort::iterator old_##ATTRNAME##index_iter; \ + \ + if((ATTRNAME##binding!=G_OFF)&&(ATTRNAME##binding!=G_OVERALL)) { \ + if(old_##ATTRNAME##_indices!=NULL) { \ + old_##ATTRNAME##index_iter=old_##ATTRNAME##_indices.begin(); \ + new_##ATTRNAME##_indices.reserve(cEstimatedTotalVerts); \ + } else { \ + new_##ATTRNAME##s.reserve(cEstimatedTotalVerts); \ + } \ + } + + INIT_ATTRVARS(coord,Vertexf); + INIT_ATTRVARS(color,Colorf); + INIT_ATTRVARS(normal,Normalf); + INIT_ATTRVARS(texcoord,TexCoordf); + +#define IsOdd(X) (((X) & 0x1)!=0) + + uint cTotalVertsOutputSoFar=0; + int nVerts; + bool bAddExtraStartVert; + + for(p=0;pget_length(p); + + // if bStripStateStartsBackfacing, then if the current strip + // ends frontfacing, we can fix the problem by just reversing + // the current strip order. But if the current strip ends + // backfacing, this will not work, since last tri is encoded for backfacing slot + // so it will be incorrectly backfacing when you put it in a backfacing + // slot AND reverse the vtx order. + + // insert an extra pad vertex at the beginning to force the + // strip backface-state parity to change (more expensive, since + // we make 1 more degen tri). We always want the first tri + // to start in a front-facing slot (unless it's a reversed end + + bStripReversalNeeded = false; + bAddExtraStartVert=false; + + if(p==0) { + cTotalVertsOutputSoFar+=nVerts+1; + } else { + if(!IsOdd(cTotalVertsOutputSoFar)) { + // we're starting on a backfacing slot + if(IsOdd(nVerts)) { + bStripReversalNeeded = true; + } else { + bAddExtraStartVert=true; + cTotalVertsOutputSoFar++; + } + } + + cTotalVertsOutputSoFar+=nVerts+2; + if(p==nPrims-1) + cTotalVertsOutputSoFar--; + } + +#define PERVERTEX_ATTRLOOP(OLDVERT_ITERATOR,NEWVERT_VECTOR,VECLENGTH,NUMSTARTPADDINGATTRS,NUMENDPADDINGATTRS) \ + if(bStripReversalNeeded) { \ + /* to preserve normal-direction property for backface-cull purposes, */ \ + /* vtx order must be reversed*/ \ + \ + OLDVERT_ITERATOR+=((VECLENGTH)-1); /* start at last vert, and go back*/ \ + /*dxgsg_cat.debug() << "doing reversal on strip " << p << " of length " << nVerts << endl;*/ \ + \ + if(p!=0) { \ + /* copy first vert twice to link with last strip*/ \ + for(int i=0;iset_coords(old_coords, new_coord_indices); + new_lengths.push_back(new_coord_indices.size()); + } else { + me->set_coords(new_coords); + new_lengths.push_back(new_coords.size()); + } + + me->set_lengths(new_lengths); + me->set_num_prims(1); + + #define SET_NEW_ATTRIBS(ATTRNAME) \ + if((ATTRNAME##binding!=G_OFF) && (ATTRNAME##binding!=G_OVERALL)) { \ + if(ATTRNAME##binding==G_PER_PRIM) \ + ATTRNAME##binding=G_PER_COMPONENT; \ + if(old_##ATTRNAME##_indices==NULL) { \ + me->set_##ATTRNAME##s(new_##ATTRNAME##s, ATTRNAME##binding); \ + } else { \ + me->set_##ATTRNAME##s(old_##ATTRNAME##s, ATTRNAME##binding, new_##ATTRNAME##_indices); \ + } \ + } + /* + int ii; + for( ii=0;iimake_dirty(); + } + } // if(link_tristrips) + + // for now, only using vertexbufs for static Geom, so + // Make sure we have at least some static Geoms in the GeomNode; + int cNumVerts=0,i,num_geoms = node->get_num_geoms(); + + // need to always put in space for color because we might have some scene-graph color we need to add? + // will that even work? I think we'd have to overwrite all the VB colors dynamically, and then restore + // them from somewhere if the global color goes away + + DWORD fvfFlags=D3DFVF_XYZ;// | D3DFVF_DIFFUSE; + + for (i = 0; (i < num_geoms); i++) { + dDrawable *drawable1 = node->get_geom(i); + if(!drawable1->is_of_type(Geom::get_class_type())) + continue; + + Geom *geom=DCAST(Geom, drawable1); + assert(geom!=NULL); + + DWORD new_fvfFlags=D3DFVF_XYZ; + + if(!geom->is_dynamic()) { + cNumVerts+=geom->get_num_vertices(); + if(geom->get_binding(G_COLOR) != G_OFF) + new_fvfFlags |= D3DFVF_DIFFUSE; + if(geom->get_binding(G_NORMAL) != G_OFF) + new_fvfFlags |= D3DFVF_NORMAL; + if(geom->get_binding(G_TEXCOORD) != G_OFF) + new_fvfFlags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); + } + if(i!=0) { + if(fvfFlags!=new_fvfFlags) { + // all primitives within a geom must use the same FVF type for the DrawPrim api + dxgsg_cat.error() << "error creating vertex buffer, geoms within geomnode require differing vertex data types!!\n"; + exit(1); + } + } else fvfFlags=new_fvfFlags; + } + + if(cNumVerts==0) { + // Never mind. + return (GeomNodeContext *)NULL; + } + + if(cNumVerts>D3DMAXNUMVERTICES) { + dxgsg_cat.error() << "geom node contains more than " << D3DMAXNUMVERTICES << " vertices, cant create 1 vertex buffer\n"; + exit(1); + } + + // Ok, we've got something; use it. + DXGeomNodeContext *dx_gnc = new DXGeomNodeContext(node); + + assert(dx_gnc!=NULL); + + // right now there is a 1-1 correspondence b/w vertbufs and geomnodecontexts. + // later multiple geomnodecontexts will use the same vertbuf + + HRESULT hr; + LPDIRECT3D7 pD3D; + + assert(_d3dDevice!=NULL); + hr=_d3dDevice->GetDirect3D(&pD3D); + assert(!FAILED(hr)); + LPDIRECT3DVERTEXBUFFER7 pD3DVertexBuffer; + DX_DECLARE_CLEAN(D3DVERTEXBUFFERDESC, VBdesc); + + VBdesc.dwCaps = D3DVBCAPS_WRITEONLY; + VBdesc.dwCaps |= _bIsTNLDevice ? 0x0 : D3DVBCAPS_SYSTEMMEMORY; + VBdesc.dwFVF=fvfFlags; + VBdesc.dwNumVertices=cNumVerts; + + hr=pD3D->CreateVertexBuffer(&VBdesc,&pD3DVertexBuffer,0x0); + if(FAILED(hr)) { + dxgsg_cat.error() << "error creating vertex buffer: " << ConvD3DErrorToString(hr) << endl; + delete dx_gnc; + exit(1); + } + + dx_gnc->_pVB = pD3DVertexBuffer; + + if(!_bIsTNLDevice) { + // create VB for ProcessVerts to xform to + + fvfFlags&=~D3DFVF_XYZ; // switch to xformed vert type + fvfFlags&=~D3DFVF_NORMAL; // xformed verts are also lighted, so no normals allowed + fvfFlags|=D3DFVF_XYZRHW; + VBdesc.dwFVF=fvfFlags; + + hr=pD3D->CreateVertexBuffer(&VBdesc,&pD3DVertexBuffer,0x0); + if(FAILED(hr)) { + dxgsg_cat.error() << "error creating xformed vertex buffer: " << ConvD3DErrorToString(hr) << endl; + delete dx_gnc; + exit(1); + } + + dx_gnc->_pXformed_VB = pD3DVertexBuffer; + } + + pD3D->Release(); + + dx_gnc->_num_verts=0; + dx_gnc->_start_index=0; + + LPVOID pVertData=NULL; + DWORD dwVBFlags = DDLOCK_NOOVERWRITE | DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR | + DDLOCK_WAIT | DDLOCK_DISCARDCONTENTS; + + hr=dx_gnc->_pVB->Lock(dwVBFlags,&pVertData,NULL); + if(FAILED(hr)) { + dxgsg_cat.error() << "error locking vertex buffer: " << ConvD3DErrorToString(hr) << endl; + delete dx_gnc; + exit(1); + } + + assert(pVertData!=NULL); + _pCurrentGeomContext = dx_gnc; + _pCurrentGeomContext->_pEndofVertData=(BYTE*)pVertData; + _bDrawPrimDoSetupVertexBuffer = true; + + + for (i = 0; (i < num_geoms); i++) { + dDrawable *drawable1 = node->get_geom(i); + if(!drawable1->is_of_type(Geom::get_class_type())) + continue; + + Geom *geom=DCAST(Geom, drawable1); + assert(geom!=NULL); + + if(geom->is_dynamic()) { + dx_gnc->_other_geoms.push_back(geom); + } else { + dx_gnc->_cached_geoms.push_back(geom); + node->get_geom(i)->draw(this); + } + } + + _bDrawPrimDoSetupVertexBuffer = false; + _pCurrentGeomContext->_pEndofVertData=NULL; + _pCurrentGeomContext = NULL; + + hr=dx_gnc->_pVB->Unlock(); + if(FAILED(hr)) { + dxgsg_cat.error() << "error unlocking vertex buffer: " << ConvD3DErrorToString(hr) << endl; + delete dx_gnc; + exit(1); + } + + assert(cNumVerts==dx_gnc->_num_verts); + + hr=dx_gnc->_pVB->Optimize(_d3dDevice,0x0); + if(FAILED(hr)) { + dxgsg_cat.error() << "error optimizing vertex buffer: " << ConvD3DErrorToString(hr) << endl; + delete dx_gnc; + exit(1); + } + + if(dxgsg_cat.is_spam()) + dxgsg_cat.spam() << "creating vertex buffer of size: " << cNumVerts << endl; + +#if 0 //DO_PSTATS + float num_verts_after = + _vertices_tristrip_pcollector.get_level() + + _vertices_trifan_pcollector.get_level() + + _vertices_tri_pcollector.get_level() + + _vertices_other_pcollector.get_level(); + float num_verts = num_verts_after - num_verts_before; + ggnc->_num_verts = (int)(num_verts + 0.5); +#endif + + bool inserted = mark_prepared_geom_node(dx_gnc); + + // If this assertion fails, the same GeomNode was prepared twice, + // which shouldn't be possible, since the GeomNode itself should + // detect this. + nassertr(inserted, NULL); + + return dx_gnc; +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::draw_geom_node +// Access: Public, Virtual +// Description: Draws a GeomNode previously indicated by a call to +// prepare_geom_node(). +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +draw_geom_node(GeomNode *node, GeomNodeContext *gnc) { + + uint i,num_geoms = node->get_num_geoms(); + + if (gnc == (GeomNodeContext *)NULL) { + + // We don't have a saved context; just draw the GeomNode in + // immediate mode. + for (i = 0; i < num_geoms; i++) { + node->get_geom(i)->draw(this); + } + return; + } + + // We do have a saved context; use it. + add_to_geom_node_record(gnc); + DXGeomNodeContext *dx_gnc = DCAST(DXGeomNodeContext, gnc); + + #ifdef _DEBUG + assert(dx_gnc->_pVB!=NULL); + assert((!_bIsTNLDevice)==(dx_gnc->_pXformed_VB!=NULL)); + #endif + + if(!_bIsTNLDevice) { + HRESULT hr; + + DWORD PVOp=D3DVOP_CLIP | D3DVOP_TRANSFORM | D3DVOP_EXTENTS; + + D3DVERTEXBUFFERDESC VBdesc; + VBdesc.dwSize=sizeof(VBdesc); + hr=dx_gnc->_pVB->GetVertexBufferDesc(&VBdesc); // would be useful to keep fvf in vertbuf struct to avoid having to do this + if(FAILED(hr)) { + dxgsg_cat.error() << "error in getvbdesc: " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(_lighting_enabled && (VBdesc.dwFVF & D3DFVF_NORMAL)) { + PVOp|=D3DVOP_LIGHT; + } + + hr=dx_gnc->_pXformed_VB->ProcessVertices(PVOp,0,dx_gnc->_num_verts,dx_gnc->_pVB,0,_d3dDevice,0x0); + if(FAILED(hr)) { + dxgsg_cat.error() << "error in ProcessVertices: " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // disable clipping, since VB is already xformed and clipped + if(_clipping_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, false); + } + + // assume we need gouraud for now. we can make this more complex to select flat conditionally later + set_shademode(D3DSHADE_GOURAUD); + int cur_startvert=dx_gnc->_start_index; + + for (i = 0; i < dx_gnc->_cached_geoms.size(); i++) { + // I think we can just draw them directly? since cant account for issued stuff (since + // its already encoded in the VB), and we can set the renderstates here (e.g. gouraud mode) + // dx_gnc->_cached_geoms[i]->draw(this); + + DPInfo *dpi=&dx_gnc->_PrimInfo[i]; + + LPDIRECT3DVERTEXBUFFER7 pVB; + if(_bIsTNLDevice) { + pVB=dx_gnc->_pVB; + } else { + pVB=dx_gnc->_pXformed_VB; + } + + HRESULT hr = _d3dDevice->DrawPrimitiveVB(dpi->primtype,pVB,cur_startvert,dpi->nVerts,0x0); + TestDrawPrimFailure(DrawPrim,hr,_pDD,dpi->nVerts,0); + + cur_startvert+=dpi->nVerts; + } + + if((!_bIsTNLDevice) && _clipping_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, true); + + // Also draw all the dynamic Geoms. + for (i = 0; i < dx_gnc->_other_geoms.size(); i++) { + dx_gnc->_other_geoms[i]->draw(this); + } + +#if 0 //def DO_PSTATS + DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector)); + _vertices_display_list_pcollector.add_level(dx_gnc->_num_verts); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian::release_geom_node +// Access: Public, Virtual +// Description: Frees the resources previously allocated via a call +// to prepare_geom_node(), including deleting the +// GeomNodeContext itself, if necessary. +//////////////////////////////////////////////////////////////////// +void DXGraphicsStateGuardian:: +release_geom_node(GeomNodeContext *gnc) { + if (gnc != (GeomNodeContext *)NULL) { + DXGeomNodeContext *dx_gnc = DCAST(DXGeomNodeContext, gnc); + + bool erased = unmark_prepared_geom_node(dx_gnc); + + // If this assertion fails, a GeomNode was released that hadn't + // been prepared (or a GeomNode was released twice). + nassertv(erased); + + dx_gnc->_node->clear_gsg(this); + delete dx_gnc; // should release vertex buffer + } +} diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h new file mode 100644 index 0000000000..bba968b4f4 --- /dev/null +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -0,0 +1,494 @@ +// Filename: dxGraphicsStateGuardian.h +// Created by: mike (02Feb99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DXGRAPHICSSTATEGUARDIAN8_H +#define DXGRAPHICSSTATEGUARDIAN8_H + +//#define GSG_VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dxGeomNodeContext8.h" +#include "dxTextureContext8.h" + +extern char * ConvD3DErrorToString(const HRESULT &error); // defined in wdxGraphicsPipe.cxx + +class PlaneNode; +class Light; + +#ifdef GSG_VERBOSE +ostream &output_gl_enum(ostream &out, GLenum v); +INLINE ostream &operator << (ostream &out, GLenum v) { + return output_gl_enum(out, v); +} +#endif + +#ifdef DO_PSTATS +#define DO_PSTATS_STUFF(XX) XX; +#else +#define DO_PSTATS_STUFF(XX) +#endif + +#define DX_DECLARE_CLEAN(type, var) \ + type var; \ + ZeroMemory(&var, sizeof(type)); \ + var.dwSize = sizeof(type); + +// #define DEBUG_RELEASES + +// this is bDoDownToZero argument to RELEASE() +#define RELEASE_DOWN_TO_ZERO true + +#ifdef DEBUG_RELEASES +#define RELEASE(OBJECT,MODULE,DBGSTR,bDoDownToZero) \ + if(((OBJECT)!=NULL)&&(!IsBadWritePtr((OBJECT),4))) { \ + refcnt = (OBJECT)->Release(); \ + MODULE##_cat.debug() << DBGSTR << " released, refcnt = " << refcnt << endl; \ + if((bDoDownToZero) && (refcnt>0)) { \ + MODULE##_cat.warning() << DBGSTR << " released but still has a non-zero refcnt(" << refcnt << "), multi-releasing it down to zero!\n"; \ + do { \ + refcnt = (OBJECT)->Release(); \ + } while(refcnt>0); \ + } \ + (OBJECT) = NULL; \ + } else { \ + MODULE##_cat.debug() << DBGSTR << " not released, ptr == NULL" << endl; \ + } + +#define PRINTREFCNT(OBJECT,STR) { (OBJECT)->AddRef(); dxgsg_cat.debug() << STR << " refcnt = " << (OBJECT)->Release() << endl; } +#else +#define RELEASE(OBJECT,MODULE,DBGSTR,bDoDownToZero) \ + if(((OBJECT)!=NULL)&&(!IsBadWritePtr((OBJECT),4))) { \ + refcnt=(OBJECT)->Release(); \ + if((bDoDownToZero) && (refcnt>0)) { \ + MODULE##_cat.warning() << DBGSTR << " released but still has a non-zero refcnt(" << refcnt << "), multi-releasing it down to zero!\n"; \ + do { \ + refcnt = (OBJECT)->Release(); \ + } while(refcnt>0); \ + } \ + (OBJECT) = NULL; \ + } + +#define PRINTREFCNT(OBJECT,STR) +#endif + +//#if defined(NOTIFY_DEBUG) || defined(DO_PSTATS) +#ifdef _DEBUG +// 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 : DXGraphicsStateGuardian +// Description : A GraphicsStateGuardian specialized for rendering +// into DX. There should be no DX calls +// outside of this object. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX DXGraphicsStateGuardian : public GraphicsStateGuardian { + friend class wdxGraphicsWindow; + friend class DXTextureContext; + +public: + DXGraphicsStateGuardian(GraphicsWindow *win); + ~DXGraphicsStateGuardian(); + + virtual void reset(); + + virtual void clear(const RenderBuffer &buffer); + virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region); + + virtual void prepare_display_region(); + + virtual void render_frame(); + virtual void render_scene(Node *root, ProjectionNode *projnode); + virtual void render_subgraph(RenderTraverser *traverser, + Node *subgraph, ProjectionNode *projnode, + const AllTransitionsWrapper &net_trans); + virtual void render_subgraph(RenderTraverser *traverser, + Node *subgraph, + const AllTransitionsWrapper &net_trans); + + 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 GeomNodeContext *prepare_geom_node(GeomNode *node); + virtual void draw_geom_node(GeomNode *node, GeomNodeContext *gnc); + virtual void release_geom_node(GeomNodeContext *gnc); + + virtual TextureContext *prepare_texture(Texture *tex); + virtual void apply_texture(TextureContext *tc); + virtual void release_texture(TextureContext *tc); + + virtual void copy_texture(TextureContext *tc, const DisplayRegion *dr); + virtual void copy_texture(TextureContext *tc, const DisplayRegion *dr, + const RenderBuffer &rb); + virtual void draw_texture(TextureContext *tc, const DisplayRegion *dr); + virtual void draw_texture(TextureContext *tc, const DisplayRegion *dr, + const RenderBuffer &rb); + + virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb); + virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb, + const DisplayRegion *dr); + + virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr); + virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr, + const RenderBuffer &rb); + virtual void draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr, + const NodeTransitions& na=NodeTransitions()); + virtual void draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr, + const RenderBuffer &rb, + const NodeTransitions& na=NodeTransitions()); + + virtual void apply_material(const Material *material); + virtual void apply_fog(Fog *fog); + + virtual void apply_light(PointLight* light); + virtual void apply_light(DirectionalLight* light); + virtual void apply_light(Spotlight* light); + virtual void apply_light(AmbientLight* light); + + virtual void issue_transform(const TransformTransition *attrib); + virtual void issue_tex_matrix(const TexMatrixTransition *attrib); + virtual void issue_color(const ColorTransition *attrib); + virtual void issue_color_transform(const ColorMatrixTransition *); + virtual void issue_alpha_transform(const AlphaTransformTransition *); + virtual void issue_texture(const TextureTransition *attrib); + virtual void issue_light(const LightTransition *attrib); + virtual void issue_material(const MaterialTransition *attrib); + virtual void issue_render_mode(const RenderModeTransition *attrib); + virtual void issue_color_blend(const ColorBlendTransition *attrib); + virtual void issue_texture_apply(const TextureApplyTransition *attrib); + virtual void issue_color_mask(const ColorMaskTransition *attrib); + virtual void issue_depth_test(const DepthTestTransition *attrib); + virtual void issue_depth_write(const DepthWriteTransition *attrib); + virtual void issue_tex_gen(const TexGenTransition *attrib); + virtual void issue_cull_face(const CullFaceTransition *attrib); + virtual void issue_stencil(const StencilTransition *attrib); + virtual void issue_clip_plane(const ClipPlaneTransition *attrib); + virtual void issue_transparency(const TransparencyTransition *attrib); + virtual void issue_fog(const FogTransition *attrib); + virtual void issue_linesmooth(const LinesmoothTransition *attrib); + + virtual bool wants_normals(void) const; + virtual bool wants_texcoords(void) const; + virtual bool wants_colors(void) const; + + virtual void begin_decal(GeomNode *base_geom, AllTransitionsWrapper &attrib); + virtual void end_decal(GeomNode *base_geom); + + INLINE float compute_distance_to(const LPoint3f &point) const; + virtual void set_color_clear_value(const Colorf& value); + +public: + // recreate_tex_callback needs these to be public + LPDIRECT3DDEVICE7 _d3dDevice; + LPDDPIXELFORMAT _pTexPixFmts; + int _cNumTexPixFmts; + +protected: + void free_pointers(); // free local internal buffers + void free_dxgsg_objects(void); // free the DirectX objects we create + virtual PT(SavedFrameBuffer) save_frame_buffer(const RenderBuffer &buffer, + CPT(DisplayRegion) dr); + virtual void restore_frame_buffer(SavedFrameBuffer *frame_buffer); + + void set_draw_buffer(const RenderBuffer &rb); + void set_read_buffer(const RenderBuffer &rb); + + void bind_texture(TextureContext *tc); + + // for storage of the flexible vertex format + char *_pCurFvfBufPtr,*_pFvfBufBasePtr; + INLINE void add_to_FVFBuf(void *data, size_t bytes) ; + WORD *_index_buf; // base of malloced array + + bool _dx_ready; + HRESULT _last_testcooplevel_result; + bool _bIsTNLDevice; + LPDIRECTDRAWSURFACE7 _back; + LPDIRECTDRAWSURFACE7 _zbuf; + LPDIRECT3D7 _d3d; + LPDIRECTDRAWSURFACE7 _pri; + LPDIRECTDRAW7 _pDD; + + RECT _view_rect; + RECT clip_rect; + HDC _front_hdc; + DXTextureContext *_pCurTexContext; + + bool _bTransformIssued; // decaling needs to tell when a transform has been issued + D3DMATRIX _SavedTransform; + + RenderBuffer::Type _cur_read_pixel_buffer; // source for copy_pixel_buffer operation + + D3DDEVICEDESC7 _D3DDevDesc; + + void GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize, + void *pIndexSpace,DWORD dwIndexSpaceByteSize, + D3DVECTOR *pCenter, float fRadius, + DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz, + DWORD *pNumVertices,DWORD *pNumIndices,DWORD fvfFlags,DWORD dwVertSize); + HRESULT RestoreAllVideoSurfaces(void); + HRESULT RecreateAllVideoSurfaces(void); + HRESULT DeleteAllVideoSurfaces(void); + +/* + 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_clip_plane(int clip_plane, bool val); + INLINE void enable_fog(bool val); + INLINE void enable_zwritemask(bool val); + INLINE void set_shademode(D3DSHADEMODE val); + + INLINE D3DTEXTUREADDRESS get_texture_wrap_mode(Texture::WrapMode wm) const; + INLINE D3DCMPFUNC get_depth_func_type(DepthTestProperty::Mode m) const; + INLINE D3DFOGMODE get_fog_mode_type(Fog::Mode m) const; + + INLINE D3DCMPFUNC get_stencil_func_type(StencilProperty::Mode m) const; + INLINE D3DSTENCILOP get_stencil_action_type(StencilProperty::Action a) 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, DWORD ref); + INLINE void call_dxBlendFunc(D3DBLEND sfunc, D3DBLEND dfunc); + INLINE void enable_lighting(bool val); + INLINE void enable_dither(bool val); + INLINE void enable_stencil_test(bool val); + bool enable_light(int light, 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 _curFVFflags; + DWORD _perPrim,_perVertex,_perComp; // these hold DrawLoopFlags bitmask values + + bool _issued_color_enabled; // WBD ADDED + bool _enable_all_color; + Colorf _issued_color; // WBD ADDED + D3DCOLOR _issued_color_D3DCOLOR; // WBD ADDED + D3DCOLOR _d3dcolor_clear_value; + + D3DSHADEMODE _CurShadeMode; + + bool _bDrawPrimDoSetupVertexBuffer; // if true, draw methods just copy vertex data into pCurrentGeomContext + DXGeomNodeContext *_pCurrentGeomContext; // used in vertex buffer setup + + // 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=D3DRENDERSTATE_FOGVERTEXMODE, + PerPixelFog=D3DRENDERSTATE_FOGTABLEMODE + } DxgsgFogType; + DxgsgFogType _doFogType; + bool _fog_enabled; +/* + TODO: cache fog state + float _fog_start; + float _fog_end; + float _fog_density; + float _fog_color; +*/ + float _alpha_func_ref; + D3DCMPFUNC _alpha_func; + + D3DBLEND _blend_source_func; + D3DBLEND _blend_dest_func; + + bool _line_smooth_enabled; + bool* _light_enabled; // bool[_max_lights] + bool _color_material_enabled; + bool _lighting_enabled; + bool _lighting_enabled_this_frame; + bool _texturing_enabled; + bool _clipping_enabled; + bool _dither_enabled; + bool _stencil_test_enabled; + bool* _clip_plane_enabled; // bool[_max_clip_planes] + bool _blend_enabled; + bool _depth_test_enabled; + bool _depth_write_enabled; + bool _alpha_test_enabled; + int _decal_level; + + RenderModeProperty::Mode _current_fill_mode; //poinr/wireframe/solid + + GraphicsChannel *_panda_gfx_channel; // cache the 1 channel dx supports + + // Cur Texture State + TextureApplyProperty::Mode _CurTexBlendMode; + Texture::FilterType _CurTexMagFilter,_CurTexMinFilter; + DWORD _CurTexAnisoDegree; + Texture::WrapMode _CurTexWrapModeU,_CurTexWrapModeV; + + PTA(Light*) _available_light_ids; + int _max_lights; + bool* _cur_light_enabled; + int _cur_light_id; + Colorf _cur_ambient_light; + LMatrix4f _current_projection_mat; + int _projection_mat_stack_count; + + PTA(PlaneNode*) _available_clip_plane_ids; + int _max_clip_planes; + bool* _cur_clip_plane_enabled; + int _cur_clip_plane_id; + + CPT(DisplayRegion) _actual_display_region; + + // Color/Alpha Matrix Transition stuff + INLINE void transform_color(Colorf &InColor,D3DCOLOR &OutColor); + bool _color_transform_required; // _color_transform_enabled || _alpha_transform_enabled + bool _color_transform_enabled; + bool _alpha_transform_enabled; + LMatrix4f _current_color_mat; + float _current_alpha_offset; + float _current_alpha_scale; + + // vars for frames/sec meter + DWORD _start_time; + DWORD _start_frame_count; + DWORD _cur_frame_count; + float _current_fps; + DWORD *_fpsmeter_verts; + DWORD _fpsmeter_fvfflags; + LPDIRECTDRAWSURFACE7 _fpsmeter_font_surf; + float _fps_u_usedwidth,_fps_v_usedheight; // fraction of fps font texture actually used + DWORD _fps_vertexsize; // size of verts used to render fps meter + void SetFPSMeterPosition(RECT &view_rect); + void FillFPSMeterTexture(void); + +public: + static GraphicsStateGuardian* + make_DXGraphicsStateGuardian(const FactoryParams ¶ms); + + static TypeHandle get_class_type(void); + static void init_type(void); + virtual TypeHandle get_type(void) const; + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + + LPDIRECT3DDEVICE7 GetD3DDevice() { return _d3dDevice; } + LPDIRECTDRAW7 GetDDInterface() { return _pDD; } + LPDIRECTDRAWSURFACE7 GetBackBuffer() { return _back; } + LPDIRECTDRAWSURFACE7 GetZBuffer() { return _zbuf; } + INLINE void Set_HDC(HDC hdc) { _front_hdc = hdc; } + void adjust_view_rect(int x, int y); + INLINE void SetDXReady(bool stat) { _dx_ready = stat; } + INLINE bool GetDXReady(void) { return _dx_ready;} + void DXGraphicsStateGuardian::SetTextureBlendMode(TextureApplyProperty::Mode TexBlendMode,bool bJustEnable); + + void dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled); + + #define DO_REACTIVATE_WINDOW true + bool CheckCooperativeLevel(bool bDoReactivateWindow = false); + + void dx_setup_after_resize(RECT viewrect,HWND mwindow) ; + void show_frame(); + void show_full_screen_frame(); + void show_windowed_frame(); + void dx_init( LPDIRECTDRAW7 context, + LPDIRECTDRAWSURFACE7 pri, + LPDIRECTDRAWSURFACE7 back, + LPDIRECTDRAWSURFACE7 zbuf, + LPDIRECT3D7 d3d, + LPDIRECT3DDEVICE7 d3dDevice, + RECT viewrect); + + friend HRESULT CALLBACK EnumTexFmtsCallback( LPDDPIXELFORMAT pddpf, VOID* param ); + +private: + static TypeHandle _type_handle; +}; + +#define ISPOW2(X) (((X) & ((X)-1))==0) + +#include "dxGraphicsStateGuardian8.I" + +#endif + diff --git a/panda/src/dxgsg8/dxSavedFrameBuffer8.I b/panda/src/dxgsg8/dxSavedFrameBuffer8.I new file mode 100644 index 0000000000..d621f689f2 --- /dev/null +++ b/panda/src/dxgsg8/dxSavedFrameBuffer8.I @@ -0,0 +1,39 @@ +// Filename: dxSavedFrameBuffer.I +// Created by: drose (06Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: DXSavedFrameBuffer::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE DXSavedFrameBuffer:: +DXSavedFrameBuffer(const RenderBuffer &buffer, CPT(DisplayRegion) dr) : + SavedFrameBuffer(buffer, dr) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: DXSavedFrameBuffer::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE DXSavedFrameBuffer:: +~DXSavedFrameBuffer() { +} + diff --git a/panda/src/dxgsg8/dxSavedFrameBuffer8.cxx b/panda/src/dxgsg8/dxSavedFrameBuffer8.cxx new file mode 100644 index 0000000000..cbc95c2735 --- /dev/null +++ b/panda/src/dxgsg8/dxSavedFrameBuffer8.cxx @@ -0,0 +1,21 @@ +// Filename: dxSavedFrameBuffer.cxx +// Created by: drose (06Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "dxSavedFrameBuffer8.h" + +TypeHandle DXSavedFrameBuffer::_type_handle; diff --git a/panda/src/dxgsg8/dxSavedFrameBuffer8.h b/panda/src/dxgsg8/dxSavedFrameBuffer8.h new file mode 100644 index 0000000000..36e0548fbf --- /dev/null +++ b/panda/src/dxgsg8/dxSavedFrameBuffer8.h @@ -0,0 +1,64 @@ +// Filename: dxSavedFrameBuffer.h +// Created by: drose (06Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DXSAVEDFRAMEBUFFER8_H +#define DXSAVEDFRAMEBUFFER8_H + +#include + +#include +#include +#include +#include + + +//////////////////////////////////////////////////////////////////// +// Class : DXSavedFrameBuffer +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX DXSavedFrameBuffer : public SavedFrameBuffer { +public: + INLINE DXSavedFrameBuffer(const RenderBuffer &buffer, + CPT(DisplayRegion) dr); + INLINE ~DXSavedFrameBuffer(); + + PT(Texture) _back_rgba; + PT(PixelBuffer) _depth; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + SavedFrameBuffer::init_type(); + register_type(_type_handle, "DXSavedFrameBuffer", + SavedFrameBuffer::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 "dxSavedFrameBuffer8.I" + +#endif + diff --git a/panda/src/dxgsg8/dxTextureContext8.cxx b/panda/src/dxgsg8/dxTextureContext8.cxx new file mode 100644 index 0000000000..8598bf86b7 --- /dev/null +++ b/panda/src/dxgsg8/dxTextureContext8.cxx @@ -0,0 +1,1915 @@ +// Filename: dxTextureContext.cxx +// Created by: drose (07Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include +#include +#include "dxTextureContext8.h" +#include "config_dxgsg8.h" +#include "dxGraphicsStateGuardian8.h" +#include "pnmImage.h" + +//#define FORCE_16bpp_1555 + +typedef enum { + None,Conv32to32,Conv32to32_NoAlpha,Conv32to24,Conv32to16_0555, + Conv32to16_1555,Conv32to16_0565,Conv32to16_4444,Conv24to32,Conv24to24, + Conv24to16_0555,Conv24to16_0565,ConvLum16to16_1555,ConvLum16to16_4444, + ConvLum16to32,ConvLum16to16,ConvLum8to8,ConvLum8to24,ConvLum8to32,ConvLum8to16_0555,ConvLum8to16_0565, + ConvAlpha8to16_4444,ConvAlpha8to32,ConvAlpha8to8 +} ConversionType; + +#ifndef NDEBUG +char *ConvNameStrs[] = {"None","Conv32to32","Conv32to32_NoAlpha","Conv32to24","Conv32to16_0555", + "Conv32to16_1555","Conv32to16_0565","Conv32to16_4444","Conv24to32","Conv24to24", + "Conv24to16_0555","Conv24to16_0565","ConvLum16to16_1555","ConvLum16to16_4444", + "ConvLum16to32","ConvLum16to16","ConvLum8to8","ConvLum8to24","ConvLum8to32", + "ConvLum8to16_0555","ConvLum8to16_0565","ConvAlpha8to16_4444","ConvAlpha8to32","ConvAlpha8to8" +}; +#endif + +char *PandaFilterNameStrs[] = {"FT_nearest","FT_linear","FT_nearest_mipmap_nearest","FT_linear_mipmap_nearest", + "FT_nearest_mipmap_linear", "FT_linear_mipmap_linear" +}; + + +TypeHandle DXTextureContext::_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: DXTextureContext::get_bits_per_pixel +// Access: Protected +// Description: Maps from the PixelBuffer's Format symbols +// to bpp. returns # of alpha bits +// Note: PixelBuffer's format indicates REQUESTED final format, +// not the stored format, which is indicated by pixelbuffer type +//////////////////////////////////////////////////////////////////// + +unsigned int DXTextureContext:: +get_bits_per_pixel(PixelBuffer::Format format, int *alphbits) { + *alphbits = 0; // assume no alpha bits + switch(format) { + case PixelBuffer::F_alpha: + *alphbits = 8; + return 8; + case PixelBuffer::F_color_index: + case PixelBuffer::F_red: + case PixelBuffer::F_green: + case PixelBuffer::F_blue: + case PixelBuffer::F_rgb332: + case PixelBuffer::F_luminance_alphamask: + *alphbits = 1; + return 16; + case PixelBuffer::F_luminance_alpha: + *alphbits = 8; + return 16; + case PixelBuffer::F_luminance: + return 8; + case PixelBuffer::F_rgba4: + *alphbits = 4; + return 16; + case PixelBuffer::F_rgba5: + *alphbits = 1; + return 16; + case PixelBuffer::F_depth_component: + case PixelBuffer::F_rgb5: + return 16; + case PixelBuffer::F_rgb8: + case PixelBuffer::F_rgb: + return 24; + case PixelBuffer::F_rgba8: + case PixelBuffer::F_rgba: + *alphbits = 8; + return 32; + case PixelBuffer::F_rgbm: + *alphbits = 1; + return 32; + case PixelBuffer::F_rgb12: + return 36; + case PixelBuffer::F_rgba12: + *alphbits = 12; + return 48; + } + return 8; +} + +HRESULT ConvertPixBuftoDDSurf(ConversionType ConvNeeded,BYTE *pbuf,LPDIRECTDRAWSURFACE7 pDDSurf) { + HRESULT hr; + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); + + if(IsBadWritePtr(pDDSurf,sizeof(DWORD))) { + dxgsg_cat.error() << "ConvertPixBuftoDDSurf failed: bad pDDSurf ptr value (" << ((void*)pDDSurf) << ")\n"; + exit(1); + } + + if(FAILED( hr = pDDSurf->Lock( NULL, &ddsd, DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL ))) { + dxgsg_cat.error() << "CreateTexture failed: _surface->Lock() failed on texture! hr = " << ConvD3DErrorToString(hr) << "\n"; + return hr; + } + //pbuf contains raw ARGB in PixelBuffer byteorder + + DWORD lPitch = ddsd.lPitch; + BYTE* pDDSurfBytes = (BYTE*)ddsd.lpSurface; + DWORD dwOrigWidth=ddsd.dwWidth,dwOrigHeight=ddsd.dwHeight; + + switch(ConvNeeded) { + case Conv32to32: + case Conv32to32_NoAlpha: { + + DWORD *pSrcWord = (DWORD *) pbuf; + DWORD *pDstWord; + DWORD dwAlphaMaskOff = (ConvNeeded==Conv32to32_NoAlpha) ? 0x00FFFFFF : 0xFFFFFFFF; + + for(DWORD y=0; y>24)); // unsigned >>, no need to & + b = (BYTE)((dwPixel>>16)&0x000000ff); + g = (BYTE)((dwPixel>> 8)&0x000000ff); + r = (BYTE)((dwPixel )&0x000000ff); + + *pDstWord = (a << 24) | (r << 16)| (g << 8) | b; +#else + BYTE r,b; + // simpler: just swap r & b + b = (BYTE)((dwPixel>>16)&0x000000ff); + r = (BYTE)((dwPixel )&0x000000ff); + *pDstWord = ((dwPixel & 0xff00ff00) | (r<<16) | b) & dwAlphaMaskOff; +#endif + } + } + break; + } + + case Conv32to16_1555: + case Conv32to16_0555: { + DWORD *pSrcWord = (DWORD *) pbuf; + WORD *pDstWord; + DWORD dwAlphaMaskOff = (ConvNeeded==Conv32to16_0555) ? 0x7FFF : 0xFFFF; + + assert(ddsd.ddpfPixelFormat.dwRBitMask==0x7C00); + // for some reason, bits are 'in-order' when converting to 16bit + + // just handle 1/15 alpha/rgb + for(DWORD y=0; y>16) & 0x00008000); // just copy high bit + + // just look at most-signf-bit for alpha. (alternately, could + // convert any non-zero alpha to full transparent) + + b = (BYTE)((dwPixel>>16) & 0x000000ff) >> 3; + g = (BYTE)((dwPixel>> 8) & 0x000000ff) >> 3; + r = (BYTE)((dwPixel ) & 0x000000ff) >> 3; + + // code truncates 8 bit values to 5 bit (or 1 for alpha) + + *pDstWord = (abit | (r << 10)| (g << 5) | b) & dwAlphaMaskOff; + } + } + break; + } + + case Conv32to16_0565: { // could merge this w/above case, but whatever + DWORD *pSrcWord = (DWORD *) pbuf; + WORD *pDstWord; + + assert(ddsd.ddpfPixelFormat.dwRBitMask==0xF800); + // for some reason, bits are 'in-order' when converting to 16bit + + // just handle 1/15 alpha/rgb + for(DWORD y=0; y>16) & 0x000000ff) >> 3; + g = (BYTE)((dwPixel>> 8) & 0x000000ff) >> 2; + r = (BYTE)((dwPixel ) & 0x000000ff) >> 3; + + // code truncates 8 bit values to 5 bit (or 1 for alpha) + + *pDstWord = ((r << 11)| (g << 5) | b); + } + } + break; + } + + + case Conv32to24: { + + DWORD *pSrcWord = (DWORD *) pbuf; + BYTE *pDstWord; + + for(DWORD y=0; y>16) & 0x000000ff); + g = (BYTE)((dwPixel>> 8) & 0x000000ff); + r = (BYTE)((dwPixel ) & 0x000000ff); + + *pDstWord = r; + *(pDstWord+1) = g; + *(pDstWord+2) = b; + } + } + break; + } + + + case Conv32to16_4444: { + DWORD *pSrcWord = (DWORD *) pbuf; + WORD *pDstWord; + + assert(ddsd.ddpfPixelFormat.dwRGBAlphaBitMask==0xf000); // assumes ARGB + assert(ddsd.ddpfPixelFormat.dwRBitMask==0x0f00); // assumes ARGB + + for(DWORD y=0; y>24)) >> 4; + b = (BYTE)((dwPixel>>16) & 0x000000ff) >> 4; + g = (BYTE)((dwPixel>> 8) & 0x000000ff) >> 4; + r = (BYTE)((dwPixel ) & 0x000000ff) >> 4; + + *pDstWord = (a << 12) | (r << 8)| (g << 4) | b; + } + } + break; + } + + + case Conv24to24: { + + BYTE *pSrcWord = (BYTE *) pbuf; + BYTE *pDstWord; + + for(DWORD y=0; y> 3; + g = *(pSrcWord+1) >> 3; + b = *(pSrcWord+2) >> 3; + + // code truncates 8 bit values to 5 bit, leaves high bit as 0 + + *pDstWord = (r << 10)| (g << 5) | b; + } + } + break; + } + + case Conv24to16_0565: { + BYTE *pSrcWord = (BYTE *) pbuf; + WORD *pDstWord; + + assert(ddsd.ddpfPixelFormat.dwRBitMask==0xF800); + // for some reason, bits are 'in-order' when converting to 16bit + + for(DWORD y=0; y> 3; + g = *(pSrcWord+1) >> 2; + b = *(pSrcWord+2) >> 3; + + // code truncates 8 bit values to 5 bit, leaves high bit as 0 + + *pDstWord = (r << 11)| (g << 5) | b; + } + } + break; + } + + case Conv24to32: { + + BYTE *pSrcWord = (BYTE *) pbuf; + DWORD *pDstWord; + + for(DWORD y=0; y> 8; + r = dwPixel & 0xFF; + + *pDstWord = (a<<24)| (r << 16)| (r << 8) | r; + } + } + break; + } + + case ConvLum16to16_4444: { + WORD *pSrcWord = (WORD *) pbuf; + WORD *pDstWord; + + assert(ddsd.ddpfPixelFormat.dwRGBAlphaBitMask==0xf000); // assumes ARGB + + for(DWORD y=0; y>8) >> 4; + r = (BYTE)(dwPixel & 0x000000ff) >> 4; + + *pDstWord = (a << 12) | (r << 8)| (r << 4) | r; + } + } + break; + } + + case ConvLum16to16_1555: { + WORD *pSrcWord = (WORD *) pbuf; + WORD *pDstWord; + + assert(ddsd.ddpfPixelFormat.dwRGBAlphaBitMask==0x8000); // assumes ARGB + + for(DWORD y=0; y> 3; + + *pDstWord = (dwPixel & 0x8000) | (r << 10)| (r << 5) | r; + } + } + break; + } + + case ConvLum16to16: { + // AL bytes are in same order + CopyMemory(pDDSurfBytes,pbuf,dwOrigWidth*dwOrigHeight*2); + break; + } + + case ConvLum8to16_0565: + case ConvLum8to16_0555: { + BYTE *pSrcWord = (BYTE *) pbuf; + WORD *pDstWord; + DWORD FarShift,OrVal,MiddleRoundShift; + + if(ConvNeeded==ConvLum8to16_0555) { + FarShift=10; OrVal=0x8000; // turn on alpha bit, just in case + MiddleRoundShift = 3; + assert(ddsd.ddpfPixelFormat.dwRBitMask==0x7C00); + } else { + FarShift=11; OrVal=0x0; + MiddleRoundShift = 2; + assert(ddsd.ddpfPixelFormat.dwRBitMask==0xF800); + } + + for(DWORD y=0; y> 3; + GrnVal = (BYTE) dwPixel >> MiddleRoundShift; + + // code truncates 8 bit values to 5 bit (set alpha=1 for opaque) + + *pDstWord = ((r << FarShift)| (GrnVal << 5) | r) | OrVal; + } + } + break; + } + + case ConvLum8to8: { + CopyMemory(pDDSurfBytes,pbuf,dwOrigWidth*dwOrigHeight); + break; + } + + case ConvLum8to32: { + + // this is kind of a waste of space, but we trade it for lum resolution + BYTE *pSrcWord = (BYTE *) pbuf; + DWORD *pDstWord; + + for(DWORD y=0; y>4); + *pDstWord = (a << 12) | 0x0FFF; // OR alpha with full white + } + } + break; + } + + default: + dxgsg_cat.error() << "CreateTexture failed! unhandled texture conversion type: "<< ConvNeeded <<" \n"; + pDDSurf->Unlock(NULL); + return E_INVALIDARG; + } + + pDDSurf->Unlock(NULL); + + return S_OK; +} + +HRESULT ConvertDDSurftoPixBuf(PixelBuffer *pixbuf,LPDIRECTDRAWSURFACE7 pDDSurf) { + + HRESULT hr; + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); + + DWORD dwNumComponents=pixbuf->get_num_components(); + + assert(pixbuf->get_component_width()==sizeof(BYTE)); // cant handle anything else now + assert(pixbuf->get_image_type()==PixelBuffer::T_unsigned_byte); // cant handle anything else now + assert((dwNumComponents==3) || (dwNumComponents==4)); // cant handle anything else now + + BYTE *pbuf=pixbuf->_image.p(); + + if(IsBadWritePtr(pDDSurf,sizeof(DWORD))) { + dxgsg_cat.error() << "ConvertDDSurftoPixBuf failed: bad pDDSurf ptr value (" << ((void*)pDDSurf) << ")\n"; + exit(1); + } + + if(FAILED( hr = pDDSurf->Lock( NULL, &ddsd, DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL ))) { + dxgsg_cat.error() << "ConvertDDSurftoPixBuf Lock() failed! hr = " << ConvD3DErrorToString(hr) << "\n"; + return hr; + } + + DWORD dwXWindowOffset=0,dwYWindowOffset=0; + DWORD dwCopyWidth=ddsd.dwWidth,dwCopyHeight=ddsd.dwHeight; + + // get window offset so we know where to start grabbing pixels + LPDIRECTDRAWCLIPPER pDDClipper; + hr = pDDSurf->GetClipper(&pDDClipper); + +#ifdef _DEBUG + if(FAILED(hr) && !((hr == DDERR_NOCLIPPERATTACHED) && dx_full_screen)) { + dxgsg_cat.error() << "ConvertDDSurftoPixBuf GetClipper failed! hr = " << ConvD3DErrorToString(hr) << "\n"; + return hr; + } +#endif + + if(hr==S_OK) { + HWND hWin; + + if(FAILED(hr = pDDClipper->GetHWnd(&hWin))) { + dxgsg_cat.error() << "ConvertDDSurftoPixBuf GetHwnd failed! hr = " << ConvD3DErrorToString(hr) << "\n"; + return hr; + } + + RECT view_rect; + GetClientRect( hWin, &view_rect ); + ClientToScreen( hWin, (POINT*)&view_rect.left ); + ClientToScreen( hWin, (POINT*)&view_rect.right ); + + dwXWindowOffset=view_rect.left; + dwYWindowOffset=view_rect.top; + dwCopyWidth=view_rect.right-view_rect.left; + dwCopyHeight=view_rect.bottom-view_rect.top; + + pDDClipper->Release(); // dec ref cnt + } + + //make sure there's enough space in the pixbuf, its size must match (especially xsize) + // or scanlines will be too long + + if(!((dwCopyWidth==pixbuf->get_xsize()) && (dwCopyHeight<=pixbuf->get_ysize()))) { + pDDSurf->Unlock(NULL); + assert(0); + dxgsg_cat.error() << "ConvertDDSurftoPixBuf, PixBuf incorrect size to hold display surface!\n"; + return E_FAIL; + } + + // others not handled yet + assert((ddsd.ddpfPixelFormat.dwRGBBitCount==32)||(ddsd.ddpfPixelFormat.dwRGBBitCount==16)||(ddsd.ddpfPixelFormat.dwRGBBitCount==24)); + + //pbuf contains raw ARGB in PixelBuffer byteorder + + DWORD lPitch = ddsd.lPitch; + BYTE* pDDSurfBytes = (BYTE*)ddsd.lpSurface; + + if(dwNumComponents==4) { + DWORD *pDstWord = (DWORD *) pbuf; + switch(ddsd.ddpfPixelFormat.dwRGBBitCount) { + + case 32: { + DWORD *pSrcWord; + + pDDSurfBytes+=ddsd.lPitch*(dwYWindowOffset+dwCopyHeight-1); + for(DWORD y=0; y>16)&0x000000ff); + g = (BYTE)((dwPixel>> 8)&0x000000ff); + b = (BYTE)((dwPixel )&0x000000ff); + + *pDstWord = (dwPixel & 0xff00ff00) | (r<<16) | b; + } + } + break; + } + + case 24: { + BYTE *pSrcByte; + + pDDSurfBytes+=ddsd.lPitch*(dwYWindowOffset+dwCopyHeight-1); + for(DWORD y=0; y> greenshift; + r = (dwPixel & redmask) >> redshift; + + *pDstWord = 0xFF000000 | (b << 16) | (g << 8) | r; + } + } + } + break; + } + } else { // convert to 24bpp pixbuf + BYTE *pDstByte = (BYTE *) pbuf; + switch(ddsd.ddpfPixelFormat.dwRGBBitCount) { + + case 32: { + DWORD *pSrcWord; + + pDDSurfBytes+=ddsd.lPitch*(dwYWindowOffset+dwCopyHeight-1); + for(DWORD y=0; y>16)&0x000000ff); + g = (BYTE)((dwPixel>> 8)&0x000000ff); + b = (BYTE)((dwPixel )&0x000000ff); + + *pDstByte++ = r; + *pDstByte++ = g; + *pDstByte++ = b; + } + } + break; + } + + case 24: { + BYTE *pSrcByte; + + pDDSurfBytes+=ddsd.lPitch*(dwYWindowOffset+dwCopyHeight-1); + for(DWORD y=0; y> greenshift; + r = (dwPixel & redmask) >> redshift; + + *pDstByte++ = r; + *pDstByte++ = g; + *pDstByte++ = b; + } + } + } + break; + } + } + + + pDDSurf->Unlock(NULL); + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Name: CreateTextureFromBitmap() +// Desc: Use a bitmap 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. +//----------------------------------------------------------------------------- +LPDIRECTDRAWSURFACE7 DXTextureContext:: +CreateTexture(LPDIRECT3DDEVICE7 pd3dDevice, int cNumTexPixFmts, LPDDPIXELFORMAT pTexPixFmts) { + HRESULT hr; + int i; + PixelBuffer *pbuf = _texture->_pbuffer; + int cNumAlphaBits; // number of alpha bits in texture pixfmt + + DDPIXELFORMAT *pDesiredPixFmt; + LPDIRECTDRAWSURFACE7 pddsRender; + LPDIRECTDRAW7 pDD = NULL; + + DDPIXELFORMAT TexFmtsArr[MAX_DX_TEXPIXFMTS]; + + ConversionType ConvNeeded; + + // make local copy of array so I can muck with it during searches for this texture fmt + memcpy(TexFmtsArr,pTexPixFmts,cNumTexPixFmts*sizeof(DDPIXELFORMAT)); + pTexPixFmts=TexFmtsArr; + + // bpp indicates requested fmt, not pixbuf fmt + DWORD bpp = get_bits_per_pixel(pbuf->get_format(), &cNumAlphaBits); + PixelBuffer::Type pixbuf_type = pbuf->get_image_type(); + DWORD cNumColorChannels = pbuf->get_num_components(); + + assert(pbuf->get_component_width()==sizeof(BYTE)); // cant handle anything else now + assert(pixbuf_type==PixelBuffer::T_unsigned_byte); // cant handle anything else now + + if((pixbuf_type != PixelBuffer::T_unsigned_byte) || (pbuf->get_component_width()!=1)) { + dxgsg_cat.error() << "CreateTexture failed, havent handled non 8-bit channel pixelbuffer types yet! \n"; + return NULL; + } + + DWORD dwOrigWidth = (DWORD)pbuf->get_xsize(); + DWORD dwOrigHeight = (DWORD)pbuf->get_ysize(); + + // Get the device caps so we can check if the device has any constraints + // when using textures + D3DDEVICEDESC7 devDesc; + if(FAILED( pd3dDevice->GetCaps( &devDesc ) )) { + goto error_exit; + } + + // Setup the new surface desc for the texture. Note how we are using the + // texture manage attribute, so Direct3D does alot of dirty work for us + DDSURFACEDESC2 ddsd; + ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) ); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH + | DDSD_PIXELFORMAT ; + + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + + // setup ddpf to match against avail fmts + + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + + if((pbuf->get_format() == PixelBuffer::F_luminance_alpha)|| + (pbuf->get_format() == PixelBuffer::F_luminance_alphamask) || + (pbuf->get_format() == PixelBuffer::F_luminance)) { + ddsd.ddpfPixelFormat.dwFlags = DDPF_LUMINANCE; + } + + ddsd.ddpfPixelFormat.dwRGBBitCount = bpp; + + if(cNumAlphaBits) { + if(bpp == 8 && cNumAlphaBits == 8) { // handle special case: Alpha only buffer + ddsd.dwFlags |= DDPF_ALPHA; + ddsd.dwAlphaBitDepth = 8; + ddsd.ddpfPixelFormat.dwAlphaBitDepth = 8; + ddsd.ddpfPixelFormat.dwFlags = DDPF_ALPHA; + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff; + } else { + ddsd.ddpfPixelFormat.dwFlags |= DDPF_ALPHAPIXELS; + if(cNumAlphaBits == 8) + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; + else if(cNumAlphaBits == 4) + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xf000; + } + } + + ddsd.dwWidth = dwOrigWidth; + ddsd.dwHeight = dwOrigHeight; + + if(!ISPOW2(ddsd.dwWidth) || !ISPOW2(ddsd.dwHeight)) { + dxgsg_cat.error() << "ERROR: texture dimensions are not a power of 2 for " << _tex->get_name() << "!!!!! \n"; +#ifdef _DEBUG + exit(1); // want to catch badtexsize errors +#else + goto error_exit; +#endif + } + + bool bShrinkOriginal; + + bShrinkOriginal=false; + if((dwOrigWidth>devDesc.dwMaxTextureWidth)||(dwOrigHeight>devDesc.dwMaxTextureHeight)) { +#ifdef _DEBUG + dxgsg_cat.error() << "WARNING: " <<_tex->get_name() << ": Image size exceeds max texture dimensions of (" << devDesc.dwMaxTextureWidth << "," << devDesc.dwMaxTextureHeight << ") !!\n" + << "Scaling "<< _tex->get_name() << " ("<< dwOrigWidth<<"," < ("<< devDesc.dwMaxTextureWidth << "," << devDesc.dwMaxTextureHeight << ") !\n"; +#endif + + if(dwOrigWidth>devDesc.dwMaxTextureWidth) + ddsd.dwWidth=devDesc.dwMaxTextureWidth; + if(dwOrigHeight>devDesc.dwMaxTextureHeight) + ddsd.dwHeight=devDesc.dwMaxTextureHeight; + bShrinkOriginal=true; + } + + // checks for SQUARE reqmt (nvidia riva128 needs this) + if((ddsd.dwWidth != ddsd.dwHeight) && (devDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )) { + + // assume pow2 textures. sum exponents, divide by 2 rounding down to get sq size + int i,width_exp,height_exp; + for(i=ddsd.dwWidth,width_exp=0;i>1;width_exp++,i>>=1); + for(i=ddsd.dwHeight,height_exp=0;i>1;height_exp++,i>>=1); + ddsd.dwHeight = ddsd.dwWidth = 1<<((width_exp+height_exp)>>1); + bShrinkOriginal=true; + +#ifdef _DEBUG + dxgsg_cat.debug() << "Scaling "<< _tex->get_name() << " ("<< dwOrigWidth<<"," < ("<< ddsd.dwWidth<<"," << ddsd.dwHeight << ") to meet HW square texture reqmt\n"; +#endif + } + + if(bShrinkOriginal) { + // need 2 add checks for errors + PNMImage pnmi_src; + PNMImage *pnmi = new PNMImage(ddsd.dwWidth, ddsd.dwHeight, cNumColorChannels); + pbuf->store(pnmi_src); + pnmi->quick_filter_from(pnmi_src,0,0); + + pbuf->load(*pnmi); // violates device independence of pixbufs + + dwOrigWidth = (DWORD)pbuf->get_xsize(); + dwOrigHeight = (DWORD)pbuf->get_ysize(); + delete pnmi; + } + +#if 0 +//#ifdef _DEBUG +// easier to use dxcapsviewer instead of this + { static BOOL bPrinted=FALSE; + if(!bPrinted) { + dxgsg_cat.debug() << "Gfx card supported TexFmts:\n"; + for(i=0;idwFlags & (DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) ) || + ( pCurPixFmt->dwFourCC != 0 ) || + ((cNumAlphaBits==0) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS))) { + + // Make sure to skip any FourCC formats, bump formats + // they are not handled by this code yet + + // note: I'm screening out alpha if no alpha requested, so + // search fails if 32-rgba avail, but not 32-bit rgb + // I could recode for that case too, hopefully this case will not pop up + + pCurPixFmt->dwRGBBitCount+=1; // incr so it wont be an exact match anymore + } + } + + // handle each bitdepth separately + + switch(bpp) { // bpp is REQUESTED bpp, not what exists in the pixbuf array + + case 32: + +#ifdef _DEBUG + if(!dx_force_16bpptextures) +#endif + for(i=0,pCurPixFmt=pTexPixFmts;idwRGBBitCount==32) && + (((pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)!=0)==(cNumAlphaBits!=0))) { + // we should have a match + assert(pCurPixFmt->dwRGBAlphaBitMask==0xFF000000); + ConvNeeded=((cNumColorChannels==3) ? Conv24to32 : Conv32to32); + goto found_matching_format; + break; + } + } + + if(cNumAlphaBits>0) { + // 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 + { + ConvTo1=Conv32to16_1555; + dwAlphaMask1=0x8000; + } + + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==16) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) + && (pCurPixFmt->dwRGBAlphaBitMask==dwAlphaMask1)) { + ConvNeeded=ConvTo1; + goto found_matching_format; + } + } + +#ifdef FORCE_16bpp_1555 + break; +#endif + + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==16) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) + && (pCurPixFmt->dwRGBAlphaBitMask==dwAlphaMask2)) { + ConvNeeded=ConvTo2; + goto found_matching_format; + } + } + + // 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!\n"; + } + + break; + + case 24: + + assert(cNumAlphaBits==0); // dont know how to handle non-zero alpha for 24bit total + +#ifdef _DEBUG + if(!dx_force_16bpptextures) +#endif + for(i=0,pCurPixFmt=pTexPixFmts;idwFlags & DDPF_RGB)&&(pCurPixFmt->dwRGBBitCount==24)) { + ConvNeeded=((cNumColorChannels==3) ? Conv24to24 : Conv32to24); + goto found_matching_format; + } + } + +#ifdef _DEBUG + if(!dx_force_16bpptextures) +#endif + + // 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 mask to ensure ARGB, not RGBA (which I am not handling here) + for(i=0,pCurPixFmt=pTexPixFmts;idwRGBBitCount==32) && (pCurPixFmt->dwFlags & DDPF_RGB) + && ((pCurPixFmt->dwRBitMask|pCurPixFmt->dwGBitMask|pCurPixFmt->dwBBitMask)==0xFFFFFF) + ) { + // I'm allowing alpha formats here. will set alpha to opaque + ConvNeeded=((cNumColorChannels==3) ? Conv24to32 : Conv32to32_NoAlpha); + goto found_matching_format; + } + } + + // no 24-bit or 32 fmt. look for 16 bit fmt + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];i16 conversion, should be true on most cards. + if((pCurPixFmt->dwFlags & DDPF_RGB) && (pCurPixFmt->dwRGBBitCount==16) + && !(pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)) { // no alpha fmts + // if numchan==4,this means user has requested we throw away the input alpha channel + if(pCurPixFmt->dwGBitMask==0x7E0) { + // assumes GBitMask is the biggest one, if we have 16 bit 3-channel + ConvNeeded=((cNumColorChannels==3) ? Conv24to16_0565 : Conv32to16_0565); + } else { + assert((pCurPixFmt->dwRBitMask|pCurPixFmt->dwGBitMask|pCurPixFmt->dwBBitMask)==0x7FFF); + ConvNeeded=((cNumColorChannels==3) ? Conv24to16_0555 : Conv32to16_0555); + } + goto found_matching_format; + } + } + + // at this point, bail. + break; + + case 16: + + if(ddsd.ddpfPixelFormat.dwFlags & DDPF_LUMINANCE) { + // look for native lum fmt +#ifdef _DEBUG + if(!dx_force_16bpptextures) +#endif + { + + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==16) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) && + (pCurPixFmt->dwFlags & DDPF_LUMINANCE)) { + ConvNeeded=ConvLum16to16; + goto found_matching_format; + } + } + + // else look for 32bpp ARGB + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==32) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) && + (pCurPixFmt->dwFlags & DDPF_RGB)) { + ConvNeeded=ConvLum16to32; + goto found_matching_format; + } + } + } + + // find compatible 16bpp fmt + ConversionType ConvTo1=ConvLum16to16_4444,ConvTo2=ConvLum16to16_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 + { + ConvTo1=ConvLum16to16_1555; + dwAlphaMask1=0x8000; + } + + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==16) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) + && (pCurPixFmt->dwRGBAlphaBitMask==dwAlphaMask1)) { + ConvNeeded=ConvTo1; + goto found_matching_format; + } + } + +#ifdef FORCE_16bpp_1555 + break; +#endif + + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==16) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) + && (pCurPixFmt->dwRGBAlphaBitMask==dwAlphaMask2)) { + ConvNeeded=ConvTo2; + goto found_matching_format; + } + } + + } else + + // look for compatible 16bit fmts, if none then give up + // (dont worry about other bitdepths for 16 bit) + + for(i=0,pCurPixFmt=pTexPixFmts;idwRGBBitCount==16)&&(pCurPixFmt->dwFlags & DDPF_RGB)) { + switch(cNumAlphaBits) { + case 0: + if(!(pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)) { + // if numchan==4,this means user has requested we throw away the input alpha channel + if(pCurPixFmt->dwGBitMask==0x7E0) { + // assumes GBitMask is the biggest one, if we have 16 bit 3-channel + ConvNeeded=((cNumColorChannels==3) ? Conv24to16_0565 : Conv32to16_0565); + } else { + assert((pCurPixFmt->dwRBitMask|pCurPixFmt->dwGBitMask|pCurPixFmt->dwBBitMask)==0x7FFF); + ConvNeeded=((cNumColorChannels==3) ? Conv24to16_0555 : Conv32to16_0555); + } + goto found_matching_format; + } + break; + case 1: + if((pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)&& + (pCurPixFmt->dwRGBAlphaBitMask==0x8000)) { + ConvNeeded=Conv32to16_1555; + goto found_matching_format; + } + break; + case 4: + if((pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)&& + (pCurPixFmt->dwRGBAlphaBitMask==0xF000)) { + ConvNeeded=Conv32to16_4444; + goto found_matching_format; + } + break; + } + } + } + + break; + + case 8: + if(ddsd.ddpfPixelFormat.dwFlags & DDPF_LUMINANCE) { + // look for native lum fmt + + assert(cNumAlphaBits==0); // dont handle those other 8bit lum fmts like 4-4, since 16 8-8 is usually supported too +#ifdef _DEBUG + if(!dx_force_16bpptextures) +#endif + { + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==8) && (pCurPixFmt->dwFlags & DDPF_LUMINANCE) && + (pCurPixFmt->dwLuminanceBitMask==0xFF)) { + ConvNeeded=ConvLum8to8; + goto found_matching_format; + } + } + + // else look for 24bpp RGB + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==24) && (pCurPixFmt->dwFlags & DDPF_RGB)) { + ConvNeeded=ConvLum8to24; + goto found_matching_format; + } + } + + // else look for 32bpp RGB + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==32) && (pCurPixFmt->dwFlags & DDPF_RGB)) { + ConvNeeded=ConvLum8to32; + goto found_matching_format; + } + } + } + + // find compatible 16bpp fmt, just look for any 565, then 0555 + DWORD dwMasks[2] = {0xF800, 0x7C00}; + + for(DWORD modenum=0;modenum<2;modenum++) + for(i=0,pCurPixFmt=&pTexPixFmts[0];idwRGBBitCount==16) && (pCurPixFmt->dwFlags & DDPF_RGB) + && (!(pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)) + && (pCurPixFmt->dwRBitMask==dwMasks[modenum])) { + ConvNeeded=ConvLum8to16_0565; + goto found_matching_format; + } + } + } else if(ddsd.ddpfPixelFormat.dwFlags & DDPF_ALPHA) { + // look for 32-bit ARGB, else 16-4444. + // skip 8bit alpha only, because I think only voodoo supports it + // and the voodoo support isn't the kind of blending model we need + // w/color assumed to be white (but need to verify this) + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==32) && (pCurPixFmt->dwFlags & DDPF_RGB) && + (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS)) { + ConvNeeded=ConvAlpha8to32; + goto found_matching_format; + } + } + + for(i=0,pCurPixFmt=&pTexPixFmts[cNumTexPixFmts-1];idwRGBBitCount==16) + && (pCurPixFmt->dwFlags & DDPF_RGB) + && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) + && (pCurPixFmt->dwRGBAlphaBitMask==0xF000)) { + ConvNeeded=ConvAlpha8to16_4444; + goto found_matching_format; + } + } + } + break; + + default: + szErrorMsg = "CreateTexture failed: unhandled pixel bitdepth in DX loader"; + } + + // if we've gotten here, haven't found a match + + dxgsg_cat.error() << szErrorMsg << "; requested tex bitdepth: " << bpp << "\n"; + goto error_exit; + + /////////////////////////////////////////////////////////// + + found_matching_format: + + ddsd.ddpfPixelFormat = *pCurPixFmt; + + // Get the device's render target, so we can then use the render target to + // get a ptr to a DDraw object. We need the DirectDraw interface for + // creating surfaces. + + pd3dDevice->GetRenderTarget( &pddsRender ); + pddsRender->GetDDInterface( (VOID**)&pDD ); + pddsRender->Release(); + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE // Turn on texture management + | DDSCAPS2_HINTSTATIC; // BUGBUG: is this ok for ALL textures? + + // 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) { + if(ft==Texture::FT_nearest_mipmap_nearest) + ft=Texture::FT_nearest; + else ft=Texture::FT_linear; + } + + if((ft==Texture::FT_linear) && !(devDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEAR)) + 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(ft != Texture::FT_linear_mipmap_linear) { + dxgsg_cat.spam() << "Forcing mipmap filtering 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((devDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_NEAREST)!=0); + + switch(ft) { + case Texture::FT_nearest_mipmap_linear: + if(!(devDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEARMIPNEAREST)) + ft=Texture::FT_nearest_mipmap_nearest; + break; + case Texture::FT_linear_mipmap_nearest: + if(!(devDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_MIPLINEAR)) + ft=Texture::FT_nearest_mipmap_nearest; + break; + case Texture::FT_linear_mipmap_linear: + if(!(devDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEARMIPLINEAR)) { + if(devDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_MIPLINEAR) + 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_linear: + if(!(devDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEAR)) + ft=Texture::FT_nearest; + break; + } + + _tex->set_minfilter(ft); + + uint aniso_degree; + + aniso_degree=1; + if(devDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANISOTROPY) { + aniso_degree=_tex->get_anisotropic_degree(); + if((aniso_degree>devDesc.dwMaxAnisotropy) +#ifdef _DEBUG + || dx_force_anisotropic_filtering +#endif + ) + aniso_degree=devDesc.dwMaxAnisotropy; + } + _tex->set_anisotropic_degree(aniso_degree); +#ifdef _DEBUG + dxgsg_cat.spam() << "CreateTexture: setting aniso degree for "<< _tex->get_name() << " to: " << aniso_degree << endl; +#endif + + if(_bHasMipMaps) { + // We dont specify mipmapcount, so CreateSurface will auto-create surfs + // for all mipmaps down to 1x1 (if driver supports deep-mipmaps, otherwise Nx1) + ddsd.ddsCaps.dwCaps |= (DDSCAPS_MIPMAP | DDSCAPS_COMPLEX); + dxgsg_cat.debug() << "CreateTexture: generating mipmaps for "<< _tex->get_name() << endl; + } + + if(devDesc.dwDevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) { + // must assign a texture to a specific stage + // for now I'm just going to use stage 0 for all + ddsd.dwTextureStage=0; + ddsd.dwFlags |= DDSD_TEXTURESTAGE; + } + + PRINTVIDMEM(pDD,&ddsd.ddsCaps,"texture surf (includes AGP mem)"); + + // Create a new surface for the texture + if(FAILED( hr = pDD->CreateSurface( &ddsd, &_surface, NULL ) )) { + dxgsg_cat.error() << "CreateTexture failed: pDD->CreateSurface() failed! hr = " << ConvD3DErrorToString(hr) << "\n"; + goto error_exit; + } + + +#ifdef _DEBUG + dxgsg_cat.debug() << "CreateTexture: "<< _tex->get_name() <<" converted " << ConvNameStrs[ConvNeeded] << " \n"; +#endif + + _PixBufConversionType=ConvNeeded; + + hr = FillDDSurfTexturePixels(); + if(FAILED(hr)) { + goto error_exit; + } + + // Done with DDraw + pDD->Release(); + + // Return the newly created texture + return _surface; + + error_exit: + + if(pDD!=NULL) + pDD->Release(); + if(_surface!=NULL) { + _surface->Release(); + _surface = NULL; + } + + return NULL; +} + +HRESULT DXTextureContext:: +FillDDSurfTexturePixels(void) { + + PixelBuffer *pbuf = _texture->get_ram_image(); + if (pbuf == (PixelBuffer *)NULL) { + dxgsg_cat.fatal() << "CreateTexture: get_ram_image() failed\n"; + // The texture doesn't have an image to load. + return E_FAIL; + } + + HRESULT hr = ConvertPixBuftoDDSurf((ConversionType)_PixBufConversionType,pbuf->_image.p(),_surface); + if(FAILED(hr)) { + return hr; + } + + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); + + _surface->GetSurfaceDesc(&ddsd); + + if(_bHasMipMaps) { + DWORD i,oldcurxsize,oldcurysize,curxsize,curysize,cMipMapCount=ddsd.dwMipMapCount; + assert(ddsd.dwMipMapCount<20); + + DWORD cNumColorChannels = pbuf->get_num_components(); + + curxsize=ddsd.dwWidth; curysize=ddsd.dwHeight; + + assert(pbuf->get_image_type()==PixelBuffer::T_unsigned_byte); // cant handle anything else now + + // all mipmap sublevels require 1/3 of total original space. alloc 1/2 for safety + BYTE *pMipMapPixBufSpace = new BYTE[((curxsize*curysize*cNumColorChannels)/2)+1024]; + + LPDIRECTDRAWSURFACE7 pCurDDSurf=_surface; + pCurDDSurf->AddRef(); // so final release doesnt release the surface + + BYTE *pDstWord = pMipMapPixBufSpace; + BYTE *pLastMipLevelStart = (BYTE *) pbuf->_image.p(); +// clock_t start1,finish1; +// start1=clock(); + for(i=1;i>1,1); + curxsize = max(curxsize>>1,1); + + assert(!((oldcurxsize==1)&&(oldcurysize==1))); + + BYTE *pSrcWord; + BYTE *pSrcLineStart=pLastMipLevelStart; + + // inc img start to DWORD boundary + while(((DWORD)pDstWord) & 0x11) + pDstWord++; + + pLastMipLevelStart = pDstWord; + + DWORD x,y,cPixelSize=cNumColorChannels; + DWORD src_row_bytelength=oldcurxsize*cPixelSize; + DWORD two_src_row_bytelength=2*src_row_bytelength; + + #define GENMIPMAP_DO_INTEGER_DIV // should be a little faster, but no rounding up + #ifdef GENMIPMAP_DO_INTEGER_DIV + DWORD DivShift=2; + if((oldcurxsize==1)||(oldcurysize==1)) + DivShift = 1; + #else + float numpixels_per_filter=4.0f; + if((oldcurxsize==1)||(oldcurysize==1)) + numpixels_per_filter=2.0f; + #endif + + DWORD x_srcptr_inc = ((oldcurxsize==1)? cPixelSize: (2*cPixelSize)); + + // box-filter shrink down, avg 4 pixels at a time + for(y=0; y1) // handle 1x[X], [X]x1 cases + colr += *(pSrcWord+cPixelSize+c); + if(oldcurysize>1) { + colr += *(pSrcWord+src_row_bytelength+c); + if(oldcurxsize>1) + colr += *(pSrcWord+src_row_bytelength+cPixelSize+c); + } + #ifdef GENMIPMAP_DO_INTEGER_DIV + colr >>= DivShift; + #else + colr = (DWORD) ((((float)colr)/numpixels_per_filter)+0.5f); + #endif + + *(pDstWord+c)=(BYTE)colr; + } + } + } + + // now copy pixbuf to final DD surf + + DDSCAPS2 ddsCaps; + LPDIRECTDRAWSURFACE7 pMipLevel_DDSurf; + ZeroMemory(&ddsCaps,sizeof(DDSCAPS2)); + ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP; + ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL; + + hr = pCurDDSurf->GetAttachedSurface(&ddsCaps, &pMipLevel_DDSurf); + if(FAILED(hr)) { + dxgsg_cat.error() << "CreateTexture failed creating mipmaps: GetAttachedSurf hr = " << ConvD3DErrorToString(hr) << "\n"; + delete [] pMipMapPixBufSpace; + pCurDDSurf->Release(); + return hr; + } + + hr = ConvertPixBuftoDDSurf((ConversionType)_PixBufConversionType,pLastMipLevelStart,pMipLevel_DDSurf); + if(FAILED(hr)) { + delete [] pMipMapPixBufSpace; + pCurDDSurf->Release(); + return hr; + } + + pCurDDSurf->Release(); + pCurDDSurf=pMipLevel_DDSurf; + } + + // finish1=clock(); + // double elapsed_time = (double)(finish1 - start1) / CLOCKS_PER_SEC; + // cerr << "mipmap gen takes " << elapsed_time << " secs for this texture\n"; + + delete [] pMipMapPixBufSpace; + pCurDDSurf->Release(); + +#ifdef _DEBUG + if(dx_debug_view_mipmaps) { +#if 0 + if(!(ddcaps.dwCaps & DDCAPS_BLTSTRETCH)) { + dxgsg_cat.error() << "CreateTexture failed debug-viewing mipmaps, BLT stretching not supported! ( we need to do SW stretch) \n"; + return hr; + } +#endif + + // display mipmaps on primary surf + HDC hTexDC; + LPDIRECTDRAWSURFACE7 pTextureCurrent,pTexturePrev = _surface; + int cury,curx; + HDC hScreenDC; + RECT scrnrect; + hScreenDC=GetDC(NULL); + + scrnrect.left=scrnrect.top=0; + scrnrect.bottom=GetDeviceCaps(hScreenDC,VERTRES); + scrnrect.right=GetDeviceCaps(hScreenDC,HORZRES); + char msg[500]; + + pTexturePrev->AddRef(); + + for(i = 0,curx=scrnrect.left,cury=scrnrect.top; i < ddsd.dwMipMapCount; i++) { + + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_cur); + pTexturePrev->GetSurfaceDesc(&ddsd_cur); + + hr = pTexturePrev->GetDC(&hTexDC); + if(FAILED(hr)) { + dxgsg_cat.error() << "GetDC failed hr = " << ConvD3DErrorToString(hr) << "\n"; + break; + } + + BOOL res; + // res = BitBlt(_dxgsg->_hdc,0,0,ddsd.dwWidth,ddsd.dwHeight, TexDC,0,0,SRCCOPY); + // loader inverts y, so use StretchBlt to re-invert it + // res = StretchBlt(_dxgsg->hdc,0,ddsd_cur.dwHeight+cury,ddsd_cur.dwWidth,-ddsd_cur.dwHeight, TexDC,0,0,ddsd_cur.dwWidth,ddsd_cur.dwHeight,SRCCOPY); +#if 0 + if(cNumAlphaBits>0) { + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; bf.BlendFlags=0; + bf.SourceConstantAlpha=255; bf.AlphaFormat=AC_SRC_ALPHA; + res = AlphaBlend(hScreenDC,curx,cury,ddsd_cur.dwWidth,ddsd_cur.dwHeight, TexDC,0,0,ddsd_cur.dwWidth,ddsd_cur.dwHeight,bf); + if(!res) { + PrintLastError(msg); + dxgsg_cat.error() << "AlphaBlend BLT failed: "<scrnrect.right) { + curx=0; cury+=(scrnrect.bottom-scrnrect.top)/2; + } + + hr = pTexturePrev->ReleaseDC(hTexDC); + + if(FAILED(hr)) { + dxgsg_cat.error() << "tex ReleaseDC failed for mip "<Release(); + continue; + } + + DDSCAPS2 ddsCaps; + ZeroMemory(&ddsCaps,sizeof(DDSCAPS2)); + ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP; + ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL; + hr = pTexturePrev->GetAttachedSurface(&ddsCaps, &pTextureCurrent); + if(FAILED(hr)) { + dxgsg_cat.error() << " failed displaying mipmaps: GetAttachedSurf hr = " << ConvD3DErrorToString(hr) << "\n"; + } + // done with the previous texture + pTexturePrev->Release(); + pTexturePrev = pTextureCurrent; + } + + ReleaseDC(0,hScreenDC); + + HANDLE hArr[1]; + MSG winmsg; + hArr[0]=GetStdHandle(STD_INPUT_HANDLE); + GetMessage(&winmsg,NULL,0,0); + + int val=MsgWaitForMultipleObjects(1,hArr,TRUE,INFINITE,QS_KEY); + if(val==-1) { + PrintLastError(msg); + dxgsg_cat.error() << " MsgWaitForMultipleObjects returns " << val << " " <get_name() << "\n"; + } + + ULONG refcnt; + +#ifdef DEBUG_RELEASES + if(_surface) { + LPDIRECTDRAW7 pDD; + _surface->GetDDInterface( (VOID**)&pDD ); + pDD->Release(); + + PRINTREFCNT(pDD,"before DeleteTex, IDDraw7"); + RELEASE(_surface,dxgsg,"texture",false); + PRINTREFCNT(pDD,"after DeleteTex, IDDraw7"); + } +#else + RELEASE(_surface,dxgsg,"texture",false); +#endif +} + + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +DXTextureContext:: +DXTextureContext(Texture *tex) : +TextureContext(tex) { +//#ifdef NDEBUG + if(dxgsg_cat.is_spam()) { + dxgsg_cat.spam() << "Creating DX texture [" << tex->get_name() << "], minfilter(" << PandaFilterNameStrs[tex->get_minfilter()] << "), magfilter("<get_magfilter()] << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n"; + } +//#endif + _surface = NULL; + _bHasMipMaps = FALSE; + _tex = tex; +} + +DXTextureContext:: +~DXTextureContext() { + DeleteTexture(); + TextureContext::~TextureContext(); + _tex = NULL; +} + diff --git a/panda/src/dxgsg8/dxTextureContext8.h b/panda/src/dxgsg8/dxTextureContext8.h new file mode 100644 index 0000000000..e160686e5f --- /dev/null +++ b/panda/src/dxgsg8/dxTextureContext8.h @@ -0,0 +1,89 @@ +// Filename: dxTextureContext.h +// Created by: drose (07Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DXTEXTURECONTEXT8_H +#define DXTEXTURECONTEXT8_H + +#include + +#define WIN32_LEAN_AND_MEAN +#ifndef STRICT +// enable strict type checking in windows.h, see msdn +#define STRICT +#endif + +#include + +#include + +#define D3D_OVERLOADS // get D3DVECTOR '+' operator, etc from d3dtypes.h +#include +#undef WIN32_LEAN_AND_MEAN + +#include +#include + +#define MAX_DX_TEXPIXFMTS 20 // should be enough for any card + +//////////////////////////////////////////////////////////////////// +// Class : DXTextureContext +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX DXTextureContext : public TextureContext { + friend class DXGraphicsStateGuardian; + friend class wdxGraphicsWindow; + +public: + DXTextureContext(Texture *tex); + ~DXTextureContext(); + + LPDIRECTDRAWSURFACE7 _surface; + Texture *_tex; // ptr to parent, primarily for access to namestr + + LPDIRECTDRAWSURFACE7 CreateTexture(LPDIRECT3DDEVICE7 pd3dDevice, int cNumTexPixFmts, LPDDPIXELFORMAT pTexPixFmts); + + bool _bHasMipMaps; + DWORD _PixBufConversionType; // enum ConversionType + + // must be public since called from global callback fns + void DeleteTexture(void); + HRESULT FillDDSurfTexturePixels(void); + +protected: + unsigned int get_bits_per_pixel(PixelBuffer::Format format, int *alphbits); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TextureContext::init_type(); + register_type(_type_handle, "DXTextureContext", + TextureContext::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; +}; + +#endif + diff --git a/panda/src/dxgsg8/dxgsg8_composite1.cxx b/panda/src/dxgsg8/dxgsg8_composite1.cxx new file mode 100644 index 0000000000..e29eaeed22 --- /dev/null +++ b/panda/src/dxgsg8/dxgsg8_composite1.cxx @@ -0,0 +1,4 @@ +#include "config_dxgsg8.cxx" +#include "dxSavedFrameBuffer8.cxx" +#include "dxTextureContext8.cxx" +#include "dxGeomNodeContext8.cxx" diff --git a/panda/src/wdxdisplay8/Sources.pp b/panda/src/wdxdisplay8/Sources.pp new file mode 100644 index 0000000000..3c846e580b --- /dev/null +++ b/panda/src/wdxdisplay8/Sources.pp @@ -0,0 +1,20 @@ +#define DIRECTORY_IF_DX yes + +#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ + dtoolutil:c dtoolbase:c dtool:m +#define USE_DX yes + +#if $[BUILD_DX8] +#begin lib_target + #define TARGET wdxdisplay8 + #define LOCAL_LIBS dxgsg8 + + #define COMBINED_SOURCES $[TARGET]_composite1.cxx + + #define SOURCES \ + config_wdxdisplay8.h wdxGraphicsPipe8.h wdxGraphicsWindow8.cxx wdxGraphicsWindow8.h + + #define INCLUDED_SOURCES config_wdxdisplay8.cxx wdxGraphicsPipe8.cxx + +#end lib_target +#endif diff --git a/panda/src/wdxdisplay8/config_wdxdisplay8.cxx b/panda/src/wdxdisplay8/config_wdxdisplay8.cxx new file mode 100644 index 0000000000..97c36b56bb --- /dev/null +++ b/panda/src/wdxdisplay8/config_wdxdisplay8.cxx @@ -0,0 +1,80 @@ +// Filename: config_wdxdisplay.cxx +// Created by: mike (07Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "config_wdxdisplay8.h" +#include "wdxGraphicsPipe8.h" +#include "wdxGraphicsWindow8.h" + +#include + +Configure(config_wdxdisplay); +NotifyCategoryDef(wdxdisplay, "display"); + +ConfigureFn(config_wdxdisplay) { + init_libwdxdisplay8(); +} + +bool dx_force_16bpp_zbuffer = config_wdxdisplay.GetBool("dx-force-16bpp-zbuffer", false); +bool bResponsive_minimized_fullscreen_window = config_wdxdisplay.GetBool("responsive-minimized-fullscreen-window",false); + +extern void AtExitFn(void); + +//////////////////////////////////////////////////////////////////// +// Function: init_libwdxdisplay +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void init_libwdxdisplay8() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + + atexit(AtExitFn); + + wdxGraphicsPipe::init_type(); + GraphicsPipe::get_factory().register_factory( + wdxGraphicsPipe::get_class_type(), + wdxGraphicsPipe::make_wdxGraphicsPipe); + wdxGraphicsWindow::init_type(); + GraphicsWindow::get_factory().register_factory( + wdxGraphicsWindow::get_class_type(), + wdxGraphicsWindow::make_wdxGraphicsWindow); + + set_global_parameters(); +} + +// cant use global var cleanly because global var static init executed after init_libwdxdisplay(), incorrectly reiniting var +Filename get_icon_filename() { + string iconname = config_wdxdisplay.GetString("win32-window-icon",""); + return ExecutionEnvironment::expand_string(iconname); +} + +Filename get_color_cursor_filename() { + string cursorname = config_wdxdisplay.GetString("win32-color-cursor",""); + return ExecutionEnvironment::expand_string(cursorname); +} + +Filename get_mono_cursor_filename() { + string cursorname = config_wdxdisplay.GetString("win32-mono-cursor",""); + return ExecutionEnvironment::expand_string(cursorname); +} diff --git a/panda/src/wdxdisplay8/config_wdxdisplay8.h b/panda/src/wdxdisplay8/config_wdxdisplay8.h new file mode 100644 index 0000000000..2393dede1f --- /dev/null +++ b/panda/src/wdxdisplay8/config_wdxdisplay8.h @@ -0,0 +1,36 @@ +// Filename: config_wdxdisplay.h +// Created by: mike (07Oct99) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef __CONFIG_WDXDISPLAY8_H__ +#define __CONFIG_WDXDISPLAY8_H__ + +#include +#include +#include + +NotifyCategoryDecl(wdxdisplay, EXPCL_PANDADX, EXPTP_PANDADX); + +extern bool bResponsive_minimized_fullscreen_window; +extern bool dx_force_16bpp_zbuffer; +extern Filename get_icon_filename(); +extern Filename get_mono_cursor_filename(); +extern Filename get_color_cursor_filename(); + +extern EXPCL_PANDADX void init_libwdxdisplay8(); + +#endif /* __CONFIG_WDXDISPLAY_H__ */ diff --git a/panda/src/wdxdisplay8/wdxGraphicsPipe8.cxx b/panda/src/wdxdisplay8/wdxGraphicsPipe8.cxx new file mode 100644 index 0000000000..499b4f9d79 --- /dev/null +++ b/panda/src/wdxdisplay8/wdxGraphicsPipe8.cxx @@ -0,0 +1,1603 @@ +// Filename: wdxGraphicsPipe.cxx +// Created by: mike (09Jan97) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "wdxGraphicsPipe8.h" +#include "config_wdxdisplay8.h" +#include +#include +#include + +//////////////////////////////////////////////////////////////////// +// Static variables +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsPipe::_type_handle; + +//wdxGraphicsPipe *global_pipe; + +wdxGraphicsPipe::wdxGraphicsPipe(const PipeSpecifier& spec) +: InteractiveGraphicsPipe(spec) { +// _width = GetSystemMetrics(SM_CXSCREEN); +// _height = GetSystemMetrics(SM_CYSCREEN); + _shift = false; +// global_pipe = this; +} + +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsPipe::get_window_type +// Access: Public, Virtual +// Description: Returns the TypeHandle of the kind of window +// preferred by this kind of pipe. +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsPipe:: +get_window_type() const { + return wdxGraphicsWindow::get_class_type(); +} + +GraphicsPipe *wdxGraphicsPipe:: +make_wdxGraphicsPipe(const FactoryParams ¶ms) { + GraphicsPipe::PipeSpec *pipe_param; + if(!get_param_into(pipe_param, params)) { + return new wdxGraphicsPipe(PipeSpecifier()); + } else { + return new wdxGraphicsPipe(pipe_param->get_specifier()); + } +} + +TypeHandle wdxGraphicsPipe::get_class_type(void) { + return _type_handle; +} + +const char *pipe_type_name="wdxGraphicsPipe"; + +void wdxGraphicsPipe::init_type(void) { + InteractiveGraphicsPipe::init_type(); + register_type(_type_handle, pipe_type_name, + InteractiveGraphicsPipe::get_class_type()); +} + +TypeHandle wdxGraphicsPipe::get_type(void) const { + return get_class_type(); +} + +wdxGraphicsPipe::wdxGraphicsPipe(void) { + wdxdisplay_cat.error() + << pipe_type_name <<"s should not be created with the default constructor" << endl; +} + +wdxGraphicsPipe::wdxGraphicsPipe(const wdxGraphicsPipe&) { + wdxdisplay_cat.error() + << pipe_type_name << "s should not be copied" << endl; +} + +wdxGraphicsPipe& wdxGraphicsPipe::operator=(const wdxGraphicsPipe&) { + wdxdisplay_cat.error() + << pipe_type_name << "s should not be assigned" << endl; + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: find_window +// Access: +// Description: Find the window that has the xwindow "win" in the +// window list for the pipe (if it exists) +//////////////////////////////////////////////////////////////////// +wdxGraphicsWindow *wdxGraphicsPipe:: +find_window(HWND win) { + int num_windows = get_num_windows(); + for(int w = 0; w < num_windows; w++) { + wdxGraphicsWindow *window = DCAST(wdxGraphicsWindow, get_window(w)); + if(window->_mwindow == win) + return window; + } + return NULL; +} + +extern char * ConvD3DErrorToString(const HRESULT &error) { + switch(error) { + case E_FAIL: + return "Unspecified error E_FAIL"; + + case DD_OK: + return "No error.\0"; + case D3DERR_BADMAJORVERSION : // (700) + return "D3DERR_BADMAJORVERSION";//: // (700) + case D3DERR_BADMINORVERSION : // (701) + return "D3DERR_BADMINORVERSION";//: // (701) + case D3DERR_INVALID_DEVICE : // (705) + return "D3DERR_INVALID_DEVICE";//: // (705) + case D3DERR_INITFAILED : // (706) + return "D3DERR_INITFAILED";//: // (706) + case D3DERR_DEVICEAGGREGATED : // (707) + return "D3DERR_DEVICEAGGREGATED";//: // (707) + case D3DERR_EXECUTE_CREATE_FAILED : // (710) + return "D3DERR_EXECUTE_CREATE_FAILED";//: // (710) + case D3DERR_EXECUTE_DESTROY_FAILED : // (711) + return "D3DERR_EXECUTE_DESTROY_FAILED";//: // (711) + case D3DERR_EXECUTE_LOCK_FAILED : // (712) + return "D3DERR_EXECUTE_LOCK_FAILED";//: // (712) + case D3DERR_EXECUTE_UNLOCK_FAILED : // (713) + return "D3DERR_EXECUTE_UNLOCK_FAILED";//: // (713) + case D3DERR_EXECUTE_LOCKED : // (714) + return "D3DERR_EXECUTE_LOCKED";//: // (714) + case D3DERR_EXECUTE_NOT_LOCKED : // (715) + return "D3DERR_EXECUTE_NOT_LOCKED";//: // (715) + case D3DERR_EXECUTE_FAILED : // (716) + return "D3DERR_EXECUTE_FAILED";//: // (716) + case D3DERR_EXECUTE_CLIPPED_FAILED : // (717) + return "D3DERR_EXECUTE_CLIPPED_FAILED";//: // (717) + case D3DERR_TEXTURE_NO_SUPPORT : // (720) + return "D3DERR_TEXTURE_NO_SUPPORT";//: // (720) + case D3DERR_TEXTURE_CREATE_FAILED : // (721) + return "D3DERR_TEXTURE_CREATE_FAILED";//: // (721) + case D3DERR_TEXTURE_DESTROY_FAILED : // (722) + return "D3DERR_TEXTURE_DESTROY_FAILED";//: // (722) + case D3DERR_TEXTURE_LOCK_FAILED : // (723) + return "D3DERR_TEXTURE_LOCK_FAILED";//: // (723) + case D3DERR_TEXTURE_UNLOCK_FAILED : // (724) + return "D3DERR_TEXTURE_UNLOCK_FAILED";//: // (724) + case D3DERR_TEXTURE_LOAD_FAILED : // (725) + return "D3DERR_TEXTURE_LOAD_FAILED";//: // (725) + case D3DERR_TEXTURE_SWAP_FAILED : // (726) + return "D3DERR_TEXTURE_SWAP_FAILED";//: // (726) + case D3DERR_TEXTURE_LOCKED : // (727) + return "D3DERR_TEXTURE_LOCKED";//: // (727) + case D3DERR_TEXTURE_NOT_LOCKED : // (728) + return "D3DERR_TEXTURE_NOT_LOCKED";//: // (728) + case D3DERR_TEXTURE_GETSURF_FAILED : // (729) + return "D3DERR_TEXTURE_GETSURF_FAILED";//: // (729) + case D3DERR_MATRIX_CREATE_FAILED : // (730) + return "D3DERR_MATRIX_CREATE_FAILED";//: // (730) + case D3DERR_MATRIX_DESTROY_FAILED : // (731) + return "D3DERR_MATRIX_DESTROY_FAILED";//: // (731) + case D3DERR_MATRIX_SETDATA_FAILED : // (732) + return "D3DERR_MATRIX_SETDATA_FAILED";//: // (732) + case D3DERR_MATRIX_GETDATA_FAILED : // (733) + return "D3DERR_MATRIX_GETDATA_FAILED";//: // (733) + case D3DERR_SETVIEWPORTDATA_FAILED : // (734) + return "D3DERR_SETVIEWPORTDATA_FAILED";//: // (734) + case D3DERR_INVALIDCURRENTVIEWPORT : // (735) + return "D3DERR_INVALIDCURRENTVIEWPORT";//: // (735) + case D3DERR_INVALIDPRIMITIVETYPE : // (736) + return "D3DERR_INVALIDPRIMITIVETYPE";//: // (736) + case D3DERR_INVALIDVERTEXTYPE : // (737) + return "D3DERR_INVALIDVERTEXTYPE";//: // (737) + case D3DERR_TEXTURE_BADSIZE : // (738) + return "D3DERR_TEXTURE_BADSIZE";//: // (738) + case D3DERR_INVALIDRAMPTEXTURE : // (739) + return "D3DERR_INVALIDRAMPTEXTURE";//: // (739) + case D3DERR_MATERIAL_CREATE_FAILED : // (740) + return "D3DERR_MATERIAL_CREATE_FAILED";//: // (740) + case D3DERR_MATERIAL_DESTROY_FAILED : // (741) + return "D3DERR_MATERIAL_DESTROY_FAILED";//: // (741) + case D3DERR_MATERIAL_SETDATA_FAILED : // (742) + return "D3DERR_MATERIAL_SETDATA_FAILED";//: // (742) + case D3DERR_MATERIAL_GETDATA_FAILED : // (743) + return "D3DERR_MATERIAL_GETDATA_FAILED";//: // (743) + case D3DERR_INVALIDPALETTE : // (744) + return "D3DERR_INVALIDPALETTE";//: // (744) + case D3DERR_ZBUFF_NEEDS_SYSTEMMEMORY : // (745) + return "D3DERR_ZBUFF_NEEDS_SYSTEMMEMORY";//: // (745) + case D3DERR_ZBUFF_NEEDS_VIDEOMEMORY : // (746) + return "D3DERR_ZBUFF_NEEDS_VIDEOMEMORY";//: // (746) + case D3DERR_SURFACENOTINVIDMEM : // (747) + return "D3DERR_SURFACENOTINVIDMEM";//: // (747) + case D3DERR_LIGHT_SET_FAILED : // (750) + return "D3DERR_LIGHT_SET_FAILED";//: // (750) + case D3DERR_LIGHTHASVIEWPORT : // (751) + return "D3DERR_LIGHTHASVIEWPORT";//: // (751) + case D3DERR_LIGHTNOTINTHISVIEWPORT : // (752) + return "D3DERR_LIGHTNOTINTHISVIEWPORT";//: // (752) + case D3DERR_SCENE_IN_SCENE : // (760) + return "D3DERR_SCENE_IN_SCENE";//: // (760) + case D3DERR_SCENE_NOT_IN_SCENE : // (761) + return "D3DERR_SCENE_NOT_IN_SCENE";//: // (761) + case D3DERR_SCENE_BEGIN_FAILED : // (762) + return "D3DERR_SCENE_BEGIN_FAILED";//: // (762) + case D3DERR_SCENE_END_FAILED : // (763) + return "D3DERR_SCENE_END_FAILED";//: // (763) + case D3DERR_INBEGIN : // (770) + return "D3DERR_INBEGIN";//: // (770) + case D3DERR_NOTINBEGIN : // (771) + return "D3DERR_NOTINBEGIN";//: // (771) + case D3DERR_NOVIEWPORTS : // (772) + return "D3DERR_NOVIEWPORTS";//: // (772) + case D3DERR_VIEWPORTDATANOTSET : // (773) + return "D3DERR_VIEWPORTDATANOTSET";//: // (773) + case D3DERR_VIEWPORTHASNODEVICE : // (774) + return "D3DERR_VIEWPORTHASNODEVICE";//: // (774) + case D3DERR_NOCURRENTVIEWPORT : // (775) + return "D3DERR_NOCURRENTVIEWPORT";//: // (775) + case D3DERR_INVALIDVERTEXFORMAT : // (2048) + return "D3DERR_INVALIDVERTEXFORMAT";//: // (2048) + case D3DERR_COLORKEYATTACHED : // (2050) + return "D3DERR_COLORKEYATTACHED";//: // (2050) + case D3DERR_VERTEXBUFFEROPTIMIZED : // (2060) + return "D3DERR_VERTEXBUFFEROPTIMIZED";//: // (2060) + case D3DERR_VBUF_CREATE_FAILED : // (2061) + return "D3DERR_VBUF_CREATE_FAILED";//: // (2061) + case D3DERR_VERTEXBUFFERLOCKED : // (2062) + return "D3DERR_VERTEXBUFFERLOCKED";//: // (2062) + case D3DERR_ZBUFFER_NOTPRESENT : // (2070) + return "D3DERR_ZBUFFER_NOTPRESENT";//: // (2070) + case D3DERR_STENCILBUFFER_NOTPRESENT : // (2071) + return "D3DERR_STENCILBUFFER_NOTPRESENT";//: // (2071) + case D3DERR_WRONGTEXTUREFORMAT : // (2072) + return "D3DERR_WRONGTEXTUREFORMAT";//: // (2072) + case D3DERR_UNSUPPORTEDCOLOROPERATION : // (2073) + return "D3DERR_UNSUPPORTEDCOLOROPERATION";//: // (2073) + case D3DERR_UNSUPPORTEDCOLORARG : // (2074) + return "D3DERR_UNSUPPORTEDCOLORARG";//: // (2074) + case D3DERR_UNSUPPORTEDALPHAOPERATION : // (2075) + return "D3DERR_UNSUPPORTEDALPHAOPERATION";//: // (2075) + case D3DERR_UNSUPPORTEDALPHAARG : // (2076) + return "D3DERR_UNSUPPORTEDALPHAARG";//: // (2076) + case D3DERR_TOOMANYOPERATIONS : // (2077) + return "D3DERR_TOOMANYOPERATIONS";//: // (2077) + case D3DERR_CONFLICTINGTEXTUREFILTER : // (2078) + return "D3DERR_CONFLICTINGTEXTUREFILTER";//: // (2078) + case D3DERR_UNSUPPORTEDFACTORVALUE : // (2079) + return "D3DERR_UNSUPPORTEDFACTORVALUE";//: // (2079) + case D3DERR_CONFLICTINGRENDERSTATE : // (2081) + return "D3DERR_CONFLICTINGRENDERSTATE";//: // (2081) + case D3DERR_UNSUPPORTEDTEXTUREFILTER : // (2082) + return "D3DERR_UNSUPPORTEDTEXTUREFILTER";//: // (2082) + case D3DERR_TOOMANYPRIMITIVES : // (2083) + return "D3DERR_TOOMANYPRIMITIVES";//: // (2083) + case D3DERR_INVALIDMATRIX : // (2084) + return "D3DERR_INVALIDMATRIX";//: // (2084) + case D3DERR_TOOMANYVERTICES : // (2085) + return "D3DERR_TOOMANYVERTICES";//: // (2085) + case D3DERR_CONFLICTINGTEXTUREPALETTE : // (2086) + return "D3DERR_CONFLICTINGTEXTUREPALETTE";//: // (2086) +//#if DX7 + case D3DERR_VERTEXBUFFERUNLOCKFAILED : // (2063) + return "D3DERR_VERTEXBUFFERUNLOCKFAILED";//: // (2063) + case D3DERR_INVALIDSTATEBLOCK : // (2100) + return "D3DERR_INVALIDSTATEBLOCK";//: // (2100) + case D3DERR_INBEGINSTATEBLOCK : // (2101) + return "D3DERR_INBEGINSTATEBLOCK";//: // (2101) + case D3DERR_NOTINBEGINSTATEBLOCK : // (2102) + return "D3DERR_NOTINBEGINSTATEBLOCK";//: // (2102) + //case D3DERR_INOVERLAYSTATEBLOCK : // (2103) + // return "D3DERR_INOVERLAYSTATEBLOCK";//: // (2103) + case DDERR_NOSTEREOHARDWARE : // ( 181 ) + return "DDERR_NOSTEREOHARDWARE ";//: // ( 181 ) + case DDERR_NOSURFACELEFT : // ( 182 ) + return "DDERR_NOSURFACELEFT ";//: // ( 182 ) + case DDERR_DDSCAPSCOMPLEXREQUIRED : // ( 542 ) + return "DDERR_DDSCAPSCOMPLEXREQUIRED";//: // ( 542 ) + case DDERR_NOTONMIPMAPSUBLEVEL : // ( 603 ) + return "DDERR_NOTONMIPMAPSUBLEVEL";//: // ( 603 ) + case DDERR_TESTFINISHED : // ( 692 ) + return "DDERR_TESTFINISHED";//: // ( 692 ) + case DDERR_NEWMODE : // ( 693 ) + return "DDERR_NEWMODE";//: // ( 693 ) +//#endif + //case D3DERR_COMMAND_UNPARSED : // (3000) + /// return "case";//D3DERR_COMMAND_UNPARSED : // (3000) + + case DDERR_ALREADYINITIALIZED : // ( 5 ) + return "DDERR_ALREADYINITIALIZED ";//: // ( 5 ) + case DDERR_CANNOTATTACHSURFACE : // ( 10 ) + return "DDERR_CANNOTATTACHSURFACE ";//: // ( 10 ) + case DDERR_CANNOTDETACHSURFACE : // ( 20 ) + return "DDERR_CANNOTDETACHSURFACE ";//: // ( 20 ) + case DDERR_CURRENTLYNOTAVAIL : // ( 40 ) + return "DDERR_CURRENTLYNOTAVAIL ";//: // ( 40 ) + case DDERR_EXCEPTION : // ( 55 ) + return "DDERR_EXCEPTION ";//: // ( 55 ) + case DDERR_HEIGHTALIGN : // ( 90 ) + return "DDERR_HEIGHTALIGN ";//: // ( 90 ) + case DDERR_INCOMPATIBLEPRIMARY : // ( 95 ) + return "DDERR_INCOMPATIBLEPRIMARY ";//: // ( 95 ) + case DDERR_INVALIDCAPS : // ( 100 ) + return "DDERR_INVALIDCAPS ";//: // ( 100 ) + case DDERR_INVALIDCLIPLIST : // ( 110 ) + return "DDERR_INVALIDCLIPLIST ";//: // ( 110 ) + case DDERR_INVALIDMODE : // ( 120 ) + return "DDERR_INVALIDMODE ";//: // ( 120 ) + case DDERR_INVALIDOBJECT : // ( 130 ) + return "DDERR_INVALIDOBJECT ";//: // ( 130 ) + case DDERR_INVALIDPIXELFORMAT : // ( 145 ) + return "DDERR_INVALIDPIXELFORMAT ";//: // ( 145 ) + case DDERR_INVALIDRECT : // ( 150 ) + return "DDERR_INVALIDRECT ";//: // ( 150 ) + case DDERR_LOCKEDSURFACES : // ( 160 ) + return "DDERR_LOCKEDSURFACES ";//: // ( 160 ) + case DDERR_NO3D : // ( 170 ) + return "DDERR_NO3D ";//: // ( 170 ) + case DDERR_NOALPHAHW : // ( 180 ) + return "DDERR_NOALPHAHW ";//: // ( 180 ) + case DDERR_NOCLIPLIST : // ( 205 ) + return "DDERR_NOCLIPLIST ";//: // ( 205 ) + case DDERR_NOCOLORCONVHW : // ( 210 ) + return "DDERR_NOCOLORCONVHW ";//: // ( 210 ) + case DDERR_NOCOOPERATIVELEVELSET : // ( 212 ) + return "DDERR_NOCOOPERATIVELEVELSET ";//: // ( 212 ) + case DDERR_NOCOLORKEY : // ( 215 ) + return "DDERR_NOCOLORKEY ";//: // ( 215 ) + case DDERR_NOCOLORKEYHW : // ( 220 ) + return "DDERR_NOCOLORKEYHW ";//: // ( 220 ) + case DDERR_NODIRECTDRAWSUPPORT : // ( 222 ) + return "DDERR_NODIRECTDRAWSUPPORT ";//: // ( 222 ) + case DDERR_NOEXCLUSIVEMODE : // ( 225 ) + return "DDERR_NOEXCLUSIVEMODE ";//: // ( 225 ) + case DDERR_NOFLIPHW : // ( 230 ) + return "DDERR_NOFLIPHW ";//: // ( 230 ) + case DDERR_NOGDI : // ( 240 ) + return "DDERR_NOGDI ";//: // ( 240 ) + case DDERR_NOMIRRORHW : // ( 250 ) + return "DDERR_NOMIRRORHW ";//: // ( 250 ) + case DDERR_NOTFOUND : // ( 255 ) + return "DDERR_NOTFOUND ";//: // ( 255 ) + case DDERR_NOOVERLAYHW : // ( 260 ) + return "DDERR_NOOVERLAYHW ";//: // ( 260 ) + case DDERR_OVERLAPPINGRECTS : // ( 270 ) + return "DDERR_OVERLAPPINGRECTS ";//: // ( 270 ) + case DDERR_NORASTEROPHW : // ( 280 ) + return "DDERR_NORASTEROPHW ";//: // ( 280 ) + case DDERR_NOROTATIONHW : // ( 290 ) + return "DDERR_NOROTATIONHW ";//: // ( 290 ) + case DDERR_NOSTRETCHHW : // ( 310 ) + return "DDERR_NOSTRETCHHW ";//: // ( 310 ) + case DDERR_NOT4BITCOLOR : // ( 316 ) + return "DDERR_NOT4BITCOLOR ";//: // ( 316 ) + case DDERR_NOT4BITCOLORINDEX : // ( 317 ) + return "DDERR_NOT4BITCOLORINDEX ";//: // ( 317 ) + case DDERR_NOT8BITCOLOR : // ( 320 ) + return "DDERR_NOT8BITCOLOR ";//: // ( 320 ) + case DDERR_NOTEXTUREHW : // ( 330 ) + return "DDERR_NOTEXTUREHW ";//: // ( 330 ) + case DDERR_NOVSYNCHW : // ( 335 ) + return "DDERR_NOVSYNCHW ";//: // ( 335 ) + case DDERR_NOZBUFFERHW : // ( 340 ) + return "DDERR_NOZBUFFERHW ";//: // ( 340 ) + case DDERR_NOZOVERLAYHW : // ( 350 ) + return "DDERR_NOZOVERLAYHW ";//: // ( 350 ) + case DDERR_OUTOFCAPS : // ( 360 ) + return "DDERR_OUTOFCAPS ";//: // ( 360 ) + case DDERR_OUTOFVIDEOMEMORY : // ( 380 ) + return "DDERR_OUTOFVIDEOMEMORY ";//: // ( 380 ) + case DDERR_OVERLAYCANTCLIP : // ( 382 ) + return "DDERR_OVERLAYCANTCLIP ";//: // ( 382 ) + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE : // ( 384 ) + return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE ";//: // ( 384 ) + case DDERR_PALETTEBUSY : // ( 387 ) + return "DDERR_PALETTEBUSY ";//: // ( 387 ) + case DDERR_COLORKEYNOTSET : // ( 400 ) + return "DDERR_COLORKEYNOTSET ";//: // ( 400 ) + case DDERR_SURFACEALREADYATTACHED : // ( 410 ) + return "DDERR_SURFACEALREADYATTACHED ";//: // ( 410 ) + case DDERR_SURFACEALREADYDEPENDENT : // ( 420 ) + return "DDERR_SURFACEALREADYDEPENDENT ";//: // ( 420 ) + case DDERR_SURFACEBUSY : // ( 430 ) + return "DDERR_SURFACEBUSY ";//: // ( 430 ) + case DDERR_CANTLOCKSURFACE : // ( 435 ) + return "DDERR_CANTLOCKSURFACE";//: // ( 435 ) + case DDERR_SURFACEISOBSCURED : // ( 440 ) + return "DDERR_SURFACEISOBSCURED ";//: // ( 440 ) + case DDERR_SURFACELOST : // ( 450 ) + return "DDERR_SURFACELOST ";//: // ( 450 ) + case DDERR_SURFACENOTATTACHED : // ( 460 ) + return "DDERR_SURFACENOTATTACHED ";//: // ( 460 ) + case DDERR_TOOBIGHEIGHT : // ( 470 ) + return "DDERR_TOOBIGHEIGHT ";//: // ( 470 ) + case DDERR_TOOBIGSIZE : // ( 480 ) + return "DDERR_TOOBIGSIZE ";//: // ( 480 ) + case DDERR_TOOBIGWIDTH : // ( 490 ) + return "DDERR_TOOBIGWIDTH ";//: // ( 490 ) + case DDERR_UNSUPPORTEDFORMAT : // ( 510 ) + return "DDERR_UNSUPPORTEDFORMAT ";//: // ( 510 ) + case DDERR_UNSUPPORTEDMASK : // ( 520 ) + return "DDERR_UNSUPPORTEDMASK ";//: // ( 520 ) + case DDERR_INVALIDSTREAM : // ( 521 ) + return "DDERR_INVALIDSTREAM";//: // ( 521 ) + case DDERR_VERTICALBLANKINPROGRESS : // ( 537 ) + return "DDERR_VERTICALBLANKINPROGRESS ";//: // ( 537 ) + case DDERR_WASSTILLDRAWING : // ( 540 ) + return "DDERR_WASSTILLDRAWING ";//: // ( 540 ) + case DDERR_XALIGN : // ( 560 ) + return "DDERR_XALIGN ";//: // ( 560 ) + case DDERR_INVALIDDIRECTDRAWGUID : // ( 561 ) + return "DDERR_INVALIDDIRECTDRAWGUID ";//: // ( 561 ) + case DDERR_DIRECTDRAWALREADYCREATED : // ( 562 ) + return "DDERR_DIRECTDRAWALREADYCREATED ";//: // ( 562 ) + case DDERR_NODIRECTDRAWHW : // ( 563 ) + return "DDERR_NODIRECTDRAWHW ";//: // ( 563 ) + case DDERR_PRIMARYSURFACEALREADYEXISTS : // ( 564 ) + return "DDERR_PRIMARYSURFACEALREADYEXISTS ";//: // ( 564 ) + case DDERR_NOEMULATION : // ( 565 ) + return "DDERR_NOEMULATION ";//: // ( 565 ) + case DDERR_REGIONTOOSMALL : // ( 566 ) + return "DDERR_REGIONTOOSMALL ";//: // ( 566 ) + case DDERR_CLIPPERISUSINGHWND : // ( 567 ) + return "DDERR_CLIPPERISUSINGHWND ";//: // ( 567 ) + case DDERR_NOCLIPPERATTACHED : // ( 568 ) + return "DDERR_NOCLIPPERATTACHED ";//: // ( 568 ) + case DDERR_NOHWND : // ( 569 ) + return "DDERR_NOHWND ";//: // ( 569 ) + case DDERR_HWNDSUBCLASSED : // ( 570 ) + return "DDERR_HWNDSUBCLASSED ";//: // ( 570 ) + case DDERR_HWNDALREADYSET : // ( 571 ) + return "DDERR_HWNDALREADYSET ";//: // ( 571 ) + case DDERR_NOPALETTEATTACHED : // ( 572 ) + return "DDERR_NOPALETTEATTACHED ";//: // ( 572 ) + case DDERR_NOPALETTEHW : // ( 573 ) + return "DDERR_NOPALETTEHW ";//: // ( 573 ) + case DDERR_BLTFASTCANTCLIP : // ( 574 ) + return "DDERR_BLTFASTCANTCLIP ";//: // ( 574 ) + case DDERR_NOBLTHW : // ( 575 ) + return "DDERR_NOBLTHW ";//: // ( 575 ) + case DDERR_NODDROPSHW : // ( 576 ) + return "DDERR_NODDROPSHW ";//: // ( 576 ) + case DDERR_OVERLAYNOTVISIBLE : // ( 577 ) + return "DDERR_OVERLAYNOTVISIBLE ";//: // ( 577 ) + case DDERR_NOOVERLAYDEST : // ( 578 ) + return "DDERR_NOOVERLAYDEST ";//: // ( 578 ) + case DDERR_INVALIDPOSITION : // ( 579 ) + return "DDERR_INVALIDPOSITION ";//: // ( 579 ) + case DDERR_NOTAOVERLAYSURFACE : // ( 580 ) + return "DDERR_NOTAOVERLAYSURFACE ";//: // ( 580 ) + case DDERR_EXCLUSIVEMODEALREADYSET : // ( 581 ) + return "DDERR_EXCLUSIVEMODEALREADYSET ";//: // ( 581 ) + case DDERR_NOTFLIPPABLE : // ( 582 ) + return "DDERR_NOTFLIPPABLE ";//: // ( 582 ) + case DDERR_CANTDUPLICATE : // ( 583 ) + return "DDERR_CANTDUPLICATE ";//: // ( 583 ) + case DDERR_NOTLOCKED : // ( 584 ) + return "DDERR_NOTLOCKED ";//: // ( 584 ) + case DDERR_CANTCREATEDC : // ( 585 ) + return "DDERR_CANTCREATEDC ";//: // ( 585 ) + case DDERR_NODC : // ( 586 ) + return "DDERR_NODC ";//: // ( 586 ) + case DDERR_WRONGMODE : // ( 587 ) + return "DDERR_WRONGMODE ";//: // ( 587 ) + case DDERR_IMPLICITLYCREATED : // ( 588 ) + return "DDERR_IMPLICITLYCREATED ";//: // ( 588 ) + case DDERR_NOTPALETTIZED : // ( 589 ) + return "DDERR_NOTPALETTIZED ";//: // ( 589 ) + case DDERR_UNSUPPORTEDMODE : // ( 590 ) + return "DDERR_UNSUPPORTEDMODE ";//: // ( 590 ) + case DDERR_NOMIPMAPHW : // ( 591 ) + return "DDERR_NOMIPMAPHW ";//: // ( 591 ) + case DDERR_INVALIDSURFACETYPE : // ( 592 ) + return "DDERR_INVALIDSURFACETYPE";//: // ( 592 ) + case DDERR_NOOPTIMIZEHW : // ( 600 ) + return "DDERR_NOOPTIMIZEHW";//: // ( 600 ) + case DDERR_NOTLOADED : // ( 601 ) + return "DDERR_NOTLOADED";//: // ( 601 ) + case DDERR_NOFOCUSWINDOW : // ( 602 ) + return "DDERR_NOFOCUSWINDOW";//: // ( 602 ) + case DDERR_DCALREADYCREATED : // ( 620 ) + return "DDERR_DCALREADYCREATED ";//: // ( 620 ) + case DDERR_NONONLOCALVIDMEM : // ( 630 ) + return "DDERR_NONONLOCALVIDMEM";//: // ( 630 ) + case DDERR_CANTPAGELOCK : // ( 640 ) + return "DDERR_CANTPAGELOCK ";//: // ( 640 ) + case DDERR_CANTPAGEUNLOCK : // ( 660 ) + return "DDERR_CANTPAGEUNLOCK ";//: // ( 660 ) + case DDERR_NOTPAGELOCKED : // ( 680 ) + return "DDERR_NOTPAGELOCKED ";//: // ( 680 ) + case DDERR_MOREDATA : // ( 690 ) + return "DDERR_MOREDATA ";//: // ( 690 ) + case DDERR_EXPIRED : // ( 691 ) + return "DDERR_EXPIRED";//: // ( 691 ) + case DDERR_VIDEONOTACTIVE : // ( 695 ) + return "DDERR_VIDEONOTACTIVE ";//: // ( 695 ) + case DDERR_DEVICEDOESNTOWNSURFACE : // ( 699 ) + return "DDERR_DEVICEDOESNTOWNSURFACE ";//: // ( 699 ) + case DXFILEERR_BADOBJECT : // (850) + return "DXFILEERR_BADOBJECT";//: // (850) + case DXFILEERR_BADVALUE : // (851) + return "DXFILEERR_BADVALUE";//: // (851) + case DXFILEERR_BADTYPE : // (852) + return "DXFILEERR_BADTYPE";//: // (852) + case DXFILEERR_BADSTREAMHANDLE : // (853) + return "DXFILEERR_BADSTREAMHANDLE";//: // (853) + case DXFILEERR_BADALLOC : // (854) + return "DXFILEERR_BADALLOC";//: // (854) + case DXFILEERR_NOTFOUND : // (855) + return "DXFILEERR_NOTFOUND";//: // (855) + case DXFILEERR_NOTDONEYET : // (856) + return "DXFILEERR_NOTDONEYET";//: // (856) + case DXFILEERR_FILENOTFOUND : // (857) + return "DXFILEERR_FILENOTFOUND";//: // (857) + case DXFILEERR_RESOURCENOTFOUND : // (858) + return "DXFILEERR_RESOURCENOTFOUND";//: // (858) + case DXFILEERR_URLNOTFOUND : // (859) + return "DXFILEERR_URLNOTFOUND";//: // (859) + case DXFILEERR_BADRESOURCE : // (860) + return "DXFILEERR_BADRESOURCE";//: // (860) + case DXFILEERR_BADFILETYPE : // (861) + return "DXFILEERR_BADFILETYPE";//: // (861) + case DXFILEERR_BADFILEVERSION : // (862) + return "DXFILEERR_BADFILEVERSION";//: // (862) + case DXFILEERR_BADFILEFLOATSIZE : // (863) + return "DXFILEERR_BADFILEFLOATSIZE";//: // (863) + case DXFILEERR_BADFILECOMPRESSIONTYPE : // (864) + return "DXFILEERR_BADFILECOMPRESSIONTYPE";//: // (864) + case DXFILEERR_BADFILE : // (865) + return "DXFILEERR_BADFILE";//: // (865) + case DXFILEERR_PARSEERROR : // (866) + return "DXFILEERR_PARSEERROR";//: // (866) + case DXFILEERR_NOTEMPLATE : // (867) + return "DXFILEERR_NOTEMPLATE";//: // (867) + case DXFILEERR_BADARRAYSIZE : // (868) + return "DXFILEERR_BADARRAYSIZE";//: // (868) + case DXFILEERR_BADDATAREFERENCE : // (869) + return "DXFILEERR_BADDATAREFERENCE";//: // (869) + case DXFILEERR_INTERNALERROR : // (870) + return "DXFILEERR_INTERNALERROR";//: // (870) + case DXFILEERR_NOMOREOBJECTS : // (871) + return "DXFILEERR_NOMOREOBJECTS";//: // (871) + case DXFILEERR_BADINTRINSICS : // (872) + return "DXFILEERR_BADINTRINSICS";//: // (872) + case DXFILEERR_NOMORESTREAMHANDLES : // (873) + return "DXFILEERR_NOMORESTREAMHANDLES";//: // (873) + case DXFILEERR_NOMOREDATA : // (874) + return "DXFILEERR_NOMOREDATA";//: // (874) + case DXFILEERR_BADCACHEFILE : // (875) + return "DXFILEERR_BADCACHEFILE";//: // (875) + case DXFILEERR_NOINTERNET : // (876) + return "DXFILEERR_NOINTERNET";//: // (876) + + case E_UNEXPECTED : + return "E_UNEXPECTED "; + case E_NOTIMPL : + return "E_NOTIMPL "; + case E_OUTOFMEMORY : + return "E_OUTOFMEMORY "; + case E_INVALIDARG : + return "E_INVALIDARG or DDERR_INVALIDPARAMS"; + case E_NOINTERFACE : + return "E_NOINTERFACE "; + case E_POINTER : + return "E_POINTER "; + case E_HANDLE : + return "E_HANDLE "; + case E_ABORT : + return "E_ABORT "; +// case E_FAIL : +// return "E_FAIL "; + case E_ACCESSDENIED : + return "E_ACCESSDENIED "; + case E_PENDING : + return "E_PENDING "; + case CO_E_INIT_TLS : + return "CO_E_INIT_TLS "; + case CO_E_INIT_SHARED_ALLOCATOR : + return "CO_E_INIT_SHARED_ALLOCATOR "; + case CO_E_INIT_MEMORY_ALLOCATOR : + return "CO_E_INIT_MEMORY_ALLOCATOR "; + case CO_E_INIT_CLASS_CACHE : + return "CO_E_INIT_CLASS_CACHE "; + case CO_E_INIT_RPC_CHANNEL : + return "CO_E_INIT_RPC_CHANNEL "; + case CO_E_INIT_TLS_SET_CHANNEL_CONTROL : + return "CO_E_INIT_TLS_SET_CHANNEL_CONTROL "; + case CO_E_INIT_TLS_CHANNEL_CONTROL : + return "CO_E_INIT_TLS_CHANNEL_CONTROL "; + case CO_E_INIT_UNACCEPTED_USER_ALLOCATOR : + return "CO_E_INIT_UNACCEPTED_USER_ALLOCATOR "; + case CO_E_INIT_SCM_MUTEX_EXISTS : + return "CO_E_INIT_SCM_MUTEX_EXISTS "; + case CO_E_INIT_SCM_FILE_MAPPING_EXISTS : + return "CO_E_INIT_SCM_FILE_MAPPING_EXISTS "; + case CO_E_INIT_SCM_MAP_VIEW_OF_FILE : + return "CO_E_INIT_SCM_MAP_VIEW_OF_FILE "; + case CO_E_INIT_SCM_EXEC_FAILURE : + return "CO_E_INIT_SCM_EXEC_FAILURE "; + case CO_E_INIT_ONLY_SINGLE_THREADED : + return "CO_E_INIT_ONLY_SINGLE_THREADED "; + case CO_E_CANT_REMOTE : + return "CO_E_CANT_REMOTE "; + case CO_E_BAD_SERVER_NAME : + return "CO_E_BAD_SERVER_NAME "; + case CO_E_WRONG_SERVER_IDENTITY : + return "CO_E_WRONG_SERVER_IDENTITY "; + case CO_E_OLE1DDE_DISABLED : + return "CO_E_OLE1DDE_DISABLED "; + case CO_E_RUNAS_SYNTAX : + return "CO_E_RUNAS_SYNTAX "; + case CO_E_CREATEPROCESS_FAILURE : + return "CO_E_CREATEPROCESS_FAILURE "; + case CO_E_RUNAS_CREATEPROCESS_FAILURE : + return "CO_E_RUNAS_CREATEPROCESS_FAILURE "; + case CO_E_RUNAS_LOGON_FAILURE : + return "CO_E_RUNAS_LOGON_FAILURE "; + case CO_E_LAUNCH_PERMSSION_DENIED : + return "CO_E_LAUNCH_PERMSSION_DENIED "; + case CO_E_START_SERVICE_FAILURE : + return "CO_E_START_SERVICE_FAILURE "; + case CO_E_REMOTE_COMMUNICATION_FAILURE : + return "CO_E_REMOTE_COMMUNICATION_FAILURE "; + case CO_E_SERVER_START_TIMEOUT : + return "CO_E_SERVER_START_TIMEOUT "; + case CO_E_CLSREG_INCONSISTENT : + return "CO_E_CLSREG_INCONSISTENT "; + case CO_E_IIDREG_INCONSISTENT : + return "CO_E_IIDREG_INCONSISTENT "; + case CO_E_NOT_SUPPORTED : + return "CO_E_NOT_SUPPORTED "; + case CO_E_RELOAD_DLL : + return "CO_E_RELOAD_DLL "; + case CO_E_MSI_ERROR : + return "CO_E_MSI_ERROR "; + case OLE_E_OLEVERB : + return "OLE_E_OLEVERB "; + case OLE_E_ADVF : + return "OLE_E_ADVF "; + case OLE_E_ENUM_NOMORE : + return "OLE_E_ENUM_NOMORE "; + case OLE_E_ADVISENOTSUPPORTED : + return "OLE_E_ADVISENOTSUPPORTED "; + case OLE_E_NOCONNECTION : + return "OLE_E_NOCONNECTION "; + case OLE_E_NOTRUNNING : + return "OLE_E_NOTRUNNING "; + case OLE_E_NOCACHE : + return "OLE_E_NOCACHE "; + case OLE_E_BLANK : + return "OLE_E_BLANK "; + case OLE_E_CLASSDIFF : + return "OLE_E_CLASSDIFF "; + case OLE_E_CANT_GETMONIKER : + return "OLE_E_CANT_GETMONIKER "; + case OLE_E_CANT_BINDTOSOURCE : + return "OLE_E_CANT_BINDTOSOURCE "; + case OLE_E_STATIC : + return "OLE_E_STATIC "; + case OLE_E_PROMPTSAVECANCELLED : + return "OLE_E_PROMPTSAVECANCELLED "; + case OLE_E_INVALIDRECT : + return "OLE_E_INVALIDRECT "; + case OLE_E_WRONGCOMPOBJ : + return "OLE_E_WRONGCOMPOBJ "; + case OLE_E_INVALIDHWND : + return "OLE_E_INVALIDHWND "; + case OLE_E_NOT_INPLACEACTIVE : + return "OLE_E_NOT_INPLACEACTIVE "; + case OLE_E_CANTCONVERT : + return "OLE_E_CANTCONVERT "; + case OLE_E_NOSTORAGE : + return "OLE_E_NOSTORAGE "; + case DV_E_FORMATETC : + return "DV_E_FORMATETC "; + case DV_E_DVTARGETDEVICE : + return "DV_E_DVTARGETDEVICE "; + case DV_E_STGMEDIUM : + return "DV_E_STGMEDIUM "; + case DV_E_STATDATA : + return "DV_E_STATDATA "; + case DV_E_LINDEX : + return "DV_E_LINDEX "; + case DV_E_TYMED : + return "DV_E_TYMED "; + case DV_E_CLIPFORMAT : + return "DV_E_CLIPFORMAT "; + case DV_E_DVASPECT : + return "DV_E_DVASPECT "; + case DV_E_DVTARGETDEVICE_SIZE : + return "DV_E_DVTARGETDEVICE_SIZE "; + case DV_E_NOIVIEWOBJECT : + return "DV_E_NOIVIEWOBJECT "; + case DRAGDROP_E_NOTREGISTERED : + return "DRAGDROP_E_NOTREGISTERED "; + case DRAGDROP_E_ALREADYREGISTERED : + return "DRAGDROP_E_ALREADYREGISTERED "; + case DRAGDROP_E_INVALIDHWND : + return "DRAGDROP_E_INVALIDHWND "; + case CLASS_E_NOAGGREGATION : + return "CLASS_E_NOAGGREGATION "; + case CLASS_E_CLASSNOTAVAILABLE : + return "CLASS_E_CLASSNOTAVAILABLE "; + case CLASS_E_NOTLICENSED : + return "CLASS_E_NOTLICENSED "; + case VIEW_E_DRAW : + return "VIEW_E_DRAW "; + case REGDB_E_READREGDB : + return "REGDB_E_READREGDB "; + case REGDB_E_WRITEREGDB : + return "REGDB_E_WRITEREGDB "; + case REGDB_E_KEYMISSING : + return "REGDB_E_KEYMISSING "; + case REGDB_E_INVALIDVALUE : + return "REGDB_E_INVALIDVALUE "; + case REGDB_E_CLASSNOTREG : + return "REGDB_E_CLASSNOTREG "; + case REGDB_E_IIDNOTREG : + return "REGDB_E_IIDNOTREG "; + case CAT_E_CATIDNOEXIST : + return "CAT_E_CATIDNOEXIST "; + case CAT_E_NODESCRIPTION : + return "CAT_E_NODESCRIPTION "; + case CS_E_PACKAGE_NOTFOUND : + return "CS_E_PACKAGE_NOTFOUND "; + case CS_E_NOT_DELETABLE : + return "CS_E_NOT_DELETABLE "; + case CS_E_CLASS_NOTFOUND : + return "CS_E_CLASS_NOTFOUND "; + case CS_E_INVALID_VERSION : + return "CS_E_INVALID_VERSION "; + case CS_E_NO_CLASSSTORE : + return "CS_E_NO_CLASSSTORE "; + case CACHE_E_NOCACHE_UPDATED : + return "CACHE_E_NOCACHE_UPDATED "; + case OLEOBJ_E_NOVERBS : + return "OLEOBJ_E_NOVERBS "; + case OLEOBJ_E_INVALIDVERB : + return "OLEOBJ_E_INVALIDVERB "; + case INPLACE_E_NOTUNDOABLE : + return "INPLACE_E_NOTUNDOABLE "; + case INPLACE_E_NOTOOLSPACE : + return "INPLACE_E_NOTOOLSPACE "; + case CONVERT10_E_OLESTREAM_GET : + return "CONVERT10_E_OLESTREAM_GET "; + case CONVERT10_E_OLESTREAM_PUT : + return "CONVERT10_E_OLESTREAM_PUT "; + case CONVERT10_E_OLESTREAM_FMT : + return "CONVERT10_E_OLESTREAM_FMT "; + case CONVERT10_E_OLESTREAM_BITMAP_TO_DIB : + return "CONVERT10_E_OLESTREAM_BITMAP_TO_DIB "; + case CONVERT10_E_STG_FMT : + return "CONVERT10_E_STG_FMT "; + case CONVERT10_E_STG_NO_STD_STREAM : + return "CONVERT10_E_STG_NO_STD_STREAM "; + case CONVERT10_E_STG_DIB_TO_BITMAP : + return "CONVERT10_E_STG_DIB_TO_BITMAP "; + case CLIPBRD_E_CANT_OPEN : + return "CLIPBRD_E_CANT_OPEN "; + case CLIPBRD_E_CANT_EMPTY : + return "CLIPBRD_E_CANT_EMPTY "; + case CLIPBRD_E_CANT_SET : + return "CLIPBRD_E_CANT_SET "; + case CLIPBRD_E_BAD_DATA : + return "CLIPBRD_E_BAD_DATA "; + case CLIPBRD_E_CANT_CLOSE : + return "CLIPBRD_E_CANT_CLOSE "; + case MK_E_CONNECTMANUALLY : + return "MK_E_CONNECTMANUALLY "; + case MK_E_EXCEEDEDDEADLINE : + return "MK_E_EXCEEDEDDEADLINE "; + case MK_E_NEEDGENERIC : + return "MK_E_NEEDGENERIC "; + case MK_E_UNAVAILABLE : + return "MK_E_UNAVAILABLE "; + case MK_E_SYNTAX : + return "MK_E_SYNTAX "; + case MK_E_NOOBJECT : + return "MK_E_NOOBJECT "; + case MK_E_INVALIDEXTENSION : + return "MK_E_INVALIDEXTENSION "; + case MK_E_INTERMEDIATEINTERFACENOTSUPPORTED : + return "MK_E_INTERMEDIATEINTERFACENOTSUPPORTED "; + case MK_E_NOTBINDABLE : + return "MK_E_NOTBINDABLE "; + case MK_E_NOTBOUND : + return "MK_E_NOTBOUND "; + case MK_E_CANTOPENFILE : + return "MK_E_CANTOPENFILE "; + case MK_E_MUSTBOTHERUSER : + return "MK_E_MUSTBOTHERUSER "; + case MK_E_NOINVERSE : + return "MK_E_NOINVERSE "; + case MK_E_NOSTORAGE : + return "MK_E_NOSTORAGE "; + case MK_E_NOPREFIX : + return "MK_E_NOPREFIX "; + case MK_E_ENUMERATION_FAILED : + return "MK_E_ENUMERATION_FAILED "; + case CO_E_NOTINITIALIZED : + return "CO_E_NOTINITIALIZED "; + case CO_E_ALREADYINITIALIZED : + return "CO_E_ALREADYINITIALIZED "; + case CO_E_CANTDETERMINECLASS : + return "CO_E_CANTDETERMINECLASS "; + case CO_E_CLASSSTRING : + return "CO_E_CLASSSTRING "; + case CO_E_IIDSTRING : + return "CO_E_IIDSTRING "; + case CO_E_APPNOTFOUND : + return "CO_E_APPNOTFOUND "; + case CO_E_APPSINGLEUSE : + return "CO_E_APPSINGLEUSE "; + case CO_E_ERRORINAPP : + return "CO_E_ERRORINAPP "; + case CO_E_DLLNOTFOUND : + return "CO_E_DLLNOTFOUND "; + case CO_E_ERRORINDLL : + return "CO_E_ERRORINDLL "; + case CO_E_WRONGOSFORAPP : + return "CO_E_WRONGOSFORAPP "; + case CO_E_OBJNOTREG : + return "CO_E_OBJNOTREG "; + case CO_E_OBJISREG : + return "CO_E_OBJISREG "; + case CO_E_OBJNOTCONNECTED : + return "CO_E_OBJNOTCONNECTED "; + case CO_E_APPDIDNTREG : + return "CO_E_APPDIDNTREG "; + case CO_E_RELEASED : + return "CO_E_RELEASED "; + case CO_E_FAILEDTOIMPERSONATE : + return "CO_E_FAILEDTOIMPERSONATE "; + case CO_E_FAILEDTOGETSECCTX : + return "CO_E_FAILEDTOGETSECCTX "; + case CO_E_FAILEDTOOPENTHREADTOKEN : + return "CO_E_FAILEDTOOPENTHREADTOKEN "; + case CO_E_FAILEDTOGETTOKENINFO : + return "CO_E_FAILEDTOGETTOKENINFO "; + case CO_E_TRUSTEEDOESNTMATCHCLIENT : + return "CO_E_TRUSTEEDOESNTMATCHCLIENT "; + case CO_E_FAILEDTOQUERYCLIENTBLANKET : + return "CO_E_FAILEDTOQUERYCLIENTBLANKET "; + case CO_E_FAILEDTOSETDACL : + return "CO_E_FAILEDTOSETDACL "; + case CO_E_ACCESSCHECKFAILED : + return "CO_E_ACCESSCHECKFAILED "; + case CO_E_NETACCESSAPIFAILED : + return "CO_E_NETACCESSAPIFAILED "; + case CO_E_WRONGTRUSTEENAMESYNTAX : + return "CO_E_WRONGTRUSTEENAMESYNTAX "; + case CO_E_INVALIDSID : + return "CO_E_INVALIDSID "; + case CO_E_CONVERSIONFAILED : + return "CO_E_CONVERSIONFAILED "; + case CO_E_NOMATCHINGSIDFOUND : + return "CO_E_NOMATCHINGSIDFOUND "; + case CO_E_LOOKUPACCSIDFAILED : + return "CO_E_LOOKUPACCSIDFAILED "; + case CO_E_NOMATCHINGNAMEFOUND : + return "CO_E_NOMATCHINGNAMEFOUND "; + case CO_E_LOOKUPACCNAMEFAILED : + return "CO_E_LOOKUPACCNAMEFAILED "; + case CO_E_SETSERLHNDLFAILED : + return "CO_E_SETSERLHNDLFAILED "; + case CO_E_FAILEDTOGETWINDIR : + return "CO_E_FAILEDTOGETWINDIR "; + case CO_E_PATHTOOLONG : + return "CO_E_PATHTOOLONG "; + case CO_E_FAILEDTOGENUUID : + return "CO_E_FAILEDTOGENUUID "; + case CO_E_FAILEDTOCREATEFILE : + return "CO_E_FAILEDTOCREATEFILE "; + case CO_E_FAILEDTOCLOSEHANDLE : + return "CO_E_FAILEDTOCLOSEHANDLE "; + case CO_E_EXCEEDSYSACLLIMIT : + return "CO_E_EXCEEDSYSACLLIMIT "; + case CO_E_ACESINWRONGORDER : + return "CO_E_ACESINWRONGORDER "; + case CO_E_INCOMPATIBLESTREAMVERSION : + return "CO_E_INCOMPATIBLESTREAMVERSION "; + case CO_E_FAILEDTOOPENPROCESSTOKEN : + return "CO_E_FAILEDTOOPENPROCESSTOKEN "; + case CO_E_DECODEFAILED : + return "CO_E_DECODEFAILED "; + case CO_E_ACNOTINITIALIZED : + return "CO_E_ACNOTINITIALIZED "; + case OLE_S_USEREG : + return "OLE_S_USEREG "; + case OLE_S_STATIC : + return "OLE_S_STATIC "; + case OLE_S_MAC_CLIPFORMAT : + return "OLE_S_MAC_CLIPFORMAT "; + case DRAGDROP_S_DROP : + return "DRAGDROP_S_DROP "; + case DRAGDROP_S_CANCEL : + return "DRAGDROP_S_CANCEL "; + case DRAGDROP_S_USEDEFAULTCURSORS : + return "DRAGDROP_S_USEDEFAULTCURSORS "; + case DATA_S_SAMEFORMATETC : + return "DATA_S_SAMEFORMATETC "; + case VIEW_S_ALREADY_FROZEN : + return "VIEW_S_ALREADY_FROZEN "; + case CACHE_S_FORMATETC_NOTSUPPORTED : + return "CACHE_S_FORMATETC_NOTSUPPORTED "; + case CACHE_S_SAMECACHE : + return "CACHE_S_SAMECACHE "; + case CACHE_S_SOMECACHES_NOTUPDATED : + return "CACHE_S_SOMECACHES_NOTUPDATED "; + case OLEOBJ_S_INVALIDVERB : + return "OLEOBJ_S_INVALIDVERB "; + case OLEOBJ_S_CANNOT_DOVERB_NOW : + return "OLEOBJ_S_CANNOT_DOVERB_NOW "; + case OLEOBJ_S_INVALIDHWND : + return "OLEOBJ_S_INVALIDHWND "; + case INPLACE_S_TRUNCATED : + return "INPLACE_S_TRUNCATED "; + case CONVERT10_S_NO_PRESENTATION : + return "CONVERT10_S_NO_PRESENTATION "; + case MK_S_REDUCED_TO_SELF : + return "MK_S_REDUCED_TO_SELF "; + case MK_S_ME : + return "MK_S_ME "; + case MK_S_HIM : + return "MK_S_HIM "; + case MK_S_US : + return "MK_S_US "; + case MK_S_MONIKERALREADYREGISTERED : + return "MK_S_MONIKERALREADYREGISTERED "; + case CO_E_CLASS_CREATE_FAILED : + return "CO_E_CLASS_CREATE_FAILED "; + case CO_E_SCM_ERROR : + return "CO_E_SCM_ERROR "; + case CO_E_SCM_RPC_FAILURE : + return "CO_E_SCM_RPC_FAILURE "; + case CO_E_BAD_PATH : + return "CO_E_BAD_PATH "; + case CO_E_SERVER_EXEC_FAILURE : + return "CO_E_SERVER_EXEC_FAILURE "; + case CO_E_OBJSRV_RPC_FAILURE : + return "CO_E_OBJSRV_RPC_FAILURE "; + case MK_E_NO_NORMALIZED : + return "MK_E_NO_NORMALIZED "; + case CO_E_SERVER_STOPPING : + return "CO_E_SERVER_STOPPING "; + case MEM_E_INVALID_ROOT : + return "MEM_E_INVALID_ROOT "; + case MEM_E_INVALID_LINK : + return "MEM_E_INVALID_LINK "; + case MEM_E_INVALID_SIZE : + return "MEM_E_INVALID_SIZE "; + case CO_S_NOTALLINTERFACES : + return "CO_S_NOTALLINTERFACES "; + case DISP_E_UNKNOWNINTERFACE : + return "DISP_E_UNKNOWNINTERFACE "; + case DISP_E_MEMBERNOTFOUND : + return "DISP_E_MEMBERNOTFOUND "; + case DISP_E_PARAMNOTFOUND : + return "DISP_E_PARAMNOTFOUND "; + case DISP_E_TYPEMISMATCH : + return "DISP_E_TYPEMISMATCH "; + case DISP_E_UNKNOWNNAME : + return "DISP_E_UNKNOWNNAME "; + case DISP_E_NONAMEDARGS : + return "DISP_E_NONAMEDARGS "; + case DISP_E_BADVARTYPE : + return "DISP_E_BADVARTYPE "; + case DISP_E_EXCEPTION : + return "DISP_E_EXCEPTION "; + case DISP_E_OVERFLOW : + return "DISP_E_OVERFLOW "; + case DISP_E_BADINDEX : + return "DISP_E_BADINDEX "; + case DISP_E_UNKNOWNLCID : + return "DISP_E_UNKNOWNLCID "; + case DISP_E_ARRAYISLOCKED : + return "DISP_E_ARRAYISLOCKED "; + case DISP_E_BADPARAMCOUNT : + return "DISP_E_BADPARAMCOUNT "; + case DISP_E_PARAMNOTOPTIONAL : + return "DISP_E_PARAMNOTOPTIONAL "; + case DISP_E_BADCALLEE : + return "DISP_E_BADCALLEE "; + case DISP_E_NOTACOLLECTION : + return "DISP_E_NOTACOLLECTION "; + case DISP_E_DIVBYZERO : + return "DISP_E_DIVBYZERO "; + case TYPE_E_BUFFERTOOSMALL : + return "TYPE_E_BUFFERTOOSMALL "; + case TYPE_E_FIELDNOTFOUND : + return "TYPE_E_FIELDNOTFOUND "; + case TYPE_E_INVDATAREAD : + return "TYPE_E_INVDATAREAD "; + case TYPE_E_UNSUPFORMAT : + return "TYPE_E_UNSUPFORMAT "; + case TYPE_E_REGISTRYACCESS : + return "TYPE_E_REGISTRYACCESS "; + case TYPE_E_LIBNOTREGISTERED : + return "TYPE_E_LIBNOTREGISTERED "; + case TYPE_E_UNDEFINEDTYPE : + return "TYPE_E_UNDEFINEDTYPE "; + case TYPE_E_QUALIFIEDNAMEDISALLOWED : + return "TYPE_E_QUALIFIEDNAMEDISALLOWED "; + case TYPE_E_INVALIDSTATE : + return "TYPE_E_INVALIDSTATE "; + case TYPE_E_WRONGTYPEKIND : + return "TYPE_E_WRONGTYPEKIND "; + case TYPE_E_ELEMENTNOTFOUND : + return "TYPE_E_ELEMENTNOTFOUND "; + case TYPE_E_AMBIGUOUSNAME : + return "TYPE_E_AMBIGUOUSNAME "; + case TYPE_E_NAMECONFLICT : + return "TYPE_E_NAMECONFLICT "; + case TYPE_E_UNKNOWNLCID : + return "TYPE_E_UNKNOWNLCID "; + case TYPE_E_DLLFUNCTIONNOTFOUND : + return "TYPE_E_DLLFUNCTIONNOTFOUND "; + case TYPE_E_BADMODULEKIND : + return "TYPE_E_BADMODULEKIND "; + case TYPE_E_SIZETOOBIG : + return "TYPE_E_SIZETOOBIG "; + case TYPE_E_DUPLICATEID : + return "TYPE_E_DUPLICATEID "; + case TYPE_E_INVALIDID : + return "TYPE_E_INVALIDID "; + case TYPE_E_TYPEMISMATCH : + return "TYPE_E_TYPEMISMATCH "; + case TYPE_E_OUTOFBOUNDS : + return "TYPE_E_OUTOFBOUNDS "; + case TYPE_E_IOERROR : + return "TYPE_E_IOERROR "; + case TYPE_E_CANTCREATETMPFILE : + return "TYPE_E_CANTCREATETMPFILE "; + case TYPE_E_CANTLOADLIBRARY : + return "TYPE_E_CANTLOADLIBRARY "; + case TYPE_E_INCONSISTENTPROPFUNCS : + return "TYPE_E_INCONSISTENTPROPFUNCS "; + case TYPE_E_CIRCULARTYPE : + return "TYPE_E_CIRCULARTYPE "; + case STG_E_INVALIDFUNCTION : + return "STG_E_INVALIDFUNCTION "; + case STG_E_FILENOTFOUND : + return "STG_E_FILENOTFOUND "; + case STG_E_PATHNOTFOUND : + return "STG_E_PATHNOTFOUND "; + case STG_E_TOOMANYOPENFILES : + return "STG_E_TOOMANYOPENFILES "; + case STG_E_ACCESSDENIED : + return "STG_E_ACCESSDENIED "; + case STG_E_INVALIDHANDLE : + return "STG_E_INVALIDHANDLE "; + case STG_E_INSUFFICIENTMEMORY : + return "STG_E_INSUFFICIENTMEMORY "; + case STG_E_INVALIDPOINTER : + return "STG_E_INVALIDPOINTER "; + case STG_E_NOMOREFILES : + return "STG_E_NOMOREFILES "; + case STG_E_DISKISWRITEPROTECTED : + return "STG_E_DISKISWRITEPROTECTED "; + case STG_E_SEEKERROR : + return "STG_E_SEEKERROR "; + case STG_E_WRITEFAULT : + return "STG_E_WRITEFAULT "; + case STG_E_READFAULT : + return "STG_E_READFAULT "; + case STG_E_SHAREVIOLATION : + return "STG_E_SHAREVIOLATION "; + case STG_E_LOCKVIOLATION : + return "STG_E_LOCKVIOLATION "; + case STG_E_FILEALREADYEXISTS : + return "STG_E_FILEALREADYEXISTS "; + case STG_E_INVALIDPARAMETER : + return "STG_E_INVALIDPARAMETER "; + case STG_E_MEDIUMFULL : + return "STG_E_MEDIUMFULL "; + case STG_E_PROPSETMISMATCHED : + return "STG_E_PROPSETMISMATCHED "; + case STG_E_ABNORMALAPIEXIT : + return "STG_E_ABNORMALAPIEXIT "; + case STG_E_INVALIDHEADER : + return "STG_E_INVALIDHEADER "; + case STG_E_INVALIDNAME : + return "STG_E_INVALIDNAME "; + case STG_E_UNKNOWN : + return "STG_E_UNKNOWN "; + case STG_E_UNIMPLEMENTEDFUNCTION : + return "STG_E_UNIMPLEMENTEDFUNCTION "; + case STG_E_INVALIDFLAG : + return "STG_E_INVALIDFLAG "; + case STG_E_INUSE : + return "STG_E_INUSE "; + case STG_E_NOTCURRENT : + return "STG_E_NOTCURRENT "; + case STG_E_REVERTED : + return "STG_E_REVERTED "; + case STG_E_CANTSAVE : + return "STG_E_CANTSAVE "; + case STG_E_OLDFORMAT : + return "STG_E_OLDFORMAT "; + case STG_E_OLDDLL : + return "STG_E_OLDDLL "; + case STG_E_SHAREREQUIRED : + return "STG_E_SHAREREQUIRED "; + case STG_E_NOTFILEBASEDSTORAGE : + return "STG_E_NOTFILEBASEDSTORAGE "; + case STG_E_EXTANTMARSHALLINGS : + return "STG_E_EXTANTMARSHALLINGS "; + case STG_E_DOCFILECORRUPT : + return "STG_E_DOCFILECORRUPT "; + case STG_E_BADBASEADDRESS : + return "STG_E_BADBASEADDRESS "; + case STG_E_INCOMPLETE : + return "STG_E_INCOMPLETE "; + case STG_E_TERMINATED : + return "STG_E_TERMINATED "; + case STG_S_CONVERTED : + return "STG_S_CONVERTED "; + case STG_S_BLOCK : + return "STG_S_BLOCK "; + case STG_S_RETRYNOW : + return "STG_S_RETRYNOW "; + case STG_S_MONITORING : + return "STG_S_MONITORING "; + case STG_S_MULTIPLEOPENS : + return "STG_S_MULTIPLEOPENS "; + case STG_S_CONSOLIDATIONFAILED : + return "STG_S_CONSOLIDATIONFAILED "; + case STG_S_CANNOTCONSOLIDATE : + return "STG_S_CANNOTCONSOLIDATE "; + case RPC_E_CALL_REJECTED : + return "RPC_E_CALL_REJECTED "; + case RPC_E_CALL_CANCELED : + return "RPC_E_CALL_CANCELED "; + case RPC_E_CANTPOST_INSENDCALL : + return "RPC_E_CANTPOST_INSENDCALL "; + case RPC_E_CANTCALLOUT_INASYNCCALL : + return "RPC_E_CANTCALLOUT_INASYNCCALL "; + case RPC_E_CANTCALLOUT_INEXTERNALCALL : + return "RPC_E_CANTCALLOUT_INEXTERNALCALL "; + case RPC_E_CONNECTION_TERMINATED : + return "RPC_E_CONNECTION_TERMINATED "; + case RPC_E_SERVER_DIED : + return "RPC_E_SERVER_DIED "; + case RPC_E_CLIENT_DIED : + return "RPC_E_CLIENT_DIED "; + case RPC_E_INVALID_DATAPACKET : + return "RPC_E_INVALID_DATAPACKET "; + case RPC_E_CANTTRANSMIT_CALL : + return "RPC_E_CANTTRANSMIT_CALL "; + case RPC_E_CLIENT_CANTMARSHAL_DATA : + return "RPC_E_CLIENT_CANTMARSHAL_DATA "; + case RPC_E_CLIENT_CANTUNMARSHAL_DATA : + return "RPC_E_CLIENT_CANTUNMARSHAL_DATA "; + case RPC_E_SERVER_CANTMARSHAL_DATA : + return "RPC_E_SERVER_CANTMARSHAL_DATA "; + case RPC_E_SERVER_CANTUNMARSHAL_DATA : + return "RPC_E_SERVER_CANTUNMARSHAL_DATA "; + case RPC_E_INVALID_DATA : + return "RPC_E_INVALID_DATA "; + case RPC_E_INVALID_PARAMETER : + return "RPC_E_INVALID_PARAMETER "; + case RPC_E_CANTCALLOUT_AGAIN : + return "RPC_E_CANTCALLOUT_AGAIN "; + case RPC_E_SERVER_DIED_DNE : + return "RPC_E_SERVER_DIED_DNE "; + case RPC_E_SYS_CALL_FAILED : + return "RPC_E_SYS_CALL_FAILED "; + case RPC_E_OUT_OF_RESOURCES : + return "RPC_E_OUT_OF_RESOURCES "; + case RPC_E_ATTEMPTED_MULTITHREAD : + return "RPC_E_ATTEMPTED_MULTITHREAD "; + case RPC_E_NOT_REGISTERED : + return "RPC_E_NOT_REGISTERED "; + case RPC_E_FAULT : + return "RPC_E_FAULT "; + case RPC_E_SERVERFAULT : + return "RPC_E_SERVERFAULT "; + case RPC_E_CHANGED_MODE : + return "RPC_E_CHANGED_MODE "; + case RPC_E_INVALIDMETHOD : + return "RPC_E_INVALIDMETHOD "; + case RPC_E_DISCONNECTED : + return "RPC_E_DISCONNECTED "; + case RPC_E_RETRY : + return "RPC_E_RETRY "; + case RPC_E_SERVERCALL_RETRYLATER : + return "RPC_E_SERVERCALL_RETRYLATER "; + case RPC_E_SERVERCALL_REJECTED : + return "RPC_E_SERVERCALL_REJECTED "; + case RPC_E_INVALID_CALLDATA : + return "RPC_E_INVALID_CALLDATA "; + case RPC_E_CANTCALLOUT_ININPUTSYNCCALL : + return "RPC_E_CANTCALLOUT_ININPUTSYNCCALL "; + case RPC_E_WRONG_THREAD : + return "RPC_E_WRONG_THREAD "; + case RPC_E_THREAD_NOT_INIT : + return "RPC_E_THREAD_NOT_INIT "; + case RPC_E_VERSION_MISMATCH : + return "RPC_E_VERSION_MISMATCH "; + case RPC_E_INVALID_HEADER : + return "RPC_E_INVALID_HEADER "; + case RPC_E_INVALID_EXTENSION : + return "RPC_E_INVALID_EXTENSION "; + case RPC_E_INVALID_IPID : + return "RPC_E_INVALID_IPID "; + case RPC_E_INVALID_OBJECT : + return "RPC_E_INVALID_OBJECT "; + case RPC_S_CALLPENDING : + return "RPC_S_CALLPENDING "; + case RPC_S_WAITONTIMER : + return "RPC_S_WAITONTIMER "; + case RPC_E_CALL_COMPLETE : + return "RPC_E_CALL_COMPLETE "; + case RPC_E_UNSECURE_CALL : + return "RPC_E_UNSECURE_CALL "; + case RPC_E_TOO_LATE : + return "RPC_E_TOO_LATE "; + case RPC_E_NO_GOOD_SECURITY_PACKAGES : + return "RPC_E_NO_GOOD_SECURITY_PACKAGES "; + case RPC_E_ACCESS_DENIED : + return "RPC_E_ACCESS_DENIED "; + case RPC_E_REMOTE_DISABLED : + return "RPC_E_REMOTE_DISABLED "; + case RPC_E_INVALID_OBJREF : + return "RPC_E_INVALID_OBJREF "; + case RPC_E_NO_CONTEXT : + return "RPC_E_NO_CONTEXT "; + case RPC_E_TIMEOUT : + return "RPC_E_TIMEOUT "; + case RPC_E_NO_SYNC : + return "RPC_E_NO_SYNC "; + case RPC_E_UNEXPECTED : + return "RPC_E_UNEXPECTED "; + case NTE_BAD_UID : + return "NTE_BAD_UID "; + case NTE_BAD_HASH : + return "NTE_BAD_HASH "; + //case NTE_BAD_HASH : + //return "NTE_BAD_HASH "; + case NTE_BAD_KEY : + return "NTE_BAD_KEY "; + case NTE_BAD_LEN : + return "NTE_BAD_LEN "; + case NTE_BAD_DATA : + return "NTE_BAD_DATA "; + case NTE_BAD_SIGNATURE : + return "NTE_BAD_SIGNATURE "; + case NTE_BAD_VER : + return "NTE_BAD_VER "; + case NTE_BAD_ALGID : + return "NTE_BAD_ALGID "; + case NTE_BAD_FLAGS : + return "NTE_BAD_FLAGS "; + case NTE_BAD_TYPE : + return "NTE_BAD_TYPE "; + case NTE_BAD_KEY_STATE : + return "NTE_BAD_KEY_STATE "; + case NTE_BAD_HASH_STATE : + return "NTE_BAD_HASH_STATE "; + case NTE_NO_KEY : + return "NTE_NO_KEY "; + case NTE_NO_MEMORY : + return "NTE_NO_MEMORY "; + case NTE_EXISTS : + return "NTE_EXISTS "; + case NTE_PERM : + return "NTE_PERM "; + case NTE_NOT_FOUND : + return "NTE_NOT_FOUND "; + case NTE_DOUBLE_ENCRYPT : + return "NTE_DOUBLE_ENCRYPT "; + case NTE_BAD_PROVIDER : + return "NTE_BAD_PROVIDER "; + case NTE_BAD_PROV_TYPE : + return "NTE_BAD_PROV_TYPE "; + case NTE_BAD_PUBLIC_KEY : + return "NTE_BAD_PUBLIC_KEY "; + case NTE_BAD_KEYSET : + return "NTE_BAD_KEYSET "; + case NTE_PROV_TYPE_NOT_DEF : + return "NTE_PROV_TYPE_NOT_DEF "; + case NTE_PROV_TYPE_ENTRY_BAD : + return "NTE_PROV_TYPE_ENTRY_BAD "; + case NTE_KEYSET_NOT_DEF : + return "NTE_KEYSET_NOT_DEF "; + case NTE_KEYSET_ENTRY_BAD : + return "NTE_KEYSET_ENTRY_BAD "; + case NTE_PROV_TYPE_NO_MATCH : + return "NTE_PROV_TYPE_NO_MATCH "; + case NTE_SIGNATURE_FILE_BAD : + return "NTE_SIGNATURE_FILE_BAD "; + case NTE_PROVIDER_DLL_FAIL : + return "NTE_PROVIDER_DLL_FAIL "; + case NTE_PROV_DLL_NOT_FOUND : + return "NTE_PROV_DLL_NOT_FOUND "; + case NTE_BAD_KEYSET_PARAM : + return "NTE_BAD_KEYSET_PARAM "; + case NTE_FAIL : + return "NTE_FAIL "; + case NTE_SYS_ERR : + return "NTE_SYS_ERR "; + case CRYPT_E_MSG_ERROR : + return "CRYPT_E_MSG_ERROR "; + case CRYPT_E_UNKNOWN_ALGO : + return "CRYPT_E_UNKNOWN_ALGO "; + case CRYPT_E_OID_FORMAT : + return "CRYPT_E_OID_FORMAT "; + case CRYPT_E_INVALID_MSG_TYPE : + return "CRYPT_E_INVALID_MSG_TYPE "; + case CRYPT_E_UNEXPECTED_ENCODING : + return "CRYPT_E_UNEXPECTED_ENCODING "; + case CRYPT_E_AUTH_ATTR_MISSING : + return "CRYPT_E_AUTH_ATTR_MISSING "; + case CRYPT_E_HASH_VALUE : + return "CRYPT_E_HASH_VALUE "; + case CRYPT_E_INVALID_INDEX : + return "CRYPT_E_INVALID_INDEX "; + case CRYPT_E_ALREADY_DECRYPTED : + return "CRYPT_E_ALREADY_DECRYPTED "; + case CRYPT_E_NOT_DECRYPTED : + return "CRYPT_E_NOT_DECRYPTED "; + case CRYPT_E_RECIPIENT_NOT_FOUND : + return "CRYPT_E_RECIPIENT_NOT_FOUND "; + case CRYPT_E_CONTROL_TYPE : + return "CRYPT_E_CONTROL_TYPE "; + case CRYPT_E_ISSUER_SERIALNUMBER : + return "CRYPT_E_ISSUER_SERIALNUMBER "; + case CRYPT_E_SIGNER_NOT_FOUND : + return "CRYPT_E_SIGNER_NOT_FOUND "; + case CRYPT_E_ATTRIBUTES_MISSING : + return "CRYPT_E_ATTRIBUTES_MISSING "; + case CRYPT_E_STREAM_MSG_NOT_READY : + return "CRYPT_E_STREAM_MSG_NOT_READY "; + case CRYPT_E_STREAM_INSUFFICIENT_DATA : + return "CRYPT_E_STREAM_INSUFFICIENT_DATA "; + case CRYPT_E_BAD_LEN : + return "CRYPT_E_BAD_LEN "; + case CRYPT_E_BAD_ENCODE : + return "CRYPT_E_BAD_ENCODE "; + case CRYPT_E_FILE_ERROR : + return "CRYPT_E_FILE_ERROR "; + case CRYPT_E_NOT_FOUND : + return "CRYPT_E_NOT_FOUND "; + case CRYPT_E_EXISTS : + return "CRYPT_E_EXISTS "; + case CRYPT_E_NO_PROVIDER : + return "CRYPT_E_NO_PROVIDER "; + case CRYPT_E_SELF_SIGNED : + return "CRYPT_E_SELF_SIGNED "; + case CRYPT_E_DELETED_PREV : + return "CRYPT_E_DELETED_PREV "; + case CRYPT_E_NO_MATCH : + return "CRYPT_E_NO_MATCH "; + case CRYPT_E_UNEXPECTED_MSG_TYPE : + return "CRYPT_E_UNEXPECTED_MSG_TYPE "; + case CRYPT_E_NO_KEY_PROPERTY : + return "CRYPT_E_NO_KEY_PROPERTY "; + case CRYPT_E_NO_DECRYPT_CERT : + return "CRYPT_E_NO_DECRYPT_CERT "; + case CRYPT_E_BAD_MSG : + return "CRYPT_E_BAD_MSG "; + case CRYPT_E_NO_SIGNER : + return "CRYPT_E_NO_SIGNER "; + case CRYPT_E_PENDING_CLOSE : + return "CRYPT_E_PENDING_CLOSE "; + case CRYPT_E_REVOKED : + return "CRYPT_E_REVOKED "; + case CRYPT_E_NO_REVOCATION_DLL : + return "CRYPT_E_NO_REVOCATION_DLL "; + case CRYPT_E_NO_REVOCATION_CHECK : + return "CRYPT_E_NO_REVOCATION_CHECK "; + case CRYPT_E_REVOCATION_OFFLINE : + return "CRYPT_E_REVOCATION_OFFLINE "; + case CRYPT_E_NOT_IN_REVOCATION_DATABASE : + return "CRYPT_E_NOT_IN_REVOCATION_DATABASE "; + case CRYPT_E_INVALID_NUMERIC_STRING : + return "CRYPT_E_INVALID_NUMERIC_STRING "; + case CRYPT_E_INVALID_PRINTABLE_STRING : + return "CRYPT_E_INVALID_PRINTABLE_STRING "; + case CRYPT_E_INVALID_IA5_STRING : + return "CRYPT_E_INVALID_IA5_STRING "; + case CRYPT_E_INVALID_X500_STRING : + return "CRYPT_E_INVALID_X500_STRING "; + case CRYPT_E_NOT_CHAR_STRING : + return "CRYPT_E_NOT_CHAR_STRING "; + case CRYPT_E_FILERESIZED : + return "CRYPT_E_FILERESIZED "; + case CRYPT_E_SECURITY_SETTINGS : + return "CRYPT_E_SECURITY_SETTINGS "; + case CRYPT_E_NO_VERIFY_USAGE_DLL : + return "CRYPT_E_NO_VERIFY_USAGE_DLL "; + case CRYPT_E_NO_VERIFY_USAGE_CHECK : + return "CRYPT_E_NO_VERIFY_USAGE_CHECK "; + case CRYPT_E_VERIFY_USAGE_OFFLINE : + return "CRYPT_E_VERIFY_USAGE_OFFLINE "; + case CRYPT_E_NOT_IN_CTL : + return "CRYPT_E_NOT_IN_CTL "; + case CRYPT_E_NO_TRUSTED_SIGNER : + return "CRYPT_E_NO_TRUSTED_SIGNER "; + case CRYPT_E_OSS_ERROR : + return "CRYPT_E_OSS_ERROR "; + case CERTSRV_E_BAD_REQUESTSUBJECT : + return "CERTSRV_E_BAD_REQUESTSUBJECT "; + case CERTSRV_E_NO_REQUEST : + return "CERTSRV_E_NO_REQUEST "; + case CERTSRV_E_BAD_REQUESTSTATUS : + return "CERTSRV_E_BAD_REQUESTSTATUS "; + case CERTSRV_E_PROPERTY_EMPTY : + return "CERTSRV_E_PROPERTY_EMPTY "; + //case CERTDB_E_JET_ERROR : + //return "CERTDB_E_JET_ERROR "; + case TRUST_E_SYSTEM_ERROR : + return "TRUST_E_SYSTEM_ERROR "; + case TRUST_E_NO_SIGNER_CERT : + return "TRUST_E_NO_SIGNER_CERT "; + case TRUST_E_COUNTER_SIGNER : + return "TRUST_E_COUNTER_SIGNER "; + case TRUST_E_CERT_SIGNATURE : + return "TRUST_E_CERT_SIGNATURE "; + case TRUST_E_TIME_STAMP : + return "TRUST_E_TIME_STAMP "; + case TRUST_E_BAD_DIGEST : + return "TRUST_E_BAD_DIGEST "; + case TRUST_E_BASIC_CONSTRAINTS : + return "TRUST_E_BASIC_CONSTRAINTS "; + case TRUST_E_FINANCIAL_CRITERIA : + return "TRUST_E_FINANCIAL_CRITERIA "; + case TRUST_E_PROVIDER_UNKNOWN : + return "TRUST_E_PROVIDER_UNKNOWN "; + case TRUST_E_ACTION_UNKNOWN : + return "TRUST_E_ACTION_UNKNOWN "; + case TRUST_E_SUBJECT_FORM_UNKNOWN : + return "TRUST_E_SUBJECT_FORM_UNKNOWN "; + case TRUST_E_SUBJECT_NOT_TRUSTED : + return "TRUST_E_SUBJECT_NOT_TRUSTED "; + case DIGSIG_E_ENCODE : + return "DIGSIG_E_ENCODE "; + case DIGSIG_E_DECODE : + return "DIGSIG_E_DECODE "; + case DIGSIG_E_EXTENSIBILITY : + return "DIGSIG_E_EXTENSIBILITY "; + case DIGSIG_E_CRYPTO : + return "DIGSIG_E_CRYPTO "; + case PERSIST_E_SIZEDEFINITE : + return "PERSIST_E_SIZEDEFINITE "; + case PERSIST_E_SIZEINDEFINITE : + return "PERSIST_E_SIZEINDEFINITE "; + case PERSIST_E_NOTSELFSIZING : + return "PERSIST_E_NOTSELFSIZING "; + case TRUST_E_NOSIGNATURE : + return "TRUST_E_NOSIGNATURE "; + case CERT_E_EXPIRED : + return "CERT_E_EXPIRED "; + case CERT_E_VALIDITYPERIODNESTING : + return "CERT_E_VALIDITYPERIODNESTING "; + case CERT_E_ROLE : + return "CERT_E_ROLE "; + case CERT_E_PATHLENCONST : + return "CERT_E_PATHLENCONST "; + case CERT_E_CRITICAL : + return "CERT_E_CRITICAL "; + case CERT_E_PURPOSE : + return "CERT_E_PURPOSE "; + case CERT_E_ISSUERCHAINING : + return "CERT_E_ISSUERCHAINING "; + case CERT_E_MALFORMED : + return "CERT_E_MALFORMED "; + case CERT_E_UNTRUSTEDROOT : + return "CERT_E_UNTRUSTEDROOT "; + case CERT_E_CHAINING : + return "CERT_E_CHAINING "; + case TRUST_E_FAIL : + return "TRUST_E_FAIL "; + case CERT_E_REVOKED : + return "CERT_E_REVOKED "; + case CERT_E_UNTRUSTEDTESTROOT : + return "CERT_E_UNTRUSTEDTESTROOT "; + case CERT_E_REVOCATION_FAILURE : + return "CERT_E_REVOCATION_FAILURE "; + case CERT_E_CN_NO_MATCH : + return "CERT_E_CN_NO_MATCH "; + case CERT_E_WRONG_USAGE : + return "CERT_E_WRONG_USAGE "; + case SPAPI_E_EXPECTED_SECTION_NAME : + return "SPAPI_E_EXPECTED_SECTION_NAME "; + case SPAPI_E_BAD_SECTION_NAME_LINE : + return "SPAPI_E_BAD_SECTION_NAME_LINE "; + case SPAPI_E_SECTION_NAME_TOO_LONG : + return "SPAPI_E_SECTION_NAME_TOO_LONG "; + case SPAPI_E_GENERAL_SYNTAX : + return "SPAPI_E_GENERAL_SYNTAX "; + case SPAPI_E_WRONG_INF_STYLE : + return "SPAPI_E_WRONG_INF_STYLE "; + case SPAPI_E_SECTION_NOT_FOUND : + return "SPAPI_E_SECTION_NOT_FOUND "; + case SPAPI_E_LINE_NOT_FOUND : + return "SPAPI_E_LINE_NOT_FOUND "; + case SPAPI_E_NO_ASSOCIATED_CLASS : + return "SPAPI_E_NO_ASSOCIATED_CLASS "; + case SPAPI_E_CLASS_MISMATCH : + return "SPAPI_E_CLASS_MISMATCH "; + case SPAPI_E_DUPLICATE_FOUND : + return "SPAPI_E_DUPLICATE_FOUND "; + case SPAPI_E_NO_DRIVER_SELECTED : + return "SPAPI_E_NO_DRIVER_SELECTED "; + case SPAPI_E_KEY_DOES_NOT_EXIST : + return "SPAPI_E_KEY_DOES_NOT_EXIST "; + case SPAPI_E_INVALID_DEVINST_NAME : + return "SPAPI_E_INVALID_DEVINST_NAME "; + case SPAPI_E_INVALID_CLASS : + return "SPAPI_E_INVALID_CLASS "; + case SPAPI_E_DEVINST_ALREADY_EXISTS : + return "SPAPI_E_DEVINST_ALREADY_EXISTS "; + case SPAPI_E_DEVINFO_NOT_REGISTERED : + return "SPAPI_E_DEVINFO_NOT_REGISTERED "; + case SPAPI_E_INVALID_REG_PROPERTY : + return "SPAPI_E_INVALID_REG_PROPERTY "; + case SPAPI_E_NO_INF : + return "SPAPI_E_NO_INF "; + case SPAPI_E_NO_SUCH_DEVINST : + return "SPAPI_E_NO_SUCH_DEVINST "; + case SPAPI_E_CANT_LOAD_CLASS_ICON : + return "SPAPI_E_CANT_LOAD_CLASS_ICON "; + case SPAPI_E_INVALID_CLASS_INSTALLER : + return "SPAPI_E_INVALID_CLASS_INSTALLER "; + case SPAPI_E_DI_DO_DEFAULT : + return "SPAPI_E_DI_DO_DEFAULT "; + case SPAPI_E_DI_NOFILECOPY : + return "SPAPI_E_DI_NOFILECOPY "; + case SPAPI_E_INVALID_HWPROFILE : + return "SPAPI_E_INVALID_HWPROFILE "; + case SPAPI_E_NO_DEVICE_SELECTED : + return "SPAPI_E_NO_DEVICE_SELECTED "; + case SPAPI_E_DEVINFO_LIST_LOCKED : + return "SPAPI_E_DEVINFO_LIST_LOCKED "; + case SPAPI_E_DEVINFO_DATA_LOCKED : + return "SPAPI_E_DEVINFO_DATA_LOCKED "; + case SPAPI_E_DI_BAD_PATH : + return "SPAPI_E_DI_BAD_PATH "; + case SPAPI_E_NO_CLASSINSTALL_PARAMS : + return "SPAPI_E_NO_CLASSINSTALL_PARAMS "; + case SPAPI_E_FILEQUEUE_LOCKED : + return "SPAPI_E_FILEQUEUE_LOCKED "; + case SPAPI_E_BAD_SERVICE_INSTALLSECT : + return "SPAPI_E_BAD_SERVICE_INSTALLSECT "; + case SPAPI_E_NO_CLASS_DRIVER_LIST : + return "SPAPI_E_NO_CLASS_DRIVER_LIST "; + case SPAPI_E_NO_ASSOCIATED_SERVICE : + return "SPAPI_E_NO_ASSOCIATED_SERVICE "; + case SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE : + return "SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE "; + case SPAPI_E_DEVICE_INTERFACE_ACTIVE : + return "SPAPI_E_DEVICE_INTERFACE_ACTIVE "; + case SPAPI_E_DEVICE_INTERFACE_REMOVED : + return "SPAPI_E_DEVICE_INTERFACE_REMOVED "; + case SPAPI_E_BAD_INTERFACE_INSTALLSECT : + return "SPAPI_E_BAD_INTERFACE_INSTALLSECT "; + case SPAPI_E_NO_SUCH_INTERFACE_CLASS : + return "SPAPI_E_NO_SUCH_INTERFACE_CLASS "; + case SPAPI_E_INVALID_REFERENCE_STRING : + return "SPAPI_E_INVALID_REFERENCE_STRING "; + case SPAPI_E_INVALID_MACHINENAME : + return "SPAPI_E_INVALID_MACHINENAME "; + case SPAPI_E_REMOTE_COMM_FAILURE : + return "SPAPI_E_REMOTE_COMM_FAILURE "; + case SPAPI_E_MACHINE_UNAVAILABLE : + return "SPAPI_E_MACHINE_UNAVAILABLE "; + case SPAPI_E_NO_CONFIGMGR_SERVICES : + return "SPAPI_E_NO_CONFIGMGR_SERVICES "; + case SPAPI_E_INVALID_PROPPAGE_PROVIDER : + return "SPAPI_E_INVALID_PROPPAGE_PROVIDER "; + case SPAPI_E_NO_SUCH_DEVICE_INTERFACE : + return "SPAPI_E_NO_SUCH_DEVICE_INTERFACE "; + case SPAPI_E_DI_POSTPROCESSING_REQUIRED : + return "SPAPI_E_DI_POSTPROCESSING_REQUIRED "; + case SPAPI_E_INVALID_COINSTALLER : + return "SPAPI_E_INVALID_COINSTALLER "; + case SPAPI_E_NO_COMPAT_DRIVERS : + return "SPAPI_E_NO_COMPAT_DRIVERS "; + case SPAPI_E_NO_DEVICE_ICON : + return "SPAPI_E_NO_DEVICE_ICON "; + case SPAPI_E_INVALID_INF_LOGCONFIG : + return "SPAPI_E_INVALID_INF_LOGCONFIG "; + case SPAPI_E_DI_DONT_INSTALL : + return "SPAPI_E_DI_DONT_INSTALL "; + case SPAPI_E_INVALID_FILTER_DRIVER : + return "SPAPI_E_INVALID_FILTER_DRIVER "; + case SPAPI_E_ERROR_NOT_INSTALLED : + return "SPAPI_E_ERROR_NOT_INSTALLED "; + + default: + static char buff[1000]; + sprintf(buff, "Unrecognized error value: %08X\0", error); + + return buff; + } +} + diff --git a/panda/src/wdxdisplay8/wdxGraphicsPipe8.h b/panda/src/wdxdisplay8/wdxGraphicsPipe8.h new file mode 100644 index 0000000000..a5b5f5542a --- /dev/null +++ b/panda/src/wdxdisplay8/wdxGraphicsPipe8.h @@ -0,0 +1,82 @@ +// Filename: wdxGraphicsPipe.h +// Created by: mike (09Jan97) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// +#ifndef WDXGRAPHICSPIPE8_H +#define WDXGRAPHICSPIPE8_H +// +//////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////// +#include + +#include +#include +#include "wdxGraphicsWindow8.h" + +#ifndef STRICT +#define STRICT +#endif +#define WINDOWS_LEAN_AND_MEAN +#include +#undef WINDOWS_LEAN_AND_MEAN + +//////////////////////////////////////////////////////////////////// +// Defines +//////////////////////////////////////////////////////////////////// +class Xclass; + +extern char * ConvD3DErrorToString(const HRESULT &error); + +//////////////////////////////////////////////////////////////////// +// Class : wdxGraphicsPipe +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX wdxGraphicsPipe : public InteractiveGraphicsPipe { +public: + wdxGraphicsPipe(const PipeSpecifier&); + + wdxGraphicsWindow* find_window(HWND win); +// ButtonHandle lookup_key(WPARAM wparam) const; + + virtual TypeHandle get_window_type() const; + +public: + + static GraphicsPipe* make_wdxGraphicsPipe(const FactoryParams ¶ms); + + static TypeHandle get_class_type(void); + static void init_type(void); + virtual TypeHandle get_type(void) const; + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + + static TypeHandle _type_handle; + +// int _width; +// int _height; + bool _shift; + +protected: + + wdxGraphicsPipe(void); + wdxGraphicsPipe(const wdxGraphicsPipe&); + wdxGraphicsPipe& operator=(const wdxGraphicsPipe&); + +}; + +#endif diff --git a/panda/src/wdxdisplay8/wdxGraphicsWindow8.cxx b/panda/src/wdxdisplay8/wdxGraphicsWindow8.cxx new file mode 100644 index 0000000000..6d0593f1f6 --- /dev/null +++ b/panda/src/wdxdisplay8/wdxGraphicsWindow8.cxx @@ -0,0 +1,2371 @@ +// Filename: wdxGraphicsWindow.cxx +// Created by: mike (09Jan00) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "wdxGraphicsWindow8.h" +#include "wdxGraphicsPipe8.h" +#include "dxGraphicsStateGuardian8.h" +#include "config_wdxdisplay8.h" + +#include +#include + +#include + +#ifdef DO_PSTATS +#include +#endif + +#define D3D_OVERLOADS +//#define INITGUID dont want this if linking w/dxguid.lib +#include + +#include + +//////////////////////////////////////////////////////////////////// +// Static variables +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsWindow::_type_handle; + +#define LAST_ERROR 0 +#define ERRORBOX_TITLE "Panda3D Error" +#define WDX_WINDOWCLASSNAME "wdxDisplay" + +typedef map HWND_PANDAWIN_MAP; + +HWND_PANDAWIN_MAP hwnd_pandawin_map; +wdxGraphicsWindow* global_wdxwinptr = NULL; // need this for temporary windproc + +extern bool dx_full_screen_antialiasing; // defined in dxgsg_config.cxx + +#define MOUSE_ENTERED 0 +#define MOUSE_EXITED 1 +#define PAUSED_TIMER_ID 7 // completely arbitrary choice +#define DXREADY ((_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}; + +static DWORD BitDepth_2_DDBDMask(DWORD iBitDepth) { + switch(iBitDepth) { + case 16: return DDBD_16; + case 32: return DDBD_32; + case 24: return DDBD_24; + case 8: return DDBD_8; + case 1: return DDBD_1; + case 2: return DDBD_2; + case 4: return DDBD_4; + } + return 0x0; +} +/* +typedef enum {DBGLEV_FATAL,DBGLEV_ERROR,DBGLEV_WARNING,DBGLEV_INFO,DBGLEV_DEBUG,DBGLEV_SPAM + } DebugLevels; + +void PrintDBGStr(DebugLevels level,HRESULT hr,const char *msgstr) { + ostream *pstrm; + static ostream dbg_strms[DBGLEV_SPAM+1]={wdxdisplay_cat.fatal,wdxdisplay_cat.error, + wdxdisplay_cat.warning,wdxdisplay_cat.info,wdxdisplay_cat.debug,wdxdisplay_cat.spam}; + assert(level<=DBGLEV_SPAM); + + pstrm=dbg_strms[level]; + (*pstrm)->fatal() << "GetDisplayMode failed, result = " << ConvD3DErrorToString(hr) << endl; +} +*/ +#ifdef _DEBUG +static void DebugPrintPixFmt(DDPIXELFORMAT* pddpf) { + static int iddpfnum=0; + ostream *dbgout = &dxgsg_cat.debug(); + + *dbgout << "ZBuf DDPF[" << iddpfnum << "]: RGBBitCount:" << pddpf->dwRGBBitCount + << " Flags:" << (void *)pddpf->dwFlags ; + + if(pddpf->dwFlags & DDPF_STENCILBUFFER) { + *dbgout << " StencilBits:" << (void *) pddpf->dwStencilBitDepth; + } + + *dbgout << endl; + + iddpfnum++; +} +#endif + +// pops up MsgBox w/system error msg +#define LAST_ERROR 0 +void PrintErrorMessage(DWORD msgID) { + LPTSTR pMessageBuffer; + + if(msgID==LAST_ERROR) + msgID=GetLastError(); + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL,msgID, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language + (LPTSTR) &pMessageBuffer, // the weird ptrptr->ptr cast is intentional, see FORMAT_MESSAGE_ALLOCATE_BUFFER + 1024, NULL); + MessageBox(GetDesktopWindow(),pMessageBuffer,_T(ERRORBOX_TITLE),MB_OK); + wdxdisplay_cat.fatal() << "System error msg: " << pMessageBuffer << endl; + LocalFree( pMessageBuffer ); +} + +//#if defined(NOTIFY_DEBUG) || defined(DO_PSTATS) +#ifdef _DEBUG +extern void dbgPrintVidMem(LPDIRECTDRAW7 pDD, LPDDSCAPS2 lpddsCaps,const char *pMsg) { + DWORD dwTotal,dwFree; + HRESULT hr; + + // These Caps bits arent allowed to be specified when calling GetAvailVidMem. + // They don't affect surface allocation in a vram heap. + +#define AVAILVIDMEM_BADCAPS (DDSCAPS_BACKBUFFER | \ + DDSCAPS_FRONTBUFFER | \ + DDSCAPS_COMPLEX | \ + DDSCAPS_FLIP | \ + DDSCAPS_OWNDC | \ + DDSCAPS_PALETTE | \ + DDSCAPS_SYSTEMMEMORY | \ + DDSCAPS_VISIBLE | \ + DDSCAPS_WRITEONLY) + + DDSCAPS2 ddsCaps = *lpddsCaps; + ddsCaps.dwCaps &= ~(AVAILVIDMEM_BADCAPS); // turn off the bad caps +// ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; done internally by DX anyway + + if(FAILED( hr = pDD->GetAvailableVidMem(&ddsCaps,&dwTotal,&dwFree))) { + wdxdisplay_cat.debug() << "GetAvailableVidMem failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Write a debug message to the console reporting the texture memory. + char tmpstr[100],tmpstr2[100]; + sprintf(tmpstr,"%.4g",dwTotal/1000000.0); + sprintf(tmpstr2,"%.4g",dwFree/1000000.0); + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "AvailableVidMem before creating "<< pMsg << ",(megs) total: " << tmpstr << " free:" << tmpstr2 <window_proc(hwnd, msg, wparam, lparam); + } else if(global_wdxwinptr!=NULL){ + // this stuff should only be used during CreateWindow() + return global_wdxwinptr->window_proc(hwnd, msg, wparam, lparam); + } else { + // should never need this?? (maybe at shutdwn?) + return DefWindowProc(hwnd, msg, wparam, lparam); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: window_proc +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +LONG wdxGraphicsWindow:: +window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + int button = -1; + int x, y, width, height; + + switch(msg) { + + case WM_PAINT: { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + + if(DXREADY) + show_frame(); + EndPaint(hwnd, &ps); + return 0; + } + + case WM_MOUSEMOVE: + if(!DXREADY) + break; + + // Win32 doesn't return the same numbers as X does when the mouse + // goes beyond the upper or left side of the window + #define SET_MOUSE_COORD(iVal,VAL) { \ + iVal = VAL; \ + if(iVal & 0x8000) \ + iVal -= 0x10000; \ + } + + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); + + if(mouse_motion_enabled() + && wparam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) { + handle_mouse_motion(x, y); + } else if(mouse_passive_motion_enabled() && + ((wparam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) == 0)) { + handle_mouse_motion(x, y); + } + return 0; + #if 0 + case WM_SYSCHAR: + case WM_CHAR: // shouldnt receive WM_CHAR unless WM_KEYDOWN stops returning 0 and passes on to DefWindProc + break; + #endif + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: { + + POINT point; + + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + + #ifdef NDEBUG + handle_keypress(lookup_key(wparam), point.x, point.y); + #else + // handle Cntrl-V paste from clipboard + if(!((wparam=='V') && (GetKeyState(VK_CONTROL) < 0))) { + handle_keypress(lookup_key(wparam), point.x, point.y); + } else { + HGLOBAL hglb; + char *lptstr; + + if (!IsClipboardFormatAvailable(CF_TEXT)) + return 0; + + if (!OpenClipboard(NULL)) + return 0; + + hglb = GetClipboardData(CF_TEXT); + if (hglb!=NULL) { + lptstr = (char *) GlobalLock(hglb); + if(lptstr != NULL) { + char *pChar; + for(pChar=lptstr;*pChar!=NULL;pChar++) { + handle_keypress(KeyboardButton::ascii_key((uchar)*pChar), point.x, point.y); + } + GlobalUnlock(hglb); + } + } + CloseClipboard(); + } + #endif + // want to use defwindproc on Alt syskey so Alt-F4 works, etc + // but do want to bypass defwindproc F10 behavior (it activates the + // main menu, but we have none) + if((msg==WM_SYSKEYDOWN)&&(wparam!=VK_F10)) + break; + else return 0; + } + + case WM_SYSKEYUP: + case WM_KEYUP: { + handle_keyrelease(lookup_key(wparam)); + return 0; + } + + case WM_LBUTTONDOWN: + button = 0; + case WM_MBUTTONDOWN: + if(button < 0) + button = 1; + case WM_RBUTTONDOWN: + if(!DXREADY) + break; + + if(button < 0) + button = 2; + SetCapture(hwnd); + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); + handle_keypress(MouseButton::button(button), x, y); + return 0; + + case WM_LBUTTONUP: + button = 0; + case WM_MBUTTONUP: + if(button < 0) + button = 1; + case WM_RBUTTONUP: + if(!DXREADY) + break; + + if(button < 0) + button = 2; + ReleaseCapture(); + #if 0 + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); + #endif + handle_keyrelease(MouseButton::button(button)); + return 0; + + case WM_MOVE: + if(!DXREADY) + break; + handle_window_move(LOWORD(lparam), HIWORD(lparam) ); + return 0; + + case WM_EXITSIZEMOVE: + #ifdef _DEBUG + wdxdisplay_cat.spam() << "WM_EXITSIZEMOVE received" << endl; + #endif + + if(_WindowAdjustingType==Resizing) { + handle_reshape(true); + } + + _WindowAdjustingType = NotAdjusting; + return 0; + + case WM_ENTERSIZEMOVE: { + if(_dxgsg==NULL) + _dxgsg->SetDXReady(true); // dont disable here because I want to see pic as I resize + _WindowAdjustingType = MovingOrResizing; + } + break; + + case WM_DISPLAYCHANGE: { +#ifdef _DEBUG + width = LOWORD(lparam); height = HIWORD(lparam); + DWORD newbitdepth=wparam; + wdxdisplay_cat.spam() <<"WM_DISPLAYCHANGE received with width:" << width << " height: " << height << " bpp: " << wparam<< endl; +#endif + + // 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 + + // if(_props._fullscreen && _window_inactive) { + // if(_dxgsg!=NULL) + // _dxgsg->CheckCooperativeLevel(DO_REACTIVATE_WINDOW); + // else reactivate_window(); + // } + + // does the windowed case handle displaychange properly? no. need to recreate all devices + } + break; + + 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((_mwindow==NULL) || dx_full_screen || ((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_SETFOCUS: { + // wdxdisplay_cat.info() << "got WM_SETFOCUS\n"; + if(!DXREADY) { + break; + } + + if(_mouse_entry_enabled) + handle_mouse_entry(MOUSE_ENTERED,_hMouseCursor); + + POINT point; + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + + // this is a hack to make sure common modifier keys have proper state + // since at focus loss, app may never receive key-up event corresponding to + // a key-down. it would be better to know the exact set of ModifierButtons the + // user is using, since we may miss some here + + int i; + for(i=0;iflags << endl; + break; + } + + case WM_GETMINMAXINFO: + wdxdisplay_cat.spam() << "WM_GETMINMAXINFO received\n" << endl; + break; +#endif + + case WM_ERASEBKGND: + // WM_ERASEBKGND will be ignored during resizing, because + // we dont want to redraw as user is manually resizing window + 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_inactive||_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? + } + return 0; + + case WM_CLOSE: + close_window(); + + // 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_CREATE: + // break; + + 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 DefWindowProc(hwnd, msg, wparam, lparam); +} + + +//////////////////////////////////////////////////////////////////// +// Function: handle_reshape +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::handle_reshape(bool bDoDxReset) { + + GdiFlush(); + + if(bDoDxReset && _dxgsg!=NULL) { + HRESULT hr; + + if(_dxgsg->GetBackBuffer()==NULL) { + //assume this is initial creation reshape and ignore this call + return; + } + + // Clear the back/primary surface to black + DX_DECLARE_CLEAN(DDBLTFX, bltfx) + bltfx.dwDDFX |= DDBLTFX_NOTEARING; + hr = _dxgsg->_pri->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx); + if(FAILED( hr )) { + wdxdisplay_cat.fatal() << "Blt to Black of Primary Surf failed! : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(FAILED(hr = _dxgsg->_pDD->TestCooperativeLevel())) { + wdxdisplay_cat.error() << "TestCooperativeLevel failed : result = " << ConvD3DErrorToString(hr) << endl; + return; + } + + _dxgsg->SetDXReady(false); // disable rendering whilst we mess with surfs + + _dxgsg->RestoreAllVideoSurfaces(); + + // Want to change rendertarget size without destroying d3d device. To save vid memory + // (and make resizing work on memory-starved 4MB cards), we need to construct + // a temporary mini-sized render target for the d3d device (it cannot point to a + // NULL rendertarget) before creating the fully resized buffers. The old + // rendertargets will be freed when these temp targets are set, and that will give + // us the memory to create the resized target + + LPDIRECTDRAWSURFACE7 pddsDummy = NULL, pddsDummyZ = NULL; + ULONG refcnt; + + DX_DECLARE_CLEAN( DDSURFACEDESC2, ddsd ); + + _dxgsg->GetBackBuffer()->GetSurfaceDesc(&ddsd); + LPDIRECTDRAW7 pDD = _dxgsg->GetDDInterface(); + + ddsd.dwFlags &= ~DDSD_PITCH; + ddsd.dwWidth = 1; ddsd.dwHeight = 1; + ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER); + + PRINTVIDMEM(pDD,&ddsd.ddsCaps,"dummy backbuf"); + + if(FAILED( hr = pDD->CreateSurface( &ddsd, &pddsDummy, NULL ) )) { + wdxdisplay_cat.fatal() << "Resize CreateSurface for temp backbuf failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + DX_DECLARE_CLEAN( DDSURFACEDESC2, ddsdZ ); + _dxgsg->GetZBuffer()->GetSurfaceDesc(&ddsdZ); + ddsdZ.dwFlags &= ~DDSD_PITCH; + ddsdZ.dwWidth = 1; ddsdZ.dwHeight = 1; + + PRINTVIDMEM(pDD,&ddsdZ.ddsCaps,"dummy zbuf"); + + if(FAILED( hr = pDD->CreateSurface( &ddsdZ, &pddsDummyZ, NULL ) )) { + wdxdisplay_cat.fatal() << "Resize CreateSurface for temp zbuf failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(FAILED( hr = pddsDummy->AddAttachedSurface( pddsDummyZ ) )) { + wdxdisplay_cat.fatal() << "Resize AddAttachedSurf for temp zbuf failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(FAILED( hr = _dxgsg->GetD3DDevice()->SetRenderTarget( pddsDummy, 0x0 ))) { + wdxdisplay_cat.fatal() + << "Resize failed to set render target to temporary surface, result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + RELEASE(pddsDummyZ,wdxdisplay,"dummy resize zbuffer",false); + RELEASE(pddsDummy,wdxdisplay,"dummy resize rendertarget buffer",false); + } + + RECT view_rect; + GetClientRect( _mwindow, &view_rect ); + ClientToScreen( _mwindow, (POINT*)&view_rect.left ); // translates top,left pnt + ClientToScreen( _mwindow, (POINT*)&view_rect.right ); // translates right,bottom pnt + + // change _props xsize,ysize + resized((view_rect.right - view_rect.left),(view_rect.bottom - view_rect.top)); + + _props._xorg = view_rect.left; // _props origin should reflect upper left of view rectangle + _props._yorg = view_rect.top; + + if(wdxdisplay_cat.is_spam()) { + wdxdisplay_cat.spam() << "reshape to origin: (" << _props._xorg << "," << _props._yorg << "), size: (" << _props._xsize << "," << _props._ysize << ")\n"; + } + + if(_dxgsg!=NULL) { + if(bDoDxReset) + _dxgsg->dx_setup_after_resize(view_rect,_mwindow); // create the new resized rendertargets + _dxgsg->SetDXReady(true); + } +} + +void wdxGraphicsWindow::deactivate_window(void) { + // current policy is to suspend minimized or deactivated fullscreen windows, but leave + // regular windows running normally + + if(_window_inactive || _exiting_window || _active_minimized_fullscreen) { + #ifdef _DEBUG + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "deactivate_window called, but ignored in current mode\n"; + #endif + return; + } + + if(bResponsive_minimized_fullscreen_window) { + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX fullscreen window switching to active minimized mode...\n"; + _active_minimized_fullscreen = true; + } else { + + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX window deactivated, waiting...\n"; + + _window_inactive = true; + } + + if(_props._fullscreen) { + // make sure window is minimized + + WINDOWPLACEMENT wndpl; + wndpl.length=sizeof(WINDOWPLACEMENT); + + if(!GetWindowPlacement(_mwindow,&wndpl)) { + wdxdisplay_cat.error() << "GetWindowPlacement failed!\n"; + return; + } + if((wndpl.showCmd!=SW_MINIMIZE)&&(wndpl.showCmd!=SW_SHOWMINIMIZED)) { + ShowWindow(_mwindow, SW_MINIMIZE); + } + + throw_event("PandaPaused"); // right now this is used to signal python event handler to disable audio + } + +// if(!bResponsive_minimized_fullscreen_window) { + // need this even in responsive-mode to trigger the dxgsg check of cooplvl, i think? + _PandaPausedTimer = SetTimer(_mwindow,PAUSED_TIMER_ID,500,NULL); + if(_PandaPausedTimer!=PAUSED_TIMER_ID) { + wdxdisplay_cat.error() << "Error in SetTimer!\n"; + } +// } +} + +void wdxGraphicsWindow::reactivate_window(void) { + if(_window_inactive) { + + // first see if dx cooperative level is OK for reactivation + // if(!_dxgsg->CheckCooperativeLevel()) + // return; + + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX window re-activated...\n"; + + _window_inactive = false; + + if(_PandaPausedTimer!=NULL) { + KillTimer(_mwindow,_PandaPausedTimer); + _PandaPausedTimer = NULL; + } + + // move window to top of zorder + // if(_props._fullscreen) + // SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER); + GdiFlush(); + + } else if(_active_minimized_fullscreen) { + if(wdxdisplay_cat.is_spam()) + wdxdisplay_cat.spam() << "WDX window unminimized from active-minimized state...\n"; + + if(_PandaPausedTimer!=NULL) { + KillTimer(_mwindow,_PandaPausedTimer); + _PandaPausedTimer = NULL; + } + + _active_minimized_fullscreen = false; + + // move window to top of zorder + // if(_props._fullscreen) + // SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER); + GdiFlush(); + } + + if(_props._fullscreen) { + throw_event("PandaRestarted"); // right now this is used to signal python event handler to re-enable audio + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Constructor +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +wdxGraphicsWindow:: +wdxGraphicsWindow(GraphicsPipe* pipe) : GraphicsWindow(pipe) { + config(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Constructor +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +wdxGraphicsWindow:: +wdxGraphicsWindow(GraphicsPipe* pipe, const + GraphicsWindow::Properties& props) : GraphicsWindow(pipe, props) { + config(); +} + +//////////////////////////////////////////////////////////////////// +// Function: config +// Access: +// Description: Set up win32 window +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::config(void) { + GraphicsWindow::config(); + + global_wdxwinptr = this; // for use during createwin() + + _hdc = NULL; + _mwindow = NULL; + _gsg = _dxgsg = NULL; + _exiting_window = false; + _window_inactive = false; + _return_control_to_app = false; + _active_minimized_fullscreen = false; + _bIsLowVidMemCard = false; + + _hOldForegroundWindow=GetForegroundWindow(); + + if(dx_full_screen || _props._fullscreen) { + _props._fullscreen = dx_full_screen = true; + } + + _WindowAdjustingType = NotAdjusting; + _hMouseCursor = NULL; + _bSizeIsMaximized=FALSE; + + // Create a GSG to manage the graphics + make_gsg(); + if(_gsg==NULL) { + wdxdisplay_cat.error() << "DXGSG creation failed!\n"; + exit(1); + } + _dxgsg = DCAST(DXGraphicsStateGuardian, _gsg); + + HINSTANCE hinstance = GetModuleHandle(NULL); + + WNDCLASS wc; + + // Clear before filling in window structure! + ZeroMemory(&wc, sizeof(WNDCLASS)); + wc.style = CS_HREDRAW | CS_VREDRAW; //CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) static_window_proc; + wc.hInstance = hinstance; + + string windows_icon_filename = get_icon_filename().to_os_specific(); + string windows_mono_cursor_filename = get_mono_cursor_filename().to_os_specific(); + + if(!windows_icon_filename.empty()) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + // loads a .ico fmt file + wc.hIcon = (HICON) LoadImage(NULL, windows_icon_filename.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); + + if(wc.hIcon==NULL) { + wdxdisplay_cat.warning() << "windows icon filename '" << windows_icon_filename << "' not found!!\n"; + } + } else { + wc.hIcon = NULL; // use default app icon + } + + _bLoadedCustomCursor=false; + + if(!windows_mono_cursor_filename.empty()) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + DWORD load_flags = LR_LOADFROMFILE; + + if(dx_full_screen) { + // I think cursors should use LR_CREATEDIBSECTION since they should not be mapped to the device palette (in the case of 256-color cursors) + // since they are not going to be used on the desktop + load_flags |= LR_CREATEDIBSECTION; + } + // loads a .cur fmt file. + _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_mono_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags); + + if(_hMouseCursor==NULL) { + wdxdisplay_cat.warning() << "windows cursor filename '" << windows_mono_cursor_filename << "' not found!!\n"; + _hMouseCursor = LoadCursor(NULL, IDC_ARROW); + } + _bLoadedCustomCursor=true; + } else { + _hMouseCursor = LoadCursor(NULL, IDC_ARROW); + } + + wc.hCursor = _hMouseCursor; + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = WDX_WINDOWCLASSNAME; + + if(!RegisterClass(&wc)) { + wdxdisplay_cat.fatal() << "could not register window class!" << endl; + exit(1); + } + + DWORD window_style = WS_POPUP | WS_SYSMENU; // for CreateWindow + + // rect now contains the coords for the entire window, not the client + if(dx_full_screen) { + + _mwindow = CreateWindow(WDX_WINDOWCLASSNAME, _props._title.c_str(), + window_style, 0, 0, _props._xsize,_props._ysize, + NULL, NULL, hinstance, 0); + } else { + RECT win_rect; + SetRect(&win_rect, _props._xorg, _props._yorg, _props._xorg + _props._xsize, + _props._yorg + _props._ysize); + + if(_props._border) + window_style |= WS_OVERLAPPEDWINDOW; // should we just use WS_THICKFRAME instead? + + AdjustWindowRect(&win_rect, window_style, FALSE); //compute window size based on desired client area size + + // make sure origin is on screen + if(win_rect.left < 0) { + win_rect.right -= win_rect.left; win_rect.left = 0; + } + if(win_rect.top < 0) { + win_rect.bottom -= win_rect.top; win_rect.top = 0; + } + + _mwindow = CreateWindow(WDX_WINDOWCLASSNAME, _props._title.c_str(), + window_style, win_rect.left, win_rect.top, win_rect.right-win_rect.left, + win_rect.bottom-win_rect.top, + NULL, NULL, hinstance, 0); + } + + if(!_mwindow) { + wdxdisplay_cat.fatal() << "config() - failed to create window" << endl; + exit(1); + } + + hwnd_pandawin_map[_mwindow] = this; + global_wdxwinptr = NULL; // get rid of any reference to this obj + + // move window to top of zorder + SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE); + + _hdc = GetDC(_mwindow); + + dx_setup(); + + _mouse_input_enabled = false; + _mouse_motion_enabled = false; + _mouse_passive_motion_enabled = false; + _mouse_entry_enabled = false; + + // Enable detection of mouse input + enable_mouse_input(true); + enable_mouse_motion(true); + enable_mouse_passive_motion(true); + // enable_mouse_entry(true); re-enable this?? + + // Now indicate that we have our keyboard/mouse device ready. + GraphicsWindowInputDevice device = GraphicsWindowInputDevice::pointer_and_keyboard("keyboard/mouse"); + _input_devices.push_back(device); + + ShowWindow(_mwindow, SW_SHOWNORMAL); + ShowWindow(_mwindow, SW_SHOWNORMAL); // call twice to override STARTUPINFO value, which may be set to hidden initially by emacs +// UpdateWindow( _mwindow ); +} + +HRESULT CALLBACK EnumDevicesCallback(LPSTR pDeviceDescription, LPSTR pDeviceName, + LPD3DDEVICEDESC7 pD3DDeviceDesc,LPVOID pContext) { + D3DDEVICEDESC7 *pd3ddevs = (D3DDEVICEDESC7 *)pContext; +#ifdef _DEBUG + wdxdisplay_cat.spam() << "Enumerating Device " << pDeviceName << " : " << pDeviceDescription << endl; +#endif + +#define REGHALIDX 0 +#define TNLHALIDX 1 + + // only saves hal and tnl devs, not sw rasts + + if(IsEqualGUID(pD3DDeviceDesc->deviceGUID,IID_IDirect3DHALDevice)) { + CopyMemory(&pd3ddevs[REGHALIDX],pD3DDeviceDesc,sizeof(D3DDEVICEDESC7)); + } else if(IsEqualGUID(pD3DDeviceDesc->deviceGUID,IID_IDirect3DTnLHalDevice)) { + CopyMemory(&pd3ddevs[TNLHALIDX],pD3DDeviceDesc,sizeof(D3DDEVICEDESC7)); + } + return DDENUMRET_OK; +} + +#define MAX_DISPLAY_MODES 100 // probably dont need this much, since i already screen for width&hgt +typedef struct { + DWORD maxWidth,maxHeight; + DWORD supportedBitDepths; // uses DDBD_* flags + LPDDSURFACEDESC2 pDDSD_Arr; + DWORD cNumSurfDescs; +} DisplayModeInfo; + +HRESULT WINAPI EnumDisplayModesCallBack(LPDDSURFACEDESC2 lpDDSurfaceDesc,LPVOID lpContext) { + DisplayModeInfo *pDMI = (DisplayModeInfo *) lpContext; + + // ddsd_search should assure this is true + assert((lpDDSurfaceDesc->dwWidth == pDMI->maxWidth) && (lpDDSurfaceDesc->dwHeight == pDMI->maxHeight)); + + // ignore refresh rates under 60Hz (and special values of 0 & 1) + if((lpDDSurfaceDesc->dwRefreshRate>1) && (lpDDSurfaceDesc->dwRefreshRate<60)) + return DDENUMRET_OK; + + assert(pDMI->cNumSurfDescs < MAX_DISPLAY_MODES); + memcpy( &(pDMI->pDDSD_Arr[pDMI->cNumSurfDescs]), lpDDSurfaceDesc, sizeof(DDSURFACEDESC2) ); + pDMI->cNumSurfDescs++; + pDMI->supportedBitDepths |= BitDepth_2_DDBDMask(lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount); + + return DDENUMRET_OK; +} + +BOOL WINAPI DriverEnumCallback( GUID* pGUID, TCHAR* strDesc,TCHAR* strName, + VOID *argptr, HMONITOR hm) { + if(hm!=NULL) // skip over non-primary display devices + return DDENUMRET_OK; + + // primary display driver will have NULL guid + // ignore that and save any non-null value, whic + // indicates a secondary driver, which is usually voodoo1/2 + if(pGUID!=NULL) { + memcpy(argptr,pGUID,sizeof(GUID)); + } + + return DDENUMRET_OK; +} + +void wdxGraphicsWindow::resize(unsigned int xsize,unsigned int ysize) { + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "resize("<SetDXReady(false); + + HRESULT hr; + + DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_curmode); + + if(FAILED(hr = _dxgsg->_pDD->GetDisplayMode(&ddsd_curmode))) { + wdxdisplay_cat.fatal() << "resize() - GetDisplayMode failed, result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_search); + + ddsd_search.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; + ddsd_search.dwWidth=xsize; ddsd_search.dwHeight=ysize; + + // not requesting same refresh rate since changing res might not support same refresh rate + + DDSURFACEDESC2 DDSD_Arr[MAX_DISPLAY_MODES]; + DisplayModeInfo DMI; + ZeroMemory(&DDSD_Arr,sizeof(DDSD_Arr)); + ZeroMemory(&DMI,sizeof(DMI)); + DMI.maxWidth=xsize; DMI.maxHeight=ysize; + DMI.pDDSD_Arr=DDSD_Arr; + + if(FAILED(hr = _dxgsg->_pDD->EnumDisplayModes(DDEDM_REFRESHRATES,&ddsd_search,&DMI,EnumDisplayModesCallBack))) { + wdxdisplay_cat.fatal() << "resize() - EnumDisplayModes failed, result = " << ConvD3DErrorToString(hr) << endl; + return; + } + + DMI.supportedBitDepths &= _dxgsg->_D3DDevDesc.dwDeviceRenderBitDepth; + + DWORD dwFullScreenBitDepth; + DWORD requested_bpp=ddsd_curmode.ddpfPixelFormat.dwRGBBitCount; + + // would like to match current bpp first. if that is not possible, try 16bpp, then 32 + DWORD requested_bpp_DDBD = BitDepth_2_DDBDMask(requested_bpp); + + if(DMI.supportedBitDepths & requested_bpp_DDBD) { + dwFullScreenBitDepth=requested_bpp; + } else if(DMI.supportedBitDepths & DDBD_16) { + dwFullScreenBitDepth=16; + } else if(DMI.supportedBitDepths & DDBD_32) { + dwFullScreenBitDepth=32; + } else { + wdxdisplay_cat.error() + << "resize failed, no fullScreen resolutions at " << xsize << "x" << ysize << endl; + return; + } + + if(FAILED(hr = _dxgsg->_pDD->TestCooperativeLevel())) { + wdxdisplay_cat.error() << "TestCooperativeLevel failed : result = " << ConvD3DErrorToString(hr) << endl; + wdxdisplay_cat.error() << "Full screen app failed to get exclusive mode on resize, exiting..\n"; + return; + } + + _dxgsg->free_dxgsg_objects(); + + // let driver choose default refresh rate (hopefully its >=60Hz) + if(FAILED( hr = _dxgsg->_pDD->SetDisplayMode( xsize,ysize,dwFullScreenBitDepth, 0L, 0L ))) { + wdxdisplay_cat.error() << "resize failed to reset display mode to (" << xsize <<"x"<_pDD,_dxgsg->_d3d,NULL); + _dxgsg->RecreateAllVideoSurfaces(); + _dxgsg->SetDXReady(true); +} + +unsigned int wdxGraphicsWindow:: +verify_window_sizes(unsigned int numsizes,unsigned int *dimen) { + DWORD num_valid_modes=0; + HRESULT hr; + + // not requesting same refresh rate since changing res might not support same refresh rate at new size + + DDSURFACEDESC2 DDSD_Arr[MAX_DISPLAY_MODES]; + DisplayModeInfo DMI; + DWORD i,*pCurDim=(DWORD *)dimen; + + + for(i=0;i_pDD->EnumDisplayModes(DDEDM_REFRESHRATES,&ddsd_search,&DMI,EnumDisplayModesCallBack))) { + wdxdisplay_cat.fatal() << "resize() - EnumDisplayModes failed, result = " << ConvD3DErrorToString(hr) << endl; + return 0; + } + + // get rid of bpp's we cant render at + DMI.supportedBitDepths &= _dxgsg->_D3DDevDesc.dwDeviceRenderBitDepth; + + bool bIsGoodMode=false; + + if(_bIsLowVidMemCard) + bIsGoodMode=(((float)xsize*(float)ysize)<=(float)(640*480)); + else bIsGoodMode=((DMI.supportedBitDepths & (DDBD_16 | DDBD_24 | DDBD_32))!=0); + + if(bIsGoodMode) + num_valid_modes++; + else { + pCurDim[0] = 0; + pCurDim[1] = 0; + } + } + + return num_valid_modes; +} + +// imperfect method to ID NVid? could also scan desc str, but that isnt fullproof either +#define IS_NVIDIA(DDDEVICEID) ((DDDEVICEID.dwVendorId==0x10DE) || (DDDEVICEID.dwVendorId==0x12D2)) +#define IS_ATI(DDDEVICEID) (DDDEVICEID.dwVendorId==0x1002) +#define IS_MATROX(DDDEVICEID) (DDDEVICEID.dwVendorId==0x102B) + +void wdxGraphicsWindow:: +check_for_color_cursor_support(void) { + // card support for non-black/white GDI cursors varies greatly. if the cursor is not supported, + // it is rendered in software by GDI, which causes a flickering effect (because it's not synced + // with flip?). GDI transparently masks what's happening so there is no easy way for app to detect + // if HW cursor support exists. alternatives are to tie cursor motion to frame rate using DDraw blts + // or overlays, or to have separate thread draw cursor (sync issues?). instead we do mono cursor + // unless card is known to support 256 color cursors + + string windows_color_cursor_filename = get_color_cursor_filename().to_os_specific(); + if(windows_color_cursor_filename.empty()) + return; + + bool bSupportsColorCursor=false; + + if(IS_NVIDIA(_DXDeviceID)) { + // all nvidia seem to support 256 color + bSupportsColorCursor=true; + } else if(IS_ATI(_DXDeviceID)) { + // radeons seem to be in the 5100 range and support color, assume anything in 6000 or above + // is newer than radeon and supports 256 color + if(((_DXDeviceID.dwDeviceId>=0x5100) && (_DXDeviceID.dwDeviceId<=0x5200)) || + (_DXDeviceID.dwDeviceId>=0x6000)) + bSupportsColorCursor=true; + } else if IS_MATROX(_DXDeviceID) { + if(_DXDeviceID.dwDeviceId==0x0525) // G400 seems to support color cursors, havent tested other matrox + bSupportsColorCursor=true; + } + + // TODO: add more cards as more testing is done + + if(bSupportsColorCursor) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + DWORD load_flags = LR_LOADFROMFILE; + + if(dx_full_screen) { + // I think cursors should use LR_CREATEDIBSECTION since they should not be mapped to the device palette (in the case of 256-color cursors) + // since they are not going to be used on the desktop + load_flags |= LR_CREATEDIBSECTION; + } + + // loads a .cur fmt file. + HCURSOR hNewMouseCursor = (HCURSOR) LoadImage(NULL, windows_color_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags ); + + if(hNewMouseCursor==NULL) { + wdxdisplay_cat.warning() << "windows color cursor filename '" << windows_color_cursor_filename << "' not found!!\n"; + return; + } + + SetClassLongPtr(_mwindow, GCLP_HCURSOR, (LONG_PTR) hNewMouseCursor); + SetCursor(hNewMouseCursor); + + if(_bLoadedCustomCursor) + DestroyCursor(_hMouseCursor); + _hMouseCursor = hNewMouseCursor; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: dx_setup +// Description: Set up the DirectX environment. The size of the +// rendered area will be computed from the Client area +// of the window (if in windowed mode) and the _props +// structure will be set accordingly. +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow:: +dx_setup() { + LPDIRECT3D7 pD3DI; + LPDIRECTDRAW7 pDD; + HRESULT hr; + DX_DECLARE_CLEAN( DDSURFACEDESC2, SurfaceDesc ); + + // Check for DirectX 7 by looking for DirectDrawCreateEx + + HINSTANCE DDHinst = LoadLibrary( "ddraw.dll" ); + if(DDHinst == 0) { + wdxdisplay_cat.fatal() << "can't locate DDRAW.DLL!" << endl; + exit(1); + } + + if(NULL == GetProcAddress( DDHinst, "DirectDrawCreateEx" )) { + wdxdisplay_cat.fatal() << "Panda currently requires at least DirectX 7.0!" << endl; + exit(1); + } + + GUID DriverGUID; + ZeroMemory(&DriverGUID,sizeof(GUID)); + + // search for early voodoo-type non-primary display drivers + // if they exist, use them for 3D (could examine 3D devices on all + // drivers and pick the best one, but I'll assume the computer setuper knows what he's doing) + if(hr = DirectDrawEnumerateEx( DriverEnumCallback, &DriverGUID, DDENUM_NONDISPLAYDEVICES )) { + wdxdisplay_cat.fatal() << "config() - DirectDrawEnumerateEx failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + GUID *pOurDriverGUID=NULL; + if(DriverGUID.Data1 != 0x0) { // assumes no driver guid ever starts with 0, so 0 means Enum found no voodoo-type device + pOurDriverGUID=&DriverGUID; + } + + // Create the Direct Draw Object + hr = DirectDrawCreateEx(pOurDriverGUID, (void **)&pDD, IID_IDirectDraw7, NULL); + if(hr != DD_OK) { + wdxdisplay_cat.fatal() + << "config() - DirectDrawCreateEx failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + FreeLibrary(DDHinst); //undo LoadLib above, decrement ddrawl.dll refcnt (after DDrawCreate, since dont want to unload/reload) + + pDD->GetDeviceIdentifier(&_DXDeviceID,0x0); + +#ifdef _DEBUG + wdxdisplay_cat.debug() << " GfxCard: " << _DXDeviceID.szDescription << "; DriverFile: '" << _DXDeviceID.szDriver << "'; VendorID: " <<_DXDeviceID.dwVendorId <<"; DriverVer: " << HIWORD(_DXDeviceID.liDriverVersion.HighPart) << "." << LOWORD(_DXDeviceID.liDriverVersion.HighPart) << "." << HIWORD(_DXDeviceID.liDriverVersion.LowPart) << "." << LOWORD(_DXDeviceID.liDriverVersion.LowPart) << endl; +#endif + + check_for_color_cursor_support(); + + // Query DirectDraw for access to Direct3D + + hr = pDD->QueryInterface( IID_IDirect3D7, (VOID**)&pD3DI ); + if(hr != DD_OK) { + wdxdisplay_cat.fatal() << "QI for D3D failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + D3DDEVICEDESC7 d3ddevs[2]; // put HAL in 0, TnLHAL in 1 + + + // just look for HAL and TnL devices right now. I dont think + // we have any interest in the sw rasts at this point + + ZeroMemory(d3ddevs,2*sizeof(D3DDEVICEDESC7)); + + hr = pD3DI->EnumDevices(EnumDevicesCallback,d3ddevs); + if(hr != DD_OK) { + wdxdisplay_cat.fatal() << "EnumDevices failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + WORD DeviceIdx=REGHALIDX; + + if(!(d3ddevs[DeviceIdx].dwDevCaps & D3DDEVCAPS_HWRASTERIZATION )) { + wdxdisplay_cat.fatal() << "No 3D HW present, exiting..." << endl; + exit(1); + } + + // select TNL if present + if(d3ddevs[TNLHALIDX].dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) { + DeviceIdx=TNLHALIDX; + } + + D3DDEVICEDESC7 *pD3DDevDesc=&d3ddevs[DeviceIdx]; + + DWORD dwRenderWidth=0, dwRenderHeight=0; + + if(dx_full_screen) { + dwRenderWidth = _props._xsize; + dwRenderHeight = _props._ysize; + _props._xorg = _props._yorg = 0; + + // CREATE FULL SCREEN BUFFERS + // Store the rectangle which contains the renderer + + DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_search); + ddsd_search.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; + ddsd_search.dwWidth=dwRenderWidth; ddsd_search.dwHeight=dwRenderHeight; + + DDSURFACEDESC2 DDSD_Arr[MAX_DISPLAY_MODES]; + DisplayModeInfo DMI; + ZeroMemory(&DDSD_Arr,sizeof(DDSD_Arr)); + ZeroMemory(&DMI,sizeof(DMI)); + DMI.maxWidth=dwRenderWidth; DMI.maxHeight=dwRenderHeight; + DMI.pDDSD_Arr=DDSD_Arr; + + if(FAILED(hr= pDD->EnumDisplayModes(DDEDM_REFRESHRATES,&ddsd_search,&DMI,EnumDisplayModesCallBack))) { + wdxdisplay_cat.fatal() << "EnumDisplayModes failed, result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + DWORD dwFullScreenBitDepth; + + // Now we try to figure out if we can use requested screen resolution and best + // rendertarget bpp and still have at least 2 meg of texture vidmem + + // Get Current VidMem avail. Note this is only an estimate, when we switch to fullscreen + // mode from desktop, more vidmem will be available (typically 1.2 meg). I dont want + // to switch to fullscreen more than once due to the annoying monitor flicker, so try + // to figure out optimal mode using this estimate + DDSCAPS2 ddsCaps; + DWORD dwTotal,dwFree; + ZeroMemory(&ddsCaps,sizeof(DDSCAPS2)); + ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; //set internally by DX anyway, dont think this any different than 0x0 + + if(FAILED( hr = pDD->GetAvailableVidMem(&ddsCaps,&dwTotal,&dwFree))) { + wdxdisplay_cat.error() << "GetAvailableVidMem failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + #ifdef _DEBUG + wdxdisplay_cat.debug() << "before FullScreen switch: GetAvailableVidMem returns Total: " << dwTotal/1000000.0 << " Free: " << dwFree/1000000.0 << endl; + #endif + + DMI.supportedBitDepths &= pD3DDevDesc->dwDeviceRenderBitDepth; + + // note: this chooses 32bpp, which may not be preferred over 16 for memory & speed reasons + if(DMI.supportedBitDepths & DDBD_32) { + dwFullScreenBitDepth=32; // go for 32bpp if its avail + } else if(DMI.supportedBitDepths & DDBD_24) { + dwFullScreenBitDepth=24; // go for 24bpp if its avail + } else if(DMI.supportedBitDepths & DDBD_16) { + dwFullScreenBitDepth=16; // do 16bpp + } else { + wdxdisplay_cat.fatal() + << "No Supported FullScreen resolutions at " << dwRenderWidth << "x" << dwRenderHeight << endl; + exit(1); + } + + if(dwFree>0) { // assume buggy drivers (this means you, FireGL2) may return zero for dwTotal, so ignore value if its 0 + + // hack: figuring out exactly what res to use is tricky, instead I will + // just use 640x480 if we have < 3 meg avail + + #define LOWVIDMEMTHRESHOLD 3500000 + if(dwFree< LOWVIDMEMTHRESHOLD) { + // we're going to need 800x600 or 640x480 at 16 bit to save enough tex vidmem + dwFullScreenBitDepth=16; // do 16bpp + dwRenderWidth=640; + dwRenderHeight=480; + _bIsLowVidMemCard = true; + wdxdisplay_cat.debug() << " "<>3); + int memleft = dwFree-rendertargetmem*2; //*2 to handle backbuf/zbuf + + if(memleft < RESERVEDTEXVIDMEM) { + dwFullScreenBitDepth=16; + wdxdisplay_cat.debug() << "using 16bpp rendertargets to save tex vidmem\n"; + assert((DMI.supportedBitDepths & DDBD_16) && (pD3DDevDesc->dwDeviceRenderBitDepth & DDBD_16)); // probably a safe assumption + rendertargetmem=dwRenderWidth*dwRenderHeight*(dwFullScreenBitDepth>>3); + memleft = dwFree-rendertargetmem*2; + + // BUGBUG: if we still cant reserve 2 megs of vidmem, need to auto-reduce the scrn res + if(memleft < RESERVEDTEXVIDMEM) + wdxdisplay_cat.debug() << " XXXXXX WARNING: cant reserve 2MB of tex vidmem. only " << memleft << " bytes available. Need to rewrite wdxdisplay to try lower resolutions XXXXXXXXXXXXXXXXXXXX\n"; + } + #endif + } + + // extern bool dx_preserve_fpu_state; + DWORD SCL_FPUFlag = DDSCL_FPUSETUP; + + // if(dx_preserve_fpu_state) + // SCL_FPUFlag = DDSCL_FPUPRESERVE; // tell d3d to preserve the fpu state across calls. this hurts perf, but is good for dbgging + + DWORD SCL_FLAGS = SCL_FPUFlag | DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT; + + if(FAILED(hr = pDD->SetCooperativeLevel(_mwindow, SCL_FLAGS))) { + wdxdisplay_cat.fatal() << "SetCooperativeLevel failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // s3 savage2000 on w95 seems to set EXCLUSIVE_MODE only if you call SetCoopLevel twice. + // so we do it, it really shouldnt be necessary if drivers werent buggy + if(FAILED(hr = pDD->SetCooperativeLevel(_mwindow, SCL_FLAGS))) { + wdxdisplay_cat.fatal() + << "SetCooperativeLevel failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(FAILED(hr = pDD->TestCooperativeLevel())) { + wdxdisplay_cat.fatal() << "TestCooperativeLevel failed : result = " << ConvD3DErrorToString(hr) << endl; + wdxdisplay_cat.fatal() << "Full screen app failed to get exclusive mode on init, exiting..\n"; + exit(1); + } + + // let driver choose default refresh rate (hopefully its >=60Hz) + if(FAILED( hr = pDD->SetDisplayMode( dwRenderWidth, dwRenderHeight, + dwFullScreenBitDepth, 0L, 0L ))) { + wdxdisplay_cat.fatal() << "failed to reset display mode to ("<GetAvailableVidMem(&ddsCaps,&dwTotal,&dwFree))) { + wdxdisplay_cat.debug() << "GetAvailableVidMem failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + wdxdisplay_cat.debug() << "after FullScreen switch: GetAvailableVidMem returns Total: " << dwTotal/1000000.0 << " Free: " << dwFree/1000000.0 << endl; + #endif + } + } + + CreateScreenBuffersAndDevice(dwRenderWidth,dwRenderHeight,pDD,pD3DI,pD3DDevDesc); + + _dxgsg->SetDXReady(true); +} + + +void wdxGraphicsWindow:: +CreateScreenBuffersAndDevice(DWORD dwRenderWidth, DWORD dwRenderHeight,LPDIRECTDRAW7 pDD, + LPDIRECT3D7 pD3DI,D3DDEVICEDESC7 *pD3DDevDesc) { + LPDIRECTDRAWSURFACE7 pPrimaryDDSurf,pBackDDSurf,pZDDSurf; + LPDIRECT3DDEVICE7 pD3DDevice; + RECT view_rect; + int i; + HRESULT hr; + DX_DECLARE_CLEAN( DDSURFACEDESC2, SurfaceDesc ); + D3DDEVICEDESC7 d3ddevs[2]; // put HAL in 0, TnLHAL in 1 + + assert(pDD!=NULL); + assert(pD3DI!=NULL); + + // select the best device if the caller does not provide one + if(pD3DDevDesc==NULL) { + + // just look for HAL and TnL devices right now. I dont think + // we have any interest in the sw rasts at this point + + ZeroMemory(d3ddevs,2*sizeof(D3DDEVICEDESC7)); + + hr = pD3DI->EnumDevices(EnumDevicesCallback,d3ddevs); + if(hr != DD_OK) { + wdxdisplay_cat.fatal() << "EnumDevices failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + WORD DeviceIdx=REGHALIDX; + + if(!(d3ddevs[DeviceIdx].dwDevCaps & D3DDEVCAPS_HWRASTERIZATION )) { + wdxdisplay_cat.fatal() << "No 3D HW present, exiting..." << endl; + exit(1); + } + + // select TNL if present + if(d3ddevs[TNLHALIDX].dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) { + DeviceIdx=TNLHALIDX; + } + + pD3DDevDesc=&d3ddevs[DeviceIdx]; + } + + DX_DECLARE_CLEAN(DDCAPS,DDCaps); + pDD->GetCaps(&DDCaps,NULL); + + if(dx_full_screen) { + // Setup to create the primary surface w/backbuffer + DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd) + ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | + DDSCAPS_FLIP | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + + if(dx_full_screen_antialiasing) { + // cant check that d3ddevice has this capability yet, so got to set it anyway. + // hope this is OK. + ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_HINTANTIALIASING; + } + + PRINTVIDMEM(pDD,&ddsd.ddsCaps,"initial primary & backbuf"); + + // Create the primary surface + if(FAILED( hr = pDD->CreateSurface( &ddsd, &pPrimaryDDSurf, NULL ) )) { + wdxdisplay_cat.fatal() << "CreateSurface failed for primary surface: result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Clear the primary surface to black + + DX_DECLARE_CLEAN(DDBLTFX, bltfx) + bltfx.dwDDFX |= DDBLTFX_NOTEARING; + hr = pPrimaryDDSurf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx); + + if(FAILED( hr )) { + wdxdisplay_cat.fatal() << "Blt to Black of Primary Surf failed! : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Get the backbuffer, which was created along with the primary. + DDSCAPS2 ddscaps = { DDSCAPS_BACKBUFFER, 0, 0, 0}; + if(FAILED( hr = pPrimaryDDSurf->GetAttachedSurface( &ddscaps, &pBackDDSurf ) )) { + wdxdisplay_cat.fatal() << "Can't get the backbuffer: result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(FAILED( hr = pBackDDSurf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx))) { + wdxdisplay_cat.fatal() << "Blt to Black of Back Surf failed! : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight); + } // end create full screen buffers + + else { // CREATE WINDOWED BUFFERS + assert(dwRenderWidth==0 && dwRenderHeight==0); // these params are ignored for windowed mode + + if(!(DDCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED)) { + wdxdisplay_cat.fatal() << "the 3D HW cannot render windowed, exiting..." << endl; + exit(1); + } + + if(FAILED(hr = pDD->GetDisplayMode( &SurfaceDesc ))) { + wdxdisplay_cat.fatal() + << "GetDisplayMode failed result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + if(SurfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8) { + wdxdisplay_cat.fatal() << "Can't run windowed in an 8-bit or less display mode" << endl; + exit(1); + } + + if(!(BitDepth_2_DDBDMask(SurfaceDesc.ddpfPixelFormat.dwRGBBitCount) & pD3DDevDesc->dwDeviceRenderBitDepth)) { + wdxdisplay_cat.fatal() << "3D Device doesnt support rendering at " << SurfaceDesc.ddpfPixelFormat.dwRGBBitCount << "bpp (current desktop bitdepth)" << endl; + exit(1); + } + +// extern bool dx_preserve_fpu_state; + DWORD SCL_FPUFlag = DDSCL_FPUSETUP; + +// if(dx_preserve_fpu_state) +// SCL_FPUFlag = DDSCL_FPUPRESERVE; // tell d3d to preserve the fpu state across calls. this hurts perf, but is good for dbgging + + if(FAILED(hr = pDD->SetCooperativeLevel(_mwindow, SCL_FPUFlag | DDSCL_NORMAL))) { + wdxdisplay_cat.fatal() << "SetCooperativeLevel failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + // Get the dimensions of the viewport and screen bounds + + GetClientRect( _mwindow, &view_rect ); + POINT ul,lr; + ul.x=view_rect.left; ul.y=view_rect.top; + lr.x=view_rect.right; lr.y=view_rect.bottom; + ClientToScreen( _mwindow, &ul ); + ClientToScreen( _mwindow, &lr ); + view_rect.left=ul.x; view_rect.top=ul.y; + view_rect.right=lr.x; view_rect.bottom=lr.y; + + dwRenderWidth = view_rect.right - view_rect.left; + dwRenderHeight = view_rect.bottom - view_rect.top; + _props._xorg = view_rect.left; // _props should reflect view rectangle + _props._yorg = view_rect.top; + _props._xsize = dwRenderWidth; + _props._ysize = dwRenderHeight; + + // Initialize the description of the primary surface + ZeroMemory( &SurfaceDesc, sizeof(DDSURFACEDESC2) ); + SurfaceDesc.dwSize = sizeof(DDSURFACEDESC2); + SurfaceDesc.dwFlags = DDSD_CAPS ; + SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + PRINTVIDMEM(pDD,&SurfaceDesc.ddsCaps,"initial primary surface"); + + // Create the primary surface. This includes all of the visible + // window, so no need to specify height/width + if(FAILED(hr = pDD->CreateSurface( &SurfaceDesc, &pPrimaryDDSurf, NULL ))) { + wdxdisplay_cat.fatal() + << "CreateSurface failed for primary surface: result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Create a clipper object which handles all our clipping for cases when + // our window is partially obscured by other windows. + LPDIRECTDRAWCLIPPER Clipper; + if(FAILED(hr = pDD->CreateClipper( 0, &Clipper, NULL ))) { + wdxdisplay_cat.fatal() + << "CreateClipper failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Associate the clipper with our window. Note that, afterwards, the + // clipper is internally referenced by the primary surface, so it is safe + // to release our local reference to it. + Clipper->SetHWnd( 0, _mwindow ); + pPrimaryDDSurf->SetClipper( Clipper ); + Clipper->Release(); + + // Clear the primary surface to black + DX_DECLARE_CLEAN(DDBLTFX, bltfx) + + if(FAILED( hr = pPrimaryDDSurf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx))) { + wdxdisplay_cat.fatal() + << "Blt to Black of Primary Surf failed! : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Setup a surface description to create a backbuffer. + SurfaceDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY; + SurfaceDesc.dwWidth = dwRenderWidth; + SurfaceDesc.dwHeight = dwRenderHeight; + + if(dx_full_screen_antialiasing) { + // cant check that d3ddevice has this capability yet, so got to set it anyway. + // hope this is OK. + SurfaceDesc.ddsCaps.dwCaps2 |= DDSCAPS2_HINTANTIALIASING; + } + + PRINTVIDMEM(pDD,&SurfaceDesc.ddsCaps,"initial backbuf"); + + // Create the backbuffer. (might want to handle failure due to running out of video memory. + if(FAILED(hr = pDD->CreateSurface( &SurfaceDesc, &pBackDDSurf, NULL ))) { + wdxdisplay_cat.fatal() + << "CreateSurface failed for backbuffer : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(FAILED( hr = pBackDDSurf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx))) { + wdxdisplay_cat.fatal() + << "Blt to Black of Back Surf failed! : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + } // end create windowed buffers + +// ======================================================== + + resized(dwRenderWidth,dwRenderHeight); // update panda channel/display rgn info + + #ifndef NDEBUG + if(!(_props._mask & W_DEPTH)) { + wdxdisplay_cat.info() << "no zbuffer requested, skipping zbuffer creation\n"; + } + #endif + + // Check if the device supports z-bufferless hidden surface removal. If so, + // we don't really need a z-buffer + if((!(pD3DDevDesc->dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) && + (_props._mask & W_DEPTH)) { + + // Get z-buffer dimensions from the render target + DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd); + pBackDDSurf->GetSurfaceDesc( &ddsd ); + + // Setup the surface desc for the z-buffer. + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; + + DDPIXELFORMAT ZBufPixFmts[MAX_DX_ZBUF_FMTS]; + cNumZBufFmts=0; + + // Get an appropiate pixel format from enumeration of the formats. On the + // first pass, we look for a zbuffer dpeth which is equal to the frame + // buffer depth (as some cards unfornately require this). + if(FAILED(pD3DI->EnumZBufferFormats( IID_IDirect3DHALDevice, EnumZBufFmtsCallback, + (VOID*)&ZBufPixFmts ))) { + wdxdisplay_cat.fatal() << "EnumZBufferFormats failed " << endl; + exit(1); + } + +#ifdef _DEBUG + { static BOOL bPrinted=FALSE; + if(!bPrinted) { + for(i=0;idwFlags & DDPF_STENCILBUFFER)!=0)) { + switch(pCurPixFmt->dwRGBBitCount) { + case 16: + pz16=pCurPixFmt; + break; + case 24: + pz24=pCurPixFmt; + break; + case 32: + pz32=pCurPixFmt; + break; + } + } + } + + if((pz16==NULL)&&(pz24==NULL)&&(pz32==NULL)) { + if(bWantStencil) + wdxdisplay_cat.fatal() << "stencil buffer requested, device has no stencil capability\n"; + else wdxdisplay_cat.fatal() << "failed to find adequate zbuffer capability\n"; + exit(1); + } + + #define SET_ZBUF_DEPTH(DEPTH) { assert(pz##DEPTH != NULL); _depth_buffer_bpp=DEPTH; ddsd.ddpfPixelFormat = *pz##DEPTH;} + + if(IS_NVIDIA(_DXDeviceID)) { + DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_pri) + pPrimaryDDSurf->GetSurfaceDesc(&ddsd_pri); + + // must pick zbuf depth to match primary surface depth for nvidia + if(ddsd_pri.ddpfPixelFormat.dwRGBBitCount==16) { + SET_ZBUF_DEPTH(16); + } else { + if(dx_force_16bpp_zbuffer) { + wdxdisplay_cat.fatal() << "'dx-force-16bpp-zbuffer #t' requires a 16bpp desktop on nvidia cards\n"; + exit(1); + } + // take the smaller of 24 or 32. (already assured to match stencil capability) + if(pz24!=NULL) { + SET_ZBUF_DEPTH(24); + } else SET_ZBUF_DEPTH(32); + } + } else { + if(dx_force_16bpp_zbuffer) { + if(pz16==NULL) { + wdxdisplay_cat.fatal() << "'dx-force-16bpp-zbuffer #t', but no 16bpp zbuf fmts available on this card\n"; + exit(1); + } + + if(wdxdisplay_cat.is_debug()) + wdxdisplay_cat.debug() << "forcing use of 16bpp Z-Buffer\n"; + SET_ZBUF_DEPTH(16); + ddsd.ddpfPixelFormat = *pz16; + } else { + // pick the highest res zbuffer format avail. Note: this is choosing to waste vid-memory + // and possibly perf for more accuracy, less z-fighting at long distance (std 16bpp would + // be smaller// maybe faster) + // order of preference 24: (should be enough), 32: probably means 24 of Z, then 16 + + if(bWantStencil && (pz32!=NULL)) { + // dont want to select 16/8 z/stencil over 24/8 z/stenc + SET_ZBUF_DEPTH(32); + } else { + if(pz24!=NULL) { + SET_ZBUF_DEPTH(24); + } else if(pz32!=NULL) { + SET_ZBUF_DEPTH(32); + } else { + SET_ZBUF_DEPTH(16); + } + } + } + } + + PRINTVIDMEM(pDD,&ddsd.ddsCaps,"initial zbuf"); + +#ifdef _DEBUG + wdxdisplay_cat.info() << "Creating " << ddsd.ddpfPixelFormat.dwRGBBitCount << "bpp zbuffer\n"; +#endif + + // Create and attach a z-buffer + if(FAILED( hr = pDD->CreateSurface( &ddsd, &pZDDSurf, NULL ) )) { + wdxdisplay_cat.fatal() << "CreateSurface failed for Z buffer: result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + if(FAILED( hr = pBackDDSurf->AddAttachedSurface( pZDDSurf ) )) { + wdxdisplay_cat.fatal() << "AddAttachedSurface failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + + // Create the device. The device is created off of our back buffer, which + // becomes the render target for the newly created device. + hr = pD3DI->CreateDevice(pD3DDevDesc->deviceGUID, pBackDDSurf, &pD3DDevice ); + if(hr != DD_OK) { + wdxdisplay_cat.fatal() << "CreateDevice failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + // Create the viewport + D3DVIEWPORT7 vp = { 0, 0, _props._xsize, _props._ysize, 0.0f, 1.0f}; + hr = pD3DDevice->SetViewport( &vp ); + if(hr != DD_OK) { + wdxdisplay_cat.fatal() << "SetViewport failed : result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + _dxgsg->Set_HDC(_hdc); + _dxgsg->dx_init(pDD, pPrimaryDDSurf, pBackDDSurf, pZDDSurf, pD3DI, pD3DDevice, view_rect); + // do not SetDXReady() yet since caller may want to do more work before letting rendering proceed +} + +//////////////////////////////////////////////////////////////////// +// Function: setup_colormap +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::setup_colormap(void) { + PIXELFORMATDESCRIPTOR pfd; + LOGPALETTE *logical; + int n; + + // should probably do this some other way than through opengl PixelFormat calls + + /* grab the pixel format */ + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + DescribePixelFormat(_hdc, GetPixelFormat(_hdc), + sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + if(!(pfd.dwFlags & PFD_NEED_PALETTE || + pfd.iPixelType == PFD_TYPE_COLORINDEX)) + return; + + n = 1 << pfd.cColorBits; + + /* allocate a bunch of memory for the logical palette (assume 256 + colors in a Win32 palette */ + logical = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + + sizeof(PALETTEENTRY) * n); + memset(logical, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n); + + /* set the entries in the logical palette */ + logical->palVersion = 0x300; + logical->palNumEntries = n; + + /* start with a copy of the current system palette */ + GetSystemPaletteEntries(_hdc, 0, 256, &logical->palPalEntry[0]); + + if(pfd.iPixelType == PFD_TYPE_RGBA) { + int redMask = (1 << pfd.cRedBits) - 1; + int greenMask = (1 << pfd.cGreenBits) - 1; + int blueMask = (1 << pfd.cBlueBits) - 1; + int i; + + /* fill in an RGBA color palette */ + for(i = 0; i < n; ++i) { + logical->palPalEntry[i].peRed = + (((i >> pfd.cRedShift) & redMask) * 255) / redMask; + logical->palPalEntry[i].peGreen = + (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask; + logical->palPalEntry[i].peBlue = + (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask; + logical->palPalEntry[i].peFlags = 0; + } + } + + _colormap = CreatePalette(logical); + free(logical); + + SelectPalette(_hdc, _colormap, FALSE); + RealizePalette(_hdc); +} + + +//////////////////////////////////////////////////////////////////// +// Function: begin_frame +// Access: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::begin_frame(void) { + GraphicsWindow::begin_frame(); +} + +void wdxGraphicsWindow::show_frame(void) { + _dxgsg->show_frame(); +} + + + +//////////////////////////////////////////////////////////////////// +// Function: end_frame +// Access: +// Description: timer info, incs frame # +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::end_frame(void) { + GraphicsWindow::end_frame(); +} + + + +//////////////////////////////////////////////////////////////////// +// Function: handle_window_move +// Access: +// Description: we receive the new x and y position of the client +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::handle_window_move(int x, int y) { + _dxgsg->adjust_view_rect(x,y); + _props._xorg = x; + _props._yorg = y; +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_mouse_motion +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::handle_mouse_motion(int x, int y) { + _input_devices[0].set_pointer_in_window(x, y); +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_mouse_entry +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::handle_mouse_entry(int state,HCURSOR hCursor) { + if(state == MOUSE_EXITED) { + _input_devices[0].set_pointer_out_of_window(); + } else { +// SetCursor(hCursor); believe this is not necessary, handled by windows + } +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_keypress +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow:: +handle_keypress(ButtonHandle key, int x, int y) { +/* + if(key.has_ascii_equivalent()) { + wdxdisplay_cat.spam() << key.get_ascii_equivalent() << endl; + + short d1 = GetKeyState(VK_CONTROL); + short d2 = GetKeyState(VK_SHIFT); + wdxdisplay_cat.spam().flags(ios::hex | ios::uppercase ); + wdxdisplay_cat.spam() << " Control: " << ((d1 < 0)? "down" : "up") << " Shift: " << ((d2 < 0)? "down" : "up") << endl; + } +*/ + _input_devices[0].set_pointer_in_window(x, y); + if(key != ButtonHandle::none()) { + _input_devices[0].button_down(key); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: handle_keyrelease +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow:: +handle_keyrelease(ButtonHandle key) { + if(key != ButtonHandle::none()) { + _input_devices[0].button_up(key); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow::supports_update +// Access: Public, Virtual +// Description: Returns true if this particular kind of +// GraphicsWindow supports use of the update() function +// to update the graphics one frame at a time, so that +// the window does not need to be the program's main +// loop. Returns false if the only way to update the +// window is to call main_loop(). +//////////////////////////////////////////////////////////////////// +bool wdxGraphicsWindow:: +supports_update() const { + return true; +} + +void INLINE process_1_event(void) { + MSG msg; + + if(!GetMessage(&msg, NULL, 0, 0)) { + // WM_QUIT received + DestroyAllWindows(false); + exit(msg.wParam); // this will invoke AtExitFn + } + + // Translate virtual key messages + TranslateMessage(&msg); + // Call window_proc + DispatchMessage(&msg); +} + +void INLINE wdxGraphicsWindow::process_events(void) { + if(_window_inactive) { + // Get 1 msg at a time until no more are left and we block and sleep, + // or message changes _return_control_to_app or _window_inactive status + + while(_window_inactive && (!_return_control_to_app)) { + process_1_event(); + } + _return_control_to_app = false; + + } else { + MSG msg; + + // handle all msgs on queue in a row + while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + process_1_event(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: update +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::update(void) { +#ifdef DO_PSTATS + _show_code_pcollector.stop(); + + if(!_window_inactive) { + PStatClient::main_tick(); + } +#endif + + process_events(); + + if(_window_inactive) { + // note _window_inactive must be checked after process_events is called, to avoid draw_callback being called + if(_idle_callback) + call_idle_callback(); + return; + } + + call_draw_callback(true); + + if(_idle_callback) + call_idle_callback(); + +#ifdef DO_PSTATS + _show_code_pcollector.start(); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: enable_mouse_input +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::enable_mouse_input(bool val) { + _mouse_input_enabled = val; +} + +//////////////////////////////////////////////////////////////////// +// Function: enable_mouse_motion +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::enable_mouse_motion(bool val) { + _mouse_motion_enabled = val; +} + +//////////////////////////////////////////////////////////////////// +// Function: enable_mouse_passive_motion +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +void wdxGraphicsWindow::enable_mouse_passive_motion(bool val) { + _mouse_passive_motion_enabled = val; +} + + +//////////////////////////////////////////////////////////////////// +// Function: wdxGraphicsWindow::get_gsg_type +// Access: Public, Virtual +// Description: Returns the TypeHandle of the kind of GSG preferred +// by this kind of window. +//////////////////////////////////////////////////////////////////// +TypeHandle wdxGraphicsWindow:: +get_gsg_type() const { + return DXGraphicsStateGuardian::get_class_type(); +} + +GraphicsWindow *wdxGraphicsWindow:: +make_wdxGraphicsWindow(const FactoryParams ¶ms) { + GraphicsWindow::WindowPipe *pipe_param; + if(!get_param_into(pipe_param, params)) { + wdxdisplay_cat.error() + << "No pipe specified for window creation!" << endl; + return NULL; + } + + GraphicsPipe *pipe = pipe_param->get_pipe(); + + GraphicsWindow::WindowProps *props_param; + if(!get_param_into(props_param, params)) { + return new wdxGraphicsWindow(pipe); + } else { + return new wdxGraphicsWindow(pipe, props_param->get_properties()); + } +} + +TypeHandle wdxGraphicsWindow::get_class_type(void) { + return _type_handle; +} + +void wdxGraphicsWindow::init_type(void) { + GraphicsWindow::init_type(); + register_type(_type_handle, "wdxGraphicsWindow", + GraphicsWindow::get_class_type()); +} + +TypeHandle wdxGraphicsWindow::get_type(void) const { + return get_class_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: lookup_key +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +ButtonHandle wdxGraphicsWindow:: +lookup_key(WPARAM wparam) const { + switch(wparam) { + case VK_BACK: return KeyboardButton::backspace(); + case VK_TAB: return KeyboardButton::tab(); + case VK_ESCAPE: return KeyboardButton::escape(); + case VK_SPACE: return KeyboardButton::space(); + case VK_UP: return KeyboardButton::up(); + case VK_DOWN: return KeyboardButton::down(); + case VK_LEFT: return KeyboardButton::left(); + case VK_RIGHT: return KeyboardButton::right(); + case VK_PRIOR: return KeyboardButton::page_up(); + case VK_NEXT: return KeyboardButton::page_down(); + case VK_HOME: return KeyboardButton::home(); + case VK_END: return KeyboardButton::end(); + case VK_F1: return KeyboardButton::f1(); + case VK_F2: return KeyboardButton::f2(); + case VK_F3: return KeyboardButton::f3(); + case VK_F4: return KeyboardButton::f4(); + case VK_F5: return KeyboardButton::f5(); + case VK_F6: return KeyboardButton::f6(); + case VK_F7: return KeyboardButton::f7(); + case VK_F8: return KeyboardButton::f8(); + case VK_F9: return KeyboardButton::f9(); + case VK_F10: return KeyboardButton::f10(); + case VK_F11: return KeyboardButton::f11(); + case VK_F12: return KeyboardButton::f12(); + case VK_INSERT: return KeyboardButton::insert(); + case VK_DELETE: return KeyboardButton::del(); + case VK_CAPITAL: return KeyboardButton::caps_lock(); + case VK_NUMLOCK: return KeyboardButton::num_lock(); + case VK_SCROLL: return KeyboardButton::scroll_lock(); + case VK_SNAPSHOT: return KeyboardButton::print_screen(); + + case VK_SHIFT: + case VK_LSHIFT: + case VK_RSHIFT: + return KeyboardButton::shift(); + + case VK_CONTROL: + case VK_LCONTROL: + case VK_RCONTROL: + return KeyboardButton::control(); + + case VK_MENU: + case VK_LMENU: + case VK_RMENU: + return KeyboardButton::alt(); + + default: + int key = MapVirtualKey(wparam, 2); + if(isascii(key) && key != 0) { + bool bCapsLockDown=((GetKeyState(VK_CAPITAL) & 0x1)!=0); + bool bShiftUp = (GetKeyState(VK_SHIFT) >= 0); + if(bShiftUp) { + if(bCapsLockDown) + key = toupper(key); + else key = tolower(key); + } else { + switch(key) { + // these keys are unaffected by capslock + case '1': key = '!'; break; + case '2': key = '@'; break; + case '3': key = '#'; break; + case '4': key = '$'; break; + case '5': key = '%'; break; + case '6': key = '^'; break; + case '7': key = '&'; break; + case '8': key = '*'; break; + case '9': key = '('; break; + case '0': key = ')'; break; + case '-': key = '_'; break; + case '=': key = '+'; break; + case ',': key = '<'; break; + case '.': key = '>'; break; + case '/': key = '?'; break; + case ';': key = ':'; break; + case '\'': key = '"'; break; + case '[': key = '{'; break; + case ']': key = '}'; break; + case '\\': key = '|'; break; + case '`': key = '~'; break; + default: + if(bCapsLockDown) + key = tolower(key); + else key = toupper(key); + } + } + return KeyboardButton::ascii_key((uchar)key); + } + break; + } + return ButtonHandle::none(); +} + +int wdxGraphicsWindow:: +get_depth_bitwidth(void) { + if((_dxgsg==NULL) || (_dxgsg->_zbuf==NULL)) + return -1; + + return _depth_buffer_bpp; + +// this is not reliable, on GF2, GetSurfDesc returns 32bpp when you created a 24bpp zbuf +// DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); +// _dxgsg->_zbuf->GetSurfaceDesc(&ddsd); +// return ddsd.ddpfPixelFormat.dwRGBBitCount; +} + +// Global system parameters we want to modify during our run +static int iMouseTrails; +static bool bCursorShadowOn,bMouseVanish; + +#ifndef SPI_GETMOUSEVANISH +// get of this when we upgrade to winxp winuser.h +#define SPI_GETMOUSEVANISH 0x1020 +#define SPI_SETMOUSEVANISH 0x1021 +#endif + +void set_global_parameters(void) { + // turn off mousetrails and cursor shadow and mouse cursor vanish + // cursor shadow causes cursor blink and reduced frame rate due to lack of driver support for + // cursor alpha blending + + // this is a win2k/xp only param, could use GetVersionEx to do it just for win2k, + // but since it is just a param it will just cause a silent error on other OS's + // that should be ok + SystemParametersInfo(SPI_GETCURSORSHADOW,NULL,&bCursorShadowOn,NULL); + SystemParametersInfo(SPI_SETCURSORSHADOW,NULL,(PVOID)false,NULL); + + SystemParametersInfo(SPI_GETMOUSETRAILS,NULL,&iMouseTrails,NULL); + SystemParametersInfo(SPI_SETMOUSETRAILS,NULL,(PVOID)0,NULL); + + // this is ME/XP only feature + SystemParametersInfo(SPI_GETMOUSEVANISH,NULL,&bMouseVanish,NULL); + SystemParametersInfo(SPI_SETMOUSEVANISH,NULL,(PVOID)false,NULL); +} + +void restore_global_parameters(void) { + SystemParametersInfo(SPI_SETCURSORSHADOW,NULL,(PVOID)bCursorShadowOn,NULL); + SystemParametersInfo(SPI_SETMOUSETRAILS,NULL,(PVOID)iMouseTrails,NULL); + SystemParametersInfo(SPI_SETMOUSEVANISH,NULL,(PVOID)bMouseVanish,NULL); +} + diff --git a/panda/src/wdxdisplay8/wdxGraphicsWindow8.h b/panda/src/wdxdisplay8/wdxGraphicsWindow8.h new file mode 100644 index 0000000000..05c4e0680a --- /dev/null +++ b/panda/src/wdxdisplay8/wdxGraphicsWindow8.h @@ -0,0 +1,144 @@ +// Filename: wdxGraphicsWindow.h +// Created by: mike (09Jan97) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// +#ifndef WDXGRAPHICSWINDOW8_H +#define WDXGRAPHICSWINDOW8_H +//#define WBD_GL_MODE 1 // if setting this, do it in dxGraphicsStateGuardian.h too +// +//////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////// +#include + +#include +#define WINDOWS_LEAN_AND_MEAN +#include +#undef WINDOWS_LEAN_AND_MEAN +#include + +//////////////////////////////////////////////////////////////////// +// Defines +//////////////////////////////////////////////////////////////////// +class wdxGraphicsPipe; + +const int WDXWIN_CONFIGURE = 4; +const int WDXWIN_EVENT = 8; + +//////////////////////////////////////////////////////////////////// +// Class : wdxGraphicsWindow +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDADX wdxGraphicsWindow : public GraphicsWindow { + friend class DXGraphicsStateGuardian; + friend class DXTextureContext; + +public: + wdxGraphicsWindow(GraphicsPipe* pipe); + wdxGraphicsWindow(GraphicsPipe* pipe, + const GraphicsWindow::Properties& props); + virtual ~wdxGraphicsWindow(void); + + virtual bool supports_update() const; + virtual void update(void); + virtual void end_frame( void ); + + virtual TypeHandle get_gsg_type() const; + static GraphicsWindow* make_wdxGraphicsWindow(const FactoryParams ¶ms); + void CreateScreenBuffersAndDevice(DWORD dwRenderWidth, DWORD dwRenderHeight, + LPDIRECTDRAW7 pDD,LPDIRECT3D7 pD3DI, + D3DDEVICEDESC7 *pD3DDevDesc); + + LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + void process_events(void); + + INLINE bool mouse_entry_enabled(void) { return _mouse_entry_enabled; } + INLINE bool mouse_motion_enabled(void) { return _mouse_motion_enabled; } + INLINE bool mouse_passive_motion_enabled(void) { + return _mouse_passive_motion_enabled; + } + void handle_window_move( int x, int y ); + void handle_mouse_motion( int x, int y ); + void handle_mouse_entry( int state, HCURSOR hMouseCursor ); + void handle_keypress( ButtonHandle key, int x, int y ); + void handle_keyrelease( ButtonHandle key); + void dx_setup(); + virtual void begin_frame( void ); + void show_frame(); + DXGraphicsStateGuardian *_dxgsg; + + virtual void resize(unsigned int xsize,unsigned int ysize); + virtual unsigned int verify_window_sizes(unsigned int numsizes,unsigned int *dimen); + virtual int get_depth_bitwidth(void); + +protected: + void CreateScreenBuffersAndDevice(LPDIRECTDRAW7 pDD,LPDIRECT3D7 pD3DI); + ButtonHandle lookup_key(WPARAM wparam) const; + virtual void config( void ); + void setup_colormap(void); + + void enable_mouse_input(bool val); + void enable_mouse_motion(bool val); + void enable_mouse_passive_motion(bool val); + void enable_mouse_entry(bool val); + void check_for_color_cursor_support(void); + DDDEVICEIDENTIFIER2 _DXDeviceID; + +public: + HWND _mwindow; + HWND _hOldForegroundWindow; + UINT_PTR _PandaPausedTimer; + +private: + HDC _hdc; + HPALETTE _colormap; + typedef enum { NotAdjusting,MovingOrResizing,Resizing } WindowAdjustType; + WindowAdjustType _WindowAdjustingType; + bool _bIsLowVidMemCard; + bool _bLoadedCustomCursor; + HCURSOR _hMouseCursor; + bool _bSizeIsMaximized; + bool _mouse_input_enabled; + bool _mouse_motion_enabled; + bool _mouse_passive_motion_enabled; + bool _mouse_entry_enabled; + bool _exiting_window; + bool _window_inactive; + bool _active_minimized_fullscreen; + bool _return_control_to_app; + int _depth_buffer_bpp; + +public: + static TypeHandle get_class_type(void); + static void init_type(void); + virtual TypeHandle get_type(void) const; + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + + void DestroyMe(bool bAtExitFnCalled); + virtual void do_close_window(); + void deactivate_window(void); + void reactivate_window(void); + void handle_reshape(bool bDoDXReset); + +private: + static TypeHandle _type_handle; +}; + +extern void set_global_parameters(void); +extern void restore_global_parameters(void); + + +#endif diff --git a/panda/src/wdxdisplay8/wdxdisplay8_composite1.cxx b/panda/src/wdxdisplay8/wdxdisplay8_composite1.cxx new file mode 100644 index 0000000000..9e0485351a --- /dev/null +++ b/panda/src/wdxdisplay8/wdxdisplay8_composite1.cxx @@ -0,0 +1,4 @@ + +#include "config_wdxdisplay8.cxx" +#include "wdxGraphicsPipe8.cxx" +