Pārlūkot izejas kodu

Merge branch 'master' into cmake

Sam Edwards 7 gadi atpakaļ
vecāks
revīzija
62f7aabe91

+ 0 - 9
direct/src/configfiles/direct.init

@@ -1,9 +0,0 @@
-ATTACH dmodels
-ATTACH panda
-MODREL ETC_PATH etc
-DOCSH set parent=`dirname $DIRECT`
-DOCSH if ( ${?PANDA_ROOT} ) then
-DOCSH   setenv PYTHONPATH "${PYTHONPATH};"`cygpath -w "$parent"`
-DOCSH else
-DOCSH   setenv PYTHONPATH "${PYTHONPATH}:$parent"
-DOCSH endif

+ 1 - 5
dtool/src/cppparser/cppStructType.cxx

@@ -306,7 +306,6 @@ is_trivial() const {
   }
 
   // Now look for functions that are virtual or con/destructors.
-  bool is_default_constructible = true;
   CPPScope::Functions::const_iterator fi;
   for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
     CPPFunctionGroup *fgroup = (*fi).second;
@@ -343,9 +342,6 @@ is_trivial() const {
           // Same for the default constructor.
           return false;
         }
-        // The presence of a non-default constructor makes the class not
-        // default-constructible.
-        is_default_constructible = false;
       }
 
       if (fgroup->_name == "operator =") {
@@ -356,7 +352,7 @@ is_trivial() const {
   }
 
   // Finally, the class must be default-constructible.
-  return is_default_constructible;
+  return is_default_constructible(V_public);
 }
 
 /**

+ 2 - 1
dtool/src/interrogate/interrogateBuilder.cxx

@@ -1389,7 +1389,8 @@ scan_element(CPPInstance *element, CPPStructType *struct_type,
     // We can only generate a getter and a setter if we can talk about the
     // type it is.
 
-    if (parameter_type->as_struct_type() != nullptr) {
+    if (parameter_type->as_struct_type() != nullptr &&
+        !parameter_type->is_trivial()) {
       // Wrap the type in a const reference.
       parameter_type = TypeManager::wrap_const_reference(parameter_type);
     }

+ 0 - 2
makepanda/installer.nsi

@@ -589,7 +589,6 @@ Section "3ds Max plug-ins" SecMaxPlugins
     File /nonfatal /r "${BUILT}\plugins\*.dle"
     File /nonfatal /r "${BUILT}\plugins\*.dlo"
     File /nonfatal /r "${BUILT}\plugins\*.ms"
-    File "${SOURCE}\doc\INSTALLING-PLUGINS.TXT"
 SectionEnd
 !endif
 
@@ -604,7 +603,6 @@ Section "Maya plug-ins" SecMayaPlugins
     SetOutPath $INSTDIR\plugins
     File /nonfatal /r "${BUILT}\plugins\*.mll"
     File /nonfatal /r "${BUILT}\plugins\*.mel"
-    File "${SOURCE}\doc\INSTALLING-PLUGINS.TXT"
 SectionEnd
 !endif
 

+ 6 - 0
panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm

@@ -134,6 +134,12 @@ get_properties(FrameBufferProperties &properties, NSOpenGLPixelFormat* pixel_for
   if (accelerated) {
     properties.set_force_hardware(1);
   }
+
+  // Cautiously setting this to true.  It appears that macOS framebuffers are
+  // sRGB-capable, but I don't really know how to verify this.
+  if (color_size == 32 && !color_float) {
+    properties.set_srgb_color(true);
+  }
 }
 
 /**

+ 9 - 4
panda/src/collide/collisionHandlerQueue.cxx

@@ -22,10 +22,15 @@ class CollisionEntrySorter {
 public:
   CollisionEntrySorter(CollisionEntry *entry) {
     _entry = entry;
-    LVector3 vec =
-      entry->get_surface_point(entry->get_from_node_path()) -
-      entry->get_from()->get_collision_origin();
-    _dist2 = vec.length_squared();
+    if (entry->has_surface_point()) {
+      LVector3 vec =
+        entry->get_surface_point(entry->get_from_node_path()) -
+        entry->get_from()->get_collision_origin();
+      _dist2 = vec.length_squared();
+    }
+    else {
+      _dist2 = make_inf((PN_stdfloat)0);
+    }
   }
   bool operator < (const CollisionEntrySorter &other) const {
     return _dist2 < other._dist2;

+ 0 - 10
panda/src/configfiles/panda.init

@@ -1,10 +0,0 @@
-SETABS PANDA_VER 0.8
-MODREL ETC_PATH built/etc
-DOCSH if ( ! $?CFG_PATH ) then
-DOCSH   setenv CFG_PATH ~
-DOCSH   setenv CFG_PATH ". ${CFG_PATH} /usr/local/etc"
-DOCSH endif
-DOSH if [ -z "$CFG_PATH" ]; then
-DOSH   CFG_PATH=". $HOME /usr/local/etc"
-DOSH   export CFG_PATH
-DOSH fi

+ 0 - 269
panda/src/dxgsg9/dxInput9.cxx

@@ -1,269 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file dxInput9.cxx
- * @author angelina jolie
- * @date 1999-10-07
- */
-
-#include "config_wdxdisplay9.h"
-#include "dxInput9.h"
-
-#define AXIS_RESOLUTION 2000   // use this many levels of resolution by default (could be more if needed and device supported it)
-#define AXIS_RANGE_CENTERED    // if defined, axis range is centered on 0, instead of starting on 0
-
-using std::endl;
-
-BOOL CALLBACK EnumGameCtrlsCallback( const DIDEVICEINSTANCE* pdidInstance,
-                                     VOID* pContext ) {
-    DI_DeviceInfos *pDevInfos = (DI_DeviceInfos *)pContext;
-
-    (*pDevInfos).push_back(*pdidInstance);
-
-    if(wdxdisplay_cat.is_debug())
-        wdxdisplay_cat.debug() << "Found DevType 0x" << (void*)pdidInstance->dwDevType << ": " << pdidInstance->tszInstanceName << ": " << pdidInstance->tszProductName <<endl;
-
-    return DIENUM_CONTINUE;
-}
-
-extern BOOL CALLBACK EnumObjectsCallbackJoystick(const DIDEVICEOBJECTINSTANCE* pdidoi,VOID* pContext);
-
-DInput9Info::DInput9Info() {
-    _pDInput9 = nullptr;
-    _hDInputDLL = nullptr;
-    _JoystickPollTimer = nullptr;
-}
-
-DInput9Info::~DInput9Info() {
-  for(UINT i=0;i<_DeviceList.size();i++) {
-      _DeviceList[i]->Unacquire();
-      SAFE_RELEASE(_DeviceList[i]);
-  }
-
-  // bugbug: need to handle this if(_JoystickPollTimer!=NULL) KillTimer(...)
-
-  SAFE_RELEASE(_pDInput9);
-  if(_hDInputDLL) {
-      FreeLibrary(_hDInputDLL);
-      _hDInputDLL=nullptr;
-  }
-}
-
-bool DInput9Info::InitDirectInput() {
-    HRESULT hr;
-
-    // assumes dx9 exists use dynamic load so non-dinput programs don't have
-    // to load dinput
-    #define DLLNAME "dinput9.dll"
-    #define DINPUTCREATE "DirectInput9Create"
-
-    HINSTANCE _hDInputDLL = LoadLibrary(DLLNAME);
-    if(_hDInputDLL == 0) {
-        wdxdisplay_cat.fatal() << "LoadLibrary(" << DLLNAME <<") failed!, error=" << GetLastError() << endl;
-        exit(1);
-    }
-
-    typedef HRESULT (WINAPI * LPDIRECTINPUT9CREATE)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
-    LPDIRECTINPUT9CREATE pDInputCreate9;
-
-    pDInputCreate9 = (LPDIRECTINPUT9CREATE) GetProcAddress(_hDInputDLL,DINPUTCREATE);
-    if(pDInputCreate9 == nullptr) {
-        wdxdisplay_cat.fatal() << "GetProcAddr failed for " << DINPUTCREATE << endl;
-        exit(1);
-    }
-
-    // Register with the DirectInput subsystem and get a pointer to a
-    // IDirectInput interface we can use.  Create a DInput object
-    if( FAILED( hr = (*pDInputCreate9)(GetModuleHandle(nullptr), DIRECTINPUT_VERSION,
-                                         IID_IDirectInput9, (VOID**)&_pDInput9, nullptr ) ) ) {
-        wdxdisplay_cat.error() << DINPUTCREATE << "failed" << D3DERRORSTRING(hr);
-        return false;
-    }
-
-    // enum all the joysticks,etc  (but not keybdmouse)
-    if( FAILED( hr = _pDInput9->EnumDevices(DI9DEVCLASS_GAMECTRL,
-                                         EnumGameCtrlsCallback,
-                                         (LPVOID)&_DevInfos, DIEDFL_ATTACHEDONLY ) ) ) {
-        wdxdisplay_cat.error() << "EnumDevices failed" << D3DERRORSTRING(hr);
-        return false;
-    }
-
-    return true;
-}
-
-bool DInput9Info::CreateJoystickOrPad(HWND _window) {
-    bool bFoundDev = false;
-    UINT devnum=0;
-    char *errstr=nullptr;
-
-    // look through the list for the first joystick or gamepad
-    for(;devnum<_DevInfos.size();devnum++) {
-        DWORD devType = GET_DIDEVICE_TYPE(_DevInfos[devnum].dwDevType);
-        if((devType==DI9DEVTYPE_GAMEPAD) ||(devType==DI9DEVTYPE_JOYSTICK)) {
-          bFoundDev=true;
-          break;
-        }
-    }
-
-    if(!bFoundDev) {
-        wdxdisplay_cat.error() << "Cant find an attached Joystick or GamePad!\n";
-        return false;
-    }
-
-    LPDIRECTINPUTDEVICE9 pJoyDevice;
-
-    // Obtain an interface to the enumerated joystick.
-    HRESULT hr = _pDInput9->CreateDevice(_DevInfos[devnum].guidInstance, &pJoyDevice, nullptr );
-    if(FAILED(hr)) {
-        errstr="CreateDevice";
-        goto handle_error;
-    }
-
-    assert(pJoyDevice!=nullptr);
-    _DeviceList.push_back(pJoyDevice);
-
-    // Set the data format to "simple joystick" - a predefined data format A
-    // data format specifies which controls on a device we are interested in,
-    // and how they should be reported.  This tells DInput that we will be
-    // passing a DIJOYSTATE2 structure to
-    // IDirectInputDevice::GetDeviceState().
-    hr = pJoyDevice->SetDataFormat(&c_dfDIJoystick2);
-    if(FAILED(hr)) {
-        errstr="SetDataFormat";
-        goto handle_error;
-    }
-
-    // must be called AFTER SetDataFormat to get all the proper flags
-    DX_DECLARE_CLEAN(DIDEVCAPS, DIDevCaps);
-    hr = pJoyDevice->GetCapabilities(&DIDevCaps);
-    assert(SUCCEEDED(hr));
-
-    _DevCaps.push_back(DIDevCaps);
-
-    if(wdxdisplay_cat.is_debug())
-        wdxdisplay_cat.debug() << "Joy/Pad has " << DIDevCaps.dwAxes << " Axes, " <<  DIDevCaps.dwButtons << " Buttons, " <<  DIDevCaps.dwPOVs << " POVs" << endl;
-
-    // Set the cooperative level to let DInput know how this device should
-    // interact with the system and with other DInput applications.
-    hr = pJoyDevice->SetCooperativeLevel( _window, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
-    if(FAILED(hr)) {
-        errstr="SetCooperativeLevel";
-        goto handle_error;
-    }
-
-    // set the minmax values property for discovered axes.
-    hr = pJoyDevice->EnumObjects(EnumObjectsCallbackJoystick, (LPVOID)pJoyDevice, DIDFT_AXIS);
-    if(FAILED(hr)) {
-        errstr="EnumObjects";
-        goto handle_error;
-    }
-
-    return true;
-
-  handle_error:
-    wdxdisplay_cat.error() << errstr << " failed for (" << _DevInfos[devnum].tszInstanceName << ":" << _DevInfos[devnum].tszProductName << ")" << D3DERRORSTRING(hr);
-    return false;
-}
-
-// ---------------------------------------------------------------------------
-// -- Name: EnumObjectsCallback() Desc: Callback function for enumerating
-// objects (axes, buttons, POVs) on a joystick.  This function enables user
-// interface elements for objects that are found to exist, and scales axes
-// minmax values.  -----------------------------------------------------------
-// ------------------
-BOOL CALLBACK EnumObjectsCallbackJoystick( const DIDEVICEOBJECTINSTANCE* pdidoi,
-                                   VOID* pContext ) {
-
-    LPDIRECTINPUTDEVICE9 pJoyDevice = (LPDIRECTINPUTDEVICE9) pContext;
-    HRESULT hr;
-
-    // For axes that are returned, set the DIPROP_RANGE property for the
-    // enumerated axis in order to scale minmax values.
-    if( pdidoi->dwType & DIDFT_AXIS ) {
-        DIPROPRANGE diprg;
-        diprg.diph.dwSize       = sizeof(DIPROPRANGE);
-        diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
-        diprg.diph.dwHow        = DIPH_BYID;
-        diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
-
-     #ifdef AXIS_RANGE_CENTERED
-        diprg.lMin              = -AXIS_RESOLUTION/2;
-        diprg.lMax              = +AXIS_RESOLUTION/2;
-     #else
-        diprg.lMin              = 0;
-        diprg.lMax              = +AXIS_RESOLUTION;
-     #endif
-
-        // Set the range for the axis
-        hr = pJoyDevice->SetProperty( DIPROP_RANGE, &diprg.diph);
-        if(FAILED(hr)) {
-          wdxdisplay_cat.error() << "SetProperty on axis failed" << D3DERRORSTRING(hr);
-          return DIENUM_STOP;
-        }
-    }
-
-    return DIENUM_CONTINUE;
-}
-
-bool DInput9Info::ReadJoystick(int devnum, DIJOYSTATE2 &js) {
-    LPDIRECTINPUTDEVICE9 pJoystick = _DeviceList[devnum];
-    assert(pJoystick!=nullptr);
-    HRESULT hr;
-    char *errstr;
-
-    // Poll the device to read the current state
-
-    hr = pJoystick->Poll();
-
-    if( FAILED(hr) ) {
-        // DInput is telling us that the input stream has been interrupted.
-        // We aren't tracking any state between polls, so we don't have any
-        // special reset that needs to be done.  We just re-acquire and try
-        // again.
-
-        if((hr==DIERR_NOTACQUIRED)||(hr == DIERR_INPUTLOST)) {
-            hr = pJoystick->Acquire();
-
-            if(FAILED(hr)) {
-                if(wdxdisplay_cat.is_spam())
-                   wdxdisplay_cat.spam() << "Acquire failed" << D3DERRORSTRING(hr);
-
-                // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This may
-                // occur when the app is minimized or in the process of
-                // switching, so just try again later
-                return false;
-            }
-
-            hr = pJoystick->Poll();
-            if(FAILED(hr)) {
-                // should never happen!
-                errstr = "Poll after successful Acquire failed";
-                goto handle_error;
-            }
-        } else {
-            errstr =  "Unknown Poll failure";
-            goto handle_error;
-        }
-    }
-
-    // should we make a vector of devstate dataformats to generalize this fn
-    // for all device types?
-
-    // Get the input's device state
-    hr = pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js);
-    if(FAILED(hr)) {
-        errstr =  "GetDeviceState failed";
-        goto handle_error;
-    }
-
-    return true;
-
-  handle_error:
-     wdxdisplay_cat.fatal() << errstr << D3DERRORSTRING(hr);
-     return false;
-}

+ 0 - 40
panda/src/dxgsg9/dxInput9.h

@@ -1,40 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file dxInput9.h
- * @author blllyjo
- * @date 1999-10-07
- */
-
-#ifndef DXINPUT9_H
-#define DXINPUT9_H
-
-#define DIRECTINPUT_VERSION 0x900
-#include <dinput.h>
-typedef std::vector<DIDEVICEINSTANCE> DI_DeviceInfos;
-typedef std::vector<DIDEVICEOBJECTINSTANCE> DI_DeviceObjInfos;
-
-class DInput9Info {
-public:
- DInput9Info();
- ~DInput9Info();
- bool InitDirectInput();
- bool CreateJoystickOrPad(HWND _window);
- bool ReadJoystick(int devnum, DIJOYSTATE2 &js);
-
- HINSTANCE _hDInputDLL;
- UINT_PTR  _JoystickPollTimer;
- LPDIRECTINPUT8 _pDInput9;
- DI_DeviceInfos _DevInfos;
- // arrays for all created devices.  Should probably put these together in a
- // struct, along with the data fmt info
- std::vector<LPDIRECTINPUTDEVICE8> _DeviceList;
- std::vector<DIDEVCAPS> _DevCaps;
-};
-
-#endif

+ 0 - 1
panda/src/dxgsg9/dxgsg9base.h

@@ -211,7 +211,6 @@ struct DXScreenData {
   bool _is_tnl_device;
   bool _can_use_hw_vertex_shaders;
   bool _can_use_pixel_shaders;
-  bool _is_dx9_1;
   UINT _supported_screen_depths_mask;
   UINT _supported_tex_formats_mask;
   bool _supports_rgba16f_texture_format;

+ 8 - 26
panda/src/dxgsg9/wdxGraphicsPipe9.cxx

@@ -193,30 +193,10 @@ init() {
   }
 
   // Create a Direct3D object.
+  __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION);
 
-  // these were taken from the 8.0 and 8.1 d3d8.h SDK headers
-    __is_dx9_1 = false;
-
-#define D3D_SDK_VERSION_9_0 D3D_SDK_VERSION
-#define D3D_SDK_VERSION_9_1 D3D_SDK_VERSION
-
-  // are we using 9.0 or 9.1?
-  WIN32_FIND_DATA TempFindData;
-  HANDLE hFind;
-  char tmppath[_MAX_PATH + 128];
-  GetSystemDirectory(tmppath, MAX_PATH);
-  strcat(tmppath, "\\dpnhpast.dll");
-  hFind = FindFirstFile (tmppath, &TempFindData);
-  if (hFind != INVALID_HANDLE_VALUE) {
-    FindClose(hFind);
-// ??? This was from DX8 __is_dx9_1 = true;
-    __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_1);
-  } else {
-    __is_dx9_1 = false;
-    __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_0);
-  }
   if (__d3d9 == nullptr) {
-    wdxdisplay9_cat.error() << "Direct3DCreate9(9." << (__is_dx9_1 ? "1" : "0") << ") failed!, error = " << GetLastError() << endl;
+    wdxdisplay9_cat.error() << "Direct3DCreate9 failed!, error = " << GetLastError() << endl;
     // release_gsg();
     goto error;
   }
@@ -361,11 +341,13 @@ find_all_card_memavails() {
       if (!ISPOW2(dwVidMemTotal)) {
         // assume they wont return a proper max value, so round up to next pow
         // of 2
-        UINT count = 0;
-        while ((dwVidMemTotal >> count) != 0x0) {
-          count++;
+        int count = get_next_higher_bit((uint32_t)(dwVidMemTotal - 1u));
+        if (count >= 32u) {
+          // Maximum value that fits in a UINT.
+          dwVidMemTotal = 0xffffffffu;
+        } else {
+          dwVidMemTotal = (1u << count);
         }
-        dwVidMemTotal = (1 << count);
       }
     }
 

+ 0 - 1
panda/src/dxgsg9/wdxGraphicsPipe9.h

@@ -93,7 +93,6 @@ private:
 
   typedef pvector<CardID> CardIDs;
   CardIDs _card_ids;
-  bool __is_dx9_1;
 
 public:
   static TypeHandle get_class_type() {

+ 1 - 2
panda/src/dxgsg9/wdxGraphicsWindow9.cxx

@@ -878,7 +878,7 @@ choose_device() {
     LARGE_INTEGER *DrvVer = &adapter_info.DriverVersion;
 
     wdxdisplay9_cat.info()
-      << "D3D9." << (dxpipe->__is_dx9_1 ?"1":"0") << " Adapter[" << i << "]: " << adapter_info.Description
+      << "D3D9 Adapter[" << i << "]: " << adapter_info.Description
       << ", Driver: " << adapter_info.Driver << ", DriverVersion: ("
       << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "."
       << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart)
@@ -979,7 +979,6 @@ consider_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) {
 
   nassertr(_dxgsg != nullptr, false);
   _wcontext._d3d9 = _d3d9;
-  _wcontext._is_dx9_1 = dxpipe->__is_dx9_1;
   _wcontext._card_id = device_info->cardID;  // could this change by end?
 
   bool bWantStencil = (_fb_properties.get_stencil_bits() > 0);

+ 0 - 1
panda/src/dxgsg9/wdxGraphicsWindow9.h

@@ -17,7 +17,6 @@
 #include "pandabase.h"
 #include "winGraphicsWindow.h"
 #include "dxGraphicsStateGuardian9.h"
-#include "dxInput9.h"
 #include "wdxGraphicsPipe9.h"
 
 class wdxGraphicsPipe9;

+ 1 - 1
panda/src/event/asyncFuture_ext.h

@@ -16,7 +16,7 @@
 
 #include "extension.h"
 #include "py_panda.h"
-#include "modelLoadRequest.h"
+#include "asyncFuture.h"
 
 #ifdef HAVE_PYTHON
 

+ 285 - 94
panda/src/gobj/shader.cxx

@@ -2468,6 +2468,96 @@ read(const ShaderFile &sfile, BamCacheRecord *record) {
   return true;
 }
 
+/**
+ * Loads the shader from the given string(s). Returns a boolean indicating
+ * success or failure.
+ */
+bool Shader::
+load(const ShaderFile &sbody, BamCacheRecord *record) {
+  _filename = ShaderFile("created-shader");
+  _fullpath = Filename();
+  _text._separate = sbody._separate;
+
+  if (sbody._separate) {
+    if (_language == SL_none) {
+      shader_cat.error()
+        << "No shader language was specified!\n";
+      return false;
+    }
+
+    if (!sbody._vertex.empty() &&
+        !do_load_source(_text._vertex, sbody._vertex, record)) {
+      return false;
+    }
+    if (!sbody._fragment.empty() &&
+        !do_load_source(_text._fragment, sbody._fragment, record)) {
+      return false;
+    }
+    if (!sbody._geometry.empty() &&
+        !do_load_source(_text._geometry, sbody._geometry, record)) {
+      return false;
+    }
+    if (!sbody._tess_control.empty() &&
+        !do_load_source(_text._tess_control, sbody._tess_control, record)) {
+      return false;
+    }
+    if (!sbody._tess_evaluation.empty() &&
+        !do_load_source(_text._tess_evaluation, sbody._tess_evaluation, record)) {
+      return false;
+    }
+    if (!sbody._compute.empty() &&
+        !do_load_source(_text._compute, sbody._compute, record)) {
+      return false;
+    }
+
+  } else {
+    if (!do_load_source(_text._shared, sbody._shared, record)) {
+      return false;
+    }
+
+    // Determine which language the shader is written in.
+    if (_language == SL_none) {
+      string header;
+      parse_init();
+      parse_line(header, true, true);
+      if (header == "//Cg") {
+        _language = SL_Cg;
+      } else {
+        shader_cat.error()
+          << "Unable to determine shader language of " << sbody._shared << "\n";
+        return false;
+      }
+    } else if (_language == SL_GLSL) {
+      shader_cat.error()
+        << "GLSL shaders must have separate shader bodies!\n";
+      return false;
+    }
+
+    // Determine which language the shader is written in.
+    if (_language == SL_Cg) {
+#ifdef HAVE_CG
+      cg_get_profile_from_header(_default_caps);
+
+      if (!cg_analyze_shader(_default_caps)) {
+        shader_cat.error()
+          << "Shader encountered an error.\n";
+        return false;
+      }
+#else
+      shader_cat.error()
+        << "Tried to load Cg shader, but no Cg support is enabled.\n";
+#endif
+    } else {
+      shader_cat.error()
+        << "Shader is not in a supported shader-language.\n";
+      return false;
+    }
+  }
+
+  _loaded = true;
+  return true;
+}
+
 /**
  * Reads the shader file from the given path into the given string.
  *
@@ -2476,37 +2566,85 @@ read(const ShaderFile &sfile, BamCacheRecord *record) {
  */
 bool Shader::
 do_read_source(string &into, const Filename &fn, BamCacheRecord *record) {
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+  PT(VirtualFile) vf = vfs->find_file(fn, get_model_path());
+  if (vf == nullptr) {
+    shader_cat.error()
+      << "Could not find shader file: " << fn << "\n";
+    return false;
+  }
+
   if (_language == SL_GLSL && glsl_preprocess) {
+    istream *source = vf->open_read_file(true);
+    if (source == nullptr) {
+      shader_cat.error()
+        << "Could not open shader file: " << fn << "\n";
+      return false;
+    }
+
     // Preprocess the GLSL file as we read it.
+    shader_cat.info()
+      << "Preprocessing shader file: " << fn << "\n";
+
     std::set<Filename> open_files;
     ostringstream sstr;
-    if (!r_preprocess_source(sstr, fn, Filename(), open_files, record)) {
+    if (!r_preprocess_source(sstr, *source, fn, vf->get_filename(), open_files, record)) {
+      vf->close_read_file(source);
       return false;
     }
+    vf->close_read_file(source);
     into = sstr.str();
 
   } else {
     shader_cat.info() << "Reading shader file: " << fn << "\n";
 
-    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
-    PT(VirtualFile) vf = vfs->find_file(fn, get_model_path());
-    if (vf == nullptr) {
-      shader_cat.error()
-        << "Could not find shader file: " << fn << "\n";
-      return false;
-    }
-
     if (!vf->read_file(into, true)) {
       shader_cat.error()
         << "Could not read shader file: " << fn << "\n";
       return false;
     }
+  }
+
+  if (record != nullptr) {
+    record->add_dependent_file(vf);
+  }
 
-    if (record != nullptr) {
-      record->add_dependent_file(vf);
+  _last_modified = std::max(_last_modified, vf->get_timestamp());
+  _source_files.push_back(vf->get_filename());
+
+  // Strip trailing whitespace.
+  while (!into.empty() && isspace(into[into.size() - 1])) {
+    into.resize(into.size() - 1);
+  }
+
+  // Except add back a newline at the end, which is needed by Intel drivers.
+  into += "\n";
+
+  return true;
+}
+
+/**
+ * Loads the shader file from the given string into the given string,
+ * performing any pre-processing on it that may be necessary.
+ *
+ * Returns false if there was an error with this shader bad enough to consider
+ * it 'invalid'.
+ */
+bool Shader::
+do_load_source(string &into, const std::string &source, BamCacheRecord *record) {
+  if (_language == SL_GLSL && glsl_preprocess) {
+    // Preprocess the GLSL file as we read it.
+    std::set<Filename> open_files;
+    std::ostringstream sstr;
+    std::istringstream in(source);
+    if (!r_preprocess_source(sstr, in, Filename("created-shader"), Filename(),
+                             open_files, record)) {
+      return false;
     }
-    _last_modified = std::max(_last_modified, vf->get_timestamp());
-    _source_files.push_back(vf->get_filename());
+    into = sstr.str();
+
+  } else {
+    into = source;
   }
 
   // Strip trailing whitespace.
@@ -2528,10 +2666,10 @@ do_read_source(string &into, const Filename &fn, BamCacheRecord *record) {
  * recursive includes.
  */
 bool Shader::
-r_preprocess_source(ostream &out, const Filename &fn,
-                    const Filename &source_dir,
-                    std::set<Filename> &once_files,
-                    BamCacheRecord *record, int depth) {
+r_preprocess_include(ostream &out, const Filename &fn,
+                     const Filename &source_dir,
+                     std::set<Filename> &once_files,
+                     BamCacheRecord *record, int depth) {
 
   if (depth > glsl_include_recursion_limit) {
     shader_cat.error()
@@ -2549,7 +2687,7 @@ r_preprocess_source(ostream &out, const Filename &fn,
   PT(VirtualFile) vf = vfs->find_file(fn, path);
   if (vf == nullptr) {
     shader_cat.error()
-      << "Could not find shader file: " << fn << "\n";
+      << "Could not find shader include: " << fn << "\n";
     return false;
   }
 
@@ -2562,7 +2700,7 @@ r_preprocess_source(ostream &out, const Filename &fn,
   istream *source = vf->open_read_file(true);
   if (source == nullptr) {
     shader_cat.error()
-      << "Could not open shader file: " << fn << "\n";
+      << "Could not open shader include: " << fn << "\n";
     return false;
   }
 
@@ -2578,34 +2716,52 @@ r_preprocess_source(ostream &out, const Filename &fn,
   // than that, unfortunately.  Don't do this for the top-level file, though.
   // We don't want anything to get in before a potential #version directive.
   int fileno = 0;
-  if (depth > 0) {
-    fileno = 2048 + _included_files.size();
-    // Write it into the vector so that we can substitute it later when we are
-    // parsing the GLSL error log.  Don't store the full filename because it
-    // would just be too long to display.
-    _included_files.push_back(fn);
-
-    out << "#line 1 " << fileno << " // " << fn << "\n";
-    if (shader_cat.is_debug()) {
-      shader_cat.debug()
-        << "Preprocessing shader include " << fileno << ": " << fn << "\n";
-    }
-  } else {
-    shader_cat.info()
-      << "Preprocessing shader file: " << fn << "\n";
+  fileno = 2048 + _included_files.size();
+
+  // Write it into the vector so that we can substitute it later when we are
+  // parsing the GLSL error log.  Don't store the full filename because it
+  // would just be too long to display.
+  _included_files.push_back(fn);
+
+  if (shader_cat.is_debug()) {
+    shader_cat.debug()
+      << "Preprocessing shader include " << fileno << ": " << fn << "\n";
   }
 
+  bool result = r_preprocess_source(out, *source, fn, full_fn, once_files, record, fileno, depth);
+  vf->close_read_file(source);
+  return result;
+}
+
+/**
+ * Loads a given GLSL stream line by line, processing any #pragma include and
+ * once statements, as well as removing any comments.
+ *
+ * The set keeps track of which files we have already included, for checking
+ * recursive includes.
+ */
+bool Shader::
+r_preprocess_source(ostream &out, istream &in, const Filename &fn,
+                    const Filename &full_fn, std::set<Filename> &once_files,
+                    BamCacheRecord *record, int fileno, int depth) {
+
   // Iterate over the lines for things we may need to preprocess.
   string line;
   int ext_google_include = 0; // 1 = warn, 2 = enable
   int ext_google_line = 0;
   bool had_include = false;
   int lineno = 0;
-  while (std::getline(*source, line)) {
+  bool write_line_directive = (fileno != 0);
+
+  while (std::getline(in, line)) {
     ++lineno;
 
     if (line.empty()) {
-      out.put('\n');
+      // We still write a newline to make sure the line numbering remains
+      // consistent, unless we are about to write a #line directive anyway.
+      if (!write_line_directive) {
+        out.put('\n');
+      }
       continue;
     }
 
@@ -2615,9 +2771,11 @@ r_preprocess_source(ostream &out, const Filename &fn,
       line.resize(line.size() - 1);
       string line2;
 
-      if (std::getline(*source, line2)) {
+      if (std::getline(in, line2)) {
         line += line2;
-        out.put('\n');
+        if (!write_line_directive) {
+          out.put('\n');
+        }
         ++lineno;
       } else {
         break;
@@ -2644,8 +2802,10 @@ r_preprocess_source(ostream &out, const Filename &fn,
       size_t block_end = line2.find("*/");
       while (block_end == string::npos) {
         // Didn't find it - look in the next line.
-        if (std::getline(*source, line2)) {
-          out.put('\n');
+        if (std::getline(in, line2)) {
+          if (!write_line_directive) {
+            out.put('\n');
+          }
           ++lineno;
           block_end = line2.find("*/");
         } else {
@@ -2663,10 +2823,21 @@ r_preprocess_source(ostream &out, const Filename &fn,
       line.resize(line.size() - 1);
     }
 
+    if (line.empty()) {
+      if (!write_line_directive) {
+        out.put('\n');
+      }
+      continue;
+    }
+
     // Check if this line contains a #directive.
     char directive[64];
     if (line.size() < 8 || sscanf(line.c_str(), " # %63s", directive) != 1) {
       // Nope.  Just pass the line through unmodified.
+      if (write_line_directive) {
+        out << "#line " << lineno << " " << fileno << " // " << fn << "\n";
+        write_line_directive = false;
+      }
       out << line << "\n";
       continue;
     }
@@ -2703,7 +2874,7 @@ r_preprocess_source(ostream &out, const Filename &fn,
         }
 
         // OK, great.  Process the include.
-        if (!r_preprocess_source(out, incfn, source_dir, once_files, record, depth + 1)) {
+        if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
           // An error occurred.  Pass on the failure.
           shader_cat.error(false) << "included at line "
             << lineno << " of file " << fn << ":\n  " << line << "\n";
@@ -2711,8 +2882,9 @@ r_preprocess_source(ostream &out, const Filename &fn,
         }
 
         // Restore the line counter.
-        out << "#line " << (lineno + 1) << " " << fileno << " // " << fn << "\n";
+        write_line_directive = true;
         had_include = true;
+        continue;
 
       } else if (strcmp(pragma, "once") == 0) {
         // Do a stricter syntax check, just to be extra safe.
@@ -2724,26 +2896,35 @@ r_preprocess_source(ostream &out, const Filename &fn,
           return false;
         }
 
-        once_files.insert(full_fn);
+        if (fileno == 0) {
+          shader_cat.warning()
+            << "#pragma once in main file at line "
+            << lineno << " of file " << fn
+#ifndef NDEBUG
+            << ":\n  " << line
+#endif
+            << "\n";
+        }
 
-      } else {
-        // Forward it, the driver will ignore it if it doesn't know it.
-        out << line << "\n";
+        if (!full_fn.empty()) {
+          once_files.insert(full_fn);
+        }
+        continue;
       }
+      // Otherwise, just pass it through to the driver.
 
     } else if (strcmp(directive, "endif") == 0) {
       // Check for an #endif after an include.  We have to restore the line
       // number in case the include happened under an #if block.
-      out << line << "\n";
       if (had_include) {
-        out << "#line " << (lineno + 1) << " " << fileno << "\n";
+        write_line_directive = true;
       }
 
     } else if (strcmp(directive, "extension") == 0) {
       // Check for special preprocessing extensions.
       char extension[256];
       char behavior[9];
-      if (sscanf(line.c_str(), " # extension%*[ \t]%255s%*[ \t]:%*[ \t]%8s", extension, behavior) == 2) {
+      if (sscanf(line.c_str(), " # extension%*[ \t]%255[^: \t] : %8s", extension, behavior) == 2) {
         // Parse the behavior string.
         int mode;
         if (strcmp(behavior, "require") == 0 || strcmp(behavior, "enable") == 0) {
@@ -2769,7 +2950,8 @@ r_preprocess_source(ostream &out, const Filename &fn,
           }
           ext_google_include = mode;
           ext_google_line = mode;
-          out << line << "\n";
+          // Still pass it through to the driver, so it can enable other
+          // extensions.
 
         } else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0) {
           // Enable the Google extension support for #include statements.
@@ -2777,14 +2959,12 @@ r_preprocess_source(ostream &out, const Filename &fn,
           // This matches the behavior of Khronos' glslang reference compiler.
           ext_google_include = mode;
           ext_google_line = mode;
+          continue;
 
         } else if (strcmp(extension, "GL_GOOGLE_cpp_style_line_directive") == 0) {
           // Enables strings in #line statements.
           ext_google_line = mode;
-
-        } else {
-          // It's an extension the driver should worry about.
-          out << line << "\n";
+          continue;
         }
       } else {
         shader_cat.error()
@@ -2792,6 +2972,7 @@ r_preprocess_source(ostream &out, const Filename &fn,
           << lineno << " of file " << fn << ":\n  " << line << "\n";
         return false;
       }
+
     } else if (ext_google_include > 0 && strcmp(directive, "include") == 0) {
       // Warn about extension use if requested.
       if (ext_google_include == 1) {
@@ -2821,7 +3002,7 @@ r_preprocess_source(ostream &out, const Filename &fn,
 
       // OK, great.  Process the include.
       Filename source_dir = full_fn.get_dirname();
-      if (!r_preprocess_source(out, incfn, source_dir, once_files, record, depth + 1)) {
+      if (!r_preprocess_include(out, incfn, source_dir, once_files, record, depth + 1)) {
         // An error occurred.  Pass on the failure.
         shader_cat.error(false) << "included at line "
           << lineno << " of file " << fn << ":\n  " << line << "\n";
@@ -2829,8 +3010,9 @@ r_preprocess_source(ostream &out, const Filename &fn,
       }
 
       // Restore the line counter.
-      out << "#line " << (lineno + 1) << " " << fileno << " // " << fn << "\n";
+      write_line_directive = true;
       had_include = true;
+      continue;
 
     } else if (ext_google_line > 0 && strcmp(directive, "line") == 0) {
       // It's a #line directive.  See if it uses a string instead of number.
@@ -2854,18 +3036,17 @@ r_preprocess_source(ostream &out, const Filename &fn,
         _included_files.push_back(Filename(filestr));
 
         out << "#line " << lineno << " " << fileno << " // " << filestr << "\n";
-
-      } else {
-        // We couldn't parse the #line directive.  Pass it through unmodified.
-        out << line << "\n";
+        continue;
       }
-    } else {
-      // Different directive (eg. #version).  Leave it untouched.
-      out << line << "\n";
     }
+
+    if (write_line_directive) {
+      out << "#line " << lineno << " " << fileno << " // " << fn << "\n";
+      write_line_directive = false;
+    }
+    out << line << "\n";
   }
 
-  vf->close_read_file(source);
   return true;
 }
 
@@ -3227,28 +3408,26 @@ make(string body, ShaderLanguage lang) {
   if (cache_generated_shaders) {
     ShaderTable::const_iterator i = _make_table.find(sbody);
     if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
-      return i->second;
+      // But check that someone hasn't modified its includes in the meantime.
+      if (!i->second->check_modified()) {
+        return i->second;
+      }
     }
   }
 
   PT(Shader) shader = new Shader(lang);
-  shader->_filename = ShaderFile("created-shader");
-  shader->_text = move(sbody);
-
-#ifdef HAVE_CG
-  if (lang == SL_Cg) {
-    shader->cg_get_profile_from_header(_default_caps);
-
-    if (!shader->cg_analyze_shader(_default_caps)) {
-      shader_cat.error()
-        << "Shader encountered an error.\n";
-      return nullptr;
-    }
+  if (!shader->load(sbody)) {
+    return nullptr;
   }
-#endif
 
   if (cache_generated_shaders) {
-    _make_table[shader->_text] = shader;
+    ShaderTable::const_iterator i = _make_table.find(shader->_text);
+    if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
+      shader = i->second;
+    } else {
+      _make_table[shader->_text] = shader;
+    }
+    _make_table[std::move(sbody)] = shader;
   }
 
   if (dump_generated_shaders) {
@@ -3290,26 +3469,27 @@ make(ShaderLanguage lang, string vertex, string fragment, string geometry,
   if (cache_generated_shaders) {
     ShaderTable::const_iterator i = _make_table.find(sbody);
     if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
-      return i->second;
+      // But check that someone hasn't modified its includes in the meantime.
+      if (!i->second->check_modified()) {
+        return i->second;
+      }
     }
   }
 
   PT(Shader) shader = new Shader(lang);
   shader->_filename = ShaderFile("created-shader");
-  shader->_text = move(sbody);
-
-#ifdef HAVE_CG
-  if (lang == SL_Cg) {
-    if (!shader->cg_analyze_shader(_default_caps)) {
-      shader_cat.error()
-        << "Shader encountered an error.\n";
-      return nullptr;
-    }
+  if (!shader->load(sbody)) {
+    return nullptr;
   }
-#endif
 
   if (cache_generated_shaders) {
-    _make_table[shader->_text] = shader;
+    ShaderTable::const_iterator i = _make_table.find(shader->_text);
+    if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
+      shader = i->second;
+    } else {
+      _make_table[shader->_text] = shader;
+    }
+    _make_table[std::move(sbody)] = shader;
   }
 
   return shader;
@@ -3333,16 +3513,27 @@ make_compute(ShaderLanguage lang, string body) {
   if (cache_generated_shaders) {
     ShaderTable::const_iterator i = _make_table.find(sbody);
     if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
-      return i->second;
+      // But check that someone hasn't modified its includes in the meantime.
+      if (!i->second->check_modified()) {
+        return i->second;
+      }
     }
   }
 
   PT(Shader) shader = new Shader(lang);
   shader->_filename = ShaderFile("created-shader");
-  shader->_text = move(sbody);
+  if (!shader->load(sbody)) {
+    return nullptr;
+  }
 
   if (cache_generated_shaders) {
-    _make_table[shader->_text] = shader;
+    ShaderTable::const_iterator i = _make_table.find(shader->_text);
+    if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
+      shader = i->second;
+    } else {
+      _make_table[shader->_text] = shader;
+    }
+    _make_table[std::move(sbody)] = shader;
   }
 
   return shader;

+ 10 - 3
panda/src/gobj/shader.h

@@ -616,11 +616,18 @@ private:
   Shader(ShaderLanguage lang);
 
   bool read(const ShaderFile &sfile, BamCacheRecord *record = nullptr);
+  bool load(const ShaderFile &sbody, BamCacheRecord *record = nullptr);
   bool do_read_source(std::string &into, const Filename &fn, BamCacheRecord *record);
-  bool r_preprocess_source(std::ostream &out, const Filename &fn,
-                           const Filename &source_dir,
+  bool do_load_source(std::string &into, const std::string &source, BamCacheRecord *record);
+  bool r_preprocess_include(std::ostream &out, const Filename &fn,
+                            const Filename &source_dir,
+                            std::set<Filename> &open_files,
+                            BamCacheRecord *record, int depth);
+  bool r_preprocess_source(std::ostream &out, std::istream &in,
+                           const Filename &fn, const Filename &full_fn,
                            std::set<Filename> &open_files,
-                           BamCacheRecord *record, int depth = 0);
+                           BamCacheRecord *record,
+                           int fileno = 0, int depth = 0);
 
   bool check_modified() const;
 

+ 1 - 1
panda/src/pipeline/cycleData.h

@@ -44,7 +44,7 @@ class EXPCL_PANDA_PIPELINE CycleData : public NodeReferenceCount
 // If we are *not* compiling in pipelining support, the CycleData object is
 // stored directly within its containing classes, and hence should not be a
 // ReferenceCount object.
-class EXPCL_PANDA_PIPELINE CycleData
+class EXPCL_PANDA_PIPELINE CycleData : public MemoryBase
 
 #endif  // DO_PIPELINING
 {

+ 1 - 0
panda/src/windisplay/winDetectDx9.cxx

@@ -18,6 +18,7 @@
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN 1
 #endif
+#undef Configure
 #include <d3d9.h>
 #include "graphicsStateGuardian.h"
 #include "graphicsPipe.h"

+ 0 - 1
pandatool/src/configfiles/pandatool.init

@@ -1 +0,0 @@
-ATTACH panda