Browse Source

integrate changes from Schell Games (plus some tab character fixes)

David Rose 16 years ago
parent
commit
58c13de4ca
100 changed files with 4121 additions and 1062 deletions
  1. 1 1
      dtool/Config.Win32.pp
  2. 7 0
      dtool/Config.pp
  3. 11 0
      dtool/LocalSetup.pp
  4. 8 0
      dtool/Package.pp
  5. 6 0
      dtool/pptempl/Global.pp
  6. 749 0
      dtool/pptempl/Template.models.nmake.pp
  7. 22 5
      dtool/pptempl/Template.nmake.pp
  8. 12 4
      dtool/pptempl/compilerSettings.pp
  9. 6 6
      dtool/src/dtoolbase/dtoolbase.h
  10. 1 1
      dtool/src/interrogatedb/py_panda.h
  11. 2 0
      dtool/src/parser-inc/NxCloth.h
  12. 2 0
      dtool/src/parser-inc/NxFluid.h
  13. 174 0
      dtool/src/parser-inc/NxPhysics.h
  14. 4 0
      dtool/src/parser-inc/Sources.pp
  15. 8 8
      dtool/src/parser-inc/ode.h
  16. 5 0
      panda/metalibs/panda/Sources.pp
  17. 28 0
      panda/metalibs/pandaphysx/Sources.pp
  18. 31 0
      panda/metalibs/pandaphysx/pandaphysx.cxx
  19. 13 0
      panda/metalibs/pandaphysx/pandaphysx.h
  20. 1 1
      panda/src/audio/Sources.pp
  21. 10 0
      panda/src/audio/audioManager.cxx
  22. 4 0
      panda/src/audio/audioManager.h
  23. 32 12
      panda/src/audio/audioSound.cxx
  24. 9 0
      panda/src/audio/audioSound.h
  25. 12 12
      panda/src/audio/config_audio.cxx
  26. 3 3
      panda/src/audio/config_audio.h
  27. 3 3
      panda/src/audiotraits/Sources.pp
  28. 1 1
      panda/src/audiotraits/config_fmodAudio.cxx
  29. 29 29
      panda/src/audiotraits/fmodAudioManager.cxx
  30. 19 19
      panda/src/audiotraits/fmodAudioManager.h
  31. 62 60
      panda/src/audiotraits/fmodAudioSound.cxx
  32. 12 13
      panda/src/audiotraits/fmodAudioSound.h
  33. 1 1
      panda/src/audiotraits/fmod_audio_composite1.cxx
  34. 6 0
      panda/src/audiotraits/globalMilesManager.cxx
  35. 198 1
      panda/src/audiotraits/milesAudioManager.cxx
  36. 14 0
      panda/src/audiotraits/milesAudioManager.h
  37. 247 0
      panda/src/audiotraits/milesAudioSample.cxx
  38. 14 0
      panda/src/audiotraits/milesAudioSample.h
  39. 6 6
      panda/src/chan/auto_bind.cxx
  40. 2 0
      panda/src/configfiles/panda.prc.pp
  41. 2 2
      panda/src/display/config_display.cxx
  42. 22 0
      panda/src/display/displayRegion.I
  43. 17 1
      panda/src/display/displayRegion.cxx
  44. 6 0
      panda/src/display/displayRegion.h
  45. 23 0
      panda/src/display/frameBufferProperties.I
  46. 3 0
      panda/src/display/frameBufferProperties.h
  47. 1 1
      panda/src/display/graphicsEngine.cxx
  48. 9 1
      panda/src/display/graphicsOutput.cxx
  49. 2 0
      panda/src/display/graphicsStateGuardian.h
  50. 1 0
      panda/src/display/graphicsWindow.h
  51. 37 0
      panda/src/dxgsg9/dxShaderContext9.cxx
  52. 5 0
      panda/src/dxgsg9/dxShaderContext9.h
  53. 1 1
      panda/src/egg/eggGroupNode.h
  54. 10 10
      panda/src/egg2pg/config_egg2pg.cxx
  55. 4 4
      panda/src/egg2pg/eggLoader.cxx
  56. 1 1
      panda/src/express/patchfile.cxx
  57. 12 0
      panda/src/glstuff/glGraphicsBuffer_src.I
  58. 298 15
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  59. 20 1
      panda/src/glstuff/glGraphicsBuffer_src.h
  60. 34 0
      panda/src/glstuff/glGraphicsStateGuardian_src.I
  61. 76 17
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  62. 10 1
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  63. 41 1
      panda/src/glstuff/glShaderContext_src.cxx
  64. 5 0
      panda/src/glstuff/glShaderContext_src.h
  65. 8 0
      panda/src/glstuff/glmisc_src.cxx
  66. 2 0
      panda/src/glstuff/glmisc_src.h
  67. 12 3
      panda/src/glstuff/panda_glext.h
  68. 5 5
      panda/src/glxdisplay/config_glxdisplay.cxx
  69. 18 18
      panda/src/glxdisplay/glxGraphicsStateGuardian.cxx
  70. 5 5
      panda/src/glxdisplay/glxGraphicsStateGuardian.h
  71. 51 51
      panda/src/glxdisplay/glxGraphicsWindow.cxx
  72. 3 0
      panda/src/gobj/Sources.pp
  73. 41 0
      panda/src/gobj/animateVerticesRequest.I
  74. 41 0
      panda/src/gobj/animateVerticesRequest.cxx
  75. 79 0
      panda/src/gobj/animateVerticesRequest.h
  76. 5 3
      panda/src/gobj/config_gobj.cxx
  77. 4 4
      panda/src/gobj/geom.cxx
  78. 10 10
      panda/src/gobj/geom.h
  79. 1 0
      panda/src/gobj/gobj_composite1.cxx
  80. 237 58
      panda/src/gobj/shader.cxx
  81. 33 6
      panda/src/gobj/shader.h
  82. 2 2
      panda/src/gobj/texture.cxx
  83. 4 0
      panda/src/gobj/texture.h
  84. 4 1
      panda/src/grutil/Sources.pp
  85. 16 14
      panda/src/grutil/cardMaker.cxx
  86. 14 0
      panda/src/grutil/config_grutil.cxx
  87. 5 0
      panda/src/grutil/config_grutil.h
  88. 25 8
      panda/src/grutil/ffmpegTexture.cxx
  89. 2 0
      panda/src/grutil/grutil_composite1.cxx
  90. 1 1
      panda/src/grutil/meshDrawer.I
  91. 68 71
      panda/src/grutil/meshDrawer.cxx
  92. 3 3
      panda/src/grutil/meshDrawer.h
  93. 40 40
      panda/src/grutil/multitexReducer.cxx
  94. 1 1
      panda/src/grutil/multitexReducer.h
  95. 1 1
      panda/src/grutil/openCVTexture.cxx
  96. 101 0
      panda/src/grutil/sceneGraphAnalyzerMeter.I
  97. 244 0
      panda/src/grutil/sceneGraphAnalyzerMeter.cxx
  98. 105 0
      panda/src/grutil/sceneGraphAnalyzerMeter.h
  99. 496 496
      panda/src/mathutil/triangulator.cxx
  100. 19 19
      panda/src/mathutil/triangulator.h

+ 1 - 1
dtool/Config.Win32.pp

@@ -20,7 +20,7 @@
 // *******************************************************************
 
 // What additional flags should we pass to interrogate?
-#define SYSTEM_IGATE_FLAGS -longlong __int64 -D_X86_ -DWIN32_VC -D"_declspec(param)=" -D"__declspec(param)=" -D_near  -D_far -D__near  -D__far -D_WIN32 -D__stdcall -Dvolatile -Dmutable
+#define SYSTEM_IGATE_FLAGS -longlong __int64 -D_X86_ -DWIN32_VC -D"_declspec(param)=" -D"__declspec(param)=" -D_near  -D_far -D__near  -D__far -D_WIN32 -D__stdcall -Dvolatile -Dmutable -DWIN32
 
 // Additional flags to pass to the Tau instrumentor.
 #define TAU_INSTRUMENTOR_FLAGS -DTAU_USE_C_API -DPROFILING_ON -DWIN32_VC -D_WIN32 -D__cdecl= -D__stdcall= -D__fastcall= -D__i386 -D_MSC_VER=1310 -D_W64=  -D_INTEGRAL_MAX_BITS=64 --exceptions --late_tiebreaker --no_class_name_injection --no_warnings --restrict --microsoft --new_for_init

+ 7 - 0
dtool/Config.pp

@@ -830,6 +830,13 @@
 #define FMODEX_LIBS $[if $[libtest $[FMODEX_LPATH],fmodex64],fmodex64,fmodex]
 #defer HAVE_FMODEX $[libtest $[FMODEX_LPATH],$[FMODEX_LIBS]]
 
+// Info for the Ageia PhysX SDK
+// note this may be overwritten in wintools Config.pp
+#define PHYSX_IPATH
+#define PHYSX_LPATH
+#define PHYSX_LIBS PhysXLoader.lib NxCharacter.lib NxCooking.lib NxExtensions.lib
+#defer HAVE_PHYSX $[libtest $[PHYSX_LPATH],$[PHYSX_LIBS]]
+
 // Info for http://www.sourceforge.net/projects/chromium
 // note this may be overwritten in wintools Config.pp
 #define CHROMIUM_IPATH /usr/include/chromium/include

+ 11 - 0
dtool/LocalSetup.pp

@@ -91,6 +91,11 @@
 #else
 #print - Did not find FMOD Ex sound library
 #endif
+#if $[HAVE_PHYSX]
+#print + Ageia PhysX
+#else
+#print - Did not find Ageia PhysX
+#endif
 #if $[HAVE_GTK]
 #print + gtk+-2
 #else
@@ -220,6 +225,9 @@ $[cdefine HAVE_RAD_MSS]
 /* Define if we have FMODex installed. */
 $[cdefine HAVE_FMODEX]
 
+/* Define if we have Ageia PhysX SDK installed. */
+$[cdefine HAVE_PHYSX]
+
 /* Define if we have Freetype 2.0 or better available. */
 $[cdefine HAVE_FREETYPE]
 
@@ -400,6 +408,9 @@ $[cdefine NOTIFY_DEBUG]
    makes sense to MSVC++. */
 $[cdefine EXPORT_TEMPLATES]
 
+/* Define if we are linking PANDAPHYSX in with PANDA. */
+$[cdefine LINK_IN_PHYSX]
+
 /* The compiled-in character(s) to expect to separate different
    components of a path list (e.g. $PRC_PATH). */
 # define DEFAULT_PATHSEP "$[DEFAULT_PATHSEP]"

+ 8 - 0
dtool/Package.pp

@@ -257,6 +257,11 @@
 #set FMODEX_LIBS $[FMODEX_LIBS]
 #set HAVE_FMODEX $[HAVE_FMODEX]
 
+#set PHYSX_IPATH $[unixfilename $[PHYSX_IPATH]]
+#set PHYSX_LPATH $[unixfilename $[PHYSX_LPATH]]
+#set PHYSX_LIBS $[PHYSX_LIBS]
+#set HAVE_PHYSX $[HAVE_PHYSX]
+
 #set CHROMIUM_IPATH $[unixfilename $[CHROMIUM_IPATH]]
 #set CHROMIUM_LPATH $[unixfilename $[CHROMIUM_LPATH]]
 #set CHROMIUM_LIBS $[CHROMIUM_LIBS]
@@ -310,6 +315,9 @@
   #define FREETYPE_LIBS $[patsubst -l%,%,$[filter -l%,$[libs]]]
 #endif
 
+#if $[HAVE_PHYSX]
+  #define GENPYCODE_LIBS $[GENPYCODE_LIBS] libpandaphysx
+#endif
 
 // Finally, include the system configure file.
 #include $[THISDIRPREFIX]pptempl/System.pp

+ 6 - 0
dtool/pptempl/Global.pp

@@ -366,6 +366,12 @@
   #define fmodex_libs $[FMODEX_LIBS]
 #endif
 
+#if $[HAVE_PHYSX]
+  #define physx_ipath $[wildcard $[PHYSX_IPATH]]
+  #define physx_lpath $[wildcard $[PHYSX_LPATH]]
+  #define physx_libs $[PHYSX_LIBS]
+#endif
+
 #if $[HAVE_CHROMIUM]
   #define chromium_ipath $[wildcard $[CHROMIUM_IPATH]]
   #define chromium_lpath $[wildcard $[CHROMIUM_LPATH]]

+ 749 - 0
dtool/pptempl/Template.models.nmake.pp

@@ -0,0 +1,749 @@
+//
+// Template.models.nmake.pp
+//
+// This file defines the Makefiles that will be built to generate
+// models (egg, bam models computed from flt, soft, alias,
+// etc. sources).  This Template file is derived from
+// Template.models.pp, but uses windows specific conventions,
+// rather than unix specific conventions.
+//
+
+#if $[< $[PPREMAKE_VERSION],0.57]
+  #error You need at least ppremake version 0.58 to build models.
+#endif
+
+// Search for the texattrib dir definition.  This will be in the
+// models_topdir directory.
+#define texattrib_dir $[dir_type $[TEXATTRIB_DIR],models_toplevel]
+
+// Prefix $[TOPDIR].  If it wasn't defined, make a default.
+#if $[texattrib_dir]
+  #define texattrib_dir $[TOPDIR]/$[texattrib_dir]
+#else
+  #define texattrib_dir $[TOPDIR]/src/maps
+#endif
+
+#define texattrib_file $[texattrib_dir]/textures.txa
+
+//////////////////////////////////////////////////////////////////////
+#if $[eq $[DIR_TYPE], models]
+//////////////////////////////////////////////////////////////////////
+
+#define pal_egg_dir pal_egg
+#define bam_dir bams
+#defer phase_prefix $[if $[PHASE],phase_$[PHASE]/]
+
+#defer install_model_dir $[install_dir]/$[phase_prefix]$[INSTALL_TO]
+#define filter_dirs $[sort $[TARGET_DIR(filter_egg filter_char_egg optchar_egg)]]
+
+#defer source_prefix $[SOURCE_DIR:%=%/]
+
+#if $[LANGUAGES]
+  #define exlanguage_sources $[notdir $[filter %.flt %.mb %.ma %.lwo %.LWO %.egg,$[wildcard $[TOPDIR]/$[DIRPREFIX]*_$[LANGUAGE].*]]]
+
+  #defun lang_add_files sources, src_ext, local_extra
+    #define default_filter
+    #define local_filter
+    #foreach ext $[src_ext]
+      #set default_filter $[default_filter] %_$[DEFAULT_LANGUAGE].$[ext]
+      #set local_filter $[local_filter] %_$[LANGUAGE].$[ext]
+    #end ext
+    #define default_langlist $[filter $[default_filter],$[sources]]
+    #define locallist $[filter $[local_filter],$[local_extra] $[exlanguage_sources]]
+    #define havelist
+    #foreach file $[default_langlist]
+      #foreach ext $[src_ext]
+        #define wantfile $[file:%_$[DEFAULT_LANGUAGE].$[ext]=%_$[LANGUAGE].$[ext]]
+        #set havelist $[havelist] $[filter $[wantfile],$[locallist]]
+      #end ext
+    #end file
+    $[havelist]
+  #end lang_add_files
+
+  #forscopes flt_egg
+    #if $[SOURCES]
+      #set SOURCES $[sort $[SOURCES] $[lang_add_files $[SOURCES], flt, ]]
+    #endif
+  #end flt_egg
+
+  #forscopes lwo_egg
+    #if $[SOURCES]
+      #set SOURCES $[sort $[SOURCES] $[lang_add_files $[SOURCES], lwo LWO, ]]
+    #endif
+  #end lwo_egg
+
+  #forscopes maya_egg
+    #if $[SOURCES]
+      #set SOURCES $[sort $[SOURCES] $[lang_add_files $[SOURCES], lwo LWO, ]]
+    #endif
+  #end maya_egg
+#endif
+
+#define build_flt_eggs \
+   $[forscopes flt_egg,$[patsubst %.flt,%$[EGG_SUFFIX].egg,$[SOURCES]]]
+
+#define build_lwo_eggs \
+   $[forscopes lwo_egg,$[patsubst %.lwo %.LWO,%$[EGG_SUFFIX].egg,$[SOURCES]]]
+
+#define build_maya_eggs \
+   $[forscopes maya_egg,$[patsubst %$[MODEL].ma %$[MODEL].mb ,$[EGG_PREFIX]%$[EGG_SUFFIX].egg,$[SOURCES]]] \
+   $[forscopes maya_char_egg,$[POLY_MODEL:%=$[EGG_PREFIX]%$[EGG_SUFFIX].egg] $[NURBS_MODEL:%=$[EGG_PREFIX]%$[EGG_SUFFIX].egg]] \
+   $[forscopes maya_char_egg,$[ANIMS:%=$[EGG_PREFIX]%$[CHAN_SUFFIX].egg]]
+
+#define build_soft_eggs \
+   $[forscopes soft_char_egg,$[POLY_MODEL:%=$[EGG_PREFIX]%$[EGG_SUFFIX].egg] $[NURBS_MODEL:%=$[EGG_PREFIX]%$[EGG_SUFFIX].egg]] \
+   $[forscopes soft_char_egg,$[ANIMS:%=$[EGG_PREFIX]%$[CHAN_SUFFIX].egg]]
+
+#define build_eggs \
+   $[sort \
+     $[build_flt_eggs] \
+     $[build_lwo_eggs] \
+     $[build_maya_eggs] \
+     $[build_soft_eggs]]
+
+#if $[LANGUAGES]
+  #forscopes install_egg filter_egg
+    #if $[SOURCES]
+      #set SOURCES $[sort $[SOURCES] $[lang_add_files $[SOURCES], egg, $[build_eggs]]]
+    #endif
+  #end install_egg filter_egg
+#endif
+
+// Get the list of egg files that are to be installed
+#define install_pal_eggs
+#define install_unpal_eggs
+#forscopes install_egg
+  #define egglist $[notdir $[SOURCES]]
+  #set install_pal_eggs $[install_pal_eggs] $[filter-out $[language_egg_filters],$[egglist]]
+  #if $[LANGUAGES]
+    // Now look for the eggs of the current language.
+    #foreach egg $[filter %_$[DEFAULT_LANGUAGE].egg,$[egglist]]
+      #define wantegg $[egg:%_$[DEFAULT_LANGUAGE].egg=%_$[LANGUAGE].egg]
+      #if $[filter $[wantegg],$[egglist]]
+          // The current language file exists.
+        #set install_pal_eggs $[install_pal_eggs] $[wantegg]
+      #else
+        #set install_pal_eggs $[install_pal_eggs] $[egg]
+      #endif
+    #end egg
+  #endif
+  #define egglist $[notdir $[UNPAL_SOURCES] $[UNPAL_SOURCES_NC]]
+  #set install_unpal_eggs $[install_unpal_eggs] $[filter-out $[language_egg_filters],$[egglist]]
+  #if $[LANGUAGES]
+    // Now look for the eggs of the current language.
+    #foreach egg $[filter %_$[DEFAULT_LANGUAGE].egg,$[egglist]]
+      #define wantegg $[egg:%_$[DEFAULT_LANGUAGE].egg=%_$[LANGUAGE].egg]
+      #if $[filter $[wantegg],$[egglist]]
+          // The current language file exists.
+        #set install_unpal_eggs $[install_unpal_eggs] $[wantegg]
+      #else
+        #set install_unpal_eggs $[install_unpal_eggs] $[egg]
+      #endif
+    #end egg
+  #endif
+#end install_egg
+#define install_eggs $[install_pal_eggs] $[install_unpal_eggs]
+
+
+// Get the list of bam files in the install directories
+#define install_egg_dirs $[sort $[forscopes install_egg,$[install_model_dir]]]
+#define installed_generic_bams $[sort $[forscopes install_egg,$[patsubst %.egg,$[install_model_dir]/%.bam,$[filter-out $[language_egg_filters],$[notdir $[SOURCES] $[UNPAL_SOURCES] $[UNPAL_SOURCES_NC]]]]]]
+#if $[LANGUAGES]
+  #define installed_language_bams $[sort $[forscopes install_egg,$[patsubst %.egg,$[install_model_dir]/%.bam,$[patsubst %_$[DEFAULT_LANGUAGE].egg,%.egg,%,,$[notdir $[SOURCES] $[UNPAL_SOURCES] $[UNPAL_SOURCES_NC]]]]]]
+#endif
+
+// And the list of dna files in the install directories.
+#define install_dna_dirs $[sort $[forscopes install_dna,$[install_model_dir]]]
+#define installed_generic_dna $[sort $[forscopes install_dna,$[patsubst %,$[install_model_dir]/%,$[filter-out $[language_dna_filters],$[notdir $[SOURCES]]]]]]
+#if $[LANGUAGES]
+  #define installed_language_dna $[sort $[forscopes install_dna,$[patsubst %,$[install_model_dir]/%,$[patsubst %_$[DEFAULT_LANGUAGE].dna,%.dna,%,,$[notdir $[SOURCES]]]]]]
+#endif
+
+#define install_other_dirs $[sort $[forscopes install_audio install_icons install_shader install_misc,$[install_model_dir]]]
+#define installed_other $[sort $[forscopes install_audio install_icons install_shader install_misc,$[SOURCES:%=$[install_model_dir]/%]]]
+
+
+#define pal_egg_targets $[sort $[patsubst %,$[pal_egg_dir]/%,$[notdir $[install_pal_eggs]]]]
+#define bam_targets $[install_eggs:%.egg=$[bam_dir]/%.bam]
+
+#output Makefile
+#format makefile
+#### Generated automatically by $[PPREMAKE] $[PPREMAKE_VERSION] from $[SOURCEFILE].
+################################# DO NOT EDIT ###########################
+
+#define all_targets \
+    Makefile \
+    $[texattrib_dir] \
+    $[filter_dirs] \
+    $[optchar_dirs] \
+    egg bam
+all : $[all_targets]
+
+egg : $[build_eggs]
+
+flt : $[build_flt_eggs]
+lwo : $[build_lwo_eggs]
+maya : $[build_maya_eggs]
+soft : $[build_soft_eggs]
+
+pal : $[if $[pal_egg_targets],$[pal_egg_dir]] $[pal_egg_targets]
+
+bam : pal $[if $[bam_targets],$[bam_dir]] $[bam_targets]
+
+#map soft_scenes soft_scene_files(soft_char_egg)
+
+unpack-soft : $[soft_scenes]
+
+#define install_bam_targets \
+    $[install_egg_dirs] \
+    $[installed_generic_bams] $[installed_language_bams]
+install-bam : $[install_bam_targets]
+
+#define install_other_targets \
+    $[install_dna_dirs] \
+    $[installed_generic_dna] $[installed_language_dna] \
+    $[install_other_dirs] \
+    $[installed_other]
+install-other : $[install_other_targets]
+
+install : all install-other install-bam
+uninstall : uninstall-other uninstall-bam
+
+clean-bam :
+#if $[bam_targets]
+$[TAB]del /f/q $[osfilename $[bam_dir]]
+#endif
+
+clean-pal : clean-bam
+#if $[pal_egg_targets]
+$[TAB]del /f/q $[osfilename $[pal_egg_dir]]
+#endif
+
+clean-flt :
+#if $[build_flt_eggs]
+$[TAB]del /f/q $[osfilename $[build_flt_eggs]]
+#endif
+
+clean-lwo :
+#if $[build_lwo_eggs]
+$[TAB]del /f/q $[osfilename $[build_lwo_eggs]]
+#endif
+
+clean-maya :
+#if $[build_maya_eggs]
+$[TAB]del /f/q $[osfilename $[build_maya_eggs]]
+#endif
+
+clean-soft :
+#if $[build_soft_eggs]
+$[TAB]del /f/q $[osfilename $[build_soft_eggs]]
+#endif
+
+clean : clean-pal
+#if $[build_eggs]
+$[TAB]del /f/q $[osfilename $[build_eggs]] *.pt
+$[TAB]del /f/q $[osfilename $[build_eggs]] *.pt
+#endif
+#if $[filter_dirs]
+$[TAB]del /f/q $[osfilename $[filter_dirs]]
+#endif
+
+// We need a rule for each directory we might need to make.  This
+// loops through the full set of directories and creates a rule to
+// make each one, as needed.
+#foreach directory $[sort \
+    $[filter_dirs] \
+    $[if $[pal_egg_targets],$[pal_egg_dir]] \
+    $[if $[bam_targets],$[bam_dir]] \
+    $[TARGET_DIR(filter_char_egg)] \
+    $[texattrib_dir] \
+    $[install_egg_dirs] \
+    $[install_dna_dirs] \
+    $[install_other_dirs] \
+    ]
+$[directory] :
+$[TAB]@if not exist $[osfilename $[directory]] mkdir $[osfilename $[directory]]
+
+// Sometimes we need a target to depend on the directory existing, without
+// being fooled by the directory's modification times.  We use this
+// phony timestamp file to achieve that.
+$[directory]/stamp :
+$[TAB]@if not exist $[osfilename $[directory]] mkdir $[osfilename $[directory]]
+$[TAB]@echo. > $[osfilename $[directory]/stamp]
+
+#end directory
+
+// Decompressing compressed files.
+#forscopes gz
+  #foreach gz $[SOURCES]
+    #define target $[gz:%.gz=%]
+    #define source $[gz]
+$[target] : $[source]
+$[TAB]del /f/q $[osfilename $[target]]
+$[TAB]gunzip $[GUNZIP_OPTS] < $[osfilename $[source]] > $[osfilename $[target]]
+
+  #end gz
+#end gz
+
+// Egg file generation from Flt files.
+#forscopes flt_egg
+  #foreach flt $[SOURCES]
+    #define target $[or $[TARGET],$[patsubst %.flt %.FLT,$[EGG_PREFIX]%$[EGG_SUFFIX].egg,$[flt]]]
+    #define source $[flt]
+$[target] : $[source]
+$[TAB]flt2egg $[FLT2EGG_OPTS] -o $[osfilename $[target]] $[osfilename $[source]]
+
+  #end flt
+#end flt_egg
+
+// Egg file generation from Lightwave files.
+#forscopes lwo_egg
+  #foreach lwo $[SOURCES]
+    #define target $[or $[TARGET],$[patsubst %.lwo %.LWO,$[EGG_PREFIX]%$[EGG_SUFFIX].egg,$[lwo]]]
+    #define source $[lwo]
+$[target] : $[source]
+$[TAB]lwo2egg $[LWO2EGG_OPTS] -o $[osfilename $[target]] $[osfilename $[source]]
+
+  #end lwo
+#end lwo_egg
+
+// Egg file generation from Maya files (for unanimated models).
+#forscopes maya_egg
+  #foreach maya $[SOURCES]
+    #define target $[or $[TARGET],$[patsubst %$[MODEL].ma %$[MODEL].mb,$[EGG_PREFIX]%$[EGG_SUFFIX].egg,$[maya]]]
+    #define source $[maya]
+$[target] : $[source]
+$[TAB]maya2egg $[MAYA2EGG_OPTS] -o $[osfilename $[target]] $[osfilename $[source]]
+
+  #end maya
+#end maya_egg
+
+// Egg character model generation from Maya files.
+#forscopes maya_char_egg
+  #if $[POLY_MODEL]
+    #define target $[EGG_PREFIX]$[POLY_MODEL].egg
+    #define source $[MAYA_PREFIX]$[or $[MODEL],$[POLY_MODEL]].mb
+$[target] : $[source]
+$[TAB]maya2egg $[MAYA2EGG_OPTS] -p -a model -cn "$[CHAR_NAME]" -o $[osfilename $[target]] $[osfilename $[source]]
+  #endif
+  #if $[NURBS_MODEL]
+    #define target $[EGG_PREFIX]$[NURBS_MODEL].egg
+    #define source $[MAYA_PREFIX]$[or $[MODEL],$[NURBS_MODEL]].mb
+$[target] : $[source]
+$[TAB]maya2egg $[MAYA2EGG_OPTS] -a model -cn "$[CHAR_NAME]" -o $[osfilename $[target]] $[osfilename $[source]]
+  #endif
+
+#end maya_char_egg
+
+// Egg animation generation from Maya files.
+#forscopes maya_char_egg
+  #foreach anim $[ANIMS]
+    #define target $[EGG_PREFIX]$[anim]$[CHAN_SUFFIX].egg
+    #define source $[MAYA_PREFIX]$[anim].mb
+    #define begin 0
+    #define end
+    #if $[$[anim]_frames]
+      #set begin $[word 1,$[$[anim]_frames]]
+      #set end $[word 2,$[$[anim]_frames]]
+    #endif
+$[target] : $[source]
+$[TAB]maya2egg $[MAYA2EGG_OPTS] -a chan -cn "$[CHAR_NAME]" -o $[osfilename $[target]] -sf $[begin] $[if $[end],-ef $[end]] $[osfilename $[source]]
+  #end anim
+#end maya_char_egg
+
+// Unpack the Soft scene database from its multifile.
+#formap scene_file soft_scenes
+  #define target $[scene_file]
+  #define source $[scene_file:$[DATABASE]/SCENES/%.1-0.dsc=$[DATABASE]/%.mf]
+$[target] : $[source]
+$[TAB]multify xf $[osfilename $[source]] -C $[DATABASE]
+#end scene_file
+
+// Egg character model generation from Soft databases.
+#forscopes soft_char_egg
+  #if $[POLY_MODEL]
+    #define target $[EGG_PREFIX]$[POLY_MODEL].egg
+    #define scene $[SCENE_PREFIX]$[MODEL].1-0.dsc
+    #define source $[DATABASE]/SCENES/$[scene]
+$[target] : $[source]
+$[TAB]$[SOFT2EGG] $[SOFT2EGG_OPTS] $[if $[SOFTIMAGE_RSRC],-r "$[osfilename $[SOFTIMAGE_RSRC]]"] -p -M $[osfilename $[target]] -N $[CHAR_NAME] -d $[DATABASE] -t $[DATABASE]/PICTURES -s $[scene]
+  #endif
+  #if $[NURBS_MODEL]
+    #define target $[EGG_PREFIX]$[NURBS_MODEL].egg
+    #define scene $[SCENE_PREFIX]$[MODEL].1-0.dsc
+    #define source $[DATABASE]/SCENES/$[scene]
+$[target] : $[source]
+$[TAB]$[SOFT2EGG] $[SOFT2EGG_OPTS] $[if $[SOFTIMAGE_RSRC],-r "$[osfilename $[SOFTIMAGE_RSRC]]"] -n -M $[osfilename $[target]] -N $[CHAR_NAME] -d $[DATABASE] -t $[DATABASE]/PICTURES -s $[scene]
+  #endif
+
+#end soft_char_egg
+
+// Egg animation generation from Soft database.
+#forscopes soft_char_egg
+  #foreach anim $[ANIMS]
+    #define target $[EGG_PREFIX]$[anim]$[CHAN_SUFFIX].egg
+    #define scene $[SCENE_PREFIX]$[anim].1-0.dsc
+    #define source $[DATABASE]/SCENES/$[scene]
+    #define begin 1
+    #define end
+    #if $[$[anim]_frames]
+      #set begin $[word 1,$[$[anim]_frames]]
+      #set end $[word 2,$[$[anim]_frames]]
+    #endif
+$[target] : $[source]
+$[TAB]$[SOFT2EGG] $[SOFT2EGG_OPTS] $[if $[SOFTIMAGE_RSRC],-r "$[osfilename $[SOFTIMAGE_RSRC]]"] -a -A $[osfilename $[target]] -N $[CHAR_NAME] -d $[DATABASE] -s $[scene] $[begin:%=-b%] $[end:%=-e%]
+  #end anim
+#end soft_char_egg
+
+// Copying egg files from A to B.
+#forscopes copy_egg
+  #for i 1,$[words $[SOURCES]]
+    #define source $[word $[i],$[SOURCES]]
+    #define target $[word $[i],$[TARGETS]]
+$[target] : $[source]
+$[TAB]copy $[osfilename $[source]] $[osfilename $[target]]
+  #end i
+#end copy_egg
+
+
+// Generic egg filters.
+#forscopes filter_egg
+  #foreach egg $[SOURCES]
+    #define source $[source_prefix]$[egg]
+    #define target $[TARGET_DIR]/$[notdir $[egg]]
+$[target] : $[source] $[pt] $[TARGET_DIR]/stamp
+$[TAB]$[COMMAND]
+  #end egg
+#end filter_egg
+
+// Generic character egg filter; applies an effect to all models and
+// animations of a particular character.
+#forscopes filter_char_egg
+  #define sources $[SOURCES:%=$[source_prefix]%]
+  #define target $[TARGET_DIR]/$[notdir $[firstword $[SOURCES]]]
+
+   // A bunch of rules to make each generated egg file depend on the
+   // first one.
+  #foreach egg $[notdir $[wordlist 2,9999,$[SOURCES]]]
+$[TARGET_DIR]/$[egg] : $[target] $[TARGET_DIR]/stamp
+$[TAB]touch $[osfilename $[TARGET_DIR]/$[egg]]
+  #end egg
+
+   // And this is the actual optchar pass.
+$[target] : $[sources] $[TARGET_DIR]/stamp
+$[TAB]$[COMMAND]
+#end filter_char_egg
+
+
+// Character optimization.
+#forscopes optchar_egg
+  #define sources $[SOURCES:%=$[source_prefix]%]
+  #define target $[TARGET_DIR]/$[notdir $[firstword $[SOURCES]]]
+
+   // A bunch of rules to make each generated egg file depend on the
+   // first one.
+  #foreach egg $[notdir $[wordlist 2,9999,$[SOURCES]]]
+$[TARGET_DIR]/$[egg] : $[target] $[TARGET_DIR]/stamp
+$[TAB]touch $[osfilename $[TARGET_DIR]/$[egg]]
+  #end egg
+
+   // And this is the actual optchar pass.
+$[target] : $[sources] $[TARGET_DIR]/stamp
+$[TAB]egg-optchar $[OPTCHAR_OPTS] -d $[osfilename $[TARGET_DIR]] $[osfilename $[sources]]
+#end optchar_egg
+
+
+// Palettization rules.
+#forscopes install_egg
+  #foreach egg $[SOURCES]
+    #define pt $[egg:%.egg=$[source_prefix]%.pt]
+    #define source $[source_prefix]$[egg]
+    #define target $[pal_egg_dir]/$[notdir $[egg]]
+$[target] : $[source] $[pt] $[pal_egg_dir]/stamp
+    #if $[PHASE]
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dr $[osfilename $[install_dir]] -dm $[osfilename $[install_dir]/%g] -ds $[osfilename $[install_dir]/textures/shadow_pal] -g phase_$[PHASE] -gdir phase_$[PHASE] -o $[osfilename $[target]] $[osfilename $[source]]
+    #else
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dr $[osfilename $[install_dir]] -dm $[osfilename $[install_dir]/%g] -ds $[osfilename $[install_dir]/textures/shadow_pal] -o $[osfilename $[target]] $[osfilename $[source]]
+    #endif
+
+$[pt] :
+$[TAB]@echo. > $[osfilename $[pt]]
+
+  #end egg
+#end install_egg
+
+
+// Bam file creation.
+#forscopes install_egg
+  #foreach egg $[SOURCES]
+    #define source $[pal_egg_dir]/$[notdir $[egg]]
+    #define target $[bam_dir]/$[notdir $[egg:%.egg=%.bam]]
+$[target] : $[source] $[bam_dir]/stamp
+$[TAB]egg2bam -pp $[osfilename $[install_dir]] -ps rel -pd $[osfilename $[install_dir]] $[EGG2BAM_OPTS] -o $[osfilename $[target]] $[osfilename $[source]]
+  #end egg
+
+  #foreach egg $[UNPAL_SOURCES]
+    #define source $[source_prefix]$[egg]
+    #define target $[bam_dir]/$[notdir $[egg:%.egg=%.bam]]
+$[target] : $[source] $[bam_dir]/stamp
+$[TAB]egg2bam $[EGG2BAM_OPTS] -o $[osfilename $[target]] $[osfilename $[source]]
+  #end egg
+
+  #foreach egg $[UNPAL_SOURCES_NC]
+    #define source $[source_prefix]$[egg]
+    #define target $[bam_dir]/$[notdir $[egg:%.egg=%.bam]]
+$[target] : $[source] $[bam_dir]/stamp
+$[TAB]egg2bam $[EGG2BAM_OPTS] -NC -o $[osfilename $[target]] $[osfilename $[source]]
+  #end egg
+#end install_egg
+
+
+// Bam file installation.
+#forscopes install_egg
+  #define egglist $[notdir $[SOURCES] $[UNPAL_SOURCES] $[UNPAL_SOURCES_NC]]
+  #foreach egg $[filter-out $[language_egg_filters],$[egglist]]
+    #define local $[egg:%.egg=%.bam]
+    #define sourcedir $[bam_dir]
+    #define dest $[install_model_dir]
+$[dest]/$[local] : $[sourcedir]/$[local]
+//      cd ./$[sourcedir] && $[INSTALL]
+$[TAB]copy /y $[osfilename $[sourcedir]/$[local]] $[osfilename $[dest]]
+
+  #end egg
+  #if $[LANGUAGES]
+    // Now look for the eggs of the current language.
+    #foreach egg $[filter %_$[DEFAULT_LANGUAGE].egg,$[egglist]]
+      #define wantegg $[egg:%_$[DEFAULT_LANGUAGE].egg=%_$[LANGUAGE].egg]
+      #if $[filter $[wantegg],$[egglist]]
+        // The current language file exists.
+        #define local $[wantegg:%.egg=%.bam]
+      #else
+        //#print Warning: $[wantegg] not listed, using $[egg]
+        #define local $[egg:%.egg=%.bam]
+      #endif
+      #define remote $[egg:%_$[DEFAULT_LANGUAGE].egg=%.bam]
+      #define sourcedir $[bam_dir]
+      #define dest $[install_model_dir]
+$[dest]/$[remote] : $[sourcedir]/$[local]
+//      cd ./$[sourcedir] && $[INSTALL]
+$[TAB]copy /y $[osfilename $[sourcedir]/$[local]] $[osfilename $[dest]/$[remote]]
+
+    #end egg
+  #endif
+#end install_egg
+
+// Bam file uninstallation.
+uninstall-bam :
+#forscopes install_egg
+  #define egglist $[notdir $[SOURCES] $[UNPAL_SOURCES] $[UNPAL_SOURCES_NC]]
+  #define generic_egglist $[filter-out $[language_egg_filters],$[egglist]]
+  #if $[LANGUAGES]
+    #define language_egglist $[patsubst %_$[DEFAULT_LANGUAGE].egg,%.egg,%,,$[egglist]]
+  #endif
+  #define files $[patsubst %.egg,$[install_model_dir]/%.bam,$[generic_egglist] $[language_egglist]]
+  #if $[files]
+$[TAB]del /f/q $[osfilename $[files]]
+  #endif
+#end install_egg
+
+
+// DNA file installation.
+#forscopes install_dna
+  #foreach file $[filter-out $[language_dna_filters],$[SOURCES]]
+    #define local $[file]
+    #define remote $[notdir $[file]]
+    #define dest $[install_model_dir]
+$[dest]/$[remote] : $[local]
+//      $[INSTALL]
+$[TAB]copy /y $[osfilename $[local]] $[osfilename $[dest]]
+
+  #end file
+  #if $[LANGUAGES]
+    // Now files of the current langauge.
+    #foreach file $[filter %_$[DEFAULT_LANGUAGE].dna,$[SOURCES]]
+      #define wantfile $[file:%_$[DEFAULT_LANGUAGE].dna=%_$[LANGUAGE].dna]
+      #if $[filter $[wantfile],$[SOURCES]]
+        // The current language file exists.
+        #define local $[wantfile]
+      #else
+        //#print Warning: $[wantfile] not listed, using $[file]
+        #define local $[file]
+      #endif
+      #define remote $[notdir $[file:%_$[DEFAULT_LANGUAGE].dna=%.dna]]
+      #define dest $[install_model_dir]
+$[dest]/$[remote] : $[local]
+//      cd ./$[sourcedir] && $[INSTALL]
+$[TAB]copy /y $[osfilename $[local]] $[osfilename $[dest]/$[remote]]
+
+    #end file
+  #endif
+#end install_dna
+
+// DNA file uninstallation.
+uninstall-other:
+#forscopes install_dna
+  #define sources $[notdir $[SOURCES]]
+  #define generic_sources $[filter-out $[language_dna_filters],$[sources]]
+  #if $[LANGUAGES]
+    #define language_sources $[patsubst %_$[DEFAULT_LANGUAGE].dna,%.dna,%,,$[sources]]
+  #endif
+  #define files $[patsubst %,$[install_model_dir]/%,$[generic_sources] $[language_sources]]
+  #if $[files]
+$[TAB]del /f/q $[osfilename $[files]]
+  #endif
+#end install_dna
+
+
+
+// Miscellaneous file installation.
+#forscopes install_audio install_icons install_shader install_misc
+  #foreach file $[SOURCES]
+    #define local $[file]
+    #define remote $[notdir $[file]]
+    #define dest $[install_model_dir]
+$[dest]/$[remote] : $[local]
+//      $[INSTALL]
+$[TAB]copy /y $[osfilename $[local]] $[osfilename $[dest]]
+
+  #end file
+#end install_audio install_icons install_shader install_misc
+
+// Miscellaneous file uninstallation.
+uninstall-other:
+#forscopes install_audio install_icons install_shader install_misc
+  #define files $[patsubst %,$[install_model_dir]/%,$[SOURCES]]
+  #if $[files]
+$[TAB]del /f/q $[osfilename $[files]]
+  #endif
+#end install_audio install_icons install_shader install_misc
+
+
+#end Makefile
+
+
+
+
+//////////////////////////////////////////////////////////////////////
+#elif $[eq $[DIR_TYPE], models_group]
+//////////////////////////////////////////////////////////////////////
+
+// This is a group directory: a directory above a collection of source
+// directories, e.g. $DTOOL/src.  We don't need to output anything in
+// this directory.
+
+
+
+//////////////////////////////////////////////////////////////////////
+#elif $[eq $[DIR_TYPE], models_toplevel]
+//////////////////////////////////////////////////////////////////////
+
+// This is the toplevel directory for a models tree, e.g. $TTMODELS.
+// Here we build the root makefile.
+
+#map subdirs
+// Iterate through all of our known source files.  Each models type
+// file gets its corresponding Makefile listed here.
+#forscopes */
+#if $[eq $[DIR_TYPE], models]
+#if $[build_directory]
+  #addmap subdirs $[DIRNAME]
+#endif
+#endif
+#end */
+
+#output Makefile
+#format makefile
+#### Generated automatically by $[PPREMAKE] $[PPREMAKE_VERSION] from $[SOURCEFILE].
+################################# DO NOT EDIT ###########################
+
+all : egg pal repal $[subdirs]
+
+install : all $[subdirs:%=install-%]
+
+#define sub_targets egg flt lwo maya soft bam pal clean-bam clean-pal clean-flt clean-lwo clean-maya clean-soft clean cleanall unpack-soft install-bam install-other uninstall-bam uninstall-other uninstall
+
+// Define the rules to propogate these targets to the Makefile within
+// each directory.
+#foreach target $[sub_targets]
+$[target] : $[subdirs:%=$[target]-%]
+#end target
+
+
+#
+# opt-pal : reorder and resize the palettes to be as optimal as
+# possible.  This forces a rebuild of all the egg files.
+#
+opt-pal : pal do-opt-pal install
+optimize-palettes : opt-pal
+
+do-opt-pal :
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dm $[osfilename $[install_dir]/%g] -opt -egg
+
+#
+# repal : reexamine the textures.txa file and do whatever needs to be
+# done to bring everything up to sync with it.  Also make sure all egg
+# files are up-to-date.
+#
+repal :
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dm $[osfilename $[install_dir]/%g] -all -egg
+
+re-pal : repal
+
+#
+# fix-pal : something has gone wrong with the palettes; rebuild all
+# palette images to fix it.
+#
+fix-pal :
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dm $[osfilename $[install_dir]/%g] -redo -all -egg
+
+#
+# undo-pal : blow away all the palettization information and start fresh.
+#
+undo-pal : clean-pal
+$[TAB]del /f/q $[osfilename $[texattrib_file:%.txa=%.boo]]
+
+#
+# pi : report the palettization information to standard output for the
+# user's perusal.
+#
+pi :
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dm $[osfilename $[install_dir]/%g] -pi
+
+.PHONY: pi.txt
+pi.txt : 
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dm $[osfilename $[install_dir]/%g] -pi >pi.txt
+
+#
+# pal-stats : report palettization statistics to standard output for the
+# user's perusal.
+#
+pal-stats :
+$[TAB]egg-palettize $[PALETTIZE_OPTS] -af $[osfilename $[texattrib_file]] -dm $[osfilename $[install_dir]/%g] -s
+stats-pal : pal-stats
+
+// Somehow, something in the cttools confuses some shells, so that
+// when we are attached, 'cd foo' doesn't work, but 'cd ./foo' does.
+// Weird.  We get around this by putting a ./ in front of each cd
+// target below.
+
+#formap dirname subdirs
+$[dirname] : $[dirnames $[if $[build_directory],$[DIRNAME]],$[DEPEND_DIRS]]
+$[TAB]cd $[osfilename ./$[RELDIR]] && $(MAKE) all
+#end dirname
+
+// Define the rules to propogate these targets to the Makefile within
+// each directory.
+#foreach target install $[sub_targets]
+  #formap dirname subdirs
+$[target]-$[dirname] :
+$[TAB]cd $[osfilename ./$[RELDIR]] && $(MAKE) $[target]
+
+  #end dirname
+#end target
+
+#end Makefile
+
+
+
+//////////////////////////////////////////////////////////////////////
+#endif // DIR_TYPE

+ 22 - 5
dtool/pptempl/Template.nmake.pp

@@ -10,10 +10,10 @@
 // so as not to confuse it with the previous Template.msvc.pp which
 // attempts to create visual studio projects.
 //
-// Steven "Sauce" Osman, July 17, 2003 
+// Steven "Sauce" Osman, July 17, 2003
 //
 // Note:
-// There's one wierd behavior when running interrogate, specifically
+// There's one weird behavior when running interrogate, specifically
 // with its -od directive.  This is because the pathname specified
 // in -od is dropped into a string in a c++ source file.  This makes
 // the c++ compiler interpret all back-slashes as escape sequences.
@@ -419,6 +419,9 @@ $[TAB] $[SHARED_LIB_C++]
 $[TAB] $[SHARED_LIB_C]
   #endif
 #endif
+#if $[eq $[USE_COMPILER], MSVC8]
+$[TAB] mt -nologo -manifest $[target].manifest -outputresource:$[target];2
+#endif
 
 #if $[build_dlls]
 $[osfilename $[ODIR]/$[get_dllname $[TARGET]].lib] : $[patsubst %,$[osfilename %],$[ODIR]/$[get_dllname $[TARGET]].$[dlllib]]
@@ -456,7 +459,11 @@ $[TAB] if exist $[file] del /f $[file]
 $[osfilename $[install_lib_dir]/$[get_dllname $[TARGET]].$[dlllib]] : $[patsubst %,$[osfilename %],$[ODIR]/$[get_dllname $[TARGET]].$[dlllib]]
 #define local $[get_dllname $[TARGET]].$[dlllib]
 #define dest $[install_lib_dir]
+#if $[eq $[USE_COMPILER], MSVC8]
+$[TAB] mt -nologo -manifest $[ODIR]/$[local].manifest -outputresource:$[ODIR]/$[local];2
+#endif
 $[TAB] xcopy /I/Y $[osfilename $[ODIR]/$[local]] $[osfilename $[dest]]
+$[TAB] xcopy /I/Y $[osfilename $[ODIR]/$[local].manifest] $[osfilename $[dest]]
 #endif
 
 $[osfilename $[install_lib_dir]/$[get_dllname $[TARGET]].lib] : $[patsubst %,$[osfilename %],$[ODIR]/$[get_dllname $[TARGET]].lib]
@@ -499,7 +506,7 @@ $[osfilename $[igateoutput]] : $[patsubst %,$[osfilename %],$[sort $[patsubst %.
 //// There's a bug here.  The -od is being passed into a string in the file.  This
 //// makes slashes look like escape sequences.
 //// The hacky fix is to use \\ instead of \.  Windows seems to still let you open files if you
-//// include multiple slashes in them.  Then, when quoted, the string will properly 
+//// include multiple slashes in them.  Then, when quoted, the string will properly
 //// be created.
 //$[TAB] $[INTERROGATE] -od $[subst \,\\,$[osfilename $[igatedb]]] -oc $[osfilename $[igateoutput]] $[interrogate_options] -module "$[igatemod]" -library "$[igatelib]" $(lib$[TARGET]_igatescan)
 // Actually, drose kindly fixed that
@@ -547,6 +554,9 @@ $[TAB] $[SHARED_LIB_C++] $[COMPILED_RESOURCES]
 #else
 $[TAB] $[SHARED_LIB_C] $[COMPILED_RESOURCES]
 #endif
+#if $[eq $[USE_COMPILER], MSVC8]
+$[TAB] mt -nologo -manifest $[target].manifest -outputresource:$[target];2
+#endif
 
 #if $[build_dlls]
 $[osfilename $[ODIR]/$[get_dllname $[TARGET]].lib] : $[patsubst %,$[osfilename %],$[ODIR]/$[get_dllname $[TARGET]].$[dlllib]]
@@ -716,6 +726,9 @@ $[TAB] $[LINK_BIN_C++]
 $[TAB] $[LINK_BIN_C]
   #endif
 #endif
+#if $[eq $[USE_COMPILER], MSVC8]
+$[TAB] mt -nologo -manifest $[target].manifest -outputresource:$[target];1
+#endif
 
 #if $[build_pdbs]
 $[osfilename $[ODIR]/$[TARGET].pdb] : $[patsubst %,$[osfilename %],$[ODIR]/$[TARGET].exe]
@@ -743,6 +756,7 @@ $[osfilename $[install_bin_dir]/$[TARGET].exe] : $[patsubst %,$[osfilename %],$[
 #define local $[TARGET].exe
 #define dest $[install_bin_dir]
 $[TAB] xcopy /I/Y $[osfilename $[ODIR]/$[local]] $[osfilename $[dest]]
+$[TAB] xcopy /I/Y $[osfilename $[ODIR]/$[local].manifest] $[osfilename $[dest]]
 
 #if $[build_pdbs]
 $[osfilename $[install_bin_dir]/$[TARGET].pdb] : $[patsubst %,$[osfilename %],$[ODIR]/$[TARGET].pdb]
@@ -784,6 +798,9 @@ $[TAB] $[LINK_BIN_C++]
 #else
 $[TAB] $[LINK_BIN_C]
 #endif
+#if $[eq $[USE_COMPILER], MSVC8]
+$[TAB] mt -nologo -manifest $[target].manifest -outputresource:$[target];1
+#endif
 
 #end noinst_bin_target test_bin_target test_lib_target
 
@@ -939,7 +956,7 @@ $[osfilename $[install_py_dir]/$[file]] : $[patsubst %,$[osfilename %],$[file]]
 #define dest $[install_py_dir]
 $[TAB] xcopy /I/Y $[osfilename $[local]] $[osfilename $[dest]]
 #end file
-   
+
 #if $[install_py]
 $[osfilename $[install_py_package_dir]/__init__.py] :
 $[TAB] echo. > $[osfilename $[install_py_package_dir]/__init__.py]
@@ -1114,7 +1131,7 @@ $[TAB] ppremake
 #elif $[or $[eq $[DIR_TYPE], models],$[eq $[DIR_TYPE], models_toplevel],$[eq $[DIR_TYPE], models_group]]
 //////////////////////////////////////////////////////////////////////
 
-#include $[THISDIRPREFIX]Template.models.pp
+#include $[THISDIRPREFIX]Template.models.nmake.pp
 
 //////////////////////////////////////////////////////////////////////
 #endif // DIR_TYPE

+ 12 - 4
dtool/pptempl/compilerSettings.pp

@@ -88,9 +88,13 @@
   #define COMMONFLAGS /DHAVE_DINKUM /Zc:forScope
 
   // use "unsafe" QIfist flt->int rounding only if FAST_FLT_TO_INT is defined
-  #define REGULAR_OPTFLAGS /O2 /Ob2 /G7 $[if $[ne $[FAST_FLT_TO_INT],], /QIfist,]
-
-  #defer OPTFLAGS $[if $[OPT_MINSIZE],/Ox /Og /Ob1 /Oi /Os /Oy /GL /G7,$[REGULAR_OPTFLAGS]]
+  #if $[or $[eq $[USE_COMPILER], MSVC7], $[eq $[USE_COMPILER], MSVC7_1]]
+    #define REGULAR_OPTFLAGS /O2 /Ob2 /G7 $[if $[ne $[FAST_FLT_TO_INT],], /QIfist,]
+    #defer OPTFLAGS $[if $[OPT_MINSIZE],/Ox /Og /Ob1 /Oi /Os /Oy /GL /G7,$[REGULAR_OPTFLAGS]]
+  #else
+    #define REGULAR_OPTFLAGS /O2 /Ob2 $[if $[ne $[FAST_FLT_TO_INT],], /QIfist,]
+    #defer OPTFLAGS $[if $[OPT_MINSIZE],/Ox /Og /Ob1 /Oi /Os /Oy /GL,$[REGULAR_OPTFLAGS]]
+  #endif
 
   //  #define OPT1FLAGS /RTCsu /GS  removing /RTCu because it crashes in dxgsg with internal compiler bug
   #define OPT1FLAGS /RTCs /GS
@@ -108,7 +112,11 @@
   #defer DEBUGFLAGS $[if $[ne $[LINK_FORCE_STATIC_RELEASE_C_RUNTIME],],/MTd, /MDd] $[BROWSEINFO_FLAG] $[DEBUGINFOFLAGS] $[DEBUGPDBFLAGS]
   #defer RELEASEFLAGS $[if $[ne $[LINK_FORCE_STATIC_RELEASE_C_RUNTIME],],/MT, /MD]
 
-  #define MAPINFOFLAGS /MAPINFO:EXPORTS /MAPINFO:LINES
+  #if $[or $[eq $[USE_COMPILER], MSVC7], $[eq $[USE_COMPILER], MSVC7_1]]
+    #define MAPINFOFLAGS /MAPINFO:EXPORTS /MAPINFO:LINES
+  #else
+    #define MAPINFOFLAGS /MAPINFO:EXPORTS
+  #endif
 
   #if $[ENABLE_PROFILING]
     #define PROFILE_FLAG /FIXED:NO

+ 6 - 6
dtool/src/dtoolbase/dtoolbase.h

@@ -202,23 +202,23 @@
 #define TAU_REPORT_THREAD_STATISTICS()
 #define TAU_REGISTER_THREAD()
 #define TAU_REGISTER_FORK(id, op) 
-#define TAU_ENABLE_INSTRUMENTATION() 		
-#define TAU_DISABLE_INSTRUMENTATION() 	
+#define TAU_ENABLE_INSTRUMENTATION() 
+#define TAU_DISABLE_INSTRUMENTATION() 
 #define TAU_ENABLE_GROUP(group)
 #define TAU_DISABLE_GROUP(group)
 #define TAU_ENABLE_GROUP_NAME(group)
 #define TAU_DISABLE_GROUP_NAME(group)
-#define TAU_ENABLE_ALL_GROUPS()			
-#define TAU_DISABLE_ALL_GROUPS()	
+#define TAU_ENABLE_ALL_GROUPS()
+#define TAU_DISABLE_ALL_GROUPS()
 #define TAU_TRACK_MEMORY()
 #define TAU_TRACK_MEMORY_HERE()
 #define TAU_ENABLE_TRACKING_MEMORY()
 #define TAU_DISABLE_TRACKING_MEMORY()
 #define TAU_TRACK_MEMORY()
 #define TAU_TRACK_MEMORY_HERE()
-#define TAU_ENABLE_TRACKING_MUSE_EVENTS()	
+#define TAU_ENABLE_TRACKING_MUSE_EVENTS()
 #define TAU_DISABLE_TRACKING_MUSE_EVENTS()
-#define TAU_TRACK_MUSE_EVENTS()		
+#define TAU_TRACK_MUSE_EVENTS()
 #define TAU_SET_INTERRUPT_INTERVAL(value)
 
 #define TAU_TRACE_SENDMSG(type, destination, length) 

+ 1 - 1
dtool/src/interrogatedb/py_panda.h

@@ -67,7 +67,7 @@ typedef int Py_ssize_t;
 // 2.4 macros which aren't available in 2.3
 #ifndef Py_RETURN_NONE
 inline PyObject* doPy_RETURN_NONE()
-{	Py_INCREF(Py_None); return Py_None; }
+{   Py_INCREF(Py_None); return Py_None; }
 #define Py_RETURN_NONE return doPy_RETURN_NONE()
 #endif
 

+ 2 - 0
dtool/src/parser-inc/NxCloth.h

@@ -0,0 +1,2 @@
+#undef NX_USE_CLOTH_API
+#define NX_USE_CLOTH_API false

+ 2 - 0
dtool/src/parser-inc/NxFluid.h

@@ -0,0 +1,2 @@
+#undef NX_USE_FLUID_API
+#define NX_USE_FLUID_API false

+ 174 - 0
dtool/src/parser-inc/NxPhysics.h

@@ -0,0 +1,174 @@
+// Filename: NxPhysics.h
+// Created by:  pratt (Apr 26, 2006)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2006, 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+// This file, and all the other files in this directory, aren't
+// intended to be compiled--they're just parsed by CPPParser (and
+// interrogate) in lieu of the actual system headers, to generate the
+// interrogate database.
+
+#ifndef NXPHYSICS_H
+#define NXPHYSICS_H
+
+#define NX_CALL_CONV
+
+
+#include "NxFoundation.h"   //include the all of the foundation SDK 
+
+
+//////////////general:
+
+#include "NxScene.h"
+#include "NxSceneDesc.h"
+
+#include "NxActor.h"
+#include "NxActorDesc.h"
+
+#include "NxMaterial.h"
+#include "NxMaterialDesc.h"
+
+#include "NxContactStreamIterator.h"
+
+#include "NxUserContactReport.h"
+#include "NxUserNotify.h"
+#include "NxUserRaycastReport.h"
+#include "NxUserEntityReport.h"
+
+#include "NxBodyDesc.h"
+
+#include "NxEffector.h"
+
+#include "NxSpringAndDamperEffector.h"
+#include "NxSpringAndDamperEffectorDesc.h"
+
+#include "NxScheduler.h"
+
+//#if NX_USE_FLUID_API
+//#include "fluids/NxFluid.h"
+//#include "fluids/NxFluidDesc.h"
+//#include "fluids/NxFluidEmitter.h"
+//#include "fluids/NxFluidEmitterDesc.h"
+//#endif
+//
+//#if NX_USE_CLOTH_API
+//#include "cloth/NxCloth.h"
+//#include "cloth/NxClothDesc.h"
+//#endif
+
+#include "NxCCDSkeleton.h"
+#include "NxTriangle.h"
+#include "NxScheduler.h"
+#include "NxSceneStats.h"
+#include "NxSceneStats2.h"
+/////////////joints:
+
+#include "NxJoint.h"
+
+#include "NxJointLimitDesc.h"
+#include "NxJointLimitPairDesc.h"
+#include "NxMotorDesc.h"
+#include "NxSpringDesc.h"
+
+#include "NxPointInPlaneJoint.h"
+#include "NxPointInPlaneJointDesc.h"
+
+#include "NxPointOnLineJoint.h"
+#include "NxPointOnLineJointDesc.h"
+
+#include "NxRevoluteJoint.h"
+#include "NxRevoluteJointDesc.h"
+
+#include "NxPrismaticJoint.h"
+#include "NxPrismaticJointDesc.h"
+
+#include "NxCylindricalJoint.h"
+#include "NxCylindricalJointDesc.h"
+
+#include "NxSphericalJoint.h"
+#include "NxSphericalJointDesc.h"
+
+#include "NxFixedJoint.h"
+#include "NxFixedJointDesc.h"
+
+#include "NxDistanceJoint.h"
+#include "NxDistanceJointDesc.h"
+
+#include "NxPulleyJoint.h"
+#include "NxPulleyJointDesc.h"
+
+#include "NxD6Joint.h"
+#include "NxD6JointDesc.h"
+
+//////////////shapes:
+
+#include "NxShape.h"
+#include "NxShapeDesc.h"
+
+#include "NxBoxShape.h"
+#include "NxBoxShapeDesc.h"
+
+#include "NxCapsuleShape.h"
+#include "NxCapsuleShapeDesc.h"
+
+#include "NxPlaneShape.h"
+#include "NxPlaneShapeDesc.h"
+
+#include "NxSphereShape.h"
+#include "NxSphereShapeDesc.h"
+
+#include "NxTriangleMesh.h"
+#include "NxTriangleMeshDesc.h"
+
+#include "NxTriangleMeshShape.h"
+#include "NxTriangleMeshShapeDesc.h"
+
+#include "NxConvexMesh.h"
+#include "NxConvexMeshDesc.h"
+
+#include "NxConvexShape.h"
+#include "NxConvexShapeDesc.h"
+
+#include "NxHeightField.h"
+#include "NxHeightFieldDesc.h"
+
+#include "NxHeightFieldShape.h"
+#include "NxHeightFieldShapeDesc.h"
+#include "NxHeightFieldSample.h"
+
+#include "NxWheelShape.h"
+#include "NxWheelShapeDesc.h"
+//////////////utils:
+
+#include "NxInertiaTensor.h"
+#include "NxIntersectionBoxBox.h"
+#include "NxIntersectionPointTriangle.h"
+#include "NxIntersectionRayPlane.h"
+#include "NxIntersectionRaySphere.h"
+#include "NxIntersectionRayTriangle.h"
+#include "NxIntersectionSegmentBox.h"
+#include "NxIntersectionSegmentCapsule.h"
+#include "NxIntersectionSweptSpheres.h"
+#include "NxPMap.h"
+#include "NxSmoothNormals.h"
+#include "NxConvexHull.h"
+#include "NxAllocateable.h"
+#include "NxExportedUtils.h"
+
+#include "PhysXLoader.h"
+
+
+#endif  // NXPHYSICS_H

+ 4 - 0
dtool/src/parser-inc/Sources.pp

@@ -14,5 +14,9 @@
     intfloat_readwrite.h mathematics.h rational.h rtp.h \
     rtsp.h rtspcodes.h setjmp.h winsock2.h \
     ode/ode.h collision_trimesh.h artools.h \
+    NxPhysics.h cloth/NxCloth.h fluids/NxFluid.h \
     netinet/tcp.h netinet/ip.h sys/socket.h \
     rfftw.h libtar.h malloc.h ucontext.h ctype.h
+
+
+

+ 8 - 8
dtool/src/parser-inc/ode.h

@@ -61,10 +61,10 @@ typedef dReal dMatrix4[4*4];
 typedef dReal dMatrix6[8*6];
 typedef dReal dQuaternion[4];
 
-struct dxWorld;		/* dynamics world */
-struct dxSpace;		/* collision space */
-struct dxBody;		/* rigid body (dynamics object) */
-struct dxGeom;		/* geometry (collision object) */
+struct dxWorld;     /* dynamics world */
+struct dxSpace;     /* collision space */
+struct dxBody;      /* rigid body (dynamics object) */
+struct dxGeom;      /* geometry (collision object) */
 struct dxJoint;
 struct dxJointNode;
 struct dxJointGroup;
@@ -77,10 +77,10 @@ typedef struct dxJoint *dJointID;
 typedef struct dxJointGroup *dJointGroupID;
 
 typedef struct dJointFeedback {
-  dVector3 f1;		/* force applied to body 1 */
-  dVector3 t1;		/* torque applied to body 1 */
-  dVector3 f2;		/* force applied to body 2 */
-  dVector3 t2;		/* torque applied to body 2 */
+  dVector3 f1;      /* force applied to body 1 */
+  dVector3 t1;      /* torque applied to body 1 */
+  dVector3 f2;      /* force applied to body 2 */
+  dVector3 t2;      /* torque applied to body 2 */
 } dJointFeedback;
 
 typedef struct dSurfaceParameters dSurfaceParameters;

+ 5 - 0
panda/metalibs/panda/Sources.pp

@@ -26,6 +26,11 @@
   interrogatedb:c dconfig:c dtoolconfig:m \
   dtoolutil:c dtoolbase:c dtool:m prc:c
 
+#if $[LINK_IN_PHYSX]
+  #define BUILDING_DLL $[BUILDING_DLL] BUILDING_PANDAPHYSX
+  #define COMPONENT_LIBS $[COMPONENT_LIBS] physx
+#endif
+
 #begin metalib_target
   #define TARGET panda
 

+ 28 - 0
panda/metalibs/pandaphysx/Sources.pp

@@ -0,0 +1,28 @@
+// 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_PANDAPHYSX
+#define BUILD_DIRECTORY $[HAVE_PHYSX]
+
+#if $[eq $[LINK_IN_PHYSX],]
+  // We don't have any components if we're linking the Physics library
+  // directly into Panda.
+  #define COMPONENT_LIBS \
+      physx
+#endif
+
+#define LOCAL_LIBS linmath putil express
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+    dtoolbase:c dtoolutil:c dtool:m prc:c
+
+#begin metalib_target
+  #define TARGET pandaphysx
+
+  #define SOURCES pandaphysx.cxx pandaphysx.h
+  #define INSTALL_HEADERS pandaphysx.h
+
+#end metalib_target

+ 31 - 0
panda/metalibs/pandaphysx/pandaphysx.cxx

@@ -0,0 +1,31 @@
+// Filename: pandaphysx.cxx
+// Created by:  pratt (Apr 20, 2006)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "pandaphysx.h"
+
+#ifndef LINK_IN_PHYSX
+#include "config_physx.h"
+#endif
+
+// By including checkPandaVersion.h, we guarantee that runtime
+// attempts to load libpandaphysx.so/.dll will fail if they
+// inadvertently link with the wrong version of libdtool.so/.dll.
+
+#include "checkPandaVersion.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libpandaphysx
+//  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_libpandaphysx() {
+#ifndef LINK_IN_PHYSX
+  init_libphysx();
+#endif
+}

+ 13 - 0
panda/metalibs/pandaphysx/pandaphysx.h

@@ -0,0 +1,13 @@
+// Filename: pandaphysx.h
+// Created by:  pratt (Apr 20, 2006)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef PANDAPHYSX_H
+#define PANDAPHYSX_H
+
+#include "pandabase.h"
+
+EXPCL_PANDAPHYSX void init_libpandaphysx();
+
+#endif

+ 1 - 1
panda/src/audio/Sources.pp

@@ -4,7 +4,7 @@
 
 #begin lib_target
   #define TARGET audio
-  #define LOCAL_LIBS putil event movies
+  #define LOCAL_LIBS putil event movies linmath
   
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx
 

+ 10 - 0
panda/src/audio/audioManager.cxx

@@ -349,3 +349,13 @@ void AudioManager::
 write(ostream &out) const {
   out << (*this) << "\n";
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AudioManager::set_speaker_configuration
+//       Access: Published
+//  Description: For use only with Miles.
+////////////////////////////////////////////////////////////////////
+void AudioManager::
+set_speaker_configuration(LVecBase3f *speaker1, LVecBase3f *speaker2, LVecBase3f *speaker3, LVecBase3f *speaker4, LVecBase3f *speaker5, LVecBase3f *speaker6, LVecBase3f *speaker7, LVecBase3f *speaker8, LVecBase3f *speaker9) {
+  // intentionally blank
+}

+ 4 - 0
panda/src/audio/audioManager.h

@@ -18,6 +18,7 @@
 
 #include "config_audio.h"
 #include "audioSound.h"
+#include "lvecBase3.h"
 #include "filterProperties.h"
 #include "movieAudio.h"
 
@@ -190,6 +191,9 @@ PUBLISHED:
   virtual void output(ostream &out) const;
   virtual void write(ostream &out) const;
 
+  // set_speaker_configuration is a Miles only method.
+  virtual void set_speaker_configuration(LVecBase3f *speaker1, LVecBase3f *speaker2=NULL, LVecBase3f *speaker3=NULL, LVecBase3f *speaker4=NULL, LVecBase3f *speaker5=NULL, LVecBase3f *speaker6=NULL, LVecBase3f *speaker7=NULL, LVecBase3f *speaker8=NULL, LVecBase3f *speaker9=NULL);
+
 public:
   static void register_AudioManager_creator(Create_AudioManager_proc* proc);
 

+ 32 - 12
panda/src/audio/audioSound.cxx

@@ -70,25 +70,45 @@ get_3d_max_distance() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioSound::getSpeakerMix
+//     Function: AudioSound::get_speaker_mix
 //       Access: Published
-//  Description: 
+//  Description: For use only with FMOD.
 ////////////////////////////////////////////////////////////////////
 float AudioSound::
 get_speaker_mix(int speaker) {
-	// intentionally blank
-	return 0.0;
+    // intentionally blank
+    return 0.0;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AudioSound::setSpeakerMix
+//     Function: AudioSound::set_speaker_mix
 //       Access: Published
-//  Description: 
+//  Description: For use only with FMOD.
 ////////////////////////////////////////////////////////////////////
 void AudioSound::
 set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float  sideright) {
-	// intentionally blank
-	;
+    // intentionally blank
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AudioSound::get_speaker_level
+//       Access: Published
+//  Description: For use only with Miles.
+////////////////////////////////////////////////////////////////////
+float AudioSound::
+get_speaker_level(int index) {
+  // intentionally blank
+  return 0.0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AudioSound::set_speaker_levels
+//       Access: Published
+//  Description: For use only with Miles.
+////////////////////////////////////////////////////////////////////
+void AudioSound::
+set_speaker_levels(float level1, float level2, float level3, float level4, float level5, float level6, float level7, float level8, float level9) {
+  // intentionally blank
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -119,8 +139,8 @@ configure_filters(FilterProperties *config) {
 ////////////////////////////////////////////////////////////////////
 int AudioSound::
 get_priority() {
-	// intentionally blank
-	return 0;
+    // intentionally blank
+    return 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -130,8 +150,8 @@ get_priority() {
 ////////////////////////////////////////////////////////////////////
 void AudioSound::
 set_priority(int priority) {
-	// intentionally blank
-	;
+    // intentionally blank
+    ;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 9 - 0
panda/src/audio/audioSound.h

@@ -120,9 +120,18 @@ PUBLISHED:
   virtual void set_3d_max_distance(float dist);
   virtual float get_3d_max_distance() const;
 
+  // *_speaker_mix and *_speaker_level(s) serve the same purpose.
+  // *_speaker_mix is for use with FMOD.
+  // *_speaker_level(s) is for use with Miles.
+  // Both interfaces exist because of a significant difference in the
+  // two APIs.  Hopefully the difference can be reconciled into a single
+  // interface at some point.
   virtual float get_speaker_mix(int speaker);
   virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float  sideright);
 
+  virtual float get_speaker_level(int index);
+  virtual void set_speaker_levels(float level1, float level2=-1.0f, float level3=-1.0f, float level4=-1.0f, float level5=-1.0f, float level6=-1.0f, float level7=-1.0f, float level8=-1.0f, float level9=-1.0f);
+
   virtual int get_priority();
   virtual void set_priority(int priority);
 

+ 12 - 12
panda/src/audio/config_audio.cxx

@@ -51,15 +51,15 @@ ConfigVariableDouble audio_volume
 
 // Config variables for OpenAL:
 
-ConfigVariableDouble audio_doppler_factor 	 
-("audio-doppler-factor", 1.0f); 	 
-	  	 
-ConfigVariableDouble audio_distance_factor 	 
-("audio-distance-factor", 1.0f); 	 
-	  	 
-ConfigVariableDouble audio_drop_off_factor 	 
-("audio-drop-off-factor", 1.0f); 	 
-	  	 
+ConfigVariableDouble audio_doppler_factor 
+("audio-doppler-factor", 1.0f); 
+
+ConfigVariableDouble audio_distance_factor 
+("audio-distance-factor", 1.0f); 
+
+ConfigVariableDouble audio_drop_off_factor 
+("audio-drop-off-factor", 1.0f); 
+
 ConfigVariableDouble audio_buffering_seconds
 ("audio-buffering-seconds", 3.0f,
  PRC_DESC("Controls the amount of audio buffering when streaming audio. "
@@ -81,9 +81,9 @@ ConfigVariableInt audio_preload_threshold
 
 // Unknown
 
-ConfigVariableInt audio_min_hw_channels 	 
-("audio-min-hw-channels", 15, 	 
-PRC_DESC("Guarantee this many channels on the local sound card, or just " 	 
+ConfigVariableInt audio_min_hw_channels 
+("audio-min-hw-channels", 15, 
+PRC_DESC("Guarantee this many channels on the local sound card, or just " 
          "play EVERYTHING in software."));
 
 // Config variables for Fmod:

+ 3 - 3
panda/src/audio/config_audio.h

@@ -44,9 +44,9 @@ extern EXPCL_PANDA_AUDIO ConfigVariableBool fmod_use_surround_sound;
 
 // Config vars for OpenAL:
 
-extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_doppler_factor; 	 
-extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_distance_factor; 	 
-extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_drop_off_factor; 	 
+extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_doppler_factor; 
+extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_distance_factor; 
+extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_drop_off_factor; 
 extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_buffering_seconds;
 extern EXPCL_PANDA_AUDIO ConfigVariableInt    audio_preload_threshold;
 

+ 3 - 3
panda/src/audiotraits/Sources.pp

@@ -10,8 +10,8 @@
   #define BUILDING_DLL BUILDING_MILES_AUDIO
   #define LOCAL_LIBS audio event pipeline
   #define WIN_SYS_LIBS $[WIN_SYS_LIBS] user32.lib advapi32.lib winmm.lib
-  
-  #define COMBINED_SOURCES $[TARGET]_composite1.cxx  
+
+  #define COMBINED_SOURCES $[TARGET]_composite1.cxx
 
   #define SOURCES \
       config_milesAudio.h \
@@ -21,7 +21,7 @@
       milesAudioSequence.I milesAudioSequence.h \
       milesAudioStream.I milesAudioStream.h \
       globalMilesManager.I globalMilesManager.h
-      
+
   #define INCLUDED_SOURCES \
       config_milesAudio.cxx milesAudioManager.cxx milesAudioSound.cxx \
       milesAudioStream.cxx globalMilesManager.cxx milesAudioSample.cxx \

+ 1 - 1
panda/src/audiotraits/config_fmodAudio.cxx

@@ -43,7 +43,7 @@ init_libFmodAudio() {
   if (initialized) {
     return;
   }
-  
+
   initialized = true;
   FmodAudioManager::init_type();
   FmodAudioSound::init_type();

+ 29 - 29
panda/src/audiotraits/fmodAudioManager.cxx

@@ -38,13 +38,13 @@
 
 TypeHandle FmodAudioManager::_type_handle;
 
-FMOD::System *FmodAudioManager::_system; 
+FMOD::System *FmodAudioManager::_system;
 pset<FmodAudioManager *> FmodAudioManager::_all_managers;
 
 bool FmodAudioManager::_system_is_valid = false;
 
 
-//  This sets the distance factor for 3D audio to use feet. 
+//  This sets the distance factor for 3D audio to use feet.
 //  FMOD uses meters by default.
 //  Since Panda use feet we need to compensate for that with a factor of 3.28
 //
@@ -80,7 +80,7 @@ AudioManager *Create_FmodAudioManager() {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::Constructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 FmodAudioManager::
 FmodAudioManager() {
@@ -90,7 +90,7 @@ FmodAudioManager() {
   unsigned int      version;
 
   _all_managers.insert(this);
-  
+
   //Init 3D attributes
   _position.x = 0;
   _position.y = 0;
@@ -120,7 +120,7 @@ FmodAudioManager() {
     //  Let check the Version of FMOD to make sure the Headers and Libraries are correct.
     result = _system->getVersion(&version);
     fmod_audio_errcheck("_system->getVersion()", result);
-  
+
     if (version < FMOD_VERSION){
       audio_error("You are using an old version of FMOD.  This program requires:" << FMOD_VERSION);
     }
@@ -133,7 +133,7 @@ FmodAudioManager() {
     }
 
     //Now we Initialize the System.
-	int nchan = fmod_number_of_sound_channels;
+    int nchan = fmod_number_of_sound_channels;
     result = _system->init(nchan, FMOD_INIT_NORMAL, 0);
     fmod_audio_errcheck("_system->init()", result);
 
@@ -172,7 +172,7 @@ FmodAudioManager() {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::Destructor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 FmodAudioManager::
 ~FmodAudioManager() {
@@ -196,7 +196,7 @@ FmodAudioManager::
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::is_valid
 //       Access: Public
-//  Description: This just check to make sure the FMOD System is 
+//  Description: This just check to make sure the FMOD System is
 //         up and running correctly.
 ////////////////////////////////////////////////////////////////////
 bool FmodAudioManager::
@@ -318,7 +318,7 @@ make_dsp(const FilterProperties::FilterConfig &conf) {
   }
 
   dsp->setUserData(USER_DSP_MAGIC);
-  
+
   return dsp;
 }
 
@@ -359,7 +359,7 @@ update_dsp_chain(FMOD::DSP *head, FilterProperties *config) {
       return;
     }
   }
-  
+
   for (int i=0; i<(int)(conf.size()); i++) {
     FMOD::DSP *dsp = make_dsp(conf[i]);
     if (dsp == 0) break;
@@ -381,8 +381,8 @@ update_dsp_chain(FMOD::DSP *head, FilterProperties *config) {
 //       Access: Public
 //  Description: Configure the global DSP filter chain.
 //
-//               FMOD has a relatively powerful DSP 
-//               implementation.  It is likely that most 
+//               FMOD has a relatively powerful DSP
+//               implementation.  It is likely that most
 //               configurations will be supported.
 ////////////////////////////////////////////////////////////////////
 bool FmodAudioManager::
@@ -407,7 +407,7 @@ PT(AudioSound) FmodAudioManager::
 get_sound(const string &file_name, bool positional, int) {
   //Needed so People use Panda's Generic UNIX Style Paths for Filename.
   //path.to_os_specific() converts it back to the proper OS version later on.
-  
+
   Filename path = file_name;
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
@@ -489,7 +489,7 @@ getSpeakerSetup() {
 //       Access: Published
 //  Description: This is to set up FMOD to use a MultiChannel Setup.
 //         This method is pretty much useless.
-//         To set a speaker setup in FMOD for Surround Sound, 
+//         To set a speaker setup in FMOD for Surround Sound,
 //         stereo, or whatever you have to set the SpeakerMode
 //         BEFORE you Initialize FMOD.
 //         Since Panda Inits the FmodAudioManager right when you
@@ -515,7 +515,7 @@ setSpeakerSetup(AudioManager::SpeakerModeCategory cat) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::set_volume(float volume)
 //       Access: Public
-//  Description: 
+//  Description:
 //        There isn't a specific system volume function in FMOD-EX,
 //        so this function is moot now.
 ////////////////////////////////////////////////////////////////////
@@ -526,7 +526,7 @@ void FmodAudioManager::set_volume(float volume) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::get_volume()
 //       Access: Public
-//  Description: 
+//  Description:
 //        There isn't a specific system volume function in FMOD-EX,
 //        so this function is moot now.
 ////////////////////////////////////////////////////////////////////
@@ -548,8 +548,8 @@ set_active(bool active) {
     _active = active;
 
     // Tell our AudioSounds to adjust:
-    for (SoundSet::iterator i = _all_sounds.begin(); 
-         i != _all_sounds.end(); 
+    for (SoundSet::iterator i = _all_sounds.begin();
+         i != _all_sounds.end();
          ++i) {
       (*i)->set_active(_active);
     }
@@ -559,7 +559,7 @@ set_active(bool active) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::get_active()
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 bool FmodAudioManager::
 get_active() const {
@@ -617,10 +617,10 @@ audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float v
   audio_debug("FmodAudioManager::audio_3d_set_listener_attributes()");
 
   FMOD_RESULT result;
-  
+
   _position.x = px;
   _position.y = pz;
-  _position.z = py; 
+  _position.z = py;
 
   _velocity.x = vx;
   _velocity.y = vz;
@@ -633,7 +633,7 @@ audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float v
   _up.x = ux;
   _up.y = uz;
   _up.z = uy;
-    
+
   result = _system->set3DListenerAttributes( 0, &_position, &_velocity, &_forward, &_up);
   fmod_audio_errcheck("_system->set3DListenerAttributes()", result);
 
@@ -660,7 +660,7 @@ audio_3d_get_listener_attributes(float *px, float *py, float *pz, float *vx, flo
 void FmodAudioManager::
 audio_3d_set_distance_factor(float factor) {
   audio_debug( "FmodAudioManager::audio_3d_set_distance_factor( factor= " << factor << ")" );
-  
+
   FMOD_RESULT result;
 
   _distance_factor = factor;
@@ -687,7 +687,7 @@ audio_3d_get_distance_factor() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::audio_3d_set_doppler_factor
 //       Access: Public
-//  Description: Exaggerates or diminishes the Doppler effect. 
+//  Description: Exaggerates or diminishes the Doppler effect.
 //               Defaults to 1.0
 ////////////////////////////////////////////////////////////////////
 void FmodAudioManager::
@@ -706,7 +706,7 @@ audio_3d_set_doppler_factor(float factor) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::audio_3d_get_doppler_factor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 float FmodAudioManager::
 audio_3d_get_doppler_factor() const {
@@ -737,7 +737,7 @@ audio_3d_set_drop_off_factor(float factor) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::audio_3d_get_drop_off_factor
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 float FmodAudioManager::
 audio_3d_get_drop_off_factor() const {
@@ -802,7 +802,7 @@ uncache_sound(const string& file_name) {
 void FmodAudioManager::
 clear_cache() {
   audio_debug("FmodAudioManager::clear_cache()");
-  
+
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -842,7 +842,7 @@ open_callback(const char *name, int, unsigned int *file_size,
     // An invalid attempt to open an unnamed file.
     return FMOD_ERR_FILE_NOTFOUND;
   }
-    
+
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
 
   PT(VirtualFile) file = vfs->get_file(Filename(name));
@@ -903,7 +903,7 @@ read_callback(void *handle, void *buffer, unsigned int size_bytes,
     return FMOD_OK;
   }
 }
-  
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioManager::seek_callback
 //       Access: Private, Static

+ 19 - 19
panda/src/audiotraits/fmodAudioManager.h

@@ -98,23 +98,23 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
   virtual ~FmodAudioManager();
 
   virtual bool is_valid();
-          
+
   virtual PT(AudioSound) get_sound(const string&, bool positional = false, int mode=SM_heuristic);
   virtual PT(AudioSound) get_sound(MovieAudio *,  bool positional = false, int mode=SM_heuristic);
-    
+
   virtual int getSpeakerSetup();
   virtual void setSpeakerSetup(SpeakerModeCategory cat);
 
   virtual void set_volume(float);
   virtual float get_volume() const;
-          
+
   virtual void set_active(bool);
   virtual bool get_active() const;
 
   virtual void stop_all_sounds();
 
   virtual void update();
-  
+
   // This controls the "set of ears" that listens to 3D spacialized sound
   // px, py, pz are position coordinates. Can be 0.0f to ignore.
   // vx, vy, vz are a velocity vector in UNITS PER SECOND (default: meters).
@@ -122,7 +122,7 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
   // ux, uy and uz are the respective components of a unit up-vector
   // These changes will NOT be invoked until audio_3d_update() is called.
   virtual void audio_3d_set_listener_attributes(float px, float py, float pz,
-                                                float vx, float xy, float xz, 
+                                                float vx, float xy, float xz,
                                                 float fx, float fy, float fz,
                                                 float ux, float uy, float uz);
 
@@ -131,13 +131,13 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
                                                 float *vx, float *vy, float *vz,
                                                 float *fx, float *fy, float *fz,
                                                 float *ux, float *uy, float *uz);
-          
+
   // Control the "relative distance factor" for 3D spacialized audio. Default is 1.0
   // Fmod uses meters internally, so give a float in Units-per meter
   // Don't know what Miles uses.
   virtual void audio_3d_set_distance_factor(float factor);
   virtual float audio_3d_get_distance_factor() const;
-
+  void most_recently_used(const string& path);
   // Control the presence of the Doppler effect. Default is 1.0
   // Exaggerated Doppler, use >1.0
   // Diminshed Doppler, use <1.0
@@ -164,27 +164,27 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
   ////////////////////////////////////////////////////////////////////
 
 private:
-  static FMOD_RESULT F_CALLBACK 
+  static FMOD_RESULT F_CALLBACK
   open_callback(const char *name, int unicode, unsigned int *file_size,
                 void **handle, void **user_data);
 
-  static FMOD_RESULT F_CALLBACK 
+  static FMOD_RESULT F_CALLBACK
   close_callback(void *handle, void *user_data);
 
-  static FMOD_RESULT F_CALLBACK 
+  static FMOD_RESULT F_CALLBACK
   read_callback(void *handle, void *buffer, unsigned int size_bytes,
                 unsigned int *bytes_read, void *user_data);
-  
-  static FMOD_RESULT F_CALLBACK 
+
+  static FMOD_RESULT F_CALLBACK
   seek_callback(void *handle, unsigned int pos, void *user_data);
-  
+
   FMOD::DSP *make_dsp(const FilterProperties::FilterConfig &conf);
   void update_dsp_chain(FMOD::DSP *head, FilterProperties *config);
   virtual bool configure_filters(FilterProperties *config);
-  
+
  private:
-  
-  static FMOD::System *_system; 
+
+  static FMOD::System *_system;
   static pset<FmodAudioManager *> _all_managers;
 
   static bool _system_is_valid;
@@ -201,10 +201,10 @@ private:
   // DLS info for MIDI files
   string _dlsname;
   FMOD_CREATESOUNDEXINFO _midi_info;
-  
+
   bool _is_valid;
   bool _active;
-  
+
   // The set of all sounds.  Needed only to implement stop_all_sounds.
   typedef pset<FmodAudioSound *> SoundSet;
   SoundSet _all_sounds;
@@ -225,7 +225,7 @@ private:
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {
-    init_type(); 
+    init_type();
     return get_class_type();
   }
 

+ 62 - 60
panda/src/audiotraits/fmodAudioSound.cxx

@@ -23,7 +23,9 @@
 
 //Panda Headers
 #include "config_audio.h"
+#include "config_util.h"
 #include "fmodAudioSound.h"
+#include "virtualFileSystem.h"
 #include "string_utils.h"
 
 TypeHandle FmodAudioSound::_type_handle;
@@ -37,7 +39,7 @@ TypeHandle FmodAudioSound::_type_handle;
 ////////////////////////////////////////////////////////////////////
 
 FmodAudioSound::
-FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) { 
+FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
   audio_debug("FmodAudioSound::FmodAudioSound() Creating new sound, filename: " << file_name  );
 
   _active = manager->get_active();
@@ -76,54 +78,54 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
   result = _manager->_system->getSpeakerMode( &_speakermode );
   fmod_audio_errcheck("_system->getSpeakerMode()", result);
 
-  // Calculate the approximate uncompressed size of the sound.
-  int size =  file_name.get_file_size();
-  string ext = downcase(file_name.get_extension());
-  if (ext != "wav") size *= 10;
-  
-  int flag = positional ? FMOD_3D : FMOD_2D;
-  int streamflag = (size > 250000) ? FMOD_CREATESTREAM : FMOD_CREATESAMPLE;
-  if (ext == "mid") {
-    streamflag = FMOD_CREATESTREAM;
-    sound_info = &_manager->_midi_info;
-    
-    if (sound_info->dlsname != NULL) {
-      audio_debug("Using DLS file " << sound_info->dlsname);
-    }
+  // Load the sound into memory
+  string raw_data;
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+  if (!vfs->read_file(file_name, raw_data, true)) {
+    audio_warning("Unable to read " << file_name);
+    return;
   }
 
-  result = _manager->_system->createSound( file_name.c_str(), FMOD_SOFTWARE | streamflag | flag , 
-                                           sound_info, &_sound);
-  if (result != FMOD_OK) {
-    audio_error("createSound(" << file_name << "): " << FMOD_ErrorString(result));
+  // Setup info that FMOD needs in order to load from memory.
+  FMOD_CREATESOUNDEXINFO soundExInfo;
+  memset(&soundExInfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
+  soundExInfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
+  soundExInfo.length = raw_data.size();
+
+  if (positional == true) {
+    result = _manager->_system->createSound(raw_data.data(), FMOD_SOFTWARE | FMOD_3D | FMOD_OPENMEMORY, &soundExInfo, &_sound);
+    fmod_audio_errcheck("_manager->_system->createSound", result);
+
+    //This is just to collect the defaults of the sound, so we don't
+    //Have to query FMOD everytime for the info.
+    //It is also important we get the '_sampleFrequency' variable here, for the
+    //'set_play_rate()' and 'get_play_rate()' methods later;
+
+    result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority);
+    fmod_audio_errcheck("_sound->getDefaults", result);
+
+    audio_debug("Sound loaded as 3D");
+  } else {
+    result = _manager->_system->createSound(raw_data.data(), FMOD_SOFTWARE | FMOD_2D | FMOD_OPENMEMORY, &soundExInfo, &_sound);
+    fmod_audio_errcheck("_manager->_system->createSound", result);
+
+    //This is just to collect the defaults of the sound, so we don't
+    //Have to query FMOD everytime for the info.
+    //It is also important we get the '_sampleFrequency' variable here, for the
+    //'set_play_rate()' and 'get_play_rate()' methods later;
+
+    result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority);
 
     // We couldn't load the sound file.  Create a blank sound record
     // instead.
-    char blank_data[100];
-    FMOD_CREATESOUNDEXINFO exinfo;
-    memset(&exinfo, 0, sizeof(exinfo));
-    memset(blank_data, 0, sizeof(blank_data));
-    exinfo.cbsize = sizeof(exinfo);
-    exinfo.length = sizeof(blank_data);
-    exinfo.numchannels = 1;
-    exinfo.defaultfrequency = 8000;
-    exinfo.format = FMOD_SOUND_FORMAT_PCM16;
-    result = _manager->_system->createSound( blank_data, FMOD_SOFTWARE | flag | FMOD_OPENMEMORY | FMOD_OPENRAW, &exinfo, &_sound);
     fmod_audio_errcheck("createSound (blank)", result);
+    audio_debug("Sound loaded as 2D");
   }
 
   // Some WAV files contain a loop bit.  This is not handled
   // consistently.  Override it.
   _sound->setLoopCount(1);
   _sound->setMode(FMOD_LOOP_OFF);
-  
-  //This is just to collect the defaults of the sound, so we don't
-  //Have to query FMOD everytime for the info.
-  //It is also important we get the '_sampleFrequency' variable here, for the
-  //'set_play_rate()' and 'get_play_rate()' methods later;
-  
-  result = _sound->getDefaults( &_sampleFrequency, &_volume , &_balance, &_priority);
-  fmod_audio_errcheck("_sound->getDefaults()", result);
 }
 
 
@@ -162,9 +164,9 @@ play() {
 //               reference count of the associated FmodAudioSound.
 ////////////////////////////////////////////////////////////////////
 FMOD_RESULT F_CALLBACK sound_end_callback(FMOD_CHANNEL *  channel, 
-					  FMOD_CHANNEL_CALLBACKTYPE  type, 
-					  void *commanddata1, 
-					  void *commanddata2) {
+                      FMOD_CHANNEL_CALLBACKTYPE  type, 
+                      void *commanddata1, 
+                      void *commanddata2) {
   if (type == FMOD_CHANNEL_CALLBACKTYPE_END) {
     FMOD::Channel *fc = (FMOD::Channel *)channel;
     void *userdata = NULL;
@@ -226,7 +228,7 @@ get_loop() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioSound::set_loop_count
 //       Access: public
-//  Description: 
+//  Description:
 //        Panda uses 0 to mean loop forever.
 //        Fmod uses negative numbers to mean loop forever.
 //        (0 means don't loop, 1 means play twice, etc.
@@ -243,12 +245,12 @@ set_loop_count(unsigned long loop_count) {
   if (loop_count == 0) {
     result = _sound->setLoopCount( -1 );
     fmod_audio_errcheck("_sound->setLoopCount()", result);
-    result =_sound->setMode(FMOD_LOOP_NORMAL);    
+    result =_sound->setMode(FMOD_LOOP_NORMAL);
     fmod_audio_errcheck("_sound->setMode()", result);
   } else if (loop_count == 1) {
     result = _sound->setLoopCount( 1 );
     fmod_audio_errcheck("_sound->setLoopCount()", result);
-    result =_sound->setMode(FMOD_LOOP_OFF);    
+    result =_sound->setMode(FMOD_LOOP_OFF);
     fmod_audio_errcheck("_sound->setMode()", result);
   } else {
     result = _sound->setLoopCount( loop_count );
@@ -293,9 +295,9 @@ set_time(float start_time) {
     _paused = true;
     return;
   }
-  
+
   int startTime = (int)(start_time * 1000);
-  
+
   if (_channel != 0) {
     // try backing up current sound.
     result = _channel->setPosition( startTime , FMOD_TIMEUNIT_MS );
@@ -314,7 +316,7 @@ set_time(float start_time) {
       }
     }
   }
-  
+
   if (_channel == 0) {
     result = _manager->_system->playSound(FMOD_CHANNEL_FREE, _sound, true, &_channel);
     fmod_audio_errcheck("_system->playSound()", result);
@@ -333,7 +335,7 @@ set_time(float start_time) {
 
     result = _channel->setPaused(false);
     fmod_audio_errcheck("_channel->setPaused()", result);
-    
+
     _self_ref = this;
   }
 }
@@ -357,7 +359,7 @@ get_time() const {
     return 0.0f;
   }
   fmod_audio_errcheck("_channel->getPosition()", result);
-  
+
   return ((double)current_time) / 1000.0;
 }
 
@@ -416,7 +418,7 @@ set_balance(float bal) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioSound::get_balance
 //       Access: public
-//  Description: -1.0 to 1.0 scale 
+//  Description: -1.0 to 1.0 scale
 //        -1 should be all the way left.
 //        1 is all the way to the right.
 ////////////////////////////////////////////////////////////////////
@@ -432,7 +434,7 @@ get_balance() const {
 //        The rate is a multiple of the sound, normal playback speed.
 //        IE 2 would play back 2 times fast, 3 would play 3 times, and so on.
 //        This can also be set to a negative number so a sound plays backwards.
-//        But rememeber if the sound is not playing, you must set the 
+//        But rememeber if the sound is not playing, you must set the
 //        sound's time to its end to hear a song play backwards.
 ////////////////////////////////////////////////////////////////////
 void FmodAudioSound::
@@ -444,7 +446,7 @@ set_play_rate(float rate) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioSound::get_play_rate
 //       Access: public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 float FmodAudioSound::
 get_play_rate() const {
@@ -460,7 +462,7 @@ void FmodAudioSound::
 set_play_rate_on_channel() {
   FMOD_RESULT result;
   float frequency = _sampleFrequency * _playrate;
-  
+
   if (_channel != 0) {
     result = _channel->setFrequency( frequency );
     if (result == FMOD_ERR_INVALID_HANDLE) {
@@ -518,7 +520,7 @@ set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
   _location.x = px;
   _location.y = pz;
   _location.z = py;
-  
+
   _velocity.x = vx;
   _velocity.y = vz;
   _velocity.z = vy;
@@ -529,7 +531,7 @@ set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
 ////////////////////////////////////////////////////////////////////
 //     Function: FmodAudioSound::set_3d_attributes_on_channel
 //       Access: public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void FmodAudioSound::
 set_3d_attributes_on_channel() {
@@ -538,7 +540,7 @@ set_3d_attributes_on_channel() {
 
   result = _sound->getMode(&soundMode);
   fmod_audio_errcheck("_sound->getMode()", result);
-  
+
   if ((_channel != 0) && (soundMode & FMOD_3D)) {
     result = _channel->set3DAttributes( &_location, &_velocity );
     if (result == FMOD_ERR_INVALID_HANDLE) {
@@ -634,7 +636,7 @@ get_speaker_mix(AudioManager::SpeakerId speaker) {
   float center;
   float sub;
   float backleft;
-  float backright; 
+  float backright;
   float sideleft;
   float sideright;
 
@@ -714,7 +716,7 @@ set_speaker_mix_or_balance_on_channel() {
                                         _mix[AudioManager::SPK_backleft],
                                         _mix[AudioManager::SPK_backright],
                                         _mix[AudioManager::SPK_sideleft],
-                                        _mix[AudioManager::SPK_sideright] 
+                                        _mix[AudioManager::SPK_sideright]
                                         );
     }
     if (result == FMOD_ERR_INVALID_HANDLE) {
@@ -815,7 +817,7 @@ set_active(bool active) {
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: FmodAudioSound::get_active 
+//     Function: FmodAudioSound::get_active
 //       Access: public
 //  Description: Returns whether the sound has been marked "active".
 ////////////////////////////////////////////////////////////////////
@@ -838,7 +840,7 @@ finished() {
 //     Function: FmodAudioSound::set_finished_event
 //       Access: public
 //  Description: NOT USED ANYMORE!!!
-//        Assign a string for the finished event to be referenced 
+//        Assign a string for the finished event to be referenced
 //              by in python by an accept method
 //
 ////////////////////////////////////////////////////////////////////
@@ -853,7 +855,7 @@ set_finished_event(const string& event) {
 //  Description:NOT USED ANYMORE!!!
 //        Return the string the finished event is referenced by
 //
-//        
+//
 ////////////////////////////////////////////////////////////////////
 const string& FmodAudioSound::
 get_finished_event() const {

+ 12 - 13
panda/src/audiotraits/fmodAudioSound.h

@@ -85,34 +85,34 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
 
   FmodAudioSound(AudioManager *manager, Filename fn, bool positional );
   ~FmodAudioSound();
-            
+
   // For best compatability, set the loop_count, start_time,
   // volume, and balance, prior to calling play().  You may
   // set them while they're playing, but it's implementation
   // specific whether you get the results.
   void play();
   void stop();
-            
+
   // loop: false = play once; true = play forever.
   // inits to false.
   void set_loop(bool loop=true);
   bool get_loop() const;
-            
+
   // loop_count: 0 = forever; 1 = play once; n = play n times.
   // inits to 1.
   void set_loop_count(unsigned long loop_count=1);
   unsigned long get_loop_count() const;
-            
+
   // 0 = begining; length() = end.
   // inits to 0.0.
   void set_time(float start_time=0.0);
   float get_time() const;
-            
+
   // 0 = minimum; 1.0 = maximum.
   // inits to 1.0.
   void set_volume(float volume=1.0);
   float get_volume() const;
-            
+
   // -1.0 is hard left
   // 0.0 is centered
   // 1.0 is hard right
@@ -126,7 +126,7 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
   float get_play_rate() const;
 
   const string &get_name() const;
-            
+
   // return: playing time in seconds.
   float length() const;
 
@@ -141,12 +141,11 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
 
   void set_3d_max_distance(float dist);
   float get_3d_max_distance() const;
-            
+
   AudioSound::SoundStatus status() const;
 
   virtual float get_speaker_mix(AudioManager::SpeakerId speaker);
   virtual void set_speaker_mix(float frontleft, float frontright, float center, float sub, float backleft, float backright, float sideleft, float  sideright);
-
   void set_active(bool active=true);
   bool get_active() const;
 
@@ -161,7 +160,7 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
 
   Filename _file_name;
 
-  float _volume; 
+  float _volume;
   float _balance;
   float _playrate;
   int   _priority;
@@ -188,10 +187,10 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
 
   virtual int get_priority();
   virtual void set_priority(int priority);
-  
+
   bool _active;
   bool _paused;
-  
+
   string _finished_event;
 
   // This reference-counting pointer is set to this while the sound is
@@ -223,7 +222,7 @@ class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {
-    init_type(); 
+    init_type();
     return get_class_type();
   }
 

+ 1 - 1
panda/src/audiotraits/fmod_audio_composite1.cxx

@@ -2,4 +2,4 @@
 #include "config_fmodAudio.cxx"
 #include "fmodAudioManager.cxx"
 #include "fmodAudioSound.cxx"
-      
+

+ 6 - 0
panda/src/audiotraits/globalMilesManager.cxx

@@ -21,6 +21,12 @@
 #include "milesAudioSample.h"
 #include "milesAudioSequence.h"
 
+#ifdef WIN32
+// For midiOutReset()
+#include <windows.h>  
+#include <mmsystem.h>
+#endif
+
 GlobalMilesManager *GlobalMilesManager::_global_ptr;
 
 ////////////////////////////////////////////////////////////////////

+ 198 - 1
panda/src/audiotraits/milesAudioManager.cxx

@@ -432,6 +432,203 @@ stop_all_sounds() {
   reduce_sounds_playing_to(0);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_set_listener_attributes
+//       Access: Public
+//  Description: Set spatial attributes of the listener for 3D
+//               sounds.  Note that Y and Z are switched to
+//               translate into Miles's coordinate system.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float vy, float vz, float fx, float fy, float fz, float ux, float uy, float uz) {
+  audio_debug("MilesAudioManager::audio_3d_set_listener_attributes()");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  AIL_set_listener_3D_position(mgr->_digital_driver, px, pz, py);
+  AIL_set_listener_3D_velocity_vector(mgr->_digital_driver, vx, vz, vy);
+  AIL_set_listener_3D_orientation(mgr->_digital_driver, fx, fz, fy, ux, uz, uy);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_get_listener_attributes
+//       Access: Public
+//  Description: Get spatial attributes of the listener for 3D
+//               sounds.  Note that Y and Z are switched to
+//               translate from Miles's coordinate system.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::audio_3d_get_listener_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz, float *fx, float *fy, float *fz, float *ux, float *uy, float *uz) {
+  audio_debug("MilesAudioManager::audio_3d_get_listener_attributes()");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  AIL_listener_3D_position(mgr->_digital_driver, px, pz, py);
+  AIL_listener_3D_velocity(mgr->_digital_driver, vx, vz, vy);
+  AIL_listener_3D_orientation(mgr->_digital_driver, fx, fz, fy, ux, uz, uy);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_set_distance_factor
+//       Access: Public
+//  Description: Set factor to allow user to easily work in a
+//               different scale.  1.0 represents meters.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::audio_3d_set_distance_factor(float factor) {
+  audio_debug("MilesAudioManager::audio_3d_set_distance_factor( factor= " << factor << ")");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  AIL_set_3D_distance_factor(mgr->_digital_driver, factor);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_get_distance_factor
+//       Access: Public
+//  Description: Get factor controlling working units.
+////////////////////////////////////////////////////////////////////
+float MilesAudioManager::audio_3d_get_distance_factor() const {
+  audio_debug("MilesAudioManager::audio_3d_get_distance_factor()");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  return AIL_3D_distance_factor(mgr->_digital_driver);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_set_doppler_factor
+//       Access: Public
+//  Description: Exaggerates or diminishes the Doppler effect. 
+//               Defaults to 1.0
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::audio_3d_set_doppler_factor(float factor) {
+  audio_debug("MilesAudioManager::audio_3d_set_doppler_factor(factor="<<factor<<")");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  AIL_set_3D_doppler_factor(mgr->_digital_driver, factor);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_get_doppler_factor
+//       Access: Public
+//  Description: Get the factor controlling the Doppler effect.
+////////////////////////////////////////////////////////////////////
+float MilesAudioManager::audio_3d_get_doppler_factor() const {
+  audio_debug("MilesAudioManager::audio_3d_get_doppler_factor()");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  return AIL_3D_doppler_factor(mgr->_digital_driver);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_set_drop_off_factor
+//       Access: Public
+//  Description: Control the effect distance has on audability.
+//               Defaults to 1.0
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::audio_3d_set_drop_off_factor(float factor) {
+  audio_debug("MilesAudioManager::audio_3d_set_drop_off_factor("<<factor<<")");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  AIL_set_3D_rolloff_factor(mgr->_digital_driver, factor);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::audio_3d_get_drop_off_factor
+//       Access: Public
+//  Description: Get the factor controlling how quickly sound falls
+//               off with distance.
+////////////////////////////////////////////////////////////////////
+float MilesAudioManager::audio_3d_get_drop_off_factor() const {
+  audio_debug("MilesAudioManager::audio_3d_get_drop_off_factor()");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+  return AIL_3D_rolloff_factor(mgr->_digital_driver);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::set_speaker_configuration
+//       Access: Published
+//  Description: Works similarly to MilesAudioSound::set_speaker_levels,
+//               but specifies the 3D positions of the speakers in space.
+//
+//               Once a NULL value is found for a speaker position,
+//               no more speaker positions will be used.
+//
+//               Note that Y and Z are switched to translate from Miles's
+//               coordinate system.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+set_speaker_configuration(LVecBase3f *speaker1, LVecBase3f *speaker2, LVecBase3f *speaker3, LVecBase3f *speaker4, LVecBase3f *speaker5, LVecBase3f *speaker6, LVecBase3f *speaker7, LVecBase3f *speaker8, LVecBase3f *speaker9) {
+  audio_debug("MilesAudioManager::set_speaker_configuration()");
+
+  GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
+
+  MSSVECTOR3D speakers[9];
+
+  if(speaker1 != NULL) {
+    speakers[0].x = speaker1->get_x();
+    speakers[0].y = speaker1->get_z();
+    speakers[0].z = speaker1->get_y();
+  }
+  if(speaker2 != NULL) {
+    speakers[1].x = speaker2->get_x();
+    speakers[1].y = speaker2->get_z();
+    speakers[1].z = speaker2->get_y();
+  }
+  if(speaker3 != NULL) {
+    speakers[2].x = speaker3->get_x();
+    speakers[2].y = speaker3->get_z();
+    speakers[2].z = speaker3->get_y();
+  }
+  if(speaker4 != NULL) {
+    speakers[3].x = speaker4->get_x();
+    speakers[3].y = speaker4->get_z();
+    speakers[3].z = speaker4->get_y();
+  }
+  if(speaker5 != NULL) {
+    speakers[4].x = speaker5->get_x();
+    speakers[4].y = speaker5->get_z();
+    speakers[4].z = speaker5->get_y();
+  }
+  if(speaker6 != NULL) {
+    speakers[5].x = speaker6->get_x();
+    speakers[5].y = speaker6->get_z();
+    speakers[5].z = speaker6->get_y();
+  }
+  if(speaker7 != NULL) {
+    speakers[6].x = speaker7->get_x();
+    speakers[6].y = speaker7->get_z();
+    speakers[6].z = speaker7->get_y();
+  }
+  if(speaker8 != NULL) {
+    speakers[7].x = speaker8->get_x();
+    speakers[7].y = speaker8->get_z();
+    speakers[7].z = speaker8->get_y();
+  }
+  if(speaker9 != NULL) {
+    speakers[8].x = speaker9->get_x();
+    speakers[8].y = speaker9->get_z();
+    speakers[8].z = speaker9->get_y();
+  }
+
+  if(speaker1 == NULL) {
+    audio_error("No valid speaker positions specified in MilesAudioManager::set_speaker_configuration().");
+  } else if(speaker2 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 1, 1.0);
+  } else if(speaker3 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 2, 1.0);
+  } else if(speaker4 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 3, 1.0);
+  } else if(speaker5 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 4, 1.0);
+  } else if(speaker6 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 5, 1.0);
+  } else if(speaker7 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 6, 1.0);
+  } else if(speaker8 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 7, 1.0);
+  } else if(speaker9 == NULL) {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 8, 1.0);
+  } else {
+    AIL_set_speaker_configuration(mgr->_digital_driver, speakers, 9, 1.0);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::update()
 //       Access: Public, Virtual
@@ -754,7 +951,6 @@ stopping_sound(MilesAudioSound *audio) {
   }
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::load
 //       Access: Private
@@ -788,6 +984,7 @@ load(const Filename &file_name) {
   if (extension == "pz") {
     extension = Filename(sd->_basename.get_basename_wo_extension()).get_extension();
   }
+
   bool is_midi_file = (downcase(extension) == "mid");
 
   if ((miles_audio_preload_threshold == -1 || file->get_file_size() < (off_t)miles_audio_preload_threshold) ||

+ 14 - 0
panda/src/audiotraits/milesAudioManager.h

@@ -71,6 +71,20 @@ public:
   void release_sound(MilesAudioSound *audioSound);
   void cleanup();
 
+  // 3D spatialized sound support.
+  // Spatialized sound was originally added for FMOD, so there are parts of the
+  // interface in the Miles implementation that are a little more awkward than
+  // they would be otherwise.
+  virtual void audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float xy, float xz, float fx, float fy, float fz, float ux, float uy, float uz);
+  virtual void audio_3d_get_listener_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz, float *fx, float *fy, float *fz, float *ux, float *uy, float *uz);
+  virtual void audio_3d_set_distance_factor(float factor);
+  virtual float audio_3d_get_distance_factor() const;
+  virtual void audio_3d_set_doppler_factor(float factor);
+  virtual float audio_3d_get_doppler_factor() const;
+  virtual void audio_3d_set_drop_off_factor(float factor);
+  virtual float audio_3d_get_drop_off_factor() const;
+  virtual void set_speaker_configuration(LVecBase3f *speaker1, LVecBase3f *speaker2=NULL, LVecBase3f *speaker3=NULL, LVecBase3f *speaker4=NULL, LVecBase3f *speaker5=NULL, LVecBase3f *speaker6=NULL, LVecBase3f *speaker7=NULL, LVecBase3f *speaker8=NULL, LVecBase3f *speaker9=NULL);
+
   virtual void output(ostream &out) const;
   virtual void write(ostream &out) const;
 

+ 247 - 0
panda/src/audiotraits/milesAudioSample.cxx

@@ -291,6 +291,253 @@ output(ostream &out) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_3d_attributes
+//       Access: public
+//  Description: Set position and velocity of this sound.  Note that
+//               Y and Z are switched to translate from Miles's
+//               coordinate system.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
+  audio_debug("MilesAudioSample::set_3d_attributes()  Setting a sound's 3D Coordinates.");
+
+  if(_sample != 0) {
+    AIL_set_sample_3D_position(_sample, px, pz, py);
+    AIL_set_sample_3D_velocity_vector(_sample, vx, vz, vy);
+  } else {
+    audio_warning("_sample == 0 in MilesAudioSample::set_3d_attributes().");
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::get_3d_attributes
+//       Access: public
+//  Description: Get position and velocity of this sound.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz) {
+  audio_debug("MilesAudioSample::get_3d_attributes().");
+
+  if(_sample != 0) {
+    AIL_sample_3D_position(_sample, px, pz, py);
+    AIL_sample_3D_velocity(_sample, vx, vz, vy);
+  } else {
+    audio_warning("_sample == 0 in MilesAudioSample::get_3d_attributes().");
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_3d_min_distance
+//       Access: public
+//  Description: Set the distance that this sound begins to fall
+//               off.  With Miles's default falloff behavior, when
+//               the distance between the sound and the listener is
+//               doubled, the volume is halved, and vice versa.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::set_3d_min_distance(float dist) {
+  audio_debug("MilesAudioSample::set_3d_min_distance() Setting the sound's 3D min distance ( min= " << dist << " ) ");
+
+  if(_sample != 0) {
+    // Implementation is awkward, since Miles gets and sets min and max distances
+    // in a single operation.
+    float max_dist;
+    int auto_3D_wet_atten;
+    AIL_sample_3D_distances(_sample, &max_dist, NULL, &auto_3D_wet_atten);
+  
+    AIL_set_sample_3D_distances(_sample, max_dist, dist, auto_3D_wet_atten);
+  } else {
+    audio_warning("_sample == 0 in MilesAudioSample::set_3d_min_distance().");
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::get_3d_min_distance
+//       Access: public
+//  Description: Get the distance that this sound begins to fall off.
+////////////////////////////////////////////////////////////////////
+float MilesAudioSample::get_3d_min_distance() const {
+  audio_debug("MilesAudioSample::get_3d_min_distance() ");
+
+  if(_sample != 0) {
+    float min_dist;
+    AIL_sample_3D_distances(_sample, NULL, &min_dist, NULL);
+    return min_dist;
+  } else {
+    audio_warning("_sample == 0 in MilesAudioSample::get_3d_min_distance().");
+    return -1.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_3d_max_distance
+//       Access: public
+//  Description: Set the distance at which this sound is clipped to
+//               silence.  Note that this value does not affect
+//               the rate at which the sound falls off, but only
+//               the distance at which it gets clipped.
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::set_3d_max_distance(float dist) {
+  audio_debug("MilesAudioSample::set_3d_max_distance() Setting the sound's 3D max distance ( max= " << dist << " ) ");
+
+  if(_sample != 0) {
+    // Implementation is awkward, since Miles gets and sets min and max distances
+    // in a single operation.
+    float min_dist;
+    int auto_3D_wet_atten;
+    AIL_sample_3D_distances(_sample, NULL, &min_dist, &auto_3D_wet_atten);
+  
+    AIL_set_sample_3D_distances(_sample, dist, min_dist, auto_3D_wet_atten);
+  } else {
+    audio_warning("_sample == 0 in MilesAudioSample::set_3d_max_distance().");
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::get_3d_max_distance
+//       Access: public
+//  Description: Get the distance at which this sound is clipped to
+//               silence.
+////////////////////////////////////////////////////////////////////
+float MilesAudioSample::get_3d_max_distance() const {
+  audio_debug("MilesAudioSample::get_3d_max_distance() ");
+
+  if(_sample != 0) {
+    float max_dist;
+    AIL_sample_3D_distances(_sample, &max_dist, NULL, NULL);
+    return max_dist;
+  } else {
+    audio_warning("_sample == 0 in MilesAudioSample::get_3d_max_distance().");
+    return -1.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::get_speaker_level
+//       Access: Published
+//  Description: Get the level of a particular logical channel (speaker).
+//               "index" specifies which speaker in an array of all the
+//               logical channels currently in use to retrieve the level
+//               of.
+//
+//               For instance, in a standard 4.0 channel setup, speakers
+//               are setup as [frontLeft, frontRight, backLeft, backRight].
+//               Thus, get_speaker_level(2) will retrieve the level of the
+//               backLeft speaker.
+//
+//               The order in which speakers appear in the array for
+//               standard speaker setups is defined to be:
+//
+//                  FRONT_LEFT 
+//                  FRONT_RIGHT 
+//                  FRONT_CENTER 
+//                  LOW_FREQUENCY (sub woofer)
+//                  BACK_LEFT 
+//                  BACK_RIGHT 
+//                  FRONT_LEFT_OF_CENTER 
+//                  FRONT_RIGHT_OF_CENTER 
+//                  BACK_CENTER 
+//                  SIDE_LEFT 
+//                  SIDE_RIGHT 
+//                  TOP_CENTER 
+//                  TOP_FRONT_LEFT 
+//                  TOP_FRONT_CENTER 
+//                  TOP_FRONT_RIGHT 
+//                  TOP_BACK_LEFT 
+//                  TOP_BACK_CENTER 
+//                  TOP_BACK_RIGHT 
+//               
+////////////////////////////////////////////////////////////////////
+float MilesAudioSample::
+get_speaker_level(int index) {
+  audio_debug("MilesAudioSample::get_speaker_level(" << index << ")");
+
+  if(_sample != 0) {
+    int numLevels;
+    float *levels = AIL_sample_channel_levels(_sample, &numLevels);
+
+    if(index < numLevels) {
+      return levels[index];
+    } else {
+      audio_error("index out of range in MilesAudioSample::get_speaker_level.  numLevels: " << numLevels);
+      return -1.0;
+    }
+  } else {
+    audio_warning("Warning: MilesAudioSample::get_speaker_level only works for sounds that are currently playing");
+    return -1.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioSample::set_speaker_levels
+//       Access: Published
+//  Description: Set the output levels on the logical channels (speakers)
+//               for this sound.  Values should be in the range 0.0 to 1.0.
+//               Levels for up to nine channels may be specified. As soon
+//               as a level is reached that falls outside the range 0.0 to
+//               1.0, the levels specified up to that point will be sent
+//               and all other levels will be ignored.
+//
+//               The user must know what the current speaker setup is in order
+//               to know which level corresponds to which speaker.
+//
+//               This method will have no effect if 3D attributes have been
+//               set for this sound.
+//
+//               The order in which speakers appear in the array for
+//               standard speaker setups is defined to be:
+//
+//                  FRONT_LEFT 
+//                  FRONT_RIGHT 
+//                  FRONT_CENTER 
+//                  LOW_FREQUENCY (sub woofer)
+//                  BACK_LEFT 
+//                  BACK_RIGHT 
+//                  FRONT_LEFT_OF_CENTER 
+//                  FRONT_RIGHT_OF_CENTER 
+//                  BACK_CENTER 
+//                  SIDE_LEFT 
+//                  SIDE_RIGHT 
+//                  TOP_CENTER 
+//                  TOP_FRONT_LEFT 
+//                  TOP_FRONT_CENTER 
+//                  TOP_FRONT_RIGHT 
+//                  TOP_BACK_LEFT 
+//                  TOP_BACK_CENTER 
+//                  TOP_BACK_RIGHT 
+//               
+////////////////////////////////////////////////////////////////////
+void MilesAudioSample::
+set_speaker_levels(float level1, float level2, float level3, float level4, float level5, float level6, float level7, float level8, float level9) {
+  audio_debug("MilesAudioSample::set_speaker_levels()");
+
+  if(_sample != 0) {
+    float levels[9] = {level1, level2, level3, level4, level5, level6, level7, level8, level9};
+
+    if((level1 < 0.0) || (level1 > 1.0)) {
+      audio_error("No valid levels specified in MilesAudioSample::set_speaker_levels().");
+    } else if((level2 < 0.0) || (level2 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 1);
+    } else if((level3 < 0.0) || (level3 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 2);
+    } else if((level4 < 0.0) || (level4 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 3);
+    } else if((level5 < 0.0) || (level5 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 4);
+    } else if((level6 < 0.0) || (level6 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 5);
+    } else if((level7 < 0.0) || (level7 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 6);
+    } else if((level8 < 0.0) || (level8 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 7);
+    } else if((level9 < 0.0) || (level9 > 1.0)) {
+      AIL_set_sample_channel_levels(_sample, levels, 8);
+    } else {
+      AIL_set_sample_channel_levels(_sample, levels, 9);
+    }
+  } else {
+    audio_warning("Warning: MilesAudioSample::set_speaker_levels only works for sounds that are currently playing");
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioSample::internal_stop
 //       Access: Private

+ 14 - 0
panda/src/audiotraits/milesAudioSample.h

@@ -53,6 +53,20 @@ public:
   virtual void cleanup();
   virtual void output(ostream &out) const;
 
+  // 3D spatialized sound support.
+  // Spatialized sound was originally added for FMOD, so there are parts of the
+  // interface in the Miles implementation that are a little more awkward than
+  // they would be otherwise.
+  void set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz);
+  void get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz);
+  void set_3d_min_distance(float dist);
+  float get_3d_min_distance() const;
+  void set_3d_max_distance(float dist);
+  float get_3d_max_distance() const;
+
+  virtual float get_speaker_level(int index);
+  virtual void set_speaker_levels(float level1, float level2=-1.0f, float level3=-1.0f, float level4=-1.0f, float level5=-1.0f, float level6=-1.0f, float level7=-1.0f, float level8=-1.0f, float level9=-1.0f);
+
 private:
   void internal_stop();
   static void AILCALLBACK finish_callback(HSAMPLE sample);

+ 6 - 6
panda/src/chan/auto_bind.cxx

@@ -217,9 +217,9 @@ auto_bind(PandaNode *root_node, AnimControlCollection &controls,
     while (ai != anims.end()) {
       // Here's an anim with no matching parts.
       if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) {
-	AnimBundles::const_iterator abi;
-	for (abi = (*ai).second.begin(); abi != (*ai).second.end(); ++abi) {
-	  extra_anims.insert(*abi);
+        AnimBundles::const_iterator abi;
+        for (abi = (*ai).second.begin(); abi != (*ai).second.end(); ++abi) {
+          extra_anims.insert(*abi);
         }
       }
       ++ai;
@@ -228,9 +228,9 @@ auto_bind(PandaNode *root_node, AnimControlCollection &controls,
     while (pi != parts.end()) {
       // And here's a part with no matching anims.
       if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) {
-	PartBundles::const_iterator pbi;
-	for (pbi = (*pi).second.begin(); pbi != (*pi).second.end(); ++pbi) {
-	  extra_parts.insert(*pbi);
+        PartBundles::const_iterator pbi;
+        for (pbi = (*pi).second.begin(); pbi != (*pi).second.end(); ++pbi) {
+          extra_parts.insert(*pbi);
         }
       }
       ++pi;

+ 2 - 0
panda/src/configfiles/panda.prc.pp

@@ -10,6 +10,8 @@
 #### Generated automatically by $[PPREMAKE] $[PPREMAKE_VERSION] from $[notdir $[THISFILENAME]].
 ################################# DO NOT EDIT ###########################
 
+plugin-path $THIS_PRC_DIR/../lib
+
 # Let's set up a default window size of 800x600.  The user can
 # override this in his or her personal prc file.
 win-size 800 600

+ 2 - 2
panda/src/display/config_display.cxx

@@ -200,8 +200,8 @@ ConfigVariableBool window_inverted
 ConfigVariableBool red_blue_stereo
 ("red-blue-stereo", false,
  PRC_DESC("Set this true to create windows with red-blue stereo mode enabled "
-	  "by default, if the framebuffer does not support true stereo "
-	  "rendering."));
+          "by default, if the framebuffer does not support true stereo "
+          "rendering."));
 
 ConfigVariableString red_blue_stereo_colors
 ("red-blue-stereo-colors", "red cyan",

+ 22 - 0
panda/src/display/displayRegion.I

@@ -25,6 +25,17 @@ operator < (const DisplayRegion &other) const {
 }
 
 ////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::get_lens_index
+//       Access: Public
+//  Description: Gets the index into a lens_node lens array. 0 default
+////////////////////////////////////////////////////////////////////
+INLINE int DisplayRegion::
+get_lens_index() const {
+  CDReader cdata(_cycler);
+  return cdata->_lens_index;
+}
+
+///////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_dimensions
 //       Access: Published
 //  Description: Retrieves the coordinates of the DisplayRegion's
@@ -763,6 +774,17 @@ get_pixel_width() const {
   return _cdata->_pr - _cdata->_pl;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegionPipelineReader::get_lens_index
+//       Access: Public
+//  Description: Gets the index into a lens_node lens array. 0 default
+////////////////////////////////////////////////////////////////////
+INLINE int DisplayRegionPipelineReader::
+get_lens_index() const
+{
+  return _cdata->_lens_index;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegionPipelineReader::get_pixel_height
 //       Access: Public

+ 17 - 1
panda/src/display/displayRegion.cxx

@@ -96,6 +96,21 @@ cleanup() {
   cdata->_cull_result = NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::set_lens_index
+//       Access: Published
+//  Description: Sets the lens index, allows for multiple lenses to
+//               be attached to a camera.  This is useful for a 
+//               variety of setups, such as fish eye rendering.
+//               The default is 0.
+////////////////////////////////////////////////////////////////////
+void DisplayRegion::set_lens_index(int index) {
+  int pipeline_stage = Thread::get_current_pipeline_stage();
+  nassertv(pipeline_stage == 0);
+  CDWriter cdata(_cycler);
+  cdata->_lens_index = index;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_dimensions
 //       Access: Published, Virtual
@@ -734,7 +749,7 @@ DisplayRegion::CData::
 CData() :
   _l(0.), _r(1.), _b(0.), _t(1.),
   _pl(0), _pr(0), _pb(0), _pt(0),
-  _pbi(0), _pti(0),
+  _pbi(0), _pti(0), _lens_index(0),
   _camera_node((Camera *)NULL),
   _active(true),
   _sort(0),
@@ -760,6 +775,7 @@ CData(const DisplayRegion::CData &copy) :
   _pt(copy._pt),
   _pbi(copy._pbi),
   _pti(copy._pti),
+  _lens_index(copy._lens_index),
   _camera(copy._camera),
   _camera_node(copy._camera_node),
   _active(copy._active),

+ 6 - 0
panda/src/display/displayRegion.h

@@ -101,6 +101,9 @@ PUBLISHED:
   virtual void set_texture_reload_priority(int texture_reload_priority);
   INLINE int get_texture_reload_priority() const;
 
+  INLINE int  get_lens_index() const;
+  void set_lens_index(int index);
+
   virtual void set_cull_traverser(CullTraverser *trav);
   CullTraverser *get_cull_traverser();
 
@@ -192,6 +195,7 @@ private:
     int _pt;
     int _pbi;
     int _pti;
+    int _lens_index; // index into which lens of a camera is associated with this display region.  0 is default
     
     NodePath _camera;
     Camera *_camera_node;
@@ -303,6 +307,8 @@ public:
   INLINE int get_pixel_width() const;
   INLINE int get_pixel_height() const;
 
+  INLINE int get_lens_index() const;
+
 private:
   DisplayRegion *_object;
   Thread *_current_thread;

+ 23 - 0
panda/src/display/frameBufferProperties.I

@@ -163,6 +163,17 @@ get_multisamples() const {
   return _property[FBP_multisamples];
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FrameBufferProperties::get_coverage_samples
+//       Access: Published
+//  Description: If coverage samples are specified, and there is
+//               hardware support, we use coverage multisampling.
+////////////////////////////////////////////////////////////////////
+INLINE int FrameBufferProperties::
+get_coverage_samples() const {
+  return _property[FBP_coverage_samples];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::get_back_buffers
 //       Access: Published
@@ -325,6 +336,18 @@ set_multisamples(int n) {
   _specified[FBP_multisamples] = true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FrameBufferProperties::set_coverage_samples
+//       Access: Published
+//  Description: If coverage samples are specified, and there is
+//               hardware support, we use coverage multisampling
+////////////////////////////////////////////////////////////////////
+INLINE void FrameBufferProperties::
+set_coverage_samples(int n) {
+  _property[FBP_coverage_samples] = n;
+  _specified[FBP_coverage_samples] = true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::set_back_buffers
 //       Access: Published

+ 3 - 0
panda/src/display/frameBufferProperties.h

@@ -42,6 +42,7 @@ private:
 
     // This section can be in any order.
     FBP_multisamples,
+    FBP_coverage_samples,
     FBP_back_buffers,
     FBP_indexed_color,
     FBP_rgb_color,
@@ -68,6 +69,7 @@ PUBLISHED:
   INLINE int get_aux_hrgba() const;
   INLINE int get_aux_float() const;
   INLINE int get_multisamples() const;
+  INLINE int get_coverage_samples() const;
   INLINE int get_back_buffers() const;
   INLINE int get_indexed_color() const;
   INLINE int get_rgb_color() const;
@@ -85,6 +87,7 @@ PUBLISHED:
   INLINE void set_aux_hrgba(int n);
   INLINE void set_aux_float(int n);
   INLINE void set_multisamples(int n);
+  INLINE void set_coverage_samples(int n);
   INLINE void set_back_buffers(int n);
   INLINE void set_indexed_color(int n);
   INLINE void set_rgb_color(int n);

+ 1 - 1
panda/src/display/graphicsEngine.cxx

@@ -1671,7 +1671,7 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
   }
   camera_node->cleanup_aux_scene_data(current_thread);
 
-  Lens *lens = camera_node->get_lens();
+  Lens *lens = camera_node->get_lens( dr->get_lens_index() );
   if (lens == (Lens *)NULL) {
     // No lens, no draw.
     return NULL;

+ 9 - 1
panda/src/display/graphicsOutput.cxx

@@ -317,7 +317,15 @@ add_render_texture(Texture *tex, RenderTextureMode mode,
              (plane == RTP_aux_rgba_3)) {
     tex->set_format(Texture::F_rgba);
     tex->set_match_framebuffer_format(true);
-  } else {
+  } else if  ((plane == RTP_aux_hrgba_0)||
+              (plane == RTP_aux_hrgba_1)||
+              (plane == RTP_aux_hrgba_2)||
+              (plane == RTP_aux_hrgba_3)) {
+    tex->set_format(Texture::F_rgba16);
+    tex->set_match_framebuffer_format(true);
+  } else
+
+  {
     display_cat.error() <<
       "add_render_texture: invalid bitplane specified.\n";
     return;

+ 2 - 0
panda/src/display/graphicsStateGuardian.h

@@ -456,6 +456,8 @@ protected:
   bool _supports_depth_stencil;
   bool _supports_shadow_filter;
   bool _supports_basic_shaders;
+  bool _supports_framebuffer_multisample;
+  bool _supports_framebuffer_blit;
   
   bool _supports_stencil;
   bool _supports_stencil_wrap;

+ 1 - 0
panda/src/display/graphicsWindow.h

@@ -23,6 +23,7 @@
 #include "mouseData.h"
 #include "modifierButtons.h"
 #include "buttonEvent.h"
+#include "keyboardButton.h"
 #include "pnotify.h"
 #include "lightMutex.h"
 #include "lightReMutex.h"

+ 37 - 0
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -51,6 +51,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
                            _cg_context,
                            _cg_vprogram,
                            _cg_fprogram, 
+                           _cg_gprogram,        // CG2 CHANGE
                            _cg_parameter_map)) {
       return;
     }
@@ -95,6 +96,24 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
       success = false;
     }    
 
+    // BEGIN CG2 CHANGE
+    if (_cg_gprogram != 0)
+    {
+        hr = cgD3D9LoadProgram(_cg_gprogram, paramater_shadowing, assembly_flags);
+        if (FAILED (hr)) {
+          dxgsg9_cat.error()
+            << "geometry shader cgD3D9LoadProgram failed "
+            << D3DERRORSTRING(hr);
+
+          CGerror error = cgGetError();
+          if (error != CG_NO_ERROR) {
+            dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
+          }
+          success = false;
+        }
+    }
+    // END CG2 CHANGE
+
     if (!success) {
       release_resources();
     }
@@ -179,6 +198,7 @@ release_resources() {
     _cg_context = 0;
     _cg_vprogram = 0;
     _cg_fprogram = 0;
+    _cg_gprogram = 0;   // CG2 CHANGE
     _cg_parameter_map.clear();
   }
 #endif
@@ -232,6 +252,23 @@ bind(GSG *gsg) {
       
       bind_state = false;
     }
+
+    // BEGIN CG2 CHANGE
+    if (_cg_gprogram != 0)
+    {
+        hr = cgD3D9BindProgram(_cg_gprogram);
+        if (FAILED (hr)) {
+          dxgsg9_cat.error() << "cgD3D9BindProgram geometry shader failed " << D3DERRORSTRING(hr);
+
+          CGerror error = cgGetError();
+          if (error != CG_NO_ERROR) {
+            dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
+          }
+
+          bind_state = false;
+        }
+    }
+    // END CG2 CHANGE
   }
 #endif
 

+ 5 - 0
panda/src/dxgsg9/dxShaderContext9.h

@@ -92,6 +92,11 @@ private:
   CGcontext _cg_context;
   CGprogram _cg_vprogram;
   CGprogram _cg_fprogram;
+
+  // BEGIN CG2 CHANGE
+  CGprogram _cg_gprogram;   // Geometry program
+  // END CG2 CHANGE
+
   pvector <CGparameter> _cg_parameter_map;
 #endif
 

+ 1 - 1
panda/src/egg/eggGroupNode.h

@@ -150,7 +150,7 @@ PUBLISHED:
   void clear_connected_shading();
   void get_connected_shading();
   void unify_attributes(bool use_connected_shading, bool allow_per_primitive,
-			bool recurse);
+                        bool recurse);
   void apply_last_attribute(bool recurse);
   void apply_first_attribute(bool recurse);
   void post_apply_flat_attribute(bool recurse);

+ 10 - 10
panda/src/egg2pg/config_egg2pg.cxx

@@ -82,16 +82,16 @@ ConfigVariableBool egg_rigid_geometry
 ConfigVariableBool egg_flat_shading
 ("egg-flat-shading", false,
  PRC_DESC("Set this true to allow the egg loader to create geometry with the "
-	  "ShadeModelAttrib::M_flat attribute set.  It will do this only "
-	  "for geometry that has per-polygon normals and/or colors.  This "
-	  "allows the egg loader to avoid duplicating vertices when they "
- 	  "are shared between connected polygons with different normals or "
-	  "colors, but it prevents the flat-shaded geometry from being "
-	  "combined with any adjacent smooth-shaded geometry (for instance, "
-	  "as the result of a flatten_strong operation).  It is false by "
-	  "default, since flat-shaded geometry is rare; but you may wish "
-	  "to set it true if your scene largely or entirely consists of "
-	  "flat-shaded polygons."));
+          "ShadeModelAttrib::M_flat attribute set.  It will do this only "
+          "for geometry that has per-polygon normals and/or colors.  This "
+          "allows the egg loader to avoid duplicating vertices when they "
+          "are shared between connected polygons with different normals or "
+          "colors, but it prevents the flat-shaded geometry from being "
+          "combined with any adjacent smooth-shaded geometry (for instance, "
+          "as the result of a flatten_strong operation).  It is false by "
+          "default, since flat-shaded geometry is rare; but you may wish "
+          "to set it true if your scene largely or entirely consists of "
+          "flat-shaded polygons."));
 
 ConfigVariableBool egg_load_old_curves
 ("egg-load-old-curves", true,

+ 4 - 4
panda/src/egg2pg/eggLoader.cxx

@@ -962,22 +962,22 @@ load_texture(TextureDef &def, EggTexture *egg_tex) {
                                       egg_tex->get_alpha_fullpath(),
                                       wanted_channels,
                                       egg_tex->get_alpha_file_channel(),
-				      egg_tex->get_read_mipmaps(), options);
+                                      egg_tex->get_read_mipmaps(), options);
     } else {
       tex = TexturePool::load_texture(egg_tex->get_fullpath(),
                                       wanted_channels,
-				      egg_tex->get_read_mipmaps(), options);
+                                      egg_tex->get_read_mipmaps(), options);
     }
     break;
 
   case EggTexture::TT_3d_texture:
     tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
-				       egg_tex->get_read_mipmaps(), options);
+                                       egg_tex->get_read_mipmaps(), options);
     break;
 
   case EggTexture::TT_cube_map:
     tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
-				     egg_tex->get_read_mipmaps(), options);
+                                     egg_tex->get_read_mipmaps(), options);
     break;
   }
 

+ 1 - 1
panda/src/express/patchfile.cxx

@@ -265,7 +265,7 @@ read_header(const Filename &patch_file) {
 //       Access: Published
 //  Description: Perform one buffer's worth of patching
 //               Returns EU_ok while patching
-//				 Returns EU_success when done
+//               Returns EU_success when done
 //               If error happens will return one of:
 //               EU_error_abort : Patching has not been initiated
 //               EU_error_file_invalid : file is corrupted

+ 12 - 0
panda/src/glstuff/glGraphicsBuffer_src.I

@@ -11,3 +11,15 @@
 // with this source code in a file named "LICENSE."
 //
 ////////////////////////////////////////////////////////////////////
+
+INLINE int CLP(GraphicsBuffer)::
+get_multisample_count()
+{
+    return _requested_multisamples;
+}
+
+INLINE int CLP(GraphicsBuffer)::
+get_coverage_sample_count()
+{
+    return _requested_coverage_samples;
+}

+ 298 - 15
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -13,7 +13,6 @@
 
 TypeHandle CLP(GraphicsBuffer)::_type_handle;
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: glGraphicsBuffer::Constructor
 //       Access: Public
@@ -29,18 +28,56 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
                     GraphicsOutput *host) :
   GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
 {
-  // An FBO doesn't have a back buffer.
+  CLP(GraphicsStateGuardian) *glgsg;
+
+  // A FBO doesn't have a back buffer.
   _draw_buffer_type       = RenderBuffer::T_front;
   _screenshot_buffer_type = RenderBuffer::T_front;
 
   // Initialize these.
   _fbo = 0;
+  _fbo_multisample = 0;
+  DCAST_INTO_V(glgsg, _gsg);
+
+  if ( glgsg->get_supports_framebuffer_multisample() && glgsg->get_supports_framebuffer_blit() ) {
+    _requested_multisamples = fb_prop.get_multisamples();
+  }
+  else {
+    _requested_multisamples = 0;
+  }
+
+  if ( glgsg->get_supports_framebuffer_multisample_coverage_nv() && glgsg->get_supports_framebuffer_blit() ) {
+    _requested_coverage_samples = fb_prop.get_coverage_samples();
+        // Note:  Only 4 and 8 actual samples are supported by the extension, with 8 or 16 coverage samples.
+    if ( (_requested_coverage_samples <= 8) && (_requested_coverage_samples > 0) ) {
+      _requested_multisamples = 4;
+      _requested_coverage_samples = 8;
+    }
+    else if (_requested_coverage_samples > 8) {
+      if (_requested_multisamples < 8)
+        _requested_multisamples = 4;
+      else
+        _requested_multisamples = 8;
+      _requested_coverage_samples = 16;
+    }
+  }
+  else {
+    _requested_coverage_samples = 0;
+  }
+
+  float maxMultisamples = 0.0f;
+  glGetFloatv(GL_MAX_SAMPLES_EXT, &maxMultisamples);
+
+  if (_requested_multisamples > maxMultisamples)
+      _requested_multisamples = maxMultisamples;
+
   _rb_size_x = 0;
   _rb_size_y = 0;
   _cube_face_active = 0;
   for (int i=0; i<RTP_COUNT; i++) {
     _rb[i] = 0;
     _tex[i] = 0;
+    _rbm[i] = 0;
   }
 
   for (int f = 0; f < 6; f++) {
@@ -108,7 +145,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
     return false;
   }
   
-  // Figure out the desired size of the buffer.
+  // Figure out the desired size of the  buffer.
   if (mode == FM_render) {
     rebuild_bitplanes();
     clear_cube_map_selection();
@@ -156,6 +193,8 @@ check_fbo() {
       GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n"; break;
     case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
       GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED_EXT\n"; break;
+    case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
+      GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT\n"; break;
     default:
       GLCAT.error() << "OTHER PROBLEM\n"; break;
     }
@@ -256,7 +295,6 @@ rebuild_bitplanes() {
         _textures[i]._rtm_mode = RTM_copy_texture;
         continue;
       }
-
       // If I can't find an appropriate slot, or if there's
       // already a texture bound to this slot, then punt
       // this texture.  
@@ -271,8 +309,8 @@ rebuild_bitplanes() {
 
     // For all slots, update the slot.
 
+//    bind_slot(rb_resize, attach, RTP_depth_stencil, GL_DEPTH_ATTACHMENT_EXT);
     bind_slot(rb_resize, attach, RTP_depth, GL_DEPTH_ATTACHMENT_EXT);
-    bind_slot(rb_resize, attach, RTP_depth_stencil, GL_DEPTH_ATTACHMENT_EXT);
     bind_slot(rb_resize, attach, RTP_color, GL_COLOR_ATTACHMENT0_EXT);
     int next = GL_COLOR_ATTACHMENT1_EXT;
     for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
@@ -287,6 +325,32 @@ rebuild_bitplanes() {
       bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i), next);
       next += 1;
     }
+    // Setup any required multisample buffers.
+    if (_requested_multisamples) {
+      if (_fbo_multisample == 0) {
+        glgsg->_glGenFramebuffers(1, &_fbo_multisample);
+      }
+      glgsg->bind_fbo(_fbo_multisample);
+      bind_slot(rb_resize, attach, RTP_depth, GL_DEPTH_ATTACHMENT_EXT);
+      bind_slot_multisample(rb_resize, attach, RTP_color, GL_COLOR_ATTACHMENT0_EXT);
+      int next = GL_COLOR_ATTACHMENT1_EXT;
+      for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
+        bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next);
+        next += 1;
+      }
+      for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
+        bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i), next);
+        next += 1;
+      }
+      for (int i=0; i<_fb_properties.get_aux_float(); i++) {
+        bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i), next);
+        next += 1;
+      }
+      glEnable(GL_MULTISAMPLE_ARB);
+    }
+    else {
+      glDisable(GL_MULTISAMPLE_ARB);
+    }
   }
   else {
     // make an FBO for each cubemap face
@@ -365,9 +429,18 @@ rebuild_bitplanes() {
     
     glgsg -> bind_fbo(_cubemap_fbo [0]);
   }
-  
+
+  if (  (_fb_properties.get_rgb_color() > 0) ||
+        (_fb_properties.get_aux_hrgba() > 0) ) {
+    glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+  }
+  else {
+    glDrawBuffer(GL_NONE);
+    glReadBuffer(GL_NONE);
+  }
+
   _cube_face_active = 0;
-  
   report_my_gl_errors();
 }
 
@@ -382,6 +455,23 @@ bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum atta
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
 
+  GLuint glFormat = GL_RGBA;
+  switch (slot) {
+    case RTP_aux_rgba_0:
+    case RTP_aux_rgba_1:
+    case RTP_aux_rgba_2:
+    case RTP_aux_rgba_3:
+        glFormat = GL_RGBA;
+        break;
+    case RTP_aux_hrgba_0:
+    case RTP_aux_hrgba_1:
+    case RTP_aux_hrgba_2:
+    case RTP_aux_hrgba_3:
+        glFormat = GL_RGBA16F_ARB;
+        break;
+  };
+
+
   Texture *tex = attach[slot];
   if (tex) {
     // If the texture is already bound to the slot, and it's
@@ -397,8 +487,12 @@ bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum atta
     tex->set_x_size(_rb_size_x);
     tex->set_y_size(_rb_size_y);
     tex->set_pad_size(_rb_size_x - _x_size, _rb_size_y - _y_size);
+    _use_depth_stencil = false;
     if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) {
-      tex->set_format(Texture::F_depth_stencil);
+      if ( _gsg->get_supports_depth_stencil() && tex->get_format() == Texture::F_depth_stencil ) {
+        tex->set_component_type(Texture::T_unsigned_int_24_8);
+        _use_depth_stencil = true;
+      }
       TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
       nassertv(tc != (TextureContext *)NULL);
       CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
@@ -411,7 +505,7 @@ bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum atta
                                        GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
                                        gtc->_index, 0);
       }
-      if (_gsg->get_supports_depth_stencil()) {
+      if (_use_depth_stencil) {
         if (tex->get_texture_type() == Texture::TT_2d_texture) {
           glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
                                          GL_TEXTURE_2D, gtc->_index, 0);
@@ -422,7 +516,11 @@ bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum atta
         }
       }
     } else {
-//      tex->set_format(Texture::F_rgba);
+      if (glFormat == GL_RGBA16F_ARB)
+        tex->set_format(Texture::F_rgba16);
+      else
+        tex->set_format(Texture::F_rgba);
+
       TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
       nassertv(tc != (TextureContext *)NULL);
       CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
@@ -495,7 +593,7 @@ bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum atta
                                           GL_RENDERBUFFER_EXT, rb);
       }
     } else {
-      glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA8_EXT,
+      glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, glFormat,
                                     _rb_size_x, _rb_size_y);
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
       glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
@@ -508,6 +606,106 @@ bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum atta
   }
 }
   
+////////////////////////////////////////////////////////////////////
+//     Function: glGraphicsBuffer::bind_slot_multisample
+//       Access: Private
+//  Description: Attaches incoming Texture or renderbuffer to the 
+//               required bitplanes for the 2 FBOs comprising a
+//               multisample graphics buffer.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsBuffer)::
+bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
+    CLP(GraphicsStateGuardian) *glgsg;
+    DCAST_INTO_V(glgsg, _gsg);
+
+    if ((_rbm[slot] != 0)&&(!rb_resize)) {
+      return;
+    }
+    if (_rbm[slot] != 0) {
+      glgsg->_glDeleteRenderbuffers(1, &(_rbm[slot]));
+      _rbm[slot] = 0;
+    }
+    glgsg->_glBindFramebuffer(GL_FRAMEBUFFER_EXT, _fbo_multisample);
+    glgsg->_glGenRenderbuffers(1, &(_rbm[slot]));
+    // Allocate and bind the renderbuffer.
+    Texture *tex = attach[slot];// if there is a texture map, use it's format as needed.
+
+    if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) {
+      if ( _gsg->get_supports_depth_stencil() && _use_depth_stencil ) {
+        glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]);
+        if (_requested_coverage_samples)
+          glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples,
+                                                             _requested_multisamples, GL_DEPTH_STENCIL_EXT,
+                                                             _rb_size_x, _rb_size_y);
+        else
+          glgsg->_glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT, _requested_multisamples, GL_DEPTH_STENCIL_EXT,
+                                      _rb_size_x, _rb_size_y);
+        GLint givenSamples = -1;
+        glgsg->_glGetRenderbufferParameteriv( GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &givenSamples);
+        glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
+        glgsg->_glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+                                          GL_RENDERBUFFER_EXT, _rbm[slot]);
+        glgsg->_glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
+                                          GL_RENDERBUFFER_EXT, _rbm[slot]);
+      } else {
+        glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]);
+        GLuint format = GL_DEPTH_COMPONENT;
+        if (tex)
+        {
+            if (tex->get_format() == Texture::F_depth_component16)
+                format = GL_DEPTH_COMPONENT16;
+            if (tex->get_format() == Texture::F_depth_component24)
+                format = GL_DEPTH_COMPONENT24;
+            if (tex->get_format() == Texture::F_depth_component32)
+                format = GL_DEPTH_COMPONENT32;
+        }
+        if (_requested_coverage_samples)
+          glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples,
+                                                             _requested_multisamples, format,
+                                                             _rb_size_x, _rb_size_y);
+        else
+          glgsg->_glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT, _requested_multisamples, format,
+                                        _rb_size_x, _rb_size_y);
+        GLint givenSamples = -1;
+        glgsg->_glGetRenderbufferParameteriv( GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &givenSamples);
+        glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
+        glgsg->_glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+                                          GL_RENDERBUFFER_EXT, _rbm[slot]);
+      }
+    }
+    else {
+        Texture *Tex = attach[slot];
+        GLuint glFormat = GL_RGBA;
+        switch (slot) {
+            case RTP_aux_rgba_0:
+            case RTP_aux_rgba_1:
+            case RTP_aux_rgba_2:
+            case RTP_aux_rgba_3:
+                glFormat = GL_RGBA;
+                break;
+            case RTP_aux_hrgba_0:
+            case RTP_aux_hrgba_1:
+            case RTP_aux_hrgba_2:
+            case RTP_aux_hrgba_3:
+                glFormat = GL_RGBA16F_ARB;
+                break;
+        };
+        glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]);
+        if (_requested_coverage_samples)
+            glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples,
+                                        _requested_multisamples, glFormat, _rb_size_x, _rb_size_y);
+        else
+            glgsg->_glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT, _requested_multisamples, glFormat,
+                                        _rb_size_x, _rb_size_y);
+        GLint givenSamples = -1;
+        glgsg->_glGetRenderbufferParameteriv( GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &givenSamples);
+        glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
+        glgsg->_glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT, attachpoint,
+                                        GL_RENDERBUFFER_EXT, _rbm[slot]);
+    }
+    glgsg->report_my_gl_errors();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: glGraphicsBuffer::generate_mipmaps
 //       Access: Private
@@ -547,7 +745,7 @@ generate_mipmaps() {
 //               should do whatever finalization is required.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
-end_frame(FrameMode mode, Thread *current_thread) {
+                         end_frame(FrameMode mode, Thread *current_thread) {
   end_frame_spam(mode);
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
 
@@ -558,8 +756,75 @@ end_frame(FrameMode mode, Thread *current_thread) {
   // Unbind the FBO
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
-  glgsg->bind_fbo(0);
   
+  // Resolve Multisample rendering if using it.
+  if (_requested_multisamples && _fbo_multisample) {
+    glgsg->report_my_gl_errors();
+    glgsg->_glBindFramebuffer( GL_DRAW_FRAMEBUFFER_EXT, _fbo );
+    glgsg->_glBindFramebuffer( GL_READ_FRAMEBUFFER_EXT, _fbo_multisample );
+
+    // If the depth buffer is shared, resolve it only on the last to render FBO.
+    int do_depth_blit = 0;
+    if (_shared_depth_buffer) {
+      CLP(GraphicsBuffer) *graphics_buffer = NULL;
+      CLP(GraphicsBuffer) *highest_sort_graphics_buffer = NULL;
+      list <CLP(GraphicsBuffer) *>::iterator graphics_buffer_iterator;
+
+      int max_sort_order = 0;
+      for (graphics_buffer_iterator = _shared_depth_buffer_list.begin();
+           graphics_buffer_iterator != _shared_depth_buffer_list.end();
+           graphics_buffer_iterator++) {
+        graphics_buffer = (*graphics_buffer_iterator);
+        if (graphics_buffer) {      
+          // this call removes the entry from the list
+          if ( graphics_buffer->get_sort() >= max_sort_order ) {
+            max_sort_order = graphics_buffer->get_sort();
+            highest_sort_graphics_buffer = graphics_buffer;
+          }
+        }      
+      }
+      if ( max_sort_order == this->get_sort() )
+        do_depth_blit = 1;
+    }
+    else
+      do_depth_blit = 1;
+    if (do_depth_blit)
+      glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y, 
+                                GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, 
+                                GL_NEAREST);
+    else
+      glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y, 
+                                GL_COLOR_BUFFER_BIT, 
+                                GL_NEAREST);
+    // Now handle the other color buffers.
+    int next = GL_COLOR_ATTACHMENT1_EXT;
+    for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
+      glReadBuffer( next );
+      glDrawBuffer( next );
+      glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y, 
+                                GL_COLOR_BUFFER_BIT, GL_NEAREST);
+      next += 1;
+    }
+    for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
+      glReadBuffer( next );
+      glDrawBuffer( next );
+      glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y, 
+                                GL_COLOR_BUFFER_BIT, GL_NEAREST);
+      next += 1;
+    }
+    for (int i=0; i<_fb_properties.get_aux_float(); i++) {
+      glReadBuffer( next );
+      glDrawBuffer( next );
+      glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y, 
+                                GL_COLOR_BUFFER_BIT, GL_NEAREST);
+      next += 1;
+    }
+    glReadBuffer( GL_COLOR_ATTACHMENT0_EXT );
+    glDrawBuffer( GL_COLOR_ATTACHMENT0_EXT );
+    glgsg->report_my_gl_errors();
+  }
+  glgsg->bind_fbo(0);
+
   if (mode == FM_render) {
     generate_mipmaps();
   }
@@ -646,7 +911,7 @@ open_buffer() {
     _fb_properties.set_stencil_bits(0);
   }
   _fb_properties.set_accum_bits(0);
-  _fb_properties.set_multisamples(0);
+  _fb_properties.set_multisamples(_host->get_fb_properties().get_multisamples());
   _fb_properties.set_back_buffers(0);
   _fb_properties.set_indexed_color(0);
   _fb_properties.set_rgb_color(1);
@@ -688,6 +953,14 @@ close_buffer() {
     }
     _tex[i] = 0;
   }
+  // Delete the renderbuffers.
+  for (int i=0; i<RTP_COUNT; i++) {
+    if (_rbm[i] != 0) {
+      glgsg->_glDeleteRenderbuffers(1, &(_rbm[i]));
+      _rb[i] = 0;
+    }
+    _tex[i] = 0;
+  }
   _rb_size_x = 0;
   _rb_size_y = 0;
   report_my_gl_errors();
@@ -744,6 +1017,17 @@ share_depth_buffer(GraphicsOutput *graphics_output) {
       state = false;    
     }
 
+    // Check multisample compatibility.
+    if ( this->get_multisample_count() != input_graphics_output->get_multisample_count() ) {
+      GLCAT.error() << "share_depth_buffer: non matching multisamples \n";
+      state = false;    
+    }
+
+    if ( this->get_coverage_sample_count() != input_graphics_output->get_coverage_sample_count() ) {
+      GLCAT.error() << "share_depth_buffer: non matching multisamples \n";
+      state = false;    
+    }
+
     if (state) {    
       // let the input GraphicsOutput know that there is an object 
       // sharing its depth buffer      
@@ -752,7 +1036,6 @@ share_depth_buffer(GraphicsOutput *graphics_output) {
       state = true;
     }
   }
-  
   report_my_gl_errors();
   return state;
 }

+ 20 - 1
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -1,5 +1,6 @@
 // Filename: glGraphicsBuffer_src.h
 // Created by:  jyelon (15Jan06)
+// Modified by: kleonard (27Jun07)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -31,6 +32,7 @@
 //               * Supports cumulative render-to-texture.
 //               * Faster than pbuffers.
 //               * Can render onto a texture without clearing it first.
+//               * Supports multisample antialiased rendering.
 //
 //               Some of these deserve a little explanation. 
 //               Auxiliary bitplanes are additional bitplanes above
@@ -48,6 +50,12 @@
 //               available (although it may still be possible to
 //               create a wglGraphicsBuffer or glxGraphicsBuffer).
 //
+//               This class now also uses the extensions 
+//               EXT_framebuffer_multisample and EXT_framebuffer_blit
+//               to allow for multisample antialiasing these offscreen
+//               render targets.  If these extensions are unavailable
+//               the buffer will render as if multisamples is 0.
+//
 ////////////////////////////////////////////////////////////////////
 
 class EXPCL_GL CLP(GraphicsBuffer) : public GraphicsBuffer {
@@ -84,17 +92,25 @@ private:
   
   void bind_slot(bool rb_resize, Texture **attach,
                  RenderTexturePlane plane, GLenum attachpoint);
+  void bind_slot_multisample(bool rb_resize, Texture **attach,
+                 RenderTexturePlane plane, GLenum attachpoint);
   bool check_fbo();
   void generate_mipmaps();
   void rebuild_bitplanes();
   
-  GLuint      _fbo;
+  GLuint      _fbo; // allows for textures to be attached for render to texture.
+  GLuint      _fbo_multisample; // all render buffers, resolves to _fbo at end of frame.
+  int         _requested_multisamples;
+  int         _requested_coverage_samples;
+  bool        _use_depth_stencil;
+
   int         _rb_size_x;
   int         _rb_size_y;
   int         _cube_face_active;
   PT(Texture) _tex[RTP_COUNT];
   GLuint      _rb[RTP_COUNT];
   GLenum      _attach_point[RTP_COUNT];
+  GLuint      _rbm[RTP_COUNT];  // A mirror of _rb, for the multisample FBO.
 
   GLuint      _cubemap_fbo [6];
   
@@ -115,6 +131,9 @@ public:
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
 
+  INLINE int get_multisample_count();
+  INLINE int get_coverage_sample_count();
+
 private:
   static TypeHandle _type_handle;
 

+ 34 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -552,6 +552,40 @@ get_clip_plane_id(int index) const {
   return GL_CLIP_PLANE0 + index;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_multisample
+//       Access: Public
+//  Description: Returns if this glGsg supports multisample 
+//               antialiasing for framebuffer objects.
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(GraphicsStateGuardian)::
+get_supports_framebuffer_multisample() {
+    return _supports_framebuffer_multisample;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_multisample
+//       Access: Public
+//  Description: Returns if this glGsg supports multisample 
+//               antialiasing for framebuffer objects.
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(GraphicsStateGuardian)::
+get_supports_framebuffer_multisample_coverage_nv() {
+    return _supports_framebuffer_multisample_coverage_nv;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_blit
+//       Access: Public
+//  Description: Returns if this glGsg supports multisample 
+//               antialiasing for framebuffer objects.
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(GraphicsStateGuardian)::
+get_supports_framebuffer_blit() {
+    return _supports_framebuffer_blit;
+}
+
 #ifndef NDEBUG
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::UsageTextureKey::Constructor

+ 76 - 17
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -74,6 +74,10 @@ PStatCollector CLP(GraphicsStateGuardian)::_primitive_batches_display_list_pcoll
 PStatCollector CLP(GraphicsStateGuardian)::_vertices_display_list_pcollector("Vertices:Display lists");
 PStatCollector CLP(GraphicsStateGuardian)::_vertices_immediate_pcollector("Vertices:Immediate mode");
 
+// KZL hack.  These track PRC settings.
+bool _track_errors = 1;
+bool _allow_flush = 1;
+
 // The following noop functions are assigned to the corresponding
 // glext function pointers in the class, in case the functions are not
 // defined by the GL, just so it will always be safe to call the
@@ -442,7 +446,7 @@ reset() {
     In the meantime, you must put both "matrix-palette 1" and
     "gl-matrix-palette 1" in your Config.prc to exercise the new
     code. */
-  if (!ConfigVariableBool("gl-matrix-palette", false, PRC_DESC("Temporary hack variable protecting untested code.  See glGraphicsStateGuardian_src.cxx."))) {
+  if (!CLP(matrix_palette)) {
     if (_supports_matrix_palette) {
       if (GLCAT.is_debug()) {
         GLCAT.debug() << "Forcing off matrix palette support.\n";
@@ -752,12 +756,15 @@ reset() {
     if (basic_shaders_only) {
       _shader_caps._active_vprofile = (int)CG_PROFILE_ARBVP1;
       _shader_caps._active_fprofile = (int)CG_PROFILE_ARBFP1;
+      _shader_caps._active_gprofile = (int)0;                     // CG2 CHANGE: No geometry shader if only using basic
     } else { 
       _shader_caps._active_vprofile = (int)cgGLGetLatestProfile(CG_GL_VERTEX);
       _shader_caps._active_fprofile = (int)cgGLGetLatestProfile(CG_GL_FRAGMENT);
+      _shader_caps._active_gprofile = (int)cgGLGetLatestProfile(CG_GL_GEOMETRY);  // CG2 CHANGE
     }
     _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40;
     _shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40;
+    _shader_caps._ultimate_gprofile = (int)CG_PROFILE_GPU_GP;   // CG2 CHANGE
     _glBindProgram = (PFNGLBINDPROGRAMARBPROC)
       get_extension_func(GLPREFIX_QUOTED, "BindProgramARB");
     // Bug workaround for radeons.
@@ -808,6 +815,24 @@ reset() {
       get_extension_func(GLPREFIX_QUOTED, "GenerateMipmapEXT");
   }
 
+  if ( has_extension("GL_EXT_framebuffer_multisample") ) {
+    _supports_framebuffer_multisample = true;
+    _glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)
+        get_extension_func(GLPREFIX_QUOTED, "RenderbufferStorageMultisampleEXT");
+  }
+
+  if ( has_extension("GL_NV_framebuffer_multisample_coverage") ) {
+    _supports_framebuffer_multisample_coverage_nv = true;
+    _glRenderbufferStorageMultisampleCoverage = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC)
+        get_extension_func(GLPREFIX_QUOTED, "RenderbufferStorageMultisampleCoverageNV");
+  }
+
+  if ( has_extension("GL_EXT_framebuffer_blit") ) {
+    _supports_framebuffer_blit = true;
+    _glBlitFramebuffer = (PFNGLBLITFRAMEBUFFEREXTPROC)
+        get_extension_func(GLPREFIX_QUOTED, "BlitFramebufferEXT");
+  }
+
   _glDrawBuffers = NULL;
   if (is_at_least_gl_version(2, 0)) {
     _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
@@ -1141,6 +1166,16 @@ reset() {
 #endif  // OPENGLES_1
   _dithering_enabled = false;
 
+  // calling glGetError() forces a sync, this turns it off if you want to.
+  if (ConfigVariableBool("gl-force-no-error", false, PRC_DESC("make the gl GSG not report errors, as doing so is a performance hit.")))
+      _track_errors = false;
+  else
+      _track_errors = true;
+  if (ConfigVariableBool("gl-force-no-flush", false, PRC_DESC("make the gl GSG not flush, as doing so is a performance hit.  This is a dangerour setting.")))
+      _allow_flush = false;
+  else
+      _allow_flush = true;
+
   _current_shader = (Shader *)NULL;
   _current_shader_context = (CLP(ShaderContext) *)NULL;
   _vertex_array_shader = (Shader *)NULL;
@@ -1725,7 +1760,9 @@ end_frame(Thread *current_thread) {
   // necessary if this is a single-buffered visual, so that the frame
   // will be finished drawing before we return to the application.
   // It's not clear what effect this has on our total frame time.
-  gl_flush();
+  if (_allow_flush) {
+    gl_flush();
+  }
   maybe_gl_finish();
 
   report_my_gl_errors();
@@ -4494,7 +4531,8 @@ draw_immediate_composite_primitives(const GeomPrimitivePipelineReader *reader, G
 void CLP(GraphicsStateGuardian)::
 gl_flush() const {
   PStatTimer timer(_flush_pcollector);
-  GLP(Flush)();
+  if (_allow_flush)
+      GLP(Flush)();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -4504,7 +4542,10 @@ gl_flush() const {
 ////////////////////////////////////////////////////////////////////
 GLenum CLP(GraphicsStateGuardian)::
 gl_get_error() const {
-  return GLP(GetError)();
+  if (_track_errors)
+      return GLP(GetError)();
+  else
+      return GL_NO_ERROR;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -4518,6 +4559,8 @@ gl_get_error() const {
 bool CLP(GraphicsStateGuardian)::
 report_errors_loop(int line, const char *source_file, GLenum error_code,
                    int &error_count) {
+  if (!_track_errors)
+    return GL_NO_ERROR;
 #ifndef NDEBUG
   while ((CLP(max_errors) < 0 || error_count < CLP(max_errors)) &&
          (error_code != GL_NO_ERROR)) {
@@ -5210,7 +5253,11 @@ get_component_type(Texture::ComponentType component_type) {
     return GL_UNSIGNED_SHORT;
   case Texture::T_float:
     return GL_FLOAT;
-
+  case Texture::T_unsigned_int_24_8:
+    if (_supports_depth_stencil)
+      return GL_UNSIGNED_INT_24_8_EXT;
+    else
+      return GL_UNSIGNED_BYTE;
   default:
     GLCAT.error() << "Invalid Texture::Type value!\n";
     return GL_UNSIGNED_BYTE;
@@ -5304,7 +5351,7 @@ get_external_image_format(Texture *tex) const {
   case Texture::F_depth_component:
     return GL_DEPTH_COMPONENT;
   case Texture::F_depth_stencil:
-    if (_supports_depth_stencil) {
+    if (CLP(force_depth_stencil)) {
       return GL_DEPTH_STENCIL_EXT;
     } else {
       return GL_DEPTH_COMPONENT;
@@ -5488,6 +5535,12 @@ get_internal_image_format(Texture *tex) const {
     return GL_COLOR_INDEX;
   case Texture::F_depth_component:
     return GL_DEPTH_COMPONENT;
+  case Texture::F_depth_component16:
+    return GL_DEPTH_COMPONENT16;
+  case Texture::F_depth_component24:
+    return GL_DEPTH_COMPONENT24;
+  case Texture::F_depth_component32:
+    return GL_DEPTH_COMPONENT32;
   case Texture::F_depth_stencil:
     if (_supports_depth_stencil) {
       return GL_DEPTH_STENCIL_EXT;
@@ -7753,7 +7806,6 @@ upload_texture_image(CLP(TextureContext) *gtc,
       }
     }
   }
-
   int highest_level = 0;
 
 #ifdef OPENGLES_1  // OpenGL ES doesn't support texture subloads.
@@ -7883,10 +7935,15 @@ upload_texture_image(CLP(TextureContext) *gtc,
     }
 
     if (num_ram_mipmap_levels == 0) {
-      if (external_format == GL_DEPTH_STENCIL_EXT || external_format == GL_DEPTH_COMPONENT) {
+      if ( (external_format == GL_DEPTH_STENCIL_EXT) && get_supports_depth_stencil() ) {
+        GLP(TexImage2D)(page_target, 0, GL_DEPTH_STENCIL_EXT,
+                        width, height, 0,
+                        GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
+      }
+      else if (external_format == GL_DEPTH_COMPONENT) {
         GLP(TexImage2D)(page_target, 0, internal_format,
                         width, height, 0,
-                        external_format, GL_UNSIGNED_INT_24_8_EXT, NULL);
+                        GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
       } else {
         GLP(TexImage2D)(page_target, 0, internal_format,
                         width, height, 0,
@@ -8579,16 +8636,18 @@ extract_texture_image(PTA_uchar &image, size_t &page_size,
   }
 
   // Now see if we were successful.
-  GLenum error_code = GLP(GetError)();
-  if (error_code != GL_NO_ERROR) {
-    GLCAT.error()
-      << "Unable to extract texture for " << *tex
-      << ", mipmap level " << n
-      << " : " << get_error_string(error_code) << "\n";
+  if (_track_errors)
+  {
+    GLenum error_code = GLP(GetError)();
+    if (error_code != GL_NO_ERROR) {
+        GLCAT.error()
+        << "Unable to extract texture for " << *tex
+        << ", mipmap level " << n
+        << " : " << get_error_string(error_code) << "\n";
     nassertr(false, false);
-    return false;
+        return false;
+    }
   }
-
   return true;
 #endif  // OPENGLES_1
 }

+ 10 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -306,7 +306,7 @@ protected:
   static GLenum get_texture_filter_type(Texture::FilterType ft,
                                         bool ignore_mipmaps);
   static Texture::FilterType get_panda_filter_type(GLenum ft);
-  static GLenum get_component_type(Texture::ComponentType component_type);
+  GLenum get_component_type(Texture::ComponentType component_type);
   GLint get_external_image_format(Texture *tex) const;
   GLint get_internal_image_format(Texture *tex) const;
   static bool is_mipmap_filter(GLenum min_filter);
@@ -505,6 +505,15 @@ public:
   PFNGLGENERATEMIPMAPEXTPROC _glGenerateMipmap;
   PFNGLBINDPROGRAMARBPROC _glBindProgram;
 
+  bool _supports_framebuffer_multisample;
+  bool _supports_framebuffer_multisample_coverage_nv;
+  INLINE bool get_supports_framebuffer_multisample();
+  INLINE bool get_supports_framebuffer_multisample_coverage_nv();
+  PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC _glRenderbufferStorageMultisample;
+  PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC _glRenderbufferStorageMultisampleCoverage;
+  bool _supports_framebuffer_blit;
+  INLINE bool get_supports_framebuffer_blit();
+  PFNGLBLITFRAMEBUFFEREXTPROC _glBlitFramebuffer;
   PFNGLDRAWBUFFERSPROC _glDrawBuffers;
   int _max_draw_buffers;
 

+ 41 - 1
panda/src/glstuff/glShaderContext_src.cxx

@@ -39,6 +39,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
                            _cg_context,
                            _cg_vprogram,
                            _cg_fprogram, 
+                           _cg_gprogram,    // CG2 CHANGE
                            _cg_parameter_map)) {
       return;
     }
@@ -64,6 +65,27 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
     if (glGetError() != GL_NO_ERROR) {
       GLCAT.error() << "GL error in ShaderContext constructor\n";
     }
+    // BEGIN CG2 CHANGE
+    if (_cg_gprogram != 0)
+    {
+        cgGLLoadProgram(_cg_gprogram);
+        if (GLCAT.is_debug()) {
+          GLCAT.debug()
+            << "Loaded geom prog: " << _cg_gprogram << "\n";
+        }
+
+        CGerror gerror = cgGetError();
+        if (gerror != CG_NO_ERROR) {
+          const char *str = (const char *)GLP(GetString)(GL_PROGRAM_ERROR_STRING_ARB);
+          GLCAT.error() << "Could not load Cg geometry program:" << s->get_filename() << " (" << 
+            cgGetProfileString(cgGetProgramProfile(_cg_gprogram)) << " " << str << ")\n";
+          release_resources();
+        }
+        if (glGetError() != GL_NO_ERROR) {
+          GLCAT.error() << "GL error in ShaderContext constructor\n";
+        }
+    }
+    // END CG2 CHANGE
   }
 #endif
 }
@@ -89,9 +111,10 @@ release_resources() {
 #ifdef HAVE_CG
   if (_cg_context) {
     cgDestroyContext(_cg_context);
-    _cg_context = 0;
+    _cg_context  = 0;
     _cg_vprogram = 0;
     _cg_fprogram = 0;
+    _cg_gprogram = 0;   // CG2 CHANGE
     _cg_parameter_map.clear();
   }
   if (glGetError() != GL_NO_ERROR) {
@@ -120,6 +143,15 @@ bind(GSG *gsg) {
     cgGLBindProgram(_cg_vprogram);
     cgGLEnableProfile(cgGetProgramProfile(_cg_fprogram));
     cgGLBindProgram(_cg_fprogram);
+
+    // BEGIN CG2 CHANGE
+    if (_cg_gprogram != 0)
+    {
+        cgGLEnableProfile(cgGetProgramProfile(_cg_gprogram));
+        cgGLBindProgram(_cg_gprogram);
+    }
+    // END CG2 CHANGE
+
     cg_report_errors();
     if (glGetError() != GL_NO_ERROR) {
       GLCAT.error() << "GL error in ShaderContext::bind\n";
@@ -139,6 +171,14 @@ unbind() {
   if (_cg_context != 0) {
     cgGLDisableProfile(cgGetProgramProfile(_cg_vprogram));
     cgGLDisableProfile(cgGetProgramProfile(_cg_fprogram));
+
+    // BEGIN CG2 CHANGE
+    if (_cg_gprogram != 0)
+    {
+        cgGLDisableProfile(cgGetProgramProfile(_cg_gprogram));
+    }
+    // END CG2 CHANGE
+
     cg_report_errors();
     if (glGetError() != GL_NO_ERROR) {
       GLCAT.error() << "GL error in ShaderContext::unbind\n";

+ 5 - 0
panda/src/glstuff/glShaderContext_src.h

@@ -50,6 +50,11 @@ private:
   CGcontext _cg_context;
   CGprogram _cg_vprogram;
   CGprogram _cg_fprogram;
+
+  // BEGIN CG2 CHANGE
+  CGprogram _cg_gprogram;
+  // END CG2 CHANGE
+
   pvector <CGparameter> _cg_parameter_map;
   void cg_report_errors();
 #endif

+ 8 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -140,6 +140,14 @@ ConfigVariableBool CLP(finish)
             "more accurately reflect where the graphics bottlenecks are.  "
             "This variable is enabled only if PStats is compiled in."));
 
+ConfigVariableBool CLP(force_depth_stencil)
+  ("gl-force-depth-stencil", false, 
+   PRC_DESC("Temporary hack variable 7x00 vs 8x00 nVidia bug.  See glGraphicsStateGuardian_src.cxx."));
+
+ConfigVariableBool CLP(matrix_palette)
+  ("gl-matrix-palette", false, 
+   PRC_DESC("Temporary hack variable protecting untested code.  See glGraphicsStateGuardian_src.cxx."));
+
 extern ConfigVariableBool CLP(parallel_arrays);
 
 void CLP(init_classes)() {

+ 2 - 0
panda/src/glstuff/glmisc_src.h

@@ -37,6 +37,8 @@ extern ConfigVariableInt CLP(max_errors);
 extern ConfigVariableEnum<GeomEnums::UsageHint> CLP(min_buffer_usage_hint);
 extern ConfigVariableBool CLP(debug_buffers);
 extern ConfigVariableBool CLP(finish);
+extern ConfigVariableBool CLP(force_depth_stencil);
+extern ConfigVariableBool CLP(matrix_palette);
 
 extern EXPCL_GL void CLP(init_classes)();
 

+ 12 - 3
panda/src/glstuff/panda_glext.h

@@ -3390,7 +3390,7 @@ extern "C" {
 #include <stddef.h>
 #ifndef GL_VERSION_2_0
 /* GL type for program/shader text */
-typedef char GLchar;			/* native character */
+typedef char GLchar;            /* native character */
 #endif
 
 #ifndef GL_VERSION_1_5
@@ -3407,8 +3407,8 @@ typedef ptrdiff_t GLsizeiptrARB;
 
 #ifndef GL_ARB_shader_objects
 /* GL types for handling shader object handles and program/shader text */
-typedef char GLcharARB;		/* native character */
-typedef unsigned int GLhandleARB;	/* shader object handle */
+typedef char GLcharARB;     /* native character */
+typedef unsigned int GLhandleARB;   /* shader object handle */
 #endif
 
 /* GL types for "half" precision (s10e5) float data in host memory */
@@ -6925,6 +6925,15 @@ GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum
 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
 #endif
 
+#ifndef GL_NV_framebuffer_multisample_coverage
+#define GL_NV_framebuffer_multisample_coverage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum, GLsizei, GLsizei, GLenum, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverage_samples, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+
 #ifndef GL_MESAX_texture_stack
 #define GL_MESAX_texture_stack 1
 #endif

+ 5 - 5
panda/src/glxdisplay/config_glxdisplay.cxx

@@ -43,16 +43,16 @@ ConfigVariableBool x_error_abort
 ConfigVariableBool glx_get_proc_address
 ("glx-get-proc-address", true,
  PRC_DESC("Set this to true to allow the use of glxGetProcAddress(), if "
-	  "it is available, to query the OpenGL extension functions.  This "
-	  "is the standard way to query extension functions."));
+          "it is available, to query the OpenGL extension functions.  This "
+          "is the standard way to query extension functions."));
 
 
 ConfigVariableBool glx_get_os_address
 ("glx-get-os-address", true,
  PRC_DESC("Set this to true to allow Panda to query the OpenGL library "
-	  "directly using standard operating system calls to locate "
-	  "addresses of extension functions.  This will be done only "
-	  "if glxGetProcAddress() cannot be used for some reason."));
+          "directly using standard operating system calls to locate "
+          "addresses of extension functions.  This will be done only "
+          "if glxGetProcAddress() cannot be used for some reason."));
 
 ConfigVariableInt x_wheel_up_button
 ("x-wheel-up-button", 4,

+ 18 - 18
panda/src/glxdisplay/glxGraphicsStateGuardian.cxx

@@ -29,7 +29,7 @@ TypeHandle glxGraphicsStateGuardian::_type_handle;
 ////////////////////////////////////////////////////////////////////
 glxGraphicsStateGuardian::
 glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
-			 glxGraphicsStateGuardian *share_with) :
+                         glxGraphicsStateGuardian *share_with) :
   GLGraphicsStateGuardian(engine, pipe)
 {
   _share_context=0;
@@ -137,7 +137,7 @@ get_properties(FrameBufferProperties &properties, XVisualInfo *visual) {
 ////////////////////////////////////////////////////////////////////
 void glxGraphicsStateGuardian::
 get_properties_advanced(FrameBufferProperties &properties, 
-			bool &pbuffer_supported, bool &pixmap_supported,
+                        bool &pbuffer_supported, bool &pixmap_supported,
                         bool &slow, fbconfig config) {
 
   properties.clear();
@@ -218,8 +218,8 @@ get_properties_advanced(FrameBufferProperties &properties,
 ////////////////////////////////////////////////////////////////////
 void glxGraphicsStateGuardian::
 choose_pixel_format(const FrameBufferProperties &properties,
-		    Display *display,
-		    int screen, bool need_pbuffer, bool need_pixmap) {
+                    Display *display,
+                    int screen, bool need_pbuffer, bool need_pixmap) {
 
   _display = display;
   _screen = screen;
@@ -291,8 +291,8 @@ choose_pixel_format(const FrameBufferProperties &properties,
       _visuals = glXGetVisualFromFBConfig(_display, _fbconfig);
       _visual = _visuals;
       if (_visual) {
-	_fbprops = best_props;
-	return;
+        _fbprops = best_props;
+        return;
       }
     }
     // This really shouldn't happen, so I'm not too careful about cleanup.
@@ -319,9 +319,9 @@ choose_pixel_format(const FrameBufferProperties &properties,
       get_properties(fbprops, _visuals+i);
       int quality = fbprops.get_quality(properties);
       if (quality > best_quality) {
-	best_quality = quality;
-	best_result = i;
-	best_props = fbprops;
+        best_quality = quality;
+        best_result = i;
+        best_props = fbprops;
       }
     }
   }
@@ -499,19 +499,19 @@ do_get_extension_func(const char *prefix, const char *name) {
       const char *funcName = NULL;
       
       if (glx_is_at_least_version(1, 4)) {
-	funcName = "glXGetProcAddress";
-	
+        funcName = "glXGetProcAddress";
+
       } else if (has_extension("GLX_ARB_get_proc_address")) {
-	funcName = "glXGetProcAddressARB";
+        funcName = "glXGetProcAddressARB";
       }
       
       if (funcName != NULL) {
-	_glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)get_system_func(funcName);
-	if (_glXGetProcAddress == NULL) {
-	  glxdisplay_cat.warning()
-	    << "Couldn't load function " << funcName
-	    << ", GL extensions may be unavailable.\n";
-	}
+        _glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)get_system_func(funcName);
+        if (_glXGetProcAddress == NULL) {
+          glxdisplay_cat.warning()
+            << "Couldn't load function " << funcName
+            << ", GL extensions may be unavailable.\n";
+        }
       }
 
       _checked_get_proc_address = true;

+ 5 - 5
panda/src/glxdisplay/glxGraphicsStateGuardian.h

@@ -78,15 +78,15 @@ public:
   INLINE const FrameBufferProperties &get_fb_properties() const;
   void get_properties(FrameBufferProperties &properties, XVisualInfo *visual);
   void get_properties_advanced(FrameBufferProperties &properties,
-			       bool &pbuffer_supported, bool &pixmap_supported,
+                               bool &pbuffer_supported, bool &pixmap_supported,
                                bool &slow, fbconfig config);
   void choose_pixel_format(const FrameBufferProperties &properties, 
-			   Display *_display,
-			   int _screen,
-			   bool need_pbuffer, bool need_pixmap);
+                           Display *_display,
+                           int _screen,
+                           bool need_pbuffer, bool need_pixmap);
   
   glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
-			   glxGraphicsStateGuardian *share_with);
+                           glxGraphicsStateGuardian *share_with);
 
   virtual ~glxGraphicsStateGuardian();
 

+ 51 - 51
panda/src/glxdisplay/glxGraphicsWindow.cxx

@@ -1080,14 +1080,14 @@ open_raw_mice()
       char phys[256];
       char uniq[256];
       if ((ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)||
-	  (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0)||
-	  (ioctl(fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0)||
-	  (ioctl(fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0)) {
-	close(fd);
-	glxdisplay_cat.error() <<
-	  "Opening raw mice: ioctl failed on " << fn << "\n";
+          (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0)||
+          (ioctl(fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0)||
+          (ioctl(fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0)) {
+        close(fd);
+        glxdisplay_cat.error() <<
+          "Opening raw mice: ioctl failed on " << fn << "\n";
       } else {
-	if (test_bit(EV_REL, evtypes) || test_bit(EV_ABS, evtypes)) {
+        if (test_bit(EV_REL, evtypes) || test_bit(EV_ABS, evtypes)) {
           for (char *p=name; *p; p++) {
             if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
               *p = '_';
@@ -1098,29 +1098,29 @@ open_raw_mice()
               *p = '_';
             }
           }
-	  string full_id = ((string)name) + "." + uniq;
-	  MouseDeviceInfo inf;
-	  inf._fd = fd;
-	  inf._input_device_index = _input_devices.size();
-	  inf._io_buffer = "";
-	  _mouse_device_info.push_back(inf);
-	  GraphicsWindowInputDevice device =
-	    GraphicsWindowInputDevice::pointer_only(this, full_id);
+          string full_id = ((string)name) + "." + uniq;
+          MouseDeviceInfo inf;
+          inf._fd = fd;
+          inf._input_device_index = _input_devices.size();
+          inf._io_buffer = "";
+          _mouse_device_info.push_back(inf);
+          GraphicsWindowInputDevice device =
+            GraphicsWindowInputDevice::pointer_only(this, full_id);
           add_input_device(device);
-	  glxdisplay_cat.info() << "Raw mouse " <<
-	    inf._input_device_index << " detected: " << full_id << "\n";
-	  any_mice = true;
-	} else {
-	  close(fd);
-	}
+          glxdisplay_cat.info() << "Raw mouse " <<
+            inf._input_device_index << " detected: " << full_id << "\n";
+          any_mice = true;
+        } else {
+          close(fd);
+        }
       }
     } else {
       if ((errno == ENOENT)||(errno == ENOTDIR)) {
-	break;
+        break;
       } else {
-	any_present = true;
-	glxdisplay_cat.error() << 
-	  "Opening raw mice: " << strerror(errno) << " " << fn << "\n";
+        any_present = true;
+        glxdisplay_cat.error() << 
+          "Opening raw mice: " << strerror(errno) << " " << fn << "\n";
       }
     }
   }
@@ -1153,21 +1153,21 @@ poll_raw_mice()
     // Read all bytes into buffer.
     if (inf._fd >= 0) {
       while (1) {
-	char tbuf[1024];
-	int nread = read(inf._fd, tbuf, sizeof(tbuf));
-	if (nread > 0) {
-	  inf._io_buffer += string(tbuf, nread);
-	} else {
-	  if ((nread < 0)&&((errno == EWOULDBLOCK) || (errno==EAGAIN))) {
-	    break;
-	  }
-	  close(inf._fd);
-	  inf._fd = -1;
-	  break;
-	}
+        char tbuf[1024];
+        int nread = read(inf._fd, tbuf, sizeof(tbuf));
+        if (nread > 0) {
+          inf._io_buffer += string(tbuf, nread);
+        } else {
+          if ((nread < 0)&&((errno == EWOULDBLOCK) || (errno==EAGAIN))) {
+            break;
+          }
+          close(inf._fd);
+          inf._fd = -1;
+          break;
+        }
       }
     }
-
+    
     // Process events.
     int nevents = inf._io_buffer.size() / sizeof(struct input_event);
     if (nevents == 0) {
@@ -1179,21 +1179,21 @@ poll_raw_mice()
     int y = dev.get_raw_pointer().get_y();
     for (int i=0; i<nevents; i++) {
       if (events[i].type == EV_REL) {
-	if (events[i].code == REL_X) x += events[i].value;
-	if (events[i].code == REL_Y) y += events[i].value;
+        if (events[i].code == REL_X) x += events[i].value;
+        if (events[i].code == REL_Y) y += events[i].value;
       } else if (events[i].type == EV_ABS) {
-	if (events[i].code == ABS_X) x = events[i].value;
-	if (events[i].code == ABS_Y) y = events[i].value;
+        if (events[i].code == ABS_X) x = events[i].value;
+        if (events[i].code == ABS_Y) y = events[i].value;
       } else if (events[i].type == EV_KEY) {
-	if ((events[i].code >= BTN_MOUSE)&&(events[i].code < BTN_MOUSE+8)) {
-	  int btn = events[i].code - BTN_MOUSE;
-	  dev.set_pointer_in_window(x,y);
-	  if (events[i].value) {
-	    dev.button_down(MouseButton::button(btn));
-	  } else {
-	    dev.button_up(MouseButton::button(btn));
-	  }
-	}
+        if ((events[i].code >= BTN_MOUSE)&&(events[i].code < BTN_MOUSE+8)) {
+          int btn = events[i].code - BTN_MOUSE;
+          dev.set_pointer_in_window(x,y);
+          if (events[i].value) {
+            dev.button_down(MouseButton::button(btn));
+          } else {
+            dev.button_up(MouseButton::button(btn));
+          }
+        }
       }
     }
     inf._io_buffer.erase(0,nevents*sizeof(struct input_event));

+ 3 - 0
panda/src/gobj/Sources.pp

@@ -12,6 +12,7 @@
 
   #define SOURCES \
     adaptiveLru.I adaptiveLru.h \
+    animateVerticesRequest.I animateVerticesRequest.h \
     bufferContext.I bufferContext.h \
     bufferContextChain.I bufferContextChain.h \
     bufferResidencyTracker.I bufferResidencyTracker.h \
@@ -79,6 +80,7 @@
     
   #define INCLUDED_SOURCES \
     adaptiveLru.cxx \
+    animateVerticesRequest.cxx \
     bufferContext.cxx \
     bufferContextChain.cxx \
     bufferResidencyTracker.cxx \
@@ -146,6 +148,7 @@
 
   #define INSTALL_HEADERS \
     adaptiveLru.I adaptiveLru.h \
+    animateVerticesRequest.I animateVerticesRequest.h \
     bufferContext.I bufferContext.h \
     bufferContextChain.I bufferContextChain.h \
     bufferResidencyTracker.I bufferResidencyTracker.h \

+ 41 - 0
panda/src/gobj/animateVerticesRequest.I

@@ -0,0 +1,41 @@
+// Filename: animateVerticesRequest.I
+// Created by:  pratt (20Nov07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimateVerticesRequest::Constructor
+//       Access: Published
+//  Description: Create a new AnimateVerticesRequest.
+////////////////////////////////////////////////////////////////////
+INLINE AnimateVerticesRequest::
+AnimateVerticesRequest(GeomVertexData *geom_vertex_data) :
+  _geom_vertex_data(geom_vertex_data),
+  _is_ready(false)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimateVerticesRequest::is_ready
+//       Access: Published
+//  Description: Returns true if this request has completed, false if
+//               it is still pending.
+////////////////////////////////////////////////////////////////////
+INLINE bool AnimateVerticesRequest::
+is_ready() const {
+  return _is_ready;
+}

+ 41 - 0
panda/src/gobj/animateVerticesRequest.cxx

@@ -0,0 +1,41 @@
+// Filename: animateVerticesRequest.cxx
+// Created by:  pratt (20Nov07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "animateVerticesRequest.h"
+#include "geomVertexData.h"
+
+TypeHandle AnimateVerticesRequest::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimateVerticesRequest::do_task
+//       Access: Protected, Virtual
+//  Description: Performs the task: that is, calls animate vertices
+//               on _geom_vertex_data.
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus AnimateVerticesRequest::
+do_task() {
+  Thread *current_thread = Thread::get_current_thread();
+
+  // There is no need to store or return a result.  The GeomVertexData caches
+  // the result and it will be used later in the rendering process.
+  _geom_vertex_data->animate_vertices(true, current_thread);
+  _is_ready = true;
+
+  // Don't continue the task; we're done.
+  return AsyncTask::DS_done;
+}

+ 79 - 0
panda/src/gobj/animateVerticesRequest.h

@@ -0,0 +1,79 @@
+// Filename: animateVerticesRequest.h
+// Created by:  pratt (20Nov07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef ANIMATEVERTICESREQUEST
+#define ANIMATEVERTICESREQUEST
+
+#include "pandabase.h"
+
+#include "asyncTask.h"
+#include "geomVertexData.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : AnimateVerticesRequest
+// Description : This class object manages a single asynchronous
+//               request to animate vertices on a GeomVertexData
+//               object.  animate_vertices will be called with
+//               force=true (i.e. blocking) in a sub-thread (if
+//               threading is available).  No result is stored or
+//               returned from this object.  It is expected that the
+//               result will be cached and available for immediate
+//               use later during rendering.  Thus it is important
+//               that the main thread block while these requests
+//               are being run (presumably on multiple CPUs/cores),
+//               to ensure that the data has been computed by the
+//               time it's needed.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_PGRAPH AnimateVerticesRequest : public AsyncTask {
+public:
+  ALLOC_DELETED_CHAIN(AnimateVerticesRequest);
+
+PUBLISHED:
+  INLINE AnimateVerticesRequest(GeomVertexData *geom_vertex_data);
+  
+  INLINE bool is_ready() const;
+  
+protected:
+    virtual AsyncTask::DoneStatus do_task();
+  
+private:
+  PT(GeomVertexData) _geom_vertex_data;
+  bool _is_ready;
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    AsyncTask::init_type();
+    register_type(_type_handle, "AnimateVerticesRequest",
+                  AsyncTask::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 "animateVerticesRequest.I"
+
+#endif

+ 5 - 3
panda/src/gobj/config_gobj.cxx

@@ -12,6 +12,7 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#include "animateVerticesRequest.h"
 #include "bufferContext.h"
 #include "config_util.h"
 #include "config_gobj.h"
@@ -108,9 +109,9 @@ ConfigVariableBool keep_texture_ram
 ConfigVariableBool compressed_textures
 ("compressed-textures", false,
  PRC_DESC("Set this to true to compress textures as they are loaded into "
-	  "texture memory, if the driver supports this.  Specifically, this "
-	  "changes the meaning of set_compression(Texture::CM_default) to "
-	  "Texture::CM_on."));
+          "texture memory, if the driver supports this.  Specifically, this "
+          "changes the meaning of set_compression(Texture::CM_default) to "
+          "Texture::CM_on."));
 
 ConfigVariableBool driver_compress_textures
 ("driver-compress-textures", false,
@@ -453,6 +454,7 @@ PRC_DESC("If this is nonzero, it represents an artificial delay, "
  
 
 ConfigureFn(config_gobj) {
+  AnimateVerticesRequest::init_type();
   BufferContext::init_type();
   Geom::init_type();
   GeomPipelineReader::init_type();

+ 4 - 4
panda/src/gobj/geom.cxx

@@ -1257,7 +1257,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
   LPoint3f min, max;
   bool found_any = false;
   do_calc_tight_bounds(min, max, found_any, vertex_data,
-		       false, LMatrix4f::ident_mat(), 
+                       false, LMatrix4f::ident_mat(), 
                        InternalName::get_vertex(),
                        cdata, current_thread);
 
@@ -1310,9 +1310,9 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
 ////////////////////////////////////////////////////////////////////
 void Geom::
 do_calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
-		     bool &found_any, 
-		     const GeomVertexData *vertex_data,
-		     bool got_mat, const LMatrix4f &mat,
+                     bool &found_any, 
+                     const GeomVertexData *vertex_data,
+                     bool got_mat, const LMatrix4f &mat,
                      const InternalName *column_name,
                      const CData *cdata, Thread *current_thread) const {
   Primitives::const_iterator pi;

+ 10 - 10
panda/src/gobj/geom.h

@@ -148,18 +148,18 @@ public:
             const GeomMunger *munger,
             const GeomVertexData *vertex_data,
             bool force, Thread *current_thread) const;
-
+  
   INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
-				bool &found_any, 
-				const GeomVertexData *vertex_data,
-				bool got_mat, const LMatrix4f &mat,
+                                bool &found_any, 
+                                const GeomVertexData *vertex_data,
+                                bool got_mat, const LMatrix4f &mat,
                                 Thread *current_thread) const;
   INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
                                 bool &found_any, Thread *current_thread) const;
   INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
-				bool &found_any, 
-				const GeomVertexData *vertex_data,
-				bool got_mat, const LMatrix4f &mat,
+                                bool &found_any, 
+                                const GeomVertexData *vertex_data,
+                                bool got_mat, const LMatrix4f &mat,
                                 const InternalName *column_name,
                                 Thread *current_thread) const;
 
@@ -172,9 +172,9 @@ private:
   void compute_internal_bounds(CData *cdata, Thread *current_thread) const;
 
   void do_calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
-			    bool &found_any, 
-			    const GeomVertexData *vertex_data,
-			    bool got_mat, const LMatrix4f &mat,
+                            bool &found_any, 
+                            const GeomVertexData *vertex_data,
+                            bool got_mat, const LMatrix4f &mat,
                             const InternalName *column_name,
                             const CData *cdata, Thread *current_thread) const;
 

+ 1 - 0
panda/src/gobj/gobj_composite1.cxx

@@ -1,4 +1,5 @@
 #include "adaptiveLru.cxx"
+#include "animateVerticesRequest.cxx"
 #include "bufferContext.cxx"
 #include "bufferContextChain.cxx"
 #include "bufferResidencyTracker.cxx"

+ 237 - 58
panda/src/gobj/shader.cxx

@@ -619,7 +619,6 @@ compile_parameter(const ShaderArgId  &arg_id,
     if (!cp_parse_eol(p, pieces, next)) {
       return false;
     }
-    
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     return true;
@@ -1079,6 +1078,12 @@ cg_release_resources() {
     cgDestroyProgram(_cg_fprogram);
     _cg_fprogram = 0;
   }
+  // BEGIN CG2 CHANGE
+  if (_cg_gprogram != 0) {
+    cgDestroyProgram(_cg_gprogram);
+    _cg_gprogram = 0;
+  }
+  // END CG2 CHANGE
   if (_cg_context != 0) {
     cgDestroyContext(_cg_context);
     _cg_context = 0;
@@ -1091,69 +1096,55 @@ cg_release_resources() {
 //  Description: xyz
 ////////////////////////////////////////////////////////////////////
 CGprogram Shader::
-cg_compile_entry_point(const char *entry, const ShaderCaps &caps, bool fshader)
+cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type)  // CG2 CHANGE
 {
   CGprogram prog;
   CGerror err;
   const char *compiler_args[100];
   int nargs = 0;
-  int override = fshader ? _cg_fprofile : _cg_vprofile;
-  int active = fshader ? caps._active_fprofile : caps._active_vprofile;
-  int ultimate = fshader ? caps._ultimate_fprofile : caps._ultimate_vprofile;
+  
+  int active, ultimate;
+
+  switch(type)
+  {
+  case ST_VERTEX:
+      active   = caps._active_vprofile;
+      ultimate = caps._ultimate_vprofile;
+      break;
+
+  case ST_FRAGMENT:
+      active   = caps._active_fprofile;
+      ultimate = caps._ultimate_fprofile;
+      break;
+
+  case ST_GEOMETRY:
+      active   = caps._active_gprofile;
+      ultimate = caps._ultimate_gprofile;
+      break;
+  };
+  
+  // END CG2 CHANGE
 
   cgGetError();
 
-  if (fshader && caps._bug_list.count(SBUG_ati_draw_buffers)) {
+  if (type == ST_FRAGMENT && caps._bug_list.count(SBUG_ati_draw_buffers)) { // CG2 CHANGE
     compiler_args[nargs++] = "-po";
     compiler_args[nargs++] = "ATI_draw_buffers";
   }
   compiler_args[nargs] = 0;
 
-  // If someone has explicitly set a profile, use it.
-  if (override != (int)CG_PROFILE_UNKNOWN) {
-    prog = cgCreateProgram(_cg_context, CG_SOURCE, _text.c_str(),
-                           (CGprofile)override, entry, (const char **)compiler_args);
-    err = cgGetError();
-    if (err == CG_NO_ERROR) {
-      return prog;
-    }
-    if (err == CG_COMPILER_ERROR) {
-      string listing = cgGetLastListing(_cg_context);
-      vector_string errlines;
-      tokenize(listing, errlines, "\n");
-      for (int i=0; i<(int)errlines.size(); i++) {
-        string line = trim(errlines[i]);
-        if (line != "") {
-          gobj_cat.error() << get_filename() << ": " << errlines[i] << "\n";
-        }
-      }
-    } else {
-      gobj_cat.error() << get_filename() << ": " << cgGetErrorString(err) << "\n";
-    }
-    if (fshader) {
-      gobj_cat.error() << "Fragment shader failed to compile with profile '"
-        << cgGetProfileString((CGprofile)override) << "'!\n";
-    } else {
-      gobj_cat.error() << "Vertex shader failed to compile with profile '"
-        << cgGetProfileString((CGprofile)override) << "'!\n";
-    }
-    if (prog != 0) {
-      cgDestroyProgram(prog);
-    }
-    return 0;
-  }
-  
   if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
     prog = cgCreateProgram(_cg_context, CG_SOURCE, _text.c_str(),
                            (CGprofile)active, entry, (const char **)compiler_args);
-    if (cgGetError() == CG_NO_ERROR) {
+    err = cgGetError();
+    if (err == CG_NO_ERROR) {
       return prog;
     }
     if (prog != 0) {
       cgDestroyProgram(prog);
     }
   }
-  
+
   prog = cgCreateProgram(_cg_context, CG_SOURCE, _text.c_str(),
                          (CGprofile)ultimate, entry, (const char **)NULL);
   err = cgGetError();
@@ -1211,8 +1202,18 @@ cg_compile_shader(const ShaderCaps &caps) {
     return false;
   }
   
-  _cg_vprogram = cg_compile_entry_point("vshader", caps, false);
-  _cg_fprogram = cg_compile_entry_point("fshader", caps, true);
+  _cg_vprogram = cg_compile_entry_point("vshader", caps, ST_VERTEX);    // CG2 CHANGE
+  _cg_fprogram = cg_compile_entry_point("fshader", caps, ST_FRAGMENT);  // CG2 CHANGE
+
+  // BEGIN CG2 CHANGE
+  if (_text.find("gshader") != -1)
+  {
+      _cg_gprogram = cg_compile_entry_point("gshader", caps, ST_GEOMETRY);
+  }
+  else
+  {
+  }
+  // END CG2 CHANGE
 
   if ((_cg_vprogram == 0)||(_cg_fprogram == 0)) {
     cg_release_resources();
@@ -1228,17 +1229,19 @@ cg_compile_shader(const ShaderCaps &caps) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 bool Shader::
-cg_analyze_entry_point(CGprogram prog, bool fshader) {
+cg_analyze_entry_point(CGprogram prog, ShaderType type /*bool fshader*/) {  // CG2 CHANGE
   CGparameter parameter;
   bool success = true;
   for (parameter = cgGetFirstLeafParameter(prog, CG_PROGRAM);
        parameter != 0;
        parameter = cgGetNextLeafParameter(parameter)) {
     CGenum vbl = cgGetParameterVariability(parameter);
+
     if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
       ShaderArgId id;
       id._name = cgGetParameterName(parameter);
-      id._fshader = fshader;
+
+      id._type  = type;         // CG2 CHANGE
       id._seqno = -1;
       success &= compile_parameter(id,
                                    cg_parameter_type(parameter),
@@ -1290,7 +1293,7 @@ cg_analyze_shader(const ShaderCaps &caps) {
     return false;
   }
 
-  if (!cg_analyze_entry_point(_cg_fprogram, true)) {
+  if (!cg_analyze_entry_point(_cg_fprogram, ST_FRAGMENT)) { // CG2 CHANGE
     cg_release_resources();
     clear_parameters();
     return false;
@@ -1303,12 +1306,23 @@ cg_analyze_shader(const ShaderCaps &caps) {
     return false;
   }
 
-  if (!cg_analyze_entry_point(_cg_vprogram, false)) {
+  if (!cg_analyze_entry_point(_cg_vprogram, ST_VERTEX)) {   // CG2 CHANGE
     cg_release_resources();
     clear_parameters();
     return false;
   }
   
+  // BEGIN CG2 CHANGE
+  if (_cg_gprogram != 0)
+  {
+      if (!cg_analyze_entry_point(_cg_gprogram, ST_GEOMETRY)) {
+          cg_release_resources();
+          clear_parameters();
+          return false;
+      }
+  }
+  // END CG2 CHANGE
+
   // Assign sequence numbers to all parameters.
   int seqno = 0;
   for (int i=0; i<(int)_mat_spec.size(); i++) {
@@ -1325,12 +1339,23 @@ cg_analyze_shader(const ShaderCaps &caps) {
   if (gobj_cat.is_debug()) {
     const char *vertex_program;
     const char *pixel_program;
+    const char *geometry_program;   // CG2 CHANGE
+
+    vertex_program   = cgGetProgramString (_cg_vprogram, CG_COMPILED_PROGRAM);
+    pixel_program    = cgGetProgramString (_cg_fprogram, CG_COMPILED_PROGRAM);
 
-    vertex_program = cgGetProgramString (_cg_vprogram, CG_COMPILED_PROGRAM);
-    pixel_program = cgGetProgramString (_cg_fprogram, CG_COMPILED_PROGRAM);
+    // BEGIN CG2 CHANGE
+    if (_cg_gprogram != 0)
+        geometry_program = cgGetProgramString (_cg_gprogram, CG_COMPILED_PROGRAM);
+    // END CG2 CHANGE
 
     gobj_cat.debug() << vertex_program << "\n";
     gobj_cat.debug() << pixel_program << "\n";
+
+    // BEGIN CG2 CHANGE
+    if (_cg_gprogram != 0)
+        gobj_cat.debug() << geometry_program << "\n";
+    // END CG2 CHANGE
   }
 
   //  // The following code is present to work around a bug in the Cg compiler.
@@ -1409,6 +1434,31 @@ cg_analyze_shader(const ShaderCaps &caps) {
   return true;
 }
 
+// BEGIN CG2 CHANGE
+CGprogram Shader::
+cg_program_from_shadertype(ShaderType type)
+{
+    CGprogram prog = 0;
+
+    switch(type)
+    {
+    case ST_VERTEX:
+        prog = _cg_vprogram;
+        break;
+
+    case ST_FRAGMENT:
+        prog = _cg_fprogram;
+        break;
+
+    case ST_GEOMETRY:
+        prog = _cg_gprogram;
+        break;
+    };
+
+    return prog;
+}
+// END CG2 CHANGE
+
 ////////////////////////////////////////////////////////////////////
 //  Function: Shader::cg_compile_for
 //  Access: Public
@@ -1422,6 +1472,7 @@ cg_compile_for(const ShaderCaps &caps,
                CGcontext &ctx,
                CGprogram &vprogram,
                CGprogram &fprogram,
+               CGprogram &gprogram,     // CG2 CHANGE
                pvector<CGparameter> &map) {
 
   // Initialize the return values to empty.
@@ -1429,6 +1480,8 @@ cg_compile_for(const ShaderCaps &caps,
   ctx = 0;
   vprogram = 0;
   fprogram = 0;
+  gprogram = 0;   // CG2 CHANGE
+
   map.clear();
   
   // Make sure the shader is compiled for the target caps.
@@ -1461,12 +1514,13 @@ cg_compile_for(const ShaderCaps &caps,
   
   for (int i=0; i<n_mat; i++) {
     const ShaderArgId &id = _mat_spec[i]._id;
-    CGprogram prog = (id._fshader) ? _cg_fprogram : _cg_vprogram;
+
+    CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
   }
   for (int i=0; i<n_tex; i++) {
     const ShaderArgId &id = _tex_spec[i]._id;
-    CGprogram prog = (id._fshader) ? _cg_fprogram : _cg_vprogram;
+    CGprogram prog = cg_program_from_shadertype(id._type);  // CG2 CHANGE
     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
     if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
       map[id._seqno] = 0;
@@ -1474,7 +1528,8 @@ cg_compile_for(const ShaderCaps &caps,
   }
   for (int i=0; i<n_var; i++) {
     const ShaderArgId &id = _var_spec[i]._id;
-    CGprogram prog = (id._fshader) ? _cg_fprogram : _cg_vprogram;
+
+    CGprogram prog = cg_program_from_shadertype(id._type);      // CG2 CHANGE
     map[id._seqno] = cgGetNamedParameter(prog, id._name.c_str());
     if (cgGetParameterBaseResource(map[id._seqno]) == CG_UNDEFINED) {
       map[id._seqno] = 0;
@@ -1486,10 +1541,13 @@ cg_compile_for(const ShaderCaps &caps,
   ctx = _cg_context;
   vprogram = _cg_vprogram;
   fprogram = _cg_fprogram;
-  
+  gprogram = _cg_gprogram;  // CG2 CHANGE
+
   _cg_context = 0;
   _cg_vprogram = 0;
   _cg_fprogram = 0;
+  _cg_gprogram = 0;     // CG2 CHANGE
+
   _cg_last_caps.clear();
 
   return true;
@@ -1519,8 +1577,10 @@ Shader(const Filename &filename, const string &text, const string &vprofile, con
   _cg_context = 0;
   _cg_vprogram = 0;
   _cg_fprogram = 0;
+  _cg_gprogram = 0; // CG2 CHANGE
   _cg_vprofile = CG_PROFILE_UNKNOWN;
   _cg_fprofile = CG_PROFILE_UNKNOWN;
+  _cg_gprofile = CG_PROFILE_UNKNOWN;
   if (vprofile != "") {
     CGprofile p = cgGetProfile(vprofile.c_str());
     if (p == CG_PROFILE_UNKNOWN) {
@@ -1540,10 +1600,14 @@ Shader(const Filename &filename, const string &text, const string &vprofile, con
   if (_default_caps._ultimate_vprofile == 0) {
     _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
     _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
-    _default_caps._ultimate_vprofile = JCG_PROFILE_GLSLV;
-    _default_caps._ultimate_fprofile = JCG_PROFILE_GLSLF;
+    _default_caps._ultimate_vprofile = cgGetProfile("glslv");
+    _default_caps._ultimate_fprofile = cgGetProfile("glslf");
+    _default_caps._ultimate_gprofile = cgGetProfile("gp4gp");
   }
   if (_header == "//Cg") {
+
+    cg_get_profile_from_header(_default_caps);  // CG2 CHANGE
+
     if (!cg_analyze_shader(_default_caps)) {
       _error_flag = true;
     }
@@ -1556,6 +1620,115 @@ Shader(const Filename &filename, const string &text, const string &vprofile, con
 
 }
 
+// BEGIN CG2 CHANGE
+
+////////////////////////////////////////////////////////////////////
+//  Function: Shader::cg_get_profile_from_header
+//  Access: Private
+//  Description: Determines the appropriate active shader profile settings
+//               based on any profile directives stored within the shader header
+////////////////////////////////////////////////////////////////////
+
+void Shader::
+cg_get_profile_from_header(ShaderCaps& caps) {
+
+    // Note this forces profile based on what is specified in the shader
+    // header string.  Should probably be relying on card caps eventually.
+
+    string buf;
+    parse_init();
+
+    // Assume that if parse doesn't extend after a parse line then
+    // we've reached the end of _text
+    int lastParse;
+
+    do
+    {
+        lastParse = _parse;
+        parse_line(buf, true, true);
+        int profilePos = buf.find("//Cg profile");
+        if (profilePos >= 0)
+        {
+            // Scan the line for known cg2 vertex program profiles
+            if ((int)buf.find("gp4vp") >= 0)
+                caps._active_vprofile = cgGetProfile("gp4vp");
+
+            // older
+            if ((int)buf.find("glslv") >= 0)
+                caps._active_vprofile = cgGetProfile("glslv");
+
+            if ((int)buf.find("arbvp1") >= 0)
+                caps._active_vprofile = cgGetProfile("arbvp1");
+
+            if ((int)buf.find("vp40") >= 0)
+                caps._active_vprofile = cgGetProfile("vp40");
+
+            if ((int)buf.find("vp30") >= 0)
+                caps._active_vprofile = cgGetProfile("vp30");
+
+            if ((int)buf.find("vp20") >= 0)
+                caps._active_vprofile = cgGetProfile("vp20");
+
+            if ((int)buf.find("vs_1_1") >= 0)
+                caps._active_vprofile = cgGetProfile("vs_1_1");
+
+            if ((int)buf.find("vs_2_0") >= 0)
+                caps._active_vprofile = cgGetProfile("vs_2_0");
+
+            if ((int)buf.find("vs_2_x") >= 0)
+                caps._active_vprofile = cgGetProfile("vs_2_x");
+
+            if ((int)buf.find("vs_3_0") >= 0)
+                caps._active_vprofile = cgGetProfile("vs_3_0");
+
+            // Scan the line for known cg2 fragment program profiles
+            if ((int)buf.find("gp4fp") >= 0)
+                caps._active_fprofile = cgGetProfile("gp4fp");
+
+            // older
+            if ((int)buf.find("glslf") >= 0)
+                caps._active_fprofile = cgGetProfile("glslf");
+
+            if ((int)buf.find("arbfp1") >= 0)
+                caps._active_fprofile = cgGetProfile("arbfp1");
+
+            if ((int)buf.find("fp40") >= 0)
+                caps._active_fprofile = cgGetProfile("fp40");
+
+            if ((int)buf.find("fp30") >= 0)
+                caps._active_fprofile = cgGetProfile("fp30");
+
+            if ((int)buf.find("fp20") >= 0)
+                caps._active_fprofile = cgGetProfile("fp20");
+
+            if ((int)buf.find("ps_1_1") >= 0)
+                caps._active_fprofile = cgGetProfile("ps_1_1");
+
+            if ((int)buf.find("ps_1_2") >= 0)
+                caps._active_fprofile = cgGetProfile("ps_1_2");
+
+            if ((int)buf.find("ps_1_3") >= 0)
+                caps._active_fprofile = cgGetProfile("ps_1_3");
+
+            if ((int)buf.find("ps_2_0") >= 0)
+                caps._active_fprofile = cgGetProfile("ps_2_0");
+
+            if ((int)buf.find("ps_2_x") >= 0)
+                caps._active_fprofile = cgGetProfile("ps_2_x");
+
+            if ((int)buf.find("ps_3_0") >= 0)
+                caps._active_fprofile = cgGetProfile("ps_3_0");
+
+            // Scan the line for known cg2 geometry program profiles
+            if ((int)buf.find("gp4gp") >= 0)
+                caps._active_gprofile = cgGetProfile("gp4gp");
+        }
+
+    } while(_parse > lastParse);
+}
+
+// END CG2 CHANGE
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::Destructor
 //       Access: Public
@@ -1571,6 +1744,7 @@ Shader::
   }
 }
 
+// Removed for now, as the profiles are now taken from the shader source.
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::load
 //       Access: Published, Static
@@ -1583,7 +1757,7 @@ Shader::
 ////////////////////////////////////////////////////////////////////
 PT(Shader) Shader::
 load(const string &file, const string &vprofile, const string &fprofile) {
-  return load(Filename(file), vprofile, fprofile);
+ return load(Filename(file), vprofile, fprofile);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1614,7 +1788,7 @@ load(const Filename &file, const string &vprofile, const string &fprofile) {
   return result;
 }
 
-////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
 //     Function: Shader::make
 //       Access: Published, Static
 //  Description: Loads the shader, using the string as shader body.
@@ -1902,6 +2076,11 @@ clear() {
   _active_fprofile = 0;
   _ultimate_vprofile = 0;
   _ultimate_fprofile = 0;
+
+  // BEGIN CG2 CHANGE
+  _active_gprofile = 0;
+  _ultimate_gprofile = 0;
+  // END CG2 CHANGE
 #endif
 }
 

+ 33 - 6
panda/src/gobj/shader.h

@@ -169,10 +169,18 @@ public:
     SMF_first,
   };
 
+  // BEGIN CG2 CHANGE
+  enum ShaderType {
+    ST_VERTEX,
+    ST_FRAGMENT,
+    ST_GEOMETRY,
+  };
+  // END CG2 CHANGE
+
   struct ShaderArgId {
-    string _name;
-    bool   _fshader;
-    int    _seqno;
+    string     _name;
+    ShaderType _type;       // CG2 CHANGE
+    int        _seqno;
   };
   
   struct ShaderMatSpec {
@@ -212,8 +220,12 @@ public:
 #ifdef HAVE_CG
     int _active_vprofile;
     int _active_fprofile;
+    int _active_gprofile;   // CG CHANGE   Geometry shader
+
     int _ultimate_vprofile;
     int _ultimate_fprofile;
+    int _ultimate_gprofile; // CG CHANGE   Geometry shader
+
     pset <ShaderBug> _bug_list;
 #endif
     void clear();
@@ -261,26 +273,41 @@ public:
  private:
   ShaderArgType cg_parameter_type(CGparameter p);
   ShaderArgDir  cg_parameter_dir(CGparameter p);
-  CGprogram     cg_compile_entry_point(const char *entry, const ShaderCaps &caps, bool fshader);
-  bool          cg_analyze_entry_point(CGprogram prog, bool fshader);
+
+  CGprogram     cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type = ST_VERTEX); // CG2 CHANGE
+
+  bool          cg_analyze_entry_point(CGprogram prog, ShaderType type);    // CG2 CHANGE
+
   bool          cg_analyze_shader(const ShaderCaps &caps);
   bool          cg_compile_shader(const ShaderCaps &caps);
   void          cg_release_resources();
   void          cg_report_errors();
   
+  // BEGIN CG2 CHANGE
+  // Determines the appropriate cg profile settings and stores them in the active shader caps
+  // based on any profile settings stored in the shader's header
+  void          cg_get_profile_from_header(ShaderCaps& caps);
+  // END CG2 CHANGE
+
   ShaderCaps _cg_last_caps;
   CGcontext  _cg_context;
   CGprogram  _cg_vprogram;
   CGprogram  _cg_fprogram;
+  CGprogram  _cg_gprogram;  // CG2 CHANGE
+
   int        _cg_vprofile;
   int        _cg_fprofile;
-  
+  int        _cg_gprofile;
+
+  CGprogram     cg_program_from_shadertype(ShaderType type);    // CG2 CHANGE
+
  public:
 
   bool          cg_compile_for(const ShaderCaps &caps,
                                CGcontext &ctx,
                                CGprogram &vprogram,
                                CGprogram &fprogram,
+                   CGprogram &gprogram,     // CG2 CHANGE
                                pvector<CGparameter> &map);
   
 #endif

+ 2 - 2
panda/src/gobj/texture.cxx

@@ -437,7 +437,7 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
   ++_properties_modified;
   ++_image_modified;
   return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
-		 alpha_file_channel, 0, 0, false, false, 
+                 alpha_file_channel, 0, 0, false, false, 
                  options, NULL);
 }
 
@@ -541,7 +541,7 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
   ++_properties_modified;
   ++_image_modified;
   return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
-		 alpha_file_channel, z, n, read_pages, read_mipmaps,
+                 alpha_file_channel, z, n, read_pages, read_mipmaps,
                  options, record);
 }
 

+ 4 - 0
panda/src/gobj/texture.h

@@ -73,6 +73,7 @@ PUBLISHED:
     T_unsigned_byte,
     T_unsigned_short,
     T_float,
+    T_unsigned_int_24_8,
   };
 
   enum Format {
@@ -112,6 +113,9 @@ PUBLISHED:
     F_rgba32,  // 32 bits per R,G,B,A channel
 
     F_depth_component,
+    F_depth_component16,
+    F_depth_component24,
+    F_depth_component32,
   };
 
   enum FilterType {

+ 4 - 1
panda/src/grutil/Sources.pp

@@ -21,6 +21,7 @@
     frameRateMeter.I frameRateMeter.h \
     meshDrawer.I meshDrawer.h \
     geoMipTerrain.I geoMipTerrain.h \
+    sceneGraphAnalyzerMeter.I sceneGraphAnalyzerMeter.h \
     heightfieldTesselator.I heightfieldTesselator.h \
     lineSegs.I lineSegs.h \
     multitexReducer.I multitexReducer.h multitexReducer.cxx \
@@ -38,9 +39,10 @@
     frameRateMeter.cxx \
     meshDrawer.cxx \
     geoMipTerrain.cxx \
+    sceneGraphAnalyzerMeter.cxx \
     heightfieldTesselator.cxx \
     nodeVertexTransform.cxx \
-    openCVTexture.cxx \    	 
+    openCVTexture.cxx \    
     pipeOcclusionCullTraverser.cxx \
     lineSegs.cxx \
     rigidBodyCombiner.cxx
@@ -54,6 +56,7 @@
     frameRateMeter.I frameRateMeter.h \
     meshDrawer.I meshDrawer.h \
     geoMipTerrain.I geoMipTerrain.h \
+    sceneGraphAnalyzerMeter.I sceneGraphAnalyzerMeter.h \
     heightfieldTesselator.I heightfieldTesselator.h \
     lineSegs.I lineSegs.h \
     multitexReducer.I multitexReducer.h \

+ 16 - 14
panda/src/grutil/cardMaker.cxx

@@ -69,15 +69,16 @@ generate() {
   if (_has_normals) {
     if (_has_uvs) {
       if (_has_3d_uvs) {
-	format = GeomVertexFormat::register_format(new GeomVertexArrayFormat
-						   (InternalName::get_vertex(), 3,
-						    GeomEnums::NT_float32, GeomEnums::C_point,
-						    InternalName::get_normal(), 3,
-						    GeomEnums::NT_float32, GeomEnums::C_vector,
-						    InternalName::get_texcoord(), 3,
-						    GeomEnums::NT_float32, GeomEnums::C_texcoord));
+        format = GeomVertexFormat::register_format
+          (new GeomVertexArrayFormat
+           (InternalName::get_vertex(), 3,
+            GeomEnums::NT_float32, GeomEnums::C_point,
+            InternalName::get_normal(), 3,
+            GeomEnums::NT_float32, GeomEnums::C_vector,
+            InternalName::get_texcoord(), 3,
+            GeomEnums::NT_float32, GeomEnums::C_texcoord));
       } else {
-	format = GeomVertexFormat::get_v3n3t2();
+        format = GeomVertexFormat::get_v3n3t2();
       }
     } else {
       format = GeomVertexFormat::get_v3n3();
@@ -85,13 +86,14 @@ generate() {
   } else {
     if (_has_uvs) {
       if (_has_3d_uvs) {
-	format = GeomVertexFormat::register_format(new GeomVertexArrayFormat
-						   (InternalName::get_vertex(), 3,
-						    GeomEnums::NT_float32, GeomEnums::C_point,
-						    InternalName::get_texcoord(), 3,
-						    GeomEnums::NT_float32, GeomEnums::C_texcoord));
+        format = GeomVertexFormat::register_format
+          (new GeomVertexArrayFormat
+           (InternalName::get_vertex(), 3,
+            GeomEnums::NT_float32, GeomEnums::C_point,
+            InternalName::get_texcoord(), 3,
+            GeomEnums::NT_float32, GeomEnums::C_texcoord));
       } else {
-	format = GeomVertexFormat::get_v3t2();
+        format = GeomVertexFormat::get_v3t2();
       }
     } else {
       format = GeomVertexFormat::get_v3();

+ 14 - 0
panda/src/grutil/config_grutil.cxx

@@ -14,6 +14,7 @@
 
 #include "config_grutil.h"
 #include "frameRateMeter.h"
+#include "sceneGraphAnalyzerMeter.h"
 #include "meshDrawer.h"
 #include "geoMipTerrain.h"
 #include "openCVTexture.h"
@@ -49,6 +50,18 @@ ConfigVariableDouble frame_rate_meter_scale
 ConfigVariableDouble frame_rate_meter_side_margins
 ("frame-rate-meter-side-margins", 0.5);
 
+ConfigVariableDouble scene_graph_analyzer_meter_update_interval
+("scene-graph-analyzer-meter-update-interval", 2.0);
+
+ConfigVariableInt scene_graph_analyzer_meter_layer_sort
+("scene-graph-analyzer-meter-layer-sort", 1000);
+
+ConfigVariableDouble scene_graph_analyzer_meter_scale
+("scene-graph-analyzer-meter-scale", 0.05);
+
+ConfigVariableDouble scene_graph_analyzer_meter_side_margins
+("scene-graph-analyzer-meter-side-margins", 0.5);
+
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libgrutil
 //  Description: Initializes the library.  This must be called at
@@ -79,6 +92,7 @@ init_libgrutil() {
   NodeVertexTransform::init_type();
   RigidBodyCombiner::init_type();
   PipeOcclusionCullTraverser::init_type();
+  SceneGraphAnalyzerMeter::init_type();
 
   MovieTexture::init_type();
   MovieTexture::register_with_read_factory();

+ 5 - 0
panda/src/grutil/config_grutil.h

@@ -30,6 +30,11 @@ extern ConfigVariableInt frame_rate_meter_layer_sort;
 extern ConfigVariableDouble frame_rate_meter_scale;
 extern ConfigVariableDouble frame_rate_meter_side_margins;
 
+extern ConfigVariableDouble scene_graph_analyzer_meter_update_interval;
+extern ConfigVariableInt scene_graph_analyzer_meter_layer_sort;
+extern ConfigVariableDouble scene_graph_analyzer_meter_scale;
+extern ConfigVariableDouble scene_graph_analyzer_meter_side_margins;
+
 extern EXPCL_PANDA_GRUTIL void init_libgrutil();
 
 #endif

+ 25 - 8
panda/src/grutil/ffmpegTexture.cxx

@@ -614,14 +614,18 @@ read(const Filename &filename) {
   
   string os_specific = filename.to_os_specific();
   // Open video file
-  if (av_open_input_file(&_format_context, os_specific.c_str(), NULL, 
-                         0, NULL) != 0) {
-    // Don't do anything, because nothing happened yet
+  int result = av_open_input_file(&_format_context, os_specific.c_str(), NULL, 
+                                  0, NULL);
+  if (result != 0) {
+    grutil_cat.error() << "ffmpeg AVERROR: " << result << endl;
+    // Don't call clear(), because nothing happened yet
     return false;
   }
 
   // Retrieve stream information
-  if (av_find_stream_info(_format_context) < 0) {
+  result = av_find_stream_info(_format_context);
+  if (result < 0) {
+    grutil_cat.error() << "ffmpeg AVERROR: " << result << endl;
     clear();
     return false;
   }
@@ -636,6 +640,8 @@ read(const Filename &filename) {
   }
 
   if (_stream_number == -1) {
+    grutil_cat.error()
+      << "ffmpeg: no stream found with codec of type CODEC_TYPE_VIDEO" << endl;
     clear();
     return false;
   }
@@ -643,21 +649,28 @@ read(const Filename &filename) {
   // Get a pointer to the codec context for the video stream
   AVCodecContext *codec_context = _format_context->streams[_stream_number]->codec;
   
+  if (grutil_cat.is_debug()) {
+    grutil_cat.debug()
+      << "ffmpeg: codec id is " << codec_context->codec_id << endl;
+  }
+
   // Find the decoder for the video stream
-  // printf("codec id is %d\n",codec_context->codec_id);
   _codec = avcodec_find_decoder(codec_context->codec_id);
   if (_codec == NULL) {
+    grutil_cat.error() << "ffmpeg: no appropriate decoder found" << endl;
     clear();
     return false;
   }
-  
+
   if (_codec->capabilities & CODEC_CAP_TRUNCATED) {
     codec_context->flags |= CODEC_FLAG_TRUNCATED;
   }
 
   // Open codec
   _codec_context = codec_context;
-  if (avcodec_open(_codec_context, _codec) < 0) {
+  result = avcodec_open(_codec_context, _codec);
+  if (result < 0) {
+    grutil_cat.error() << "ffmpeg AVERROR: " << result << endl;
     _codec_context = NULL;
     clear();
     return false;
@@ -668,10 +681,12 @@ read(const Filename &filename) {
   if (_codec_context->pix_fmt != PIX_FMT_RGBA32) {
     _frame_out = avcodec_alloc_frame();
     if (_frame_out == NULL) {
+      grutil_cat.error()
+        << "ffmpeg: unable to allocate AVPFrame (BGR24)" << endl;
       clear();
       return false;
     }
-    
+
     // Determine required buffer size and allocate buffer
     _image_size_bytes = avpicture_get_size(PIX_FMT_BGR24, _codec_context->width,
                                            _codec_context->height);
@@ -685,6 +700,8 @@ read(const Filename &filename) {
   } else {
     _frame_out = avcodec_alloc_frame();
     if (_frame_out == NULL) {
+      grutil_cat.error()
+        << "ffmpeg: unable to allocate AVPFrame (RGBA32)" << endl;
       clear();
       return false;
     }

+ 2 - 0
panda/src/grutil/grutil_composite1.cxx

@@ -6,3 +6,5 @@
 #include "lineSegs.cxx"
 #include "fisheyeMaker.cxx"
 #include "frameRateMeter.cxx"
+#include "sceneGraphAnalyzerMeter.cxx"
+

+ 1 - 1
panda/src/grutil/meshDrawer.I

@@ -55,7 +55,7 @@ INLINE MeshDrawer::
 //               Geom drawer expects a plate of square image for
 //               most of its billboard operatoins.  If plate size is
 //               3 the frame numbering would look like this:
-//				   0 1 2
+//                 0 1 2
 //                 3 4 5
 //                 6 7 8
 //               you can select any frame you like for many of the

+ 68 - 71
panda/src/grutil/meshDrawer.cxx

@@ -225,10 +225,10 @@ void MeshDrawer::billboard(LVector3f pos, int frame, float size, LVector4f _colo
 //               billboarding effect.
 ////////////////////////////////////////////////////////////////////
 void MeshDrawer::segment(LVector3f start, LVector3f stop, int frame,
-           float thickness, LVector4f color) {
-	link_segment(start, frame, thickness, color);
-	link_segment(stop, frame, thickness, color);
-	link_segment_end(frame, color);
+                         float thickness, LVector4f color) {
+  link_segment(start, frame, thickness, color);
+  link_segment(stop, frame, thickness, color);
+  link_segment_end(frame, color);
 }
 ////////////////////////////////////////////////////////////////////
 //     Function: MeshDrawer::cross_segment
@@ -238,8 +238,7 @@ void MeshDrawer::segment(LVector3f start, LVector3f stop, int frame,
 //               and instead draws 2 planes in a cross.
 ////////////////////////////////////////////////////////////////////
 void MeshDrawer::cross_segment(LVector3f start, LVector3f stop, int frame,
-           float thickness, LVector4f color) {
-
+                               float thickness, LVector4f color) {
   float u = float(int(frame%_plate_size))*_frame_size;
   float v = 1.0f-float(int(frame/_plate_size+1))*_frame_size;
 
@@ -279,37 +278,35 @@ void MeshDrawer::cross_segment(LVector3f start, LVector3f stop, int frame,
 //               and color on both sides.
 ////////////////////////////////////////////////////////////////////
 void MeshDrawer::uneven_segment(LVector3f start, LVector3f stop,
-		int frame, int multi_frame,
-		float thickness_start, LVector4f color_start,
-		float thickness_stop, LVector4f color_stop) {
-
-	float u = float(int(frame%_plate_size))*_frame_size;
-	float v = 1.0f-float(int(frame/_plate_size+1))*_frame_size;
-
-	LVector3f v1 = start - _up*thickness_start;
-	LVector3f v2 = stop - _up*thickness_stop;
-	LVector3f v3 = stop + _up*thickness_stop;
-	LVector3f v4 = start + _up*thickness_start;
-
-	tri(v1, color_start, LVector2f(u,v),
-		  v2, color_stop, LVector2f(u+_frame_size*multi_frame,v),
-		  v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size));
-	tri(v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size),
-		  v4, color_start, LVector2f(u,v+_frame_size),
-		  v1, color_start, LVector2f(u,v));
-
-	v1 = start - _right*thickness_start;
-	v2 = stop - _right*thickness_stop;
-	v3 = stop + _right*thickness_stop;
-	v4 = start + _right*thickness_start;
-
-	tri(v1, color_start, LVector2f(u,v),
-		  v2, color_stop, LVector2f(u+_frame_size*multi_frame,v),
-		  v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size));
-	tri(v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size),
-		  v4, color_start, LVector2f(u,v+_frame_size),
-		  v1, color_start, LVector2f(u,v));
-
+                                int frame, int multi_frame,
+                                float thickness_start, LVector4f color_start,
+                                float thickness_stop, LVector4f color_stop) {
+  float u = float(int(frame%_plate_size))*_frame_size;
+  float v = 1.0f-float(int(frame/_plate_size+1))*_frame_size;
+  
+  LVector3f v1 = start - _up*thickness_start;
+  LVector3f v2 = stop - _up*thickness_stop;
+  LVector3f v3 = stop + _up*thickness_stop;
+  LVector3f v4 = start + _up*thickness_start;
+  
+  tri(v1, color_start, LVector2f(u,v),
+      v2, color_stop, LVector2f(u+_frame_size*multi_frame,v),
+      v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size));
+  tri(v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size),
+      v4, color_start, LVector2f(u,v+_frame_size),
+      v1, color_start, LVector2f(u,v));
+  
+  v1 = start - _right*thickness_start;
+  v2 = stop - _right*thickness_stop;
+  v3 = stop + _right*thickness_stop;
+  v4 = start + _right*thickness_start;
+  
+  tri(v1, color_start, LVector2f(u,v),
+      v2, color_stop, LVector2f(u+_frame_size*multi_frame,v),
+      v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size));
+  tri(v3, color_stop, LVector2f(u+_frame_size*multi_frame,v+_frame_size),
+      v4, color_start, LVector2f(u,v+_frame_size),
+      v1, color_start, LVector2f(u,v));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -426,36 +423,36 @@ void MeshDrawer::geometry(NodePath draw_node) {
 //               parameters.
 ////////////////////////////////////////////////////////////////////
 void MeshDrawer::link_segment(LVector3f pos, int frame,
-		float thickness, LVector4f color) {
+        float thickness, LVector4f color) {
   assert(_render.get_error_type() == NodePath::ET_ok);
   assert(_camera.get_error_type() == NodePath::ET_ok);
-	/*
-	 * X
-	 * ---X
-	 * ===0---X
-	 * ===0===0---X
-	 * ===0===0===O---X
-	 * ===0===0===0===End
-	 *
-	 * first call marks position X
-	 * second call moves position and promises to draw segment
-	 * it can't draw it yet because next segment might bend it
-	 * third call finally draws segment
-	 * and the chain continues till
-	 * link_segment_end to flush the linking segments is called.
-	 */
-
-	// mark 1st position
-	if(_at_start==0) {
-		_last_pos = pos;
-		_last_thickness = thickness;
-		_last_color = color;
-		_at_start=1;
-		return;
-	}
-
-	LVector3f start = _last_pos;
-	LVector3f stop = pos;
+    /*
+     * X
+     * ---X
+     * ===0---X
+     * ===0===0---X
+     * ===0===0===O---X
+     * ===0===0===0===End
+     *
+     * first call marks position X
+     * second call moves position and promises to draw segment
+     * it can't draw it yet because next segment might bend it
+     * third call finally draws segment
+     * and the chain continues till
+     * link_segment_end to flush the linking segments is called.
+     */
+
+    // mark 1st position
+    if(_at_start==0) {
+        _last_pos = pos;
+        _last_thickness = thickness;
+        _last_color = color;
+        _at_start=1;
+        return;
+    }
+
+    LVector3f start = _last_pos;
+    LVector3f stop = pos;
 
   LVector3f cam_start3d = _camera.get_relative_point(_render, start);
   LPoint2f cam_start2d = LVector2f();
@@ -481,12 +478,12 @@ void MeshDrawer::link_segment(LVector3f pos, int frame,
   // we need to draw it when we know what the next segment looks like
   // because it can bend it a little
   if(_at_start==1) {
-		_last_v1 = now_v1;
-		_last_v2 = now_v2;
-		_last_v3 = now_v3;
-		_last_v4 = now_v4;
-		_at_start = 2;
-		return;
+        _last_v1 = now_v1;
+        _last_v2 = now_v2;
+        _last_v3 = now_v3;
+        _last_v4 = now_v4;
+        _at_start = 2;
+        return;
   }
 
   // draw the last segment a little bent

+ 3 - 3
panda/src/grutil/meshDrawer.h

@@ -66,9 +66,9 @@ PUBLISHED:
   void segment(LVector3f start, LVector3f stop, int frame, float thickness, LVector4f color);
   void cross_segment(LVector3f start, LVector3f stop, int frame, float thickness, LVector4f color);
   void uneven_segment(LVector3f start, LVector3f stop,
-  		int frame, int multi_frame,
-  		float thickness_start, LVector4f color_start,
-  		float thickness_stop, LVector4f color_stop);
+        int frame, int multi_frame,
+        float thickness_start, LVector4f color_start,
+        float thickness_stop, LVector4f color_stop);
 
   void link_segment(LVector3f pos, int frame, float thickness, LVector4f color);
   void link_segment_end(int frame, LVector4f color);

+ 40 - 40
panda/src/grutil/multitexReducer.cxx

@@ -751,7 +751,7 @@ void MultitexReducer::
 make_texture_layer(const NodePath &render, 
                    const MultitexReducer::StageInfo &stage_info, 
                    const MultitexReducer::GeomList &geom_list,
-		   const TexCoordf &min_uv, const TexCoordf &max_uv,
+                   const TexCoordf &min_uv, const TexCoordf &max_uv,
                    bool force_use_geom, bool transparent_base) {
   CPT(RenderAttrib) cba;
 
@@ -807,45 +807,45 @@ make_texture_layer(const NodePath &render,
     switch (stage_info._stage->get_combine_rgb_mode()) {
     case TextureStage::CM_modulate:
       {
-	TextureStage::CombineSource source0 = stage_info._stage->get_combine_rgb_source0();
-	TextureStage::CombineOperand operand0 = stage_info._stage->get_combine_rgb_operand0();
-	TextureStage::CombineSource source1 = stage_info._stage->get_combine_rgb_source1();
-	TextureStage::CombineOperand operand1 = stage_info._stage->get_combine_rgb_operand1();
-	// Since modulate doesn't care about order, let's establish
-	// the convention that the lowest-numbered source 
-	// operand is in slot 0 (just for purposes of comparison).
-	if (source1 < source0) {
-	  source0 = stage_info._stage->get_combine_rgb_source1();
-	  operand0 = stage_info._stage->get_combine_rgb_operand1();
-	  source1 = stage_info._stage->get_combine_rgb_source0();
-	  operand1 = stage_info._stage->get_combine_rgb_operand0();
-	}
-
-	if (source0 == TextureStage::CS_primary_color &&
-	    source1 == TextureStage::CS_previous) {
-	  // This is just a trick to re-apply the vertex (lighting)
-	  // color on the top of the texture stack.  We can ignore it,
-	  // since the flattened texture will do this anyway.
-	  return;
-	  
-	} else if (source0 == TextureStage::CS_texture &&
-		   source1 == TextureStage::CS_constant) {
-	  // Scaling the texture by a flat color.
-	  cba = ColorBlendAttrib::make
-	    (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
-	     ColorBlendAttrib::O_zero, stage_info._stage->get_color());
-	  
-	} else if (source0 == TextureStage::CS_texture &&
-		   source1 == TextureStage::CS_previous) {
-	  // Just an ordinary modulate.
-	  cba = ColorBlendAttrib::make
-	    (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color,
-	     ColorBlendAttrib::O_zero);
-	  
-	} else {
-	  // Some other kind of modulate; we don't support it.
-	  return;
-	}
+        TextureStage::CombineSource source0 = stage_info._stage->get_combine_rgb_source0();
+        TextureStage::CombineOperand operand0 = stage_info._stage->get_combine_rgb_operand0();
+        TextureStage::CombineSource source1 = stage_info._stage->get_combine_rgb_source1();
+        TextureStage::CombineOperand operand1 = stage_info._stage->get_combine_rgb_operand1();
+        // Since modulate doesn't care about order, let's establish
+        // the convention that the lowest-numbered source 
+        // operand is in slot 0 (just for purposes of comparison).
+        if (source1 < source0) {
+          source0 = stage_info._stage->get_combine_rgb_source1();
+          operand0 = stage_info._stage->get_combine_rgb_operand1();
+          source1 = stage_info._stage->get_combine_rgb_source0();
+          operand1 = stage_info._stage->get_combine_rgb_operand0();
+        }
+        
+        if (source0 == TextureStage::CS_primary_color &&
+            source1 == TextureStage::CS_previous) {
+          // This is just a trick to re-apply the vertex (lighting)
+          // color on the top of the texture stack.  We can ignore it,
+          // since the flattened texture will do this anyway.
+          return;
+          
+        } else if (source0 == TextureStage::CS_texture &&
+                   source1 == TextureStage::CS_constant) {
+          // Scaling the texture by a flat color.
+          cba = ColorBlendAttrib::make
+            (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color,
+             ColorBlendAttrib::O_zero, stage_info._stage->get_color());
+          
+        } else if (source0 == TextureStage::CS_texture &&
+                   source1 == TextureStage::CS_previous) {
+          // Just an ordinary modulate.
+          cba = ColorBlendAttrib::make
+            (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color,
+             ColorBlendAttrib::O_zero);
+          
+        } else {
+          // Some other kind of modulate; we don't support it.
+          return;
+        }
       }
       break;
 

+ 1 - 1
panda/src/grutil/multitexReducer.h

@@ -134,7 +134,7 @@ private:
   void make_texture_layer(const NodePath &render, 
                           const StageInfo &stage_info, 
                           const GeomList &geom_list,
-			  const TexCoordf &min_uv, const TexCoordf &max_uv,
+                          const TexCoordf &min_uv, const TexCoordf &max_uv,
                           bool force_use_geom, bool transparent_base);
   void transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
                      const GeomList &geom_list, bool preserve_color);

+ 1 - 1
panda/src/grutil/openCVTexture.cxx

@@ -339,7 +339,7 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
   if (!alpha_fullpath.empty()) {
     if (!page._alpha.read(alpha_fullpath)) {
       grutil_cat.error()
-	<< "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
+        << "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
       page._color.clear();
       return false;
     }

+ 101 - 0
panda/src/grutil/sceneGraphAnalyzerMeter.I

@@ -0,0 +1,101 @@
+// Filename: sceneGraphAnalyzerMeter.I
+// Created by:  pratt (14Feb07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::get_window
+//       Access: Published
+//  Description: Returns the GraphicsOutput that was passed to
+//               setup_window(), or NULL if setup_window() has not
+//               been called.
+////////////////////////////////////////////////////////////////////
+INLINE GraphicsOutput *SceneGraphAnalyzerMeter::
+get_window() const {
+  return _window;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::get_display_region
+//       Access: Published
+//  Description: Returns the DisplayRegion that the meter has created
+//               to render itself into the window to setup_window(),
+//               or NULL if setup_window() has not been called.
+////////////////////////////////////////////////////////////////////
+INLINE DisplayRegion *SceneGraphAnalyzerMeter::
+get_display_region() const {
+  return _display_region;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::set_update_interval
+//       Access: Published
+//  Description: Specifies the number of seconds that should elapse
+//               between updates to the meter.  This should be
+//               reasonably slow (e.g. 0.5 to 2.0) so that the
+//               calculation of the scene graph analysis does not
+//               itself dominate the frame rate.
+////////////////////////////////////////////////////////////////////
+INLINE void SceneGraphAnalyzerMeter::
+set_update_interval(double update_interval) {
+  _update_interval = update_interval;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::get_update_interval
+//       Access: Published
+//  Description: Returns the number of seconds that will elapse
+//               between updates to the frame rate indication.
+////////////////////////////////////////////////////////////////////
+INLINE double SceneGraphAnalyzerMeter::
+get_update_interval() const {
+  return _update_interval;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::set_node
+//       Access: Published
+//  Description: Sets the node to be analyzed.
+////////////////////////////////////////////////////////////////////
+INLINE void SceneGraphAnalyzerMeter::
+set_node(PandaNode *node) {
+  _node = node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::get_node
+//       Access: Published
+//  Description: Returns the node to be analyzed.
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode *SceneGraphAnalyzerMeter::
+get_node() const {
+  return _node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::update
+//       Access: Published
+//  Description: You can call this to explicitly force the
+//               SceneGraphAnalyzerMeter to update itself with the
+//               latest scene graph analysis information.
+//               Normally, it is not necessary to call this explicitly.
+////////////////////////////////////////////////////////////////////
+INLINE void SceneGraphAnalyzerMeter::
+update() {
+  Thread *current_thread = Thread::get_current_thread();
+  do_update(current_thread);
+}

+ 244 - 0
panda/src/grutil/sceneGraphAnalyzerMeter.cxx

@@ -0,0 +1,244 @@
+// Filename: sceneGraphAnalyzerMeter.cxx
+// Created by:  pratt (14Feb07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "sceneGraphAnalyzerMeter.h"
+#include "camera.h"
+#include "displayRegion.h"
+#include "orthographicLens.h"
+#include "config_grutil.h"
+#include "depthTestAttrib.h"
+#include "depthWriteAttrib.h"
+#include "pStatTimer.h"
+#include <stdio.h>  // For sprintf/snprintf
+
+PStatCollector SceneGraphAnalyzerMeter::_show_analyzer_pcollector("*:Show scene graph analysis");
+
+TypeHandle SceneGraphAnalyzerMeter::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SceneGraphAnalyzerMeter::
+SceneGraphAnalyzerMeter(const string &name, PandaNode *node) : TextNode(name) {
+  set_cull_callback();
+
+  Thread *current_thread = Thread::get_current_thread();
+
+  _update_interval = scene_graph_analyzer_meter_update_interval;
+  _last_update = 0.0f;
+  _node = node;
+  _clock_object = ClockObject::get_global_clock();
+
+  set_align(A_left);
+  set_transform(LMatrix4f::scale_mat(scene_graph_analyzer_meter_scale) * 
+                LMatrix4f::translate_mat(LVector3f::rfu(-1.0f + scene_graph_analyzer_meter_side_margins * scene_graph_analyzer_meter_scale, 0.0f, 1.0f - scene_graph_analyzer_meter_scale)));
+  set_card_color(0.0f, 0.0f, 0.0f, 0.4f);
+  set_card_as_margin(scene_graph_analyzer_meter_side_margins, scene_graph_analyzer_meter_side_margins, 0.1f, 0.0f);
+  set_usage_hint(Geom::UH_client);
+
+  do_update(current_thread);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SceneGraphAnalyzerMeter::
+~SceneGraphAnalyzerMeter() {
+  clear_window();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::setup_window
+//       Access: Published
+//  Description: Sets up the frame rate meter to create a
+//               DisplayRegion to render itself into the indicated
+//               window.
+////////////////////////////////////////////////////////////////////
+void SceneGraphAnalyzerMeter::
+setup_window(GraphicsOutput *window) {
+  clear_window();
+
+  _window = window;
+
+  _root = NodePath("scene_graph_analyzer_root");
+  _root.attach_new_node(this);
+
+  CPT(RenderAttrib) dt = DepthTestAttrib::make(DepthTestAttrib::M_none);
+  CPT(RenderAttrib) dw = DepthWriteAttrib::make(DepthWriteAttrib::M_off);
+  _root.node()->set_attrib(dt, 1);
+  _root.node()->set_attrib(dw, 1);
+  _root.set_material_off(1);
+  _root.set_two_sided(1, 1);
+
+  // Create a display region that covers the entire window.
+  _display_region = _window->make_display_region();
+  _display_region->set_sort(scene_graph_analyzer_meter_layer_sort);
+
+  // Finally, we need a camera to associate with the display region.
+  PT(Camera) camera = new Camera("scene_graph_analyzer_camera");
+  NodePath camera_np = _root.attach_new_node(camera);
+
+  PT(Lens) lens = new OrthographicLens;
+  
+  static const float left = -1.0f;
+  static const float right = 1.0f;
+  static const float bottom = -1.0f;
+  static const float top = 1.0f;
+  lens->set_film_size(right - left, top - bottom);
+  lens->set_film_offset((right + left) * 0.5, (top + bottom) * 0.5);
+  lens->set_near_far(-1000, 1000);
+  
+  camera->set_lens(lens);
+  camera->set_scene(_root);
+  _display_region->set_camera(camera_np);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::clear_window
+//       Access: Published
+//  Description: Undoes the effect of a previous call to
+//               setup_window().
+////////////////////////////////////////////////////////////////////
+void SceneGraphAnalyzerMeter::
+clear_window() {
+  if (_window != (GraphicsOutput *)NULL) {
+    _window->remove_display_region(_display_region);
+    _window = (GraphicsOutput *)NULL;
+    _display_region = (DisplayRegion *)NULL;
+  }
+  _root = NodePath();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::cull_callback
+//       Access: Protected, Virtual
+//  Description: This function will be called during the cull
+//               traversal to perform any additional operations that
+//               should be performed at cull time.  This may include
+//               additional manipulation of render state or additional
+//               visible/invisible decisions, or any other arbitrary
+//               operation.
+//
+//               Note that this function will *not* be called unless
+//               set_cull_callback() is called in the constructor of
+//               the derived class.  It is necessary to call
+//               set_cull_callback() to indicated that we require
+//               cull_callback() to be called.
+//
+//               By the time this function is called, the node has
+//               already passed the bounding-volume test for the
+//               viewing frustum, and the node's transform and state
+//               have already been applied to the indicated
+//               CullTraverserData object.
+//
+//               The return value is true if this node should be
+//               visible, or false if it should be culled.
+////////////////////////////////////////////////////////////////////
+bool SceneGraphAnalyzerMeter::
+cull_callback(CullTraverser *trav, CullTraverserData &data) {
+  Thread *current_thread = trav->get_current_thread();
+
+  // Statistics
+  PStatTimer timer(_show_analyzer_pcollector, current_thread);
+  
+  // Check to see if it's time to update.
+  double now = _clock_object->get_frame_time(current_thread);
+  double elapsed = now - _last_update;
+  if (elapsed < 0.0 || elapsed >= _update_interval) {
+    do_update(current_thread);
+  }
+
+  return TextNode::cull_callback(trav, data);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphAnalyzerMeter::do_update
+//       Access: Private
+//  Description: Resets the text according to the current frame rate.
+////////////////////////////////////////////////////////////////////
+void SceneGraphAnalyzerMeter::
+do_update(Thread *current_thread) {
+  _last_update = _clock_object->get_frame_time(current_thread);
+
+  _scene_graph_analyzer.clear();
+  _scene_graph_analyzer.add_node( _node );
+
+  static const size_t buffer_size = 1024;
+  char buffer[buffer_size];
+
+  char *pattern = "Nodes: %d\n"
+                  "Instances: %d\n"
+                  "Transforms: %d\n"
+                  "Nodes with Attribs: %d\n"
+                  "GeomNodes: %d\n"
+                  "Geoms: %d\n"
+                  "GeomVertexDatas: %d\n"
+                  "Vertices: %d\n"
+                  "Normals: %d\n"
+                  "TexCoords: %d\n"
+                  "Tris: %d\n"
+                  "Lines: %d\n"
+                  "Points: %d\n"
+                  "Texture memory: %.1f KB\n";
+
+#ifdef WIN32_VC
+  _snprintf(buffer, buffer_size, pattern,
+          _scene_graph_analyzer.get_num_nodes(),
+          _scene_graph_analyzer.get_num_instances(),
+          _scene_graph_analyzer.get_num_transforms(),
+          _scene_graph_analyzer.get_num_nodes_with_attribs(),
+          _scene_graph_analyzer.get_num_geom_nodes(),
+          _scene_graph_analyzer.get_num_geoms(),
+          _scene_graph_analyzer.get_num_geom_vertex_datas(),
+          _scene_graph_analyzer.get_num_vertices(),
+          _scene_graph_analyzer.get_num_normals(),
+          _scene_graph_analyzer.get_num_texcoords(),
+          _scene_graph_analyzer.get_num_tris(),
+          _scene_graph_analyzer.get_num_lines(),
+          _scene_graph_analyzer.get_num_points(),
+          _scene_graph_analyzer.get_texture_bytes()/1024.0);
+#else
+  snprintf(buffer, buffer_size, pattern,
+           _scene_graph_analyzer.get_num_nodes(),
+           _scene_graph_analyzer.get_num_instances(),
+           _scene_graph_analyzer.get_num_transforms(),
+           _scene_graph_analyzer.get_num_nodes_with_attribs(),
+           _scene_graph_analyzer.get_num_geom_nodes(),
+           _scene_graph_analyzer.get_num_geoms(),
+           _scene_graph_analyzer.get_num_geom_vertex_datas(),
+           _scene_graph_analyzer.get_num_vertices(),
+           _scene_graph_analyzer.get_num_normals(),
+           _scene_graph_analyzer.get_num_texcoords(),
+           _scene_graph_analyzer.get_num_tris(),
+           _scene_graph_analyzer.get_num_lines(),
+           _scene_graph_analyzer.get_num_points(),
+           _scene_graph_analyzer.get_texture_bytes()/1024.0);
+#endif
+  nassertv(strlen(buffer) < buffer_size);
+
+  if (get_text() == buffer) {
+    // Never mind; the data hasn't changed.
+    return;
+  }
+
+  set_text(buffer);
+}

+ 105 - 0
panda/src/grutil/sceneGraphAnalyzerMeter.h

@@ -0,0 +1,105 @@
+// Filename: sceneGraphAnalyzerMeter.h
+// Created by:  pratt (14Feb07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SCENEGRAPHANALYZERMETER_H
+#define SCENEGRAPHANALYZERMETER_H
+
+#include "pandabase.h"
+#include "textNode.h"
+#include "nodePath.h"
+#include "graphicsOutput.h"
+#include "displayRegion.h"
+#include "pointerTo.h"
+#include "sceneGraphAnalyzer.h"
+#include "pStatCollector.h"
+
+class PandaNode;
+class GraphicsChannel;
+class ClockObject;
+
+////////////////////////////////////////////////////////////////////
+//       Class : SceneGraphAnalyzerMeter
+// Description : This is a special TextNode that automatically updates
+//               itself with output from a SceneGraphAnalyzer instance.
+//               It can be placed anywhere in the world where you'd like
+//               to see the output from SceneGraphAnalyzer.
+//
+//               It also has a special mode in which it may be
+//               attached directly to a channel or window.  If this is
+//               done, it creates a DisplayRegion for itself and renders
+//               itself in the upper-right-hand corner.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA SceneGraphAnalyzerMeter : public TextNode {
+PUBLISHED:
+  SceneGraphAnalyzerMeter(const string &name, PandaNode *node);
+  virtual ~SceneGraphAnalyzerMeter();
+
+  void setup_window(GraphicsOutput *window);
+  void clear_window();
+
+  INLINE GraphicsOutput *get_window() const;
+  INLINE DisplayRegion *get_display_region() const;
+
+  INLINE void set_update_interval(double update_interval);
+  INLINE double get_update_interval() const;
+
+  INLINE void set_node(PandaNode *node);
+  INLINE PandaNode *get_node() const;
+
+  INLINE void update();
+
+protected:
+  virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
+
+private:
+  void do_update(Thread *current_thread);
+
+private:
+  PT(GraphicsOutput) _window;
+  PT(DisplayRegion) _display_region;
+  NodePath _root;
+  SceneGraphAnalyzer _scene_graph_analyzer;
+
+  double _update_interval;
+  double _last_update;
+  PandaNode *_node;
+  ClockObject *_clock_object;
+
+  static PStatCollector _show_analyzer_pcollector;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TextNode::init_type();
+    register_type(_type_handle, "SceneGraphAnalyzerMeter",
+                  TextNode::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 "sceneGraphAnalyzerMeter.I"
+
+#endif

File diff suppressed because it is too large
+ 496 - 496
panda/src/mathutil/triangulator.cxx


+ 19 - 19
panda/src/mathutil/triangulator.h

@@ -85,15 +85,15 @@ private:
   } point_t, vector_t;
   
 
-  struct segment_t {	
+  struct segment_t {
     INLINE segment_t();
     INLINE segment_t(Triangulator *t, int v0_i, int v1_i, int prev, int next);
 
-    point_t v0, v1;		/* two endpoints */
-    int is_inserted;		/* inserted in trapezoidation yet ? */
-    int root0, root1;		/* root nodes in Q */
-    int next;			/* Next logical segment */
-    int prev;			/* Previous segment */
+    point_t v0, v1;             /* two endpoints */
+    int is_inserted;            /* inserted in trapezoidation yet ? */
+    int root0, root1;           /* root nodes in Q */
+    int next;                   /* Next logical segment */
+    int prev;                   /* Previous segment */
     int v0_i; // index to user's vertex number
   };
 
@@ -105,12 +105,12 @@ private:
   /* Trapezoid attributes */
 
   typedef struct {
-    int lseg, rseg;		/* two adjoining segments */
-    point_t hi, lo;		/* max/min y-values */
+    int lseg, rseg;             /* two adjoining segments */
+    point_t hi, lo;             /* max/min y-values */
     int u0, u1;
     int d0, d1;
-    int sink;			/* pointer to corresponding in Q */
-    int usave, uside;		/* I forgot what this means */
+    int sink;                   /* pointer to corresponding in Q */
+    int usave, uside;           /* I forgot what this means */
     int state;
   } trap_t;
   
@@ -118,27 +118,27 @@ private:
   /* Node attributes for every node in the query structure */
   
   typedef struct {
-    int nodetype;			/* Y-node or S-node */
+    int nodetype;                       /* Y-node or S-node */
     int segnum;
     point_t yval;
     int trnum;
-    int parent;			/* doubly linked DAG */
-    int left, right;		/* children */
+    int parent;                 /* doubly linked DAG */
+    int left, right;            /* children */
   } node_t;
 
 
   typedef struct {
     int vnum;
-    int next;			/* Circularly linked list  */
-    int prev;			/* describing the monotone */
-    int marked;			/* polygon */
-  } monchain_t;			
+    int next;                   /* Circularly linked list  */
+    int prev;                   /* describing the monotone */
+    int marked;                 /* polygon */
+  } monchain_t;
   
   
   typedef struct {
     point_t pt;
-    int vnext[4];			/* next vertices for the 4 chains */
-    int vpos[4];			/* position of v in the 4 chains */
+    int vnext[4];                       /* next vertices for the 4 chains */
+    int vpos[4];                        /* position of v in the 4 chains */
     int nextfree;
     int user_i;  // index to user's vertex number
   } vertexchain_t;

Some files were not shown because too many files changed in this diff