diff --git a/README.md b/README.md index a6e1a267a5..c1cf59a4df 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ are included as part of the Windows 7.1 SDK. You will also need to have the third-party dependency libraries available for the build scripts to use. These are available from one of these two URLs, depending on whether you are on a 32-bit or 64-bit system: -https://www.panda3d.org/download/panda3d-1.9.3/panda3d-1.9.3-tools-win32.zip -https://www.panda3d.org/download/panda3d-1.9.3/panda3d-1.9.3-tools-win64.zip +https://www.panda3d.org/download/panda3d-1.9.4/panda3d-1.9.4-tools-win32.zip +https://www.panda3d.org/download/panda3d-1.9.4/panda3d-1.9.4-tools-win64.zip After acquiring these dependencies, you may simply build Panda3D from the command prompt using the following command: @@ -97,7 +97,7 @@ macOS ----- On macOS, you will need to download a set of precompiled thirdparty packages in order to -compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.9.3/panda3d-1.9.3-tools-mac.tar.gz). +compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.9.4/panda3d-1.9.4-tools-mac.tar.gz). After placing the thirdparty directory inside the panda3d source directory, you may build Panda3D using a command like the following: diff --git a/direct/src/distributed/DistributedObject.py b/direct/src/distributed/DistributedObject.py index 0ed3e90a54..64fd3ecc20 100644 --- a/direct/src/distributed/DistributedObject.py +++ b/direct/src/distributed/DistributedObject.py @@ -4,7 +4,6 @@ from panda3d.core import * from panda3d.direct import * from direct.directnotify.DirectNotifyGlobal import directNotify from direct.distributed.DistributedObjectBase import DistributedObjectBase -from direct.showbase.PythonUtil import StackTrace #from PyDatagram import PyDatagram #from PyDatagramIterator import PyDatagramIterator @@ -259,7 +258,10 @@ class DistributedObject(DistributedObjectBase): def _destroyDO(self): # after this is called, the object is no longer a DistributedObject # but may still be used as a DelayDeleted object - self.destroyDoStackTrace = StackTrace() + if __debug__: + # StackTrace is omitted in packed versions + from direct.showbase.PythonUtil import StackTrace + self.destroyDoStackTrace = StackTrace() # check for leftover cached data that was not retrieved or flushed by this object # this will catch typos in the data name in calls to get/setCachedData if hasattr(self, '_cachedData'): diff --git a/direct/src/distributed/DoCollectionManager.py b/direct/src/distributed/DoCollectionManager.py index 16bf345f4e..fcff96e218 100755 --- a/direct/src/distributed/DoCollectionManager.py +++ b/direct/src/distributed/DoCollectionManager.py @@ -312,7 +312,6 @@ class DoCollectionManager: else: self.notify.warning('handleSetLocation: object %s not present' % self.getMsgChannel()) - @exceptionLogged() def storeObjectLocation(self, object, parentId, zoneId): oldParentId = object.parentId oldZoneId = object.zoneId diff --git a/direct/src/distributed/StagedObject.py b/direct/src/distributed/StagedObject.py index 7692dc3684..3127bd6e06 100755 --- a/direct/src/distributed/StagedObject.py +++ b/direct/src/distributed/StagedObject.py @@ -17,7 +17,6 @@ class StagedObject: call any "handle" functions. """ self.__state = initState - pass def goOnStage(self, *args, **kw): """ @@ -29,8 +28,6 @@ class StagedObject: if not self.isOnStage(): self.handleOnStage(*args, **kw) - pass - pass def handleOnStage(self): """ @@ -39,7 +36,6 @@ class StagedObject: Don't forget to call down to this one, though. """ self.__state = StagedObject.ON - pass def goOffStage(self, *args, **kw): """ @@ -51,8 +47,6 @@ class StagedObject: if not self.isOffStage(): self.handleOffStage(*args, **kw) - pass - pass def handleOffStage(self): """ @@ -61,7 +55,6 @@ class StagedObject: Don't forget to call down to this one, though. """ self.__state = StagedObject.OFF - pass def isOnStage(self): return self.__state == StagedObject.ON diff --git a/direct/src/fsm/FourState.py b/direct/src/fsm/FourState.py index df653825f9..af7b7d650c 100755 --- a/direct/src/fsm/FourState.py +++ b/direct/src/fsm/FourState.py @@ -90,7 +90,8 @@ class FourState: off (and so is state 2 which is oposite of 4 and therefore oposite of 'on'). """ - assert self.debugPrint("FourState(names=%s)"%(names)) + self.stateIndex = 0 + assert self.__debugPrint("FourState(names=%s)"%(names)) self.track = None self.stateTime = 0.0 self.names = names @@ -120,7 +121,6 @@ class FourState: self.exitState4, [names[1]]), } - self.stateIndex = 0 self.fsm = ClassicFSM.ClassicFSM('FourState', list(self.states.values()), # Initial State @@ -131,7 +131,7 @@ class FourState: self.fsm.enterInitialState() def setTrack(self, track): - assert self.debugPrint("setTrack(track=%s)"%(track,)) + assert self.__debugPrint("setTrack(track=%s)"%(track,)) if self.track is not None: self.track.pause() self.track = None @@ -147,27 +147,27 @@ class FourState: # If the client wants the state changed it needs to # send a request to the AI. #def setIsOn(self, isOn): - # assert self.debugPrint("setIsOn(isOn=%s)"%(isOn,)) + # assert self.__debugPrint("setIsOn(isOn=%s)"%(isOn,)) # pass def isOn(self): - assert self.debugPrint("isOn() returning %s (stateIndex=%s)"%(self.stateIndex==4, self.stateIndex)) + assert self.__debugPrint("isOn() returning %s (stateIndex=%s)"%(self.stateIndex==4, self.stateIndex)) return self.stateIndex==4 def changedOnState(self, isOn): """ Allow derived classes to overide this. """ - assert self.debugPrint("changedOnState(isOn=%s)"%(isOn,)) + assert self.__debugPrint("changedOnState(isOn=%s)"%(isOn,)) ##### state 0 ##### def enterState0(self): - assert self.debugPrint("enter0()") + assert self.__debugPrint("enter0()") self.enterStateN(0) def exitState0(self): - assert self.debugPrint("exit0()") + assert self.__debugPrint("exit0()") # It's important for FourStates to broadcast their state # when they are generated on the client. Before I put this in, # if a door was generated and went directly to an 'open' state, @@ -177,43 +177,43 @@ class FourState: ##### state 1 ##### def enterState1(self): - assert self.debugPrint("enterState1()") + assert self.__debugPrint("enterState1()") self.enterStateN(1) def exitState1(self): - assert self.debugPrint("exitState1()") + assert self.__debugPrint("exitState1()") ##### state 2 ##### def enterState2(self): - assert self.debugPrint("enterState2()") + assert self.__debugPrint("enterState2()") self.enterStateN(2) def exitState2(self): - assert self.debugPrint("exitState2()") + assert self.__debugPrint("exitState2()") ##### state 3 ##### def enterState3(self): - assert self.debugPrint("enterState3()") + assert self.__debugPrint("enterState3()") self.enterStateN(3) def exitState3(self): - assert self.debugPrint("exitState3()") + assert self.__debugPrint("exitState3()") ##### state 4 ##### def enterState4(self): - assert self.debugPrint("enterState4()") + assert self.__debugPrint("enterState4()") self.enterStateN(4) self.changedOnState(1) def exitState4(self): - assert self.debugPrint("exitState4()") + assert self.__debugPrint("exitState4()") self.changedOnState(0) if __debug__: - def debugPrint(self, message): + def __debugPrint(self, message): """for debugging""" return self.notify.debug("%d (%d) %s"%( id(self), self.stateIndex==4, message)) diff --git a/direct/src/fsm/FourStateAI.py b/direct/src/fsm/FourStateAI.py index 6f5ff8d966..eee4b43a76 100755 --- a/direct/src/fsm/FourStateAI.py +++ b/direct/src/fsm/FourStateAI.py @@ -93,11 +93,11 @@ class FourStateAI: off (and so is state 2 which is oposite of state 4 and therefore oposite of 'on'). """ - assert self.debugPrint( + self.stateIndex = 0 + assert self.__debugPrint( "FourStateAI(names=%s, durations=%s)" %(names, durations)) self.doLaterTask = None - self.stateIndex = 0 assert len(names) == 5 assert len(names) == len(durations) self.names = names @@ -137,7 +137,7 @@ class FourStateAI: self.fsm.enterInitialState() def delete(self): - assert self.debugPrint("delete()") + assert self.__debugPrint("delete()") if self.doLaterTask is not None: self.doLaterTask.remove() del self.doLaterTask @@ -145,15 +145,15 @@ class FourStateAI: del self.fsm def getState(self): - assert self.debugPrint("getState() returning %s"%(self.stateIndex,)) + assert self.__debugPrint("getState() returning %s"%(self.stateIndex,)) return [self.stateIndex] def sendState(self): - assert self.debugPrint("sendState()") + assert self.__debugPrint("sendState()") self.sendUpdate('setState', self.getState()) def setIsOn(self, isOn): - assert self.debugPrint("setIsOn(isOn=%s)"%(isOn,)) + assert self.__debugPrint("setIsOn(isOn=%s)"%(isOn,)) if isOn: if self.stateIndex != 4: # ...if it's not On; request turning on: @@ -170,7 +170,7 @@ class FourStateAI: # self.fsm.request(self.states[nextState]) def isOn(self): - assert self.debugPrint("isOn() returning %s (stateIndex=%s)"%(self.stateIndex==4, self.stateIndex)) + assert self.__debugPrint("isOn() returning %s (stateIndex=%s)"%(self.stateIndex==4, self.stateIndex)) return self.stateIndex==4 def changedOnState(self, isOn): @@ -179,12 +179,12 @@ class FourStateAI: The self.isOn value has toggled. Call getIsOn() to get the current state. """ - assert self.debugPrint("changedOnState(isOn=%s)"%(isOn,)) + assert self.__debugPrint("changedOnState(isOn=%s)"%(isOn,)) ##### states ##### def switchToNextStateTask(self, task): - assert self.debugPrint("switchToNextStateTask()") + assert self.__debugPrint("switchToNextStateTask()") self.fsm.request(self.states[self.nextStateIndex]) return Task.done @@ -193,11 +193,11 @@ class FourStateAI: This function is intentionaly simple so that derived classes may easily alter the network message. """ - assert self.debugPrint("distributeStateChange()") + assert self.__debugPrint("distributeStateChange()") self.sendState() def enterStateN(self, stateIndex, nextStateIndex): - assert self.debugPrint( + assert self.__debugPrint( "enterStateN(stateIndex=%s, nextStateIndex=%s)"% (stateIndex, nextStateIndex)) self.stateIndex = stateIndex @@ -211,7 +211,7 @@ class FourStateAI: "enterStateN-timer-%s"%id(self)) def exitStateN(self): - assert self.debugPrint("exitStateN()") + assert self.__debugPrint("exitStateN()") if self.doLaterTask: taskMgr.remove(self.doLaterTask) self.doLaterTask=None @@ -219,56 +219,56 @@ class FourStateAI: ##### state 0 ##### def enterState0(self): - assert self.debugPrint("enter0()") + assert self.__debugPrint("enter0()") self.enterStateN(0, 0) def exitState0(self): - assert self.debugPrint("exit0()") + assert self.__debugPrint("exit0()") ##### state 1 ##### def enterState1(self): - #assert self.debugPrint("enterState1()") + #assert self.__debugPrint("enterState1()") self.enterStateN(1, 2) def exitState1(self): - assert self.debugPrint("exitState1()") + assert self.__debugPrint("exitState1()") self.exitStateN() ##### state 2 ##### def enterState2(self): - #assert self.debugPrint("enterState2()") + #assert self.__debugPrint("enterState2()") self.enterStateN(2, 3) def exitState2(self): - assert self.debugPrint("exitState2()") + assert self.__debugPrint("exitState2()") self.exitStateN() ##### state 3 ##### def enterState3(self): - #assert self.debugPrint("enterState3()") + #assert self.__debugPrint("enterState3()") self.enterStateN(3, 4) def exitState3(self): - assert self.debugPrint("exitState3()") + assert self.__debugPrint("exitState3()") self.exitStateN() ##### state 4 ##### def enterState4(self): - assert self.debugPrint("enterState4()") + assert self.__debugPrint("enterState4()") self.enterStateN(4, 1) self.changedOnState(1) def exitState4(self): - assert self.debugPrint("exitState4()") + assert self.__debugPrint("exitState4()") self.exitStateN() self.changedOnState(0) if __debug__: - def debugPrint(self, message): + def __debugPrint(self, message): """for debugging""" return self.notify.debug("%d (%d) %s"%( id(self), self.stateIndex==4, message)) diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index d3e22a1fc3..4a8a13ee64 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,3 +1,18 @@ +------------------------ RELEASE 1.9.4 ------------------------ + +One of the bugfixes in the last 1.9.3 release introduced a regression, +therefore it was decided to make another 1.9.x release. + +* Fix 1.9.3 regression with generating geometry in threaded pipeline +* Various compile warning fixes +* Fix occasional crash in PNMImage::quick_filter_from() +* Fix issue taking screenshots from an OpenGL FBO buffer +* Fix various issues with MeshDrawer +* Fix issue with collision sphere generation in bam2egg +* Fix compile errors with more obscure Python configurations +* Fix assert when using Texture.load_sub_image to load whole image +* Fix fsm FourState + ------------------------ RELEASE 1.9.3 ------------------------ This issue fixes several bugs that were still found in 1.9.2. diff --git a/dtool/src/dtoolbase/typeHandle.cxx b/dtool/src/dtoolbase/typeHandle.cxx index 6f4d7bc1d1..ed85da8d03 100644 --- a/dtool/src/dtoolbase/typeHandle.cxx +++ b/dtool/src/dtoolbase/typeHandle.cxx @@ -45,7 +45,9 @@ get_memory_usage(MemoryClass memory_class) const { void TypeHandle:: inc_memory_usage(MemoryClass memory_class, size_t size) { #ifdef DO_MEMORY_USAGE +#ifdef _DEBUG assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit); +#endif if ((*this) != TypeHandle::none()) { TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL); assert(rnode != (TypeRegistryNode *)NULL); @@ -53,7 +55,7 @@ inc_memory_usage(MemoryClass memory_class, size_t size) { // cerr << *this << ".inc(" << memory_class << ", " << size << ") -> " << // rnode->_memory_usage[memory_class] << "\n"; if (rnode->_memory_usage[memory_class] < 0) { - cerr << "Memory usage overflow for type " << *this << ".\n"; + cerr << "Memory usage overflow for type " << rnode->_name << ".\n"; abort(); } } @@ -67,7 +69,9 @@ inc_memory_usage(MemoryClass memory_class, size_t size) { void TypeHandle:: dec_memory_usage(MemoryClass memory_class, size_t size) { #ifdef DO_MEMORY_USAGE +#ifdef _DEBUG assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit); +#endif if ((*this) != TypeHandle::none()) { TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL); assert(rnode != (TypeRegistryNode *)NULL); @@ -98,7 +102,7 @@ allocate_array(size_t size) { assert(rnode != (TypeRegistryNode *)NULL); AtomicAdjust::add(rnode->_memory_usage[MC_array], (AtomicAdjust::Integer)alloc_size); if (rnode->_memory_usage[MC_array] < 0) { - cerr << "Memory usage overflow for type " << *this << ".\n"; + cerr << "Memory usage overflow for type " << rnode->_name << ".\n"; abort(); } } diff --git a/dtool/src/dtoolbase/typeRegistry.I b/dtool/src/dtoolbase/typeRegistry.I index f0105c1eda..e35f37c207 100644 --- a/dtool/src/dtoolbase/typeRegistry.I +++ b/dtool/src/dtoolbase/typeRegistry.I @@ -23,6 +23,19 @@ freshen_derivations() { } } +/** + * Returns the pointer to the global TypeRegistry object. + */ +INLINE TypeRegistry *TypeRegistry:: +ptr() { + // It's OK that we don't acquire the lock, because we guarantee that this is + // called at static init time. + if (_global_pointer == NULL) { + init_global_pointer(); + } + return _global_pointer; +} + /** * Ensures the lock pointer has been allocated. */ diff --git a/dtool/src/dtoolbase/typeRegistry.cxx b/dtool/src/dtoolbase/typeRegistry.cxx index 7349d20dd4..01b8ec498a 100644 --- a/dtool/src/dtoolbase/typeRegistry.cxx +++ b/dtool/src/dtoolbase/typeRegistry.cxx @@ -488,20 +488,6 @@ write(ostream &out) const { _lock->release(); } -/** - * Returns the pointer to the global TypeRegistry object. - */ -TypeRegistry *TypeRegistry:: -ptr() { - init_lock(); - _lock->acquire(); - if (_global_pointer == NULL) { - init_global_pointer(); - } - _lock->release(); - return _global_pointer; -} - /** * */ @@ -531,6 +517,7 @@ TypeRegistry() { */ void TypeRegistry:: init_global_pointer() { + init_lock(); init_memory_hook(); _global_pointer = new TypeRegistry; } diff --git a/dtool/src/dtoolbase/typeRegistry.h b/dtool/src/dtoolbase/typeRegistry.h index 828cee6c8c..651eb1904b 100644 --- a/dtool/src/dtoolbase/typeRegistry.h +++ b/dtool/src/dtoolbase/typeRegistry.h @@ -77,7 +77,7 @@ PUBLISHED: void write(ostream &out) const; // ptr() returns the pointer to the global TypeRegistry object. - static TypeRegistry *ptr(); + static INLINE TypeRegistry *ptr(); MAKE_SEQ_PROPERTY(typehandles, get_num_typehandles, get_typehandle); MAKE_SEQ_PROPERTY(root_classes, get_num_root_classes, get_root_class); diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 2b51f87689..6ca45df628 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -1133,7 +1133,8 @@ write_class_declarations(ostream &out, ostream *out_h, Object *obj) { // to a macro function. out << "typedef " << c_class_name << " " << class_name << "_localtype;\n"; if (obj->_itype.has_destructor() || - obj->_itype.destructor_is_inherited()) { + obj->_itype.destructor_is_inherited() || + obj->_itype.destructor_is_implicit()) { if (TypeManager::is_reference_count(type)) { out << "Define_Module_ClassRef"; @@ -6219,7 +6220,7 @@ write_make_seq(ostream &out, Object *obj, const std::string &ClassName, // the assumption that the called method doesn't do anything with this // tuple other than unpack it (which is a fairly safe assumption to make). out << " PyTupleObject args;\n"; - out << " (void)PyObject_INIT_VAR(&args, &PyTuple_Type, 1);\n"; + out << " (void)PyObject_INIT_VAR((PyVarObject *)&args, &PyTuple_Type, 1);\n"; } out << diff --git a/dtool/src/interrogatedb/interrogateType.I b/dtool/src/interrogatedb/interrogateType.I index f6037fc571..b5527bbd23 100644 --- a/dtool/src/interrogatedb/interrogateType.I +++ b/dtool/src/interrogatedb/interrogateType.I @@ -343,6 +343,14 @@ destructor_is_inherited() const { return (_flags & F_inherited_destructor) != 0; } +/** + * + */ +INLINE bool InterrogateType:: +destructor_is_implicit() const { + return (_flags & F_implicit_destructor) != 0; +} + /** * */ diff --git a/dtool/src/interrogatedb/interrogateType.h b/dtool/src/interrogatedb/interrogateType.h index a1cedd1d82..151e10b5f5 100644 --- a/dtool/src/interrogatedb/interrogateType.h +++ b/dtool/src/interrogatedb/interrogateType.h @@ -82,6 +82,7 @@ public: INLINE FunctionIndex get_constructor(int n) const; INLINE bool has_destructor() const; INLINE bool destructor_is_inherited() const; + INLINE bool destructor_is_implicit() const; INLINE FunctionIndex get_destructor() const; INLINE int number_of_elements() const; INLINE ElementIndex get_element(int n) const; diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index f5e77e0dbb..d66ee88c21 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -303,8 +303,14 @@ template INLINE bool DTOOL_Call_ExtractThisPointer(PyObject *self, T *& // Functions related to error reporting. EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred(); +// _PyErr_OCCURRED is an undocumented macro version of PyErr_Occurred. +// Some implementations of the CPython API (e.g. PyPy's cpyext) do not define +// it, so in these cases we just silently fall back to PyErr_Occurred. +#ifndef _PyErr_OCCURRED +#define _PyErr_OCCURRED() PyErr_Occurred() +#endif + #ifdef NDEBUG -// _PyErr_OCCURRED is an undocumented inline version of PyErr_Occurred. #define Dtool_CheckErrorOccurred() (_PyErr_OCCURRED() != NULL) #else #define Dtool_CheckErrorOccurred() _Dtool_CheckErrorOccurred() diff --git a/dtool/src/parser-inc/btBulletDynamicsCommon.h b/dtool/src/parser-inc/btBulletDynamicsCommon.h index f62fc5bee6..aaf2309f4d 100644 --- a/dtool/src/parser-inc/btBulletDynamicsCommon.h +++ b/dtool/src/parser-inc/btBulletDynamicsCommon.h @@ -65,7 +65,6 @@ class btPoint2PointConstraint; class btPolyhedralConvexShape; class btQuaternion; class btSequentialImpulseConstraintSolver; -class btScalar; class btSliderConstraint; class btSoftBodyHelpers; class btSoftBodyRigidBodyCollisionConfiguration; @@ -80,11 +79,13 @@ class btTranslationalLimitMotor; class btTriangleMesh; class btTypedConstraint; class btTypedObject; -class btVector3; class btVehicleRaycaster; template class btAlignedObjectArray; +struct btVector3 {}; +typedef double btScalar; + class btWheelInfo { public: class RaycastInfo; diff --git a/dtool/src/prc/configVariableBool.I b/dtool/src/prc/configVariableBool.I index 4e6b0ab35f..7eba0820d0 100644 --- a/dtool/src/prc/configVariableBool.I +++ b/dtool/src/prc/configVariableBool.I @@ -67,7 +67,7 @@ operator = (bool value) { /** * Returns the variable's value. */ -INLINE ConfigVariableBool:: +ALWAYS_INLINE ConfigVariableBool:: operator bool () const { return get_value(); } @@ -100,12 +100,11 @@ set_value(bool value) { /** * Returns the variable's value. */ -INLINE bool ConfigVariableBool:: +ALWAYS_INLINE bool ConfigVariableBool:: get_value() const { TAU_PROFILE("bool ConfigVariableBool::get_value() const", " ", TAU_USER); if (!is_cache_valid(_local_modified)) { - mark_cache_valid(((ConfigVariableBool *)this)->_local_modified); - ((ConfigVariableBool *)this)->_cache = get_bool_word(0); + reload_value(); } return _cache; } diff --git a/dtool/src/prc/configVariableBool.cxx b/dtool/src/prc/configVariableBool.cxx index d063b06fd5..7fb604642d 100644 --- a/dtool/src/prc/configVariableBool.cxx +++ b/dtool/src/prc/configVariableBool.cxx @@ -12,3 +12,12 @@ */ #include "configVariableBool.h" + +/** + * Refreshes the cached value. + */ +void ConfigVariableBool:: +reload_value() const { + mark_cache_valid(_local_modified); + _cache = get_bool_word(0); +} diff --git a/dtool/src/prc/configVariableBool.h b/dtool/src/prc/configVariableBool.h index a0d8b0b1dd..9f486c4266 100644 --- a/dtool/src/prc/configVariableBool.h +++ b/dtool/src/prc/configVariableBool.h @@ -29,13 +29,13 @@ PUBLISHED: const string &description = string(), int flags = 0); INLINE void operator = (bool value); - INLINE operator bool () const; + ALWAYS_INLINE operator bool () const; INLINE size_t size() const; INLINE bool operator [] (size_t n) const; INLINE void set_value(bool value); - INLINE bool get_value() const; + ALWAYS_INLINE bool get_value() const; INLINE bool get_default_value() const; MAKE_PROPERTY(value, get_value, set_value); MAKE_PROPERTY(default_value, get_default_value); @@ -44,8 +44,10 @@ PUBLISHED: INLINE void set_word(size_t n, bool value); private: - AtomicAdjust::Integer _local_modified; - bool _cache; + void reload_value() const; + + mutable AtomicAdjust::Integer _local_modified; + mutable bool _cache; }; #include "configVariableBool.I" diff --git a/dtool/src/prc/notifyCategory.I b/dtool/src/prc/notifyCategory.I index a485447dcc..07d3634d92 100644 --- a/dtool/src/prc/notifyCategory.I +++ b/dtool/src/prc/notifyCategory.I @@ -70,7 +70,12 @@ is_on(NotifySeverity severity) const { */ INLINE bool NotifyCategory:: is_spam() const { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(is_on(NS_spam), 0); +#else return is_on(NS_spam); +#endif } /** @@ -78,7 +83,12 @@ is_spam() const { */ INLINE bool NotifyCategory:: is_debug() const { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(is_on(NS_debug), 0); +#else return is_on(NS_debug); +#endif } #else /** diff --git a/dtool/src/prc/notifyCategoryProxy.I b/dtool/src/prc/notifyCategoryProxy.I index 08c253f081..ae829eeedb 100644 --- a/dtool/src/prc/notifyCategoryProxy.I +++ b/dtool/src/prc/notifyCategoryProxy.I @@ -69,7 +69,12 @@ is_on(NotifySeverity severity) { template INLINE bool NotifyCategoryProxy:: is_spam() { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(get_unsafe_ptr()->is_spam(), 0); +#else return get_unsafe_ptr()->is_spam(); +#endif } #else template @@ -86,7 +91,12 @@ is_spam() { template INLINE bool NotifyCategoryProxy:: is_debug() { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(get_unsafe_ptr()->is_debug(), 0); +#else return get_unsafe_ptr()->is_debug(); +#endif } #else template diff --git a/dtool/src/prc/pnotify.h b/dtool/src/prc/pnotify.h index a8254cc910..414b97d2a4 100644 --- a/dtool/src/prc/pnotify.h +++ b/dtool/src/prc/pnotify.h @@ -122,6 +122,13 @@ private: // constant expressions and compilation will fail if the assertion is not // true. +#ifdef __GNUC__ +// Tell the optimizer to optimize for the case where the condition is true. +#define _nassert_check(condition) (__builtin_expect(!(condition), 0)) +#else +#define _nassert_check(condition) (!(condition)) +#endif + #ifdef NDEBUG #define nassertr(condition, return_value) @@ -131,14 +138,14 @@ private: #define nassertr_always(condition, return_value) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ return return_value; \ } \ } #define nassertv_always(condition) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ return; \ } \ } @@ -151,7 +158,7 @@ private: #define nassertr(condition, return_value) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ if (Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) { \ return return_value; \ } \ @@ -160,7 +167,7 @@ private: #define nassertv(condition) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ if (Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) { \ return; \ } \ @@ -168,7 +175,7 @@ private: } #define nassertd(condition) \ - if (!(condition) && \ + if (_nassert_check(condition) && \ Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) #define nassertr_always(condition, return_value) nassertr(condition, return_value) @@ -177,7 +184,7 @@ private: #define nassert_raise(message) Notify::ptr()->assert_failure(message, __LINE__, __FILE__) #define enter_debugger_if(condition) \ - if (condition) { \ + if (_nassert_check(condition)) { \ Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__); \ __asm { int 3 } \ } diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index d5bbb5d19a..9692e8cdbb 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -571,6 +571,10 @@ if (COMPILER == "MSVC"): #LibName(pkg, 'ddraw.lib') LibName(pkg, 'dxguid.lib') + if SDK.get("VISUALSTUDIO_VERSION") == '14.0': + # dxerr needs this for __vsnwprintf definition. + LibName(pkg, 'legacy_stdio_definitions.lib') + if not PkgSkip("FREETYPE") and os.path.isdir(GetThirdpartyDir() + "freetype/include/freetype2"): IncDirectory("FREETYPE", GetThirdpartyDir() + "freetype/include/freetype2") @@ -637,7 +641,6 @@ if (COMPILER == "MSVC"): if (PkgSkip("FFTW")==0): LibName("FFTW", GetThirdpartyDir() + "fftw/lib/rfftw.lib") if (PkgSkip("FFTW")==0): LibName("FFTW", GetThirdpartyDir() + "fftw/lib/fftw.lib") if (PkgSkip("ARTOOLKIT")==0):LibName("ARTOOLKIT",GetThirdpartyDir() + "artoolkit/lib/libAR.lib") - if (PkgSkip("ASSIMP")==0): PkgDisable("ASSIMP") # Not yet supported if (PkgSkip("OPENCV")==0): LibName("OPENCV", GetThirdpartyDir() + "opencv/lib/cv.lib") if (PkgSkip("OPENCV")==0): LibName("OPENCV", GetThirdpartyDir() + "opencv/lib/highgui.lib") if (PkgSkip("OPENCV")==0): LibName("OPENCV", GetThirdpartyDir() + "opencv/lib/cvaux.lib") @@ -652,6 +655,9 @@ if (COMPILER == "MSVC"): if (PkgSkip("FCOLLADA")==0): LibName("FCOLLADA", GetThirdpartyDir() + "fcollada/lib/FCollada.lib") IncDirectory("FCOLLADA", GetThirdpartyDir() + "fcollada/include/FCollada") + if (PkgSkip("ASSIMP")==0): + LibName("ASSIMP", GetThirdpartyDir() + "assimp/lib/assimp.lib") + IncDirectory("ASSIMP", GetThirdpartyDir() + "assimp/include/assimp") if (PkgSkip("SQUISH")==0): if GetOptimize() <= 2: LibName("SQUISH", GetThirdpartyDir() + "squish/lib/squishd.lib") @@ -1291,7 +1297,7 @@ def CompileCxx(obj,src,opts): cmd += " -fno-strict-aliasing" if optlevel >= 3: - cmd += " -ffast-math" + cmd += " -ffast-math -fno-stack-protector" if optlevel == 3: # Fast math is nice, but we'd like to see NaN in dev builds. cmd += " -fno-finite-math-only" @@ -2789,17 +2795,17 @@ else: tp_dir = GetThirdpartyDir() if tp_dir is not None: - dylibs = set() + dylibs = {} if GetTarget() == 'darwin': # Make a list of all the dylibs we ship, to figure out whether we should use # install_name_tool to correct the library reference to point to our copy. for lib in glob.glob(tp_dir + "/*/lib/*.dylib"): - dylibs.add(os.path.basename(lib)) + dylibs[os.path.basename(lib)] = os.path.basename(os.path.realpath(lib)) if not PkgSkip("PYTHON"): for lib in glob.glob(tp_dir + "/*/lib/" + SDK["PYTHONVERSION"] + "/*.dylib"): - dylibs.add(os.path.basename(lib)) + dylibs[os.path.basename(lib)] = os.path.basename(os.path.realpath(lib)) for pkg in PkgListGet(): if PkgSkip(pkg): @@ -2854,7 +2860,8 @@ if tp_dir is not None: libdep = line.split(" ", 1)[0] dep_basename = os.path.basename(libdep) if dep_basename in dylibs: - oscmd("install_name_tool -change %s %s%s %s" % (libdep, dep_prefix, dep_basename, target), True) + dep_target = dylibs[dep_basename] + oscmd("install_name_tool -change %s %s%s %s" % (libdep, dep_prefix, dep_target, target), True) JustBuilt([target], [tp_lib]) @@ -2875,7 +2882,8 @@ if tp_dir is not None: CopyFile(GetOutputDir() + "/" + base, tp_lib) if GetTarget() == 'windows': - CopyAllFiles(GetOutputDir() + "/bin/", tp_dir + "extras/bin/") + if os.path.isdir(os.path.join(tp_dir, "extras", "bin")): + CopyAllFiles(GetOutputDir() + "/bin/", tp_dir + "extras/bin/") if not PkgSkip("PYTHON") and not RTDIST: # We need to copy the Python DLL to the bin directory for now. @@ -5575,7 +5583,7 @@ if not PkgSkip("PANDATOOL") and not PkgSkip("ASSIMP"): TargetAdd('p3assimp_composite1.obj', opts=OPTS, input='p3assimp_composite1.cxx') TargetAdd('libp3assimp.dll', input='p3assimp_composite1.obj') TargetAdd('libp3assimp.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libp3assimp.dll', opts=OPTS) + TargetAdd('libp3assimp.dll', opts=OPTS+['ZLIB']) # # DIRECTORY: pandatool/src/daeprogs/ diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 2f6482c68f..ab1ec01feb 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -76,7 +76,8 @@ MAYAVERSIONINFO = [("MAYA6", "6.0"), ("MAYA2014","2014"), ("MAYA2015","2015"), ("MAYA2016","2016"), - ("MAYA20165","2016.5") + ("MAYA20165","2016.5"), + ("MAYA2017","2017") ] MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"), @@ -2383,6 +2384,8 @@ def SetupVisualStudioEnviron(): os.environ["VCINSTALLDIR"] = SDK["VISUALSTUDIO"] + "VC" os.environ["WindowsSdkDir"] = SDK["MSPLATFORM"] + winsdk_ver = SDK["MSPLATFORM_VERSION"] + # Determine the directories to look in based on the architecture. arch = GetTargetArch() bindir = "" @@ -2398,9 +2401,16 @@ def SetupVisualStudioEnviron(): # Special version of the tools that run on x86. bindir = 'x86_' + bindir - binpath = SDK["VISUALSTUDIO"] + "VC\\bin\\" + bindir - if not os.path.isdir(binpath): - exit("Couldn't find compilers in %s. You may need to install the Windows SDK 7.1 and the Visual C++ 2010 SP1 Compiler Update for Windows SDK 7.1." % binpath) + vc_binpath = SDK["VISUALSTUDIO"] + "VC\\bin" + binpath = os.path.join(vc_binpath, bindir) + if not os.path.isfile(binpath + "\\cl.exe"): + # Try the x86 tools, those should work just as well. + if arch == 'x64' and os.path.isfile(vc_binpath + "\\x86_amd64\\cl.exe"): + binpath = "{0}\\x86_amd64;{0}".format(vc_binpath) + elif winsdk_ver.startswith('10.'): + exit("Couldn't find compilers in %s. You may need to install the Windows SDK 7.1 and the Visual C++ 2010 SP1 Compiler Update for Windows SDK 7.1." % binpath) + else: + exit("Couldn't find compilers in %s." % binpath) AddToPathEnv("PATH", binpath) AddToPathEnv("PATH", SDK["VISUALSTUDIO"] + "Common7\\IDE") diff --git a/models/panda-model.egg b/models/panda-model.egg index df9ca085a0..5a3b6ec7d1 100755 --- a/models/panda-model.egg +++ b/models/panda-model.egg @@ -12378,11 +12378,6 @@ { Tex1 } { 670 158 673 { panda_mesh.verts } } } - { - { 1 1 1 1 } - { Tex1 } - { 602 674 627 { panda_mesh.verts } } - } { { 1 1 1 1 } { Tex1 } @@ -12398,16 +12393,6 @@ { Tex1 } { 628 630 676 { panda_mesh.verts } } } - { - { 1 1 1 1 } - { Tex1 } - { 674 676 630 { panda_mesh.verts } } - } - { - { 1 1 1 1 } - { Tex1 } - { 630 627 674 { panda_mesh.verts } } - } { { 1 1 1 1 } { Tex1 } @@ -16888,11 +16873,6 @@ { Tex1 } { 826 1321 1320 { panda_mesh.verts } } } - { - { 1 1 1 1 } - { Tex1 } - { 674 602 627 { panda_mesh.verts } } - } { { 1 1 1 1 } { Tex1 } @@ -16908,16 +16888,6 @@ { Tex1 } { 630 1283 676 { panda_mesh.verts } } } - { - { 1 1 1 1 } - { Tex1 } - { 676 674 630 { panda_mesh.verts } } - } - { - { 1 1 1 1 } - { Tex1 } - { 627 630 674 { panda_mesh.verts } } - } { { 1 1 1 1 } { Tex1 } @@ -24400,7 +24370,7 @@ } { 294 295 593 595 597 600 602 624 625 626 627 628 629 630 631 632 - 633 634 635 636 637 638 649 650 651 653 656 657 658 659 674 675 + 633 634 635 636 637 638 649 650 651 653 656 657 658 659 675 676 956 957 1251 1254 1256 1258 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1301 1302 1303 1305 1308 1309 1310 1311 1325 diff --git a/panda/src/bullet/bulletAllHitsRayResult.h b/panda/src/bullet/bulletAllHitsRayResult.h index c5ff637ac9..b0b31e04d3 100644 --- a/panda/src/bullet/bulletAllHitsRayResult.h +++ b/panda/src/bullet/bulletAllHitsRayResult.h @@ -39,6 +39,13 @@ PUBLISHED: int get_shape_part() const; int get_triangle_index() const; + MAKE_PROPERTY(node, get_node); + MAKE_PROPERTY(hit_pos, get_hit_pos); + MAKE_PROPERTY(hit_normal, get_hit_normal); + MAKE_PROPERTY(hit_fraction, get_hit_fraction); + MAKE_PROPERTY(shape_part, get_shape_part); + MAKE_PROPERTY(triangle_index, get_triangle_index); + private: const btCollisionObject *_object; btVector3 _normal; @@ -69,6 +76,11 @@ PUBLISHED: const BulletRayHit get_hit(int idx) const; MAKE_SEQ(get_hits, get_num_hits, get_hit); + MAKE_PROPERTY(from_pos, get_from_pos); + MAKE_PROPERTY(to_pos, get_to_pos); + MAKE_PROPERTY(closest_hit_fraction, get_closest_hit_fraction); + MAKE_SEQ_PROPERTY(hits, get_num_hits, get_hit); + public: virtual bool needsCollision(btBroadphaseProxy* proxy0) const; virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace); diff --git a/panda/src/bullet/bulletBodyNode.cxx b/panda/src/bullet/bulletBodyNode.cxx index cb4d39c444..b078864ccc 100644 --- a/panda/src/bullet/bulletBodyNode.cxx +++ b/panda/src/bullet/bulletBodyNode.cxx @@ -442,6 +442,15 @@ set_active(bool active, bool force) { } } +/** + * + */ +void BulletBodyNode:: +force_active(bool active) { + + set_active(active, true); +} + /** * If true, this object will be deactivated after a certain amount of time has * passed without movement. If false, the object will always remain active. diff --git a/panda/src/bullet/bulletBodyNode.h b/panda/src/bullet/bulletBodyNode.h index 53fe6c7136..562e88c7fb 100644 --- a/panda/src/bullet/bulletBodyNode.h +++ b/panda/src/bullet/bulletBodyNode.h @@ -56,7 +56,7 @@ PUBLISHED: // Static and kinematic INLINE bool is_static() const; INLINE bool is_kinematic() const; - + INLINE void set_static(bool value); INLINE void set_kinematic(bool value); @@ -79,6 +79,7 @@ PUBLISHED: // Deactivation bool is_active() const; void set_active(bool active, bool force=false); + void force_active(bool active); void set_deactivation_time(PN_stdfloat dt); PN_stdfloat get_deactivation_time() const; @@ -86,7 +87,7 @@ PUBLISHED: void set_deactivation_enabled(bool enabled); bool is_deactivation_enabled() const; - // Debug Visualistion + // Debug Visualisation INLINE void set_debug_enabled(const bool enabled); INLINE bool is_debug_enabled() const; @@ -100,6 +101,7 @@ PUBLISHED: #if BT_BULLET_VERSION >= 281 INLINE PN_stdfloat get_rolling_friction() const; INLINE void set_rolling_friction(PN_stdfloat friction); + MAKE_PROPERTY(rolling_friction, get_rolling_friction, set_rolling_friction); #endif INLINE bool has_anisotropic_friction() const; @@ -115,6 +117,27 @@ PUBLISHED: // Special void set_transform_dirty(); + MAKE_SEQ_PROPERTY(shapes, get_num_shapes, get_shape); + MAKE_SEQ_PROPERTY(shape_pos, get_num_shapes, get_shape_pos); + MAKE_SEQ_PROPERTY(shape_mat, get_num_shapes, get_shape_mat); + MAKE_SEQ_PROPERTY(shape_transform, get_num_shapes, get_shape_transform); + MAKE_PROPERTY(shape_bounds, get_shape_bounds); + MAKE_PROPERTY(static, is_static, set_static); + MAKE_PROPERTY(kinematic, is_kinematic, set_kinematic); + MAKE_PROPERTY(collision_notification, notifies_collisions, notify_collisions); + MAKE_PROPERTY(collision_response, get_collision_response, set_collision_response); + MAKE_PROPERTY(contact_response, has_contact_response); + MAKE_PROPERTY(contact_processing_threshold, get_contact_processing_threshold, set_contact_processing_threshold); + MAKE_PROPERTY(active, is_active, force_active); + MAKE_PROPERTY(deactivation_time, get_deactivation_time, set_deactivation_time); + MAKE_PROPERTY(deactivation_enabled, is_deactivation_enabled, set_deactivation_enabled); + MAKE_PROPERTY(debug_enabled, is_debug_enabled, set_debug_enabled); + MAKE_PROPERTY(restitution, get_restitution, set_restitution); + MAKE_PROPERTY(friction, get_friction, set_friction); + MAKE_PROPERTY(anisotropic_friction, get_anisotropic_friction, set_anisotropic_friction); + MAKE_PROPERTY(ccd_swept_sphere_radius, get_ccd_swept_sphere_radius, set_ccd_swept_sphere_radius); + MAKE_PROPERTY(ccd_motion_threshold, get_ccd_motion_threshold, set_ccd_motion_threshold); + public: virtual btCollisionObject *get_object() const = 0; diff --git a/panda/src/bullet/bulletBoxShape.h b/panda/src/bullet/bulletBoxShape.h index 82b1f10412..72a897d799 100644 --- a/panda/src/bullet/bulletBoxShape.h +++ b/panda/src/bullet/bulletBoxShape.h @@ -42,6 +42,9 @@ PUBLISHED: static BulletBoxShape *make_from_solid(const CollisionBox *solid); + MAKE_PROPERTY(half_extents_with_margin, get_half_extents_with_margin); + MAKE_PROPERTY(half_extents_without_margin, get_half_extents_without_margin); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletCapsuleShape.h b/panda/src/bullet/bulletCapsuleShape.h index 5e2150c27c..b89001064f 100644 --- a/panda/src/bullet/bulletCapsuleShape.h +++ b/panda/src/bullet/bulletCapsuleShape.h @@ -34,6 +34,9 @@ PUBLISHED: INLINE PN_stdfloat get_radius() const; INLINE PN_stdfloat get_half_height() const; + MAKE_PROPERTY(radius, get_radius); + MAKE_PROPERTY(half_height, get_half_height); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletCharacterControllerNode.cxx b/panda/src/bullet/bulletCharacterControllerNode.cxx index 8d9dfdf434..c6af3842e9 100644 --- a/panda/src/bullet/bulletCharacterControllerNode.cxx +++ b/panda/src/bullet/bulletCharacterControllerNode.cxx @@ -296,7 +296,6 @@ set_gravity(PN_stdfloat gravity) { #endif } - /** * */ @@ -304,4 +303,4 @@ void BulletCharacterControllerNode:: set_use_ghost_sweep_test(bool value) { return _character->setUseGhostSweepTest(value); -} +} \ No newline at end of file diff --git a/panda/src/bullet/bulletCharacterControllerNode.h b/panda/src/bullet/bulletCharacterControllerNode.h index 80f6aab834..1ced97ab9d 100644 --- a/panda/src/bullet/bulletCharacterControllerNode.h +++ b/panda/src/bullet/bulletCharacterControllerNode.h @@ -39,20 +39,27 @@ PUBLISHED: BulletShape *get_shape() const; + void set_gravity(PN_stdfloat gravity); PN_stdfloat get_gravity() const; - PN_stdfloat get_max_slope() const; void set_fall_speed(PN_stdfloat fall_speed); void set_jump_speed(PN_stdfloat jump_speed); void set_max_jump_height(PN_stdfloat max_jump_height); + void set_max_slope(PN_stdfloat max_slope); - void set_gravity(PN_stdfloat gravity); + PN_stdfloat get_max_slope() const; + void set_use_ghost_sweep_test(bool value); bool is_on_ground() const; bool can_jump() const; void do_jump(); + MAKE_PROPERTY(shape, get_shape); + MAKE_PROPERTY(gravity, get_gravity, set_gravity); + MAKE_PROPERTY(max_slope, get_max_slope, set_max_slope); + MAKE_PROPERTY(on_ground, is_on_ground); + public: INLINE virtual btPairCachingGhostObject *get_ghost() const; INLINE virtual btCharacterControllerInterface *get_character() const; diff --git a/panda/src/bullet/bulletClosestHitRayResult.h b/panda/src/bullet/bulletClosestHitRayResult.h index 0f2bd67128..c6c31f19d0 100644 --- a/panda/src/bullet/bulletClosestHitRayResult.h +++ b/panda/src/bullet/bulletClosestHitRayResult.h @@ -44,6 +44,15 @@ PUBLISHED: int get_shape_part() const; int get_triangle_index() const; + MAKE_PROPERTY(from_pos, get_from_pos); + MAKE_PROPERTY(to_pos, get_to_pos); + MAKE_PROPERTY(node, get_node); + MAKE_PROPERTY(hit_pos, get_hit_pos); + MAKE_PROPERTY(hit_normal, get_hit_normal); + MAKE_PROPERTY(hit_fraction, get_hit_fraction); + MAKE_PROPERTY(shape_part, get_shape_part); + MAKE_PROPERTY(triangle_index, get_triangle_index); + public: virtual bool needsCollision(btBroadphaseProxy* proxy0) const; virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace); diff --git a/panda/src/bullet/bulletClosestHitSweepResult.h b/panda/src/bullet/bulletClosestHitSweepResult.h index 44a82e5fb8..aba5ff57d8 100644 --- a/panda/src/bullet/bulletClosestHitSweepResult.h +++ b/panda/src/bullet/bulletClosestHitSweepResult.h @@ -41,6 +41,13 @@ PUBLISHED: LVector3 get_hit_normal() const; PN_stdfloat get_hit_fraction() const; + MAKE_PROPERTY(from_pos, get_from_pos); + MAKE_PROPERTY(to_pos, get_to_pos); + MAKE_PROPERTY(node, get_node); + MAKE_PROPERTY(hit_pos, get_hit_pos); + MAKE_PROPERTY(hit_normal, get_hit_normal); + MAKE_PROPERTY(hit_fraction, get_hit_fraction); + public: virtual bool needsCollision(btBroadphaseProxy* proxy0) const; diff --git a/panda/src/bullet/bulletConeShape.h b/panda/src/bullet/bulletConeShape.h index 21349bac14..97b99b01fe 100644 --- a/panda/src/bullet/bulletConeShape.h +++ b/panda/src/bullet/bulletConeShape.h @@ -34,6 +34,9 @@ PUBLISHED: INLINE PN_stdfloat get_radius() const; INLINE PN_stdfloat get_height() const; + MAKE_PROPERTY(radius, get_radius); + MAKE_PROPERTY(height, get_height); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletConeTwistConstraint.h b/panda/src/bullet/bulletConeTwistConstraint.h index 1cc4cc61e6..7e5c782915 100644 --- a/panda/src/bullet/bulletConeTwistConstraint.h +++ b/panda/src/bullet/bulletConeTwistConstraint.h @@ -56,6 +56,10 @@ PUBLISHED: INLINE CPT(TransformState) get_frame_a() const; INLINE CPT(TransformState) get_frame_b() const; + MAKE_PROPERTY(fix_threshold, get_fix_threshold, set_fix_threshold); + MAKE_PROPERTY(frame_a, get_frame_a); + MAKE_PROPERTY(frame_b, get_frame_b); + public: virtual btTypedConstraint *ptr() const; diff --git a/panda/src/bullet/bulletConstraint.I b/panda/src/bullet/bulletConstraint.I index b2f4666608..d66f5b6099 100644 --- a/panda/src/bullet/bulletConstraint.I +++ b/panda/src/bullet/bulletConstraint.I @@ -34,7 +34,7 @@ set_breaking_threshold(PN_stdfloat threshold) { * Returns the applied impluse limit for breaking the constraint. */ INLINE PN_stdfloat BulletConstraint:: -set_breaking_threshold() const { +get_breaking_threshold() const { return (PN_stdfloat)ptr()->getBreakingImpulseThreshold(); } diff --git a/panda/src/bullet/bulletConstraint.h b/panda/src/bullet/bulletConstraint.h index 9f97be7af8..85b0f0d63d 100644 --- a/panda/src/bullet/bulletConstraint.h +++ b/panda/src/bullet/bulletConstraint.h @@ -34,13 +34,13 @@ PUBLISHED: BulletRigidBodyNode *get_rigid_body_b(); void enable_feedback(bool value); - void set_debug_draw_size(PN_stdfloat size); - PN_stdfloat get_applied_impulse() const; + void set_debug_draw_size(PN_stdfloat size); PN_stdfloat get_debug_draw_size(); + PN_stdfloat get_applied_impulse() const; INLINE void set_breaking_threshold(PN_stdfloat threshold); - INLINE PN_stdfloat set_breaking_threshold() const; + INLINE PN_stdfloat get_breaking_threshold() const; INLINE void set_enabled(bool enabled); INLINE bool is_enabled() const; @@ -54,6 +54,13 @@ PUBLISHED: void set_param(ConstraintParam num, PN_stdfloat value, int axis=-1); PN_stdfloat get_param(ConstraintParam num, int axis=-1); + MAKE_PROPERTY(rigid_body_a, get_rigid_body_a); + MAKE_PROPERTY(rigid_body_b, get_rigid_body_b); + MAKE_PROPERTY(debug_draw_size, get_debug_draw_size, set_debug_draw_size); + MAKE_PROPERTY(applied_impulse, get_applied_impulse); + MAKE_PROPERTY(breaking_threshold, get_breaking_threshold, set_breaking_threshold); + MAKE_PROPERTY(enabled, is_enabled, set_enabled); + public: virtual btTypedConstraint *ptr() const = 0; diff --git a/panda/src/bullet/bulletContactCallbackData.h b/panda/src/bullet/bulletContactCallbackData.h index a83f66ff9c..c6c45c1e07 100644 --- a/panda/src/bullet/bulletContactCallbackData.h +++ b/panda/src/bullet/bulletContactCallbackData.h @@ -41,6 +41,14 @@ PUBLISHED: INLINE int get_index0() const; INLINE int get_index1() const; + MAKE_PROPERTY(manifold, get_manifold); + MAKE_PROPERTY(node0, get_node0); + MAKE_PROPERTY(node1, get_node1); + MAKE_PROPERTY(part_id0, get_part_id0); + MAKE_PROPERTY(part_id1, get_part_id1); + MAKE_PROPERTY(index0, get_index0); + MAKE_PROPERTY(index1, get_index1); + private: BulletManifoldPoint &_mp; PandaNode *_node0; diff --git a/panda/src/bullet/bulletContactCallbacks.h b/panda/src/bullet/bulletContactCallbacks.h index fa338154f8..27e8093e55 100644 --- a/panda/src/bullet/bulletContactCallbacks.h +++ b/panda/src/bullet/bulletContactCallbacks.h @@ -26,7 +26,7 @@ #include "eventParameter.h" #include "pandaNode.h" -struct UserPersitentData { +struct UserPersistentData { PT(PandaNode) node0; PT(PandaNode) node1; }; @@ -64,7 +64,7 @@ contact_added_callback(btManifoldPoint &cp, bullet_cat.debug() << "contact added: " << cp.m_userPersistentData << endl; // Gather persistent data - UserPersitentData *data = new UserPersitentData(); + UserPersistentData *data = new UserPersistentData(); data->node0 = node0; data->node1 = node1; @@ -126,7 +126,7 @@ contact_destroyed_callback(void *userPersistentData) { bullet_cat.debug() << "contact removed: " << userPersistentData << endl; - UserPersitentData *data = (UserPersitentData *)userPersistentData; + UserPersistentData *data = (UserPersistentData *)userPersistentData; // Send event if (bullet_enable_contact_events) { diff --git a/panda/src/bullet/bulletContactResult.h b/panda/src/bullet/bulletContactResult.h index 3e0e216135..afcf1ea51a 100644 --- a/panda/src/bullet/bulletContactResult.h +++ b/panda/src/bullet/bulletContactResult.h @@ -39,6 +39,14 @@ PUBLISHED: INLINE int get_part_id0() const; INLINE int get_part_id1() const; + MAKE_PROPERTY(manifold_point, get_manifold_point); + MAKE_PROPERTY(node0, get_node0); + MAKE_PROPERTY(node1, get_node1); + MAKE_PROPERTY(idx0, get_idx0); + MAKE_PROPERTY(idx1, get_idx1); + MAKE_PROPERTY(part_id0, get_part_id0); + MAKE_PROPERTY(part_id1, get_part_id1); + private: static btManifoldPoint _empty; @@ -64,6 +72,7 @@ PUBLISHED: INLINE int get_num_contacts() const; INLINE BulletContact get_contact(int idx); MAKE_SEQ(get_contacts, get_num_contacts, get_contact); + MAKE_SEQ_PROPERTY(contacts, get_num_contacts, get_contact); public: #if BT_BULLET_VERSION >= 281 diff --git a/panda/src/bullet/bulletConvexPointCloudShape.h b/panda/src/bullet/bulletConvexPointCloudShape.h index e1199d7a5b..bb5b5d2029 100644 --- a/panda/src/bullet/bulletConvexPointCloudShape.h +++ b/panda/src/bullet/bulletConvexPointCloudShape.h @@ -36,6 +36,8 @@ PUBLISHED: INLINE int get_num_points() const; + MAKE_PROPERTY(num_points, get_num_points); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletCylinderShape.h b/panda/src/bullet/bulletCylinderShape.h index d4e9beb31f..23c8781756 100644 --- a/panda/src/bullet/bulletCylinderShape.h +++ b/panda/src/bullet/bulletCylinderShape.h @@ -36,6 +36,10 @@ PUBLISHED: INLINE LVecBase3 get_half_extents_without_margin() const; INLINE LVecBase3 get_half_extents_with_margin() const; + MAKE_PROPERTY(radius, get_radius); + MAKE_PROPERTY(half_extents_without_margin, get_half_extents_without_margin); + MAKE_PROPERTY(half_extents_with_margin, get_half_extents_with_margin); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletDebugNode.I b/panda/src/bullet/bulletDebugNode.I index 4d4d8aa069..eae681aba5 100644 --- a/panda/src/bullet/bulletDebugNode.I +++ b/panda/src/bullet/bulletDebugNode.I @@ -29,6 +29,15 @@ show_wireframe(bool show) { draw_mask_changed(); } +/** + * + */ +INLINE bool BulletDebugNode:: +get_show_wireframe() const { + + return _wireframe; +} + /** * */ @@ -39,6 +48,15 @@ show_constraints(bool show) { draw_mask_changed(); } +/** + * + */ +INLINE bool BulletDebugNode:: +get_show_constraints() const { + + return _constraints; +} + /** * */ @@ -49,6 +67,15 @@ show_bounding_boxes(bool show) { draw_mask_changed(); } +/** + * + */ +INLINE bool BulletDebugNode:: +get_show_bounding_boxes() const { + + return _bounds; +} + /** * */ @@ -57,3 +84,12 @@ show_normals(bool show) { _drawer._normals = show; } + +/** + * + */ +INLINE bool BulletDebugNode:: +get_show_normals() const { + + return _drawer._normals; +} \ No newline at end of file diff --git a/panda/src/bullet/bulletDebugNode.h b/panda/src/bullet/bulletDebugNode.h index 5104438381..987e1a7450 100644 --- a/panda/src/bullet/bulletDebugNode.h +++ b/panda/src/bullet/bulletDebugNode.h @@ -35,6 +35,15 @@ PUBLISHED: INLINE void show_constraints(bool show); INLINE void show_bounding_boxes(bool show); INLINE void show_normals(bool show); + INLINE bool get_show_wireframe() const; + INLINE bool get_show_constraints() const; + INLINE bool get_show_bounding_boxes() const; + INLINE bool get_show_normals() const; + + MAKE_PROPERTY(wireframe, get_show_wireframe, show_wireframe); + MAKE_PROPERTY(constraints, get_show_constraints, show_constraints); + MAKE_PROPERTY(bounding_boxes, get_show_bounding_boxes, show_bounding_boxes); + MAKE_PROPERTY(normals, get_show_normals, show_normals); public: virtual bool safe_to_flatten() const; diff --git a/panda/src/bullet/bulletFilterCallbackData.h b/panda/src/bullet/bulletFilterCallbackData.h index 00a244cff8..36e3117716 100644 --- a/panda/src/bullet/bulletFilterCallbackData.h +++ b/panda/src/bullet/bulletFilterCallbackData.h @@ -36,6 +36,10 @@ PUBLISHED: INLINE void set_collide(bool collide); INLINE bool get_collide() const; + MAKE_PROPERTY(node_0, get_node_0); + MAKE_PROPERTY(node_1, get_node_1); + MAKE_PROPERTY(collide, get_collide, set_collide); + private: PandaNode *_node0; PandaNode *_node1; diff --git a/panda/src/bullet/bulletGenericConstraint.h b/panda/src/bullet/bulletGenericConstraint.h index c43c2217be..523330ca0f 100644 --- a/panda/src/bullet/bulletGenericConstraint.h +++ b/panda/src/bullet/bulletGenericConstraint.h @@ -61,6 +61,10 @@ PUBLISHED: INLINE CPT(TransformState) get_frame_a() const; INLINE CPT(TransformState) get_frame_b() const; + MAKE_PROPERTY(translational_limit_motor, get_translational_limit_motor); + MAKE_PROPERTY(frame_a, get_frame_a); + MAKE_PROPERTY(frame_b, get_frame_b); + public: virtual btTypedConstraint *ptr() const; diff --git a/panda/src/bullet/bulletGhostNode.h b/panda/src/bullet/bulletGhostNode.h index 3e8f2b6465..2cf5f73f21 100644 --- a/panda/src/bullet/bulletGhostNode.h +++ b/panda/src/bullet/bulletGhostNode.h @@ -38,6 +38,8 @@ PUBLISHED: INLINE int get_num_overlapping_nodes() const; INLINE PandaNode *get_overlapping_node(int idx) const; MAKE_SEQ(get_overlapping_nodes, get_num_overlapping_nodes, get_overlapping_node); + + MAKE_SEQ_PROPERTY(overlapping_nodes, get_num_overlapping_nodes, get_overlapping_node); public: virtual btCollisionObject *get_object() const; diff --git a/panda/src/bullet/bulletHelper.h b/panda/src/bullet/bulletHelper.h index 5b3aaf6152..c63f70f111 100644 --- a/panda/src/bullet/bulletHelper.h +++ b/panda/src/bullet/bulletHelper.h @@ -51,6 +51,9 @@ PUBLISHED: static void make_texcoords_for_patch(Geom *geom, int resx, int resy); + MAKE_PROPERTY(sb_index, get_sb_index); + MAKE_PROPERTY(sb_flip, get_sb_flip); + private: static PT(InternalName) _sb_index; static PT(InternalName) _sb_flip; diff --git a/panda/src/bullet/bulletHingeConstraint.h b/panda/src/bullet/bulletHingeConstraint.h index e5d5228454..81cf0b2674 100644 --- a/panda/src/bullet/bulletHingeConstraint.h +++ b/panda/src/bullet/bulletHingeConstraint.h @@ -73,6 +73,13 @@ PUBLISHED: INLINE CPT(TransformState) get_frame_a() const; INLINE CPT(TransformState) get_frame_b() const; + MAKE_PROPERTY(hinge_angle, get_hinge_angle); + MAKE_PROPERTY(lower_limit, get_lower_limit); + MAKE_PROPERTY(upper_limit, get_upper_limit); + MAKE_PROPERTY(angular_only, get_angular_only, set_angular_only); + MAKE_PROPERTY(frame_a, get_frame_a); + MAKE_PROPERTY(frame_b, get_frame_b); + public: virtual btTypedConstraint *ptr() const; diff --git a/panda/src/bullet/bulletManifoldPoint.h b/panda/src/bullet/bulletManifoldPoint.h index 4184ed9d97..a7bc271599 100644 --- a/panda/src/bullet/bulletManifoldPoint.h +++ b/panda/src/bullet/bulletManifoldPoint.h @@ -68,6 +68,30 @@ PUBLISHED: INLINE PN_stdfloat get_contact_cfm1() const; INLINE PN_stdfloat get_contact_cfm2() const; + MAKE_PROPERTY(life_time, get_life_time); + MAKE_PROPERTY(distance, get_distance); + MAKE_PROPERTY(applied_impulse, get_applied_impulse, set_applied_impulse); + MAKE_PROPERTY(position_world_on_a, get_position_world_on_a); + MAKE_PROPERTY(position_world_on_b, get_position_world_on_b); + MAKE_PROPERTY(normal_world_on_b, get_normal_world_on_b); + MAKE_PROPERTY(local_point_a, get_local_point_a); + MAKE_PROPERTY(local_point_b, get_local_point_b); + MAKE_PROPERTY(part_id0, get_part_id0); + MAKE_PROPERTY(part_id1, get_part_id1); + MAKE_PROPERTY(index0, get_index0); + MAKE_PROPERTY(index1, get_index1); + MAKE_PROPERTY(lateral_friction_initialized, get_lateral_friction_initialized, set_lateral_friction_initialized); + MAKE_PROPERTY(lateral_friction_dir1, get_lateral_friction_dir1, set_lateral_friction_dir1); + MAKE_PROPERTY(lateral_friction_dir2, get_lateral_friction_dir2, set_lateral_friction_dir2); + MAKE_PROPERTY(contact_motion1, get_contact_motion1, set_contact_motion1); + MAKE_PROPERTY(contact_motion2, get_contact_motion2, set_contact_motion2); + MAKE_PROPERTY(combined_friction, get_combined_friction, set_combined_friction); + MAKE_PROPERTY(combined_restitution, get_combined_restitution, set_combined_restitution); + MAKE_PROPERTY(applied_impulse_lateral1, get_applied_impulse_lateral1, set_applied_impulse_lateral1); + MAKE_PROPERTY(applied_impulse_lateral2, get_applied_impulse_lateral2, set_applied_impulse_lateral2); + MAKE_PROPERTY(contact_cfm1, get_contact_cfm1, set_contact_cfm1); + MAKE_PROPERTY(contact_cfm2, get_contact_cfm2, set_contact_cfm2); + public: BulletManifoldPoint(btManifoldPoint &pt); diff --git a/panda/src/bullet/bulletMinkowskiSumShape.h b/panda/src/bullet/bulletMinkowskiSumShape.h index 3b6aa6bc1f..dd148ce335 100644 --- a/panda/src/bullet/bulletMinkowskiSumShape.h +++ b/panda/src/bullet/bulletMinkowskiSumShape.h @@ -43,6 +43,12 @@ PUBLISHED: INLINE PN_stdfloat get_margin() const; + MAKE_PROPERTY(transform_a, get_transform_a, set_transform_a); + MAKE_PROPERTY(transform_b, get_transform_b, set_transform_b); + MAKE_PROPERTY(shape_a, get_shape_a); + MAKE_PROPERTY(shape_b, get_shape_b); + MAKE_PROPERTY(margin, get_margin); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletMultiSphereShape.h b/panda/src/bullet/bulletMultiSphereShape.h index b3a55bd5e3..2fb9c6c3a0 100644 --- a/panda/src/bullet/bulletMultiSphereShape.h +++ b/panda/src/bullet/bulletMultiSphereShape.h @@ -37,6 +37,10 @@ PUBLISHED: INLINE LPoint3 get_sphere_pos(int index) const; INLINE PN_stdfloat get_sphere_radius(int index) const; + MAKE_PROPERTY(sphere_count, get_sphere_count); + MAKE_SEQ_PROPERTY(sphere_pos, get_sphere_count, get_sphere_pos); + MAKE_SEQ_PROPERTY(sphere_radius, get_sphere_count, get_sphere_radius); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletPersistentManifold.h b/panda/src/bullet/bulletPersistentManifold.h index 2878d0b7ed..25feb57493 100644 --- a/panda/src/bullet/bulletPersistentManifold.h +++ b/panda/src/bullet/bulletPersistentManifold.h @@ -42,6 +42,12 @@ PUBLISHED: void clear_manifold(); + MAKE_PROPERTY(node0, get_node0); + MAKE_PROPERTY(node1, get_node1); + MAKE_SEQ_PROPERTY(manifold_points, get_num_manifold_points, get_manifold_point); + MAKE_PROPERTY(contact_breaking_threshold, get_contact_breaking_threshold); + MAKE_PROPERTY(contact_processing_threshold, get_contact_processing_threshold); + public: BulletPersistentManifold(btPersistentManifold *manifold); diff --git a/panda/src/bullet/bulletPlaneShape.h b/panda/src/bullet/bulletPlaneShape.h index 44a8e9ede6..4e75bfc2e6 100644 --- a/panda/src/bullet/bulletPlaneShape.h +++ b/panda/src/bullet/bulletPlaneShape.h @@ -42,6 +42,9 @@ PUBLISHED: static BulletPlaneShape *make_from_solid(const CollisionPlane *solid); + MAKE_PROPERTY(plane_normal, get_plane_normal); + MAKE_PROPERTY(plane_constant, get_plane_constant); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletRigidBodyNode.h b/panda/src/bullet/bulletRigidBodyNode.h index ea59c9202c..c8afaeb8bb 100644 --- a/panda/src/bullet/bulletRigidBodyNode.h +++ b/panda/src/bullet/bulletRigidBodyNode.h @@ -86,6 +86,23 @@ PUBLISHED: // Special bool pick_dirty_flag(); + MAKE_PROPERTY(mass, get_mass, set_mass); + MAKE_PROPERTY(inv_mass, get_inv_mass); + MAKE_PROPERTY(inertia, get_inertia, set_inertia); + MAKE_PROPERTY(inv_inertia_diag_local, get_inv_inertia_diag_local); + MAKE_PROPERTY(inv_inertia_tensor_world, get_inv_inertia_tensor_world); + MAKE_PROPERTY(linear_velocity, get_linear_velocity, set_linear_velocity); + MAKE_PROPERTY(angular_velocity, get_angular_velocity, set_angular_velocity); + MAKE_PROPERTY(linear_damping, get_linear_damping, set_linear_damping); + MAKE_PROPERTY(angular_damping, get_angular_damping, set_angular_damping); + MAKE_PROPERTY(total_force, get_total_force); + MAKE_PROPERTY(total_torque, get_total_torque); + MAKE_PROPERTY(linear_sleep_threshold, get_linear_sleep_threshold, set_linear_sleep_threshold); + MAKE_PROPERTY(angular_sleep_threshold, get_angular_sleep_threshold, set_angular_sleep_threshold); + MAKE_PROPERTY(gravity, get_gravity, set_gravity); + MAKE_PROPERTY(linear_factor, get_linear_factor, set_linear_factor); + MAKE_PROPERTY(angular_factor, get_angular_factor, set_angular_factor); + public: virtual btCollisionObject *get_object() const; diff --git a/panda/src/bullet/bulletRotationalLimitMotor.h b/panda/src/bullet/bulletRotationalLimitMotor.h index b82db7ad57..a1cce18ff4 100644 --- a/panda/src/bullet/bulletRotationalLimitMotor.h +++ b/panda/src/bullet/bulletRotationalLimitMotor.h @@ -50,6 +50,13 @@ PUBLISHED: INLINE PN_stdfloat get_current_position() const; INLINE PN_stdfloat get_accumulated_impulse() const; + MAKE_PROPERTY(limited, is_limited); + MAKE_PROPERTY(motor_enabled, get_motor_enabled, set_motor_enabled); + MAKE_PROPERTY(current_limit, get_current_limit); + MAKE_PROPERTY(current_error, get_current_error); + MAKE_PROPERTY(current_position, get_current_position); + MAKE_PROPERTY(accumulated_impulse, get_accumulated_impulse); + public: BulletRotationalLimitMotor(btRotationalLimitMotor &motor); diff --git a/panda/src/bullet/bulletShape.h b/panda/src/bullet/bulletShape.h index 8094cd1efb..8ebeaf9290 100644 --- a/panda/src/bullet/bulletShape.h +++ b/panda/src/bullet/bulletShape.h @@ -45,10 +45,20 @@ PUBLISHED: PN_stdfloat get_margin() const; BoundingSphere get_shape_bounds() const; + + MAKE_PROPERTY(polyhedral, is_polyhedral); + MAKE_PROPERTY(convex, is_convex); + MAKE_PROPERTY(convex_2d, is_convex_2d); + MAKE_PROPERTY(concave, is_concave); + MAKE_PROPERTY(infinite, is_infinite); + MAKE_PROPERTY(non_moving, is_non_moving); + MAKE_PROPERTY(soft_body, is_soft_body); + MAKE_PROPERTY(margin, get_margin, set_margin); + MAKE_PROPERTY(name, get_name); + MAKE_PROPERTY(shape_bounds, get_shape_bounds); public: virtual btCollisionShape *ptr() const = 0; - LVecBase3 get_local_scale() const; void set_local_scale(const LVecBase3 &scale); diff --git a/panda/src/bullet/bulletSliderConstraint.h b/panda/src/bullet/bulletSliderConstraint.h index b2ea28046e..181cb3a94a 100644 --- a/panda/src/bullet/bulletSliderConstraint.h +++ b/panda/src/bullet/bulletSliderConstraint.h @@ -74,6 +74,21 @@ PUBLISHED: INLINE CPT(TransformState) get_frame_a() const; INLINE CPT(TransformState) get_frame_b() const; + MAKE_PROPERTY(linear_pos, get_linear_pos); + MAKE_PROPERTY(angular_pos, get_angular_pos); + MAKE_PROPERTY(lower_linear_limit, get_lower_linear_limit, set_lower_linear_limit); + MAKE_PROPERTY(upper_linear_limit, get_upper_linear_limit, set_upper_linear_limit); + MAKE_PROPERTY(lower_angular_limit, get_lower_angular_limit, set_lower_angular_limit); + MAKE_PROPERTY(upper_angular_limit, get_upper_angular_limit, set_upper_angular_limit); + MAKE_PROPERTY(powered_linear_motor, get_powered_linear_motor, set_powered_linear_motor); + MAKE_PROPERTY(target_linear_motor_velocity, get_target_linear_motor_velocity, set_target_linear_motor_velocity); + MAKE_PROPERTY(max_linear_motor_force, get_max_linear_motor_force, set_max_linear_motor_force); + MAKE_PROPERTY(powered_angular_motor, get_powered_angular_motor, set_powered_angular_motor); + MAKE_PROPERTY(target_angular_motor_velocity, get_target_angular_motor_velocity, set_target_angular_motor_velocity); + MAKE_PROPERTY(max_angular_motor_force, get_max_angular_motor_force, set_max_angular_motor_force); + MAKE_PROPERTY(frame_a, get_frame_a); + MAKE_PROPERTY(frame_b, get_frame_b); + public: virtual btTypedConstraint *ptr() const; diff --git a/panda/src/bullet/bulletSoftBodyConfig.I b/panda/src/bullet/bulletSoftBodyConfig.I index 811463d492..eed9499bbb 100644 --- a/panda/src/bullet/bulletSoftBodyConfig.I +++ b/panda/src/bullet/bulletSoftBodyConfig.I @@ -113,7 +113,7 @@ set_pressure_coefficient(PN_stdfloat value) { * Getter for property kVC. */ INLINE PN_stdfloat BulletSoftBodyConfig:: -get_volume_conversation_coefficient() const { +get_volume_conservation_coefficient() const { return (PN_stdfloat)_cfg.kVC; } @@ -122,7 +122,7 @@ get_volume_conversation_coefficient() const { * Setter for property kVC. */ INLINE void BulletSoftBodyConfig:: -set_volume_conversation_coefficient(PN_stdfloat value) { +set_volume_conservation_coefficient(PN_stdfloat value) { _cfg.kVC = (btScalar)value; } diff --git a/panda/src/bullet/bulletSoftBodyConfig.h b/panda/src/bullet/bulletSoftBodyConfig.h index e3bf316881..2411797146 100644 --- a/panda/src/bullet/bulletSoftBodyConfig.h +++ b/panda/src/bullet/bulletSoftBodyConfig.h @@ -56,7 +56,7 @@ PUBLISHED: INLINE void set_drag_coefficient(PN_stdfloat value); INLINE void set_lift_coefficient(PN_stdfloat value); INLINE void set_pressure_coefficient(PN_stdfloat value); - INLINE void set_volume_conversation_coefficient(PN_stdfloat value); + INLINE void set_volume_conservation_coefficient(PN_stdfloat value); INLINE void set_dynamic_friction_coefficient(PN_stdfloat value); INLINE void set_pose_matching_coefficient(PN_stdfloat value); INLINE void set_rigid_contacts_hardness(PN_stdfloat value); @@ -81,7 +81,7 @@ PUBLISHED: INLINE PN_stdfloat get_drag_coefficient() const; INLINE PN_stdfloat get_lift_coefficient() const; INLINE PN_stdfloat get_pressure_coefficient() const; - INLINE PN_stdfloat get_volume_conversation_coefficient() const; + INLINE PN_stdfloat get_volume_conservation_coefficient() const; INLINE PN_stdfloat get_dynamic_friction_coefficient() const; INLINE PN_stdfloat get_pose_matching_coefficient() const; INLINE PN_stdfloat get_rigid_contacts_hardness() const; @@ -101,6 +101,32 @@ PUBLISHED: INLINE int get_drift_solver_iterations() const; INLINE int get_cluster_solver_iterations() const; + MAKE_PROPERTY(aero_model, get_aero_model, set_aero_model); + MAKE_PROPERTY(velocities_correction_factor, get_velocities_correction_factor, set_velocities_correction_factor); + MAKE_PROPERTY(damping_coefficient, get_damping_coefficient, set_damping_coefficient); + MAKE_PROPERTY(drag_coefficient, get_drag_coefficient, set_drag_coefficient); + MAKE_PROPERTY(lift_coefficient, get_lift_coefficient, set_lift_coefficient); + MAKE_PROPERTY(pressure_coefficient, get_pressure_coefficient, set_pressure_coefficient); + MAKE_PROPERTY(volume_conservation_coefficient, get_volume_conservation_coefficient, set_volume_conservation_coefficient); + MAKE_PROPERTY(dynamic_friction_coefficient, get_dynamic_friction_coefficient, set_dynamic_friction_coefficient); + MAKE_PROPERTY(pose_matching_coefficient, get_pose_matching_coefficient, set_pose_matching_coefficient); + MAKE_PROPERTY(rigid_contacts_hardness, get_rigid_contacts_hardness, set_rigid_contacts_hardness); + MAKE_PROPERTY(kinetic_contacts_hardness, get_kinetic_contacts_hardness, set_kinetic_contacts_hardness); + MAKE_PROPERTY(soft_contacts_hardness, get_soft_contacts_hardness, set_soft_contacts_hardness); + MAKE_PROPERTY(anchors_hardness, get_anchors_hardness, set_anchors_hardness); + MAKE_PROPERTY(soft_vs_rigid_hardness, get_soft_vs_rigid_hardness, set_soft_vs_rigid_hardness); + MAKE_PROPERTY(soft_vs_kinetic_hardness, get_soft_vs_kinetic_hardness, set_soft_vs_kinetic_hardness); + MAKE_PROPERTY(soft_vs_soft_hardness, get_soft_vs_soft_hardness, set_soft_vs_soft_hardness); + MAKE_PROPERTY(soft_vs_rigid_impulse_split, get_soft_vs_rigid_impulse_split, set_soft_vs_rigid_impulse_split); + MAKE_PROPERTY(soft_vs_kinetic_impulse_split, get_soft_vs_kinetic_impulse_split, set_soft_vs_kinetic_impulse_split); + MAKE_PROPERTY(soft_vs_soft_impulse_split, get_soft_vs_soft_impulse_split, set_soft_vs_soft_impulse_split); + MAKE_PROPERTY(maxvolume, get_maxvolume, set_maxvolume); + MAKE_PROPERTY(timescale, get_timescale, set_timescale); + MAKE_PROPERTY(positions_solver_iterations, get_positions_solver_iterations, set_positions_solver_iterations); + MAKE_PROPERTY(velocities_solver_iterations, get_velocities_solver_iterations, set_velocities_solver_iterations); + MAKE_PROPERTY(drift_solver_iterations, get_drift_solver_iterations, set_drift_solver_iterations); + MAKE_PROPERTY(cluster_solver_iterations, get_cluster_solver_iterations, set_cluster_solver_iterations); + public: BulletSoftBodyConfig(btSoftBody::Config &cfg); diff --git a/panda/src/bullet/bulletSoftBodyMaterial.h b/panda/src/bullet/bulletSoftBodyMaterial.h index b2a70c1d9d..3f1c07a7aa 100644 --- a/panda/src/bullet/bulletSoftBodyMaterial.h +++ b/panda/src/bullet/bulletSoftBodyMaterial.h @@ -27,16 +27,17 @@ PUBLISHED: INLINE ~BulletSoftBodyMaterial(); INLINE static BulletSoftBodyMaterial empty(); - INLINE void set_linear_stiffness(PN_stdfloat value); INLINE PN_stdfloat get_linear_stiffness() const; - MAKE_PROPERTY(linear_stiffness, get_linear_stiffness, set_linear_stiffness); + INLINE void set_linear_stiffness(PN_stdfloat value); - INLINE void set_angular_stiffness(PN_stdfloat value); INLINE PN_stdfloat get_angular_stiffness() const; - MAKE_PROPERTY(angular_stiffness, get_angular_stiffness, set_angular_stiffness); + INLINE void set_angular_stiffness(PN_stdfloat value); - INLINE void set_volume_preservation(PN_stdfloat value); INLINE PN_stdfloat get_volume_preservation() const; + INLINE void set_volume_preservation(PN_stdfloat value); + + MAKE_PROPERTY(linear_stiffness, get_linear_stiffness, set_linear_stiffness); + MAKE_PROPERTY(angular_stiffness, get_angular_stiffness, set_angular_stiffness); MAKE_PROPERTY(volume_preservation, get_volume_preservation, set_volume_preservation); public: diff --git a/panda/src/bullet/bulletSoftBodyNode.h b/panda/src/bullet/bulletSoftBodyNode.h index 38d95c1fd9..0f37217dfe 100644 --- a/panda/src/bullet/bulletSoftBodyNode.h +++ b/panda/src/bullet/bulletSoftBodyNode.h @@ -50,6 +50,13 @@ PUBLISHED: INLINE PN_stdfloat get_area() const; INLINE int is_attached() const; + MAKE_PROPERTY(pos, get_pos); + MAKE_PROPERTY(velocity, get_velocity); + MAKE_PROPERTY(normal, get_normal); + MAKE_PROPERTY(inv_mass, get_inv_mass); + MAKE_PROPERTY(area, get_area); + MAKE_PROPERTY(attached, is_attached); + public: BulletSoftBodyNodeElement(btSoftBody::Node &node); @@ -203,6 +210,14 @@ PUBLISHED: const char *face, const char *node); + MAKE_PROPERTY(cfg, get_cfg); + MAKE_PROPERTY(world_info, get_world_info); + MAKE_PROPERTY(wind_velocity, get_wind_velocity, set_wind_velocity); + MAKE_PROPERTY(aabb, get_aabb); + MAKE_PROPERTY(num_clusters, get_num_clusters); + MAKE_SEQ_PROPERTY(materials, get_num_materials, get_material); + MAKE_SEQ_PROPERTY(nodes, get_num_nodes, get_node); + public: virtual btCollisionObject *get_object() const; diff --git a/panda/src/bullet/bulletSoftBodyShape.h b/panda/src/bullet/bulletSoftBodyShape.h index 28a5aab9a6..85f62df88f 100644 --- a/panda/src/bullet/bulletSoftBodyShape.h +++ b/panda/src/bullet/bulletSoftBodyShape.h @@ -31,6 +31,8 @@ PUBLISHED: BulletSoftBodyNode *get_body() const; + MAKE_PROPERTY(body, get_body); + public: BulletSoftBodyShape(btSoftBodyCollisionShape *shapePtr); diff --git a/panda/src/bullet/bulletSoftBodyWorldInfo.h b/panda/src/bullet/bulletSoftBodyWorldInfo.h index c0aa23454b..5cae2fa0d5 100644 --- a/panda/src/bullet/bulletSoftBodyWorldInfo.h +++ b/panda/src/bullet/bulletSoftBodyWorldInfo.h @@ -43,6 +43,12 @@ PUBLISHED: void garbage_collect(int lifetime=256); + MAKE_PROPERTY(air_density, get_air_density, set_air_density); + MAKE_PROPERTY(water_density, get_water_density, set_water_density); + MAKE_PROPERTY(water_offset, get_water_offset, set_water_offset); + MAKE_PROPERTY(water_normal, get_water_normal, set_water_normal); + MAKE_PROPERTY(gravity, get_gravity, set_gravity); + public: BulletSoftBodyWorldInfo(btSoftBodyWorldInfo &_info); diff --git a/panda/src/bullet/bulletSphereShape.h b/panda/src/bullet/bulletSphereShape.h index 877f24f5df..815728c908 100644 --- a/panda/src/bullet/bulletSphereShape.h +++ b/panda/src/bullet/bulletSphereShape.h @@ -40,6 +40,8 @@ PUBLISHED: static BulletSphereShape *make_from_solid(const CollisionSphere *solid); + MAKE_PROPERTY(radius, get_radius); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletSphericalConstraint.h b/panda/src/bullet/bulletSphericalConstraint.h index 26f04825ea..4aad8b4ee9 100644 --- a/panda/src/bullet/bulletSphericalConstraint.h +++ b/panda/src/bullet/bulletSphericalConstraint.h @@ -48,6 +48,9 @@ PUBLISHED: LPoint3 get_pivot_in_a() const; LPoint3 get_pivot_in_b() const; + MAKE_PROPERTY(pivot_a, get_pivot_in_a, set_pivot_a); + MAKE_PROPERTY(pivot_b, get_pivot_in_b, set_pivot_b); + public: virtual btTypedConstraint *ptr() const; diff --git a/panda/src/bullet/bulletTickCallbackData.h b/panda/src/bullet/bulletTickCallbackData.h index 80c8570fe1..6218ac237c 100644 --- a/panda/src/bullet/bulletTickCallbackData.h +++ b/panda/src/bullet/bulletTickCallbackData.h @@ -30,6 +30,8 @@ PUBLISHED: INLINE PN_stdfloat get_timestep() const; + MAKE_PROPERTY(timestep, get_timestep); + private: btScalar _timestep; diff --git a/panda/src/bullet/bulletTranslationalLimitMotor.h b/panda/src/bullet/bulletTranslationalLimitMotor.h index bfbdd5e870..f339daefef 100644 --- a/panda/src/bullet/bulletTranslationalLimitMotor.h +++ b/panda/src/bullet/bulletTranslationalLimitMotor.h @@ -32,8 +32,8 @@ PUBLISHED: INLINE void set_motor_enabled(int axis, bool enable); INLINE void set_low_limit(const LVecBase3 &limit); - INLINE void set_high_limit(const LVecBase3 & limit); - INLINE void set_target_velocity(const LVecBase3&velocity); + INLINE void set_high_limit(const LVecBase3 &limit); + INLINE void set_target_velocity(const LVecBase3 &velocity); INLINE void set_max_motor_force(const LVecBase3 &force); INLINE void set_damping(PN_stdfloat damping); INLINE void set_softness(PN_stdfloat softness); @@ -49,6 +49,10 @@ PUBLISHED: INLINE LPoint3 get_current_diff() const; INLINE LVector3 get_accumulated_impulse() const; + MAKE_PROPERTY(current_error, get_current_error); + MAKE_PROPERTY(current_diff, get_current_diff); + MAKE_PROPERTY(accumulated_impulse, get_accumulated_impulse); + public: BulletTranslationalLimitMotor(btTranslationalLimitMotor &motor); diff --git a/panda/src/bullet/bulletTriangleMesh.h b/panda/src/bullet/bulletTriangleMesh.h index ade3ccfd7f..71dfe39a50 100644 --- a/panda/src/bullet/bulletTriangleMesh.h +++ b/panda/src/bullet/bulletTriangleMesh.h @@ -55,6 +55,9 @@ PUBLISHED: virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level) const; + MAKE_PROPERTY(num_triangles, get_num_triangles); + MAKE_PROPERTY(welding_distance, get_welding_distance, set_welding_distance); + public: INLINE btTriangleMesh *ptr() const; diff --git a/panda/src/bullet/bulletTriangleMeshShape.h b/panda/src/bullet/bulletTriangleMeshShape.h index 7a40dd5782..022df31655 100644 --- a/panda/src/bullet/bulletTriangleMeshShape.h +++ b/panda/src/bullet/bulletTriangleMeshShape.h @@ -41,6 +41,9 @@ PUBLISHED: INLINE bool is_static() const; INLINE bool is_dynamic() const; + MAKE_PROPERTY(static, is_static); + MAKE_PROPERTY(dynamic, is_dynamic); + public: virtual btCollisionShape *ptr() const; diff --git a/panda/src/bullet/bulletVehicle.h b/panda/src/bullet/bulletVehicle.h index 7ced2acb46..8b7f7862c6 100644 --- a/panda/src/bullet/bulletVehicle.h +++ b/panda/src/bullet/bulletVehicle.h @@ -46,6 +46,13 @@ PUBLISHED: INLINE PN_stdfloat get_friction_slip() const; INLINE PN_stdfloat get_max_suspension_force() const; + MAKE_PROPERTY(suspension_stiffness, get_suspension_stiffness, set_suspension_stiffness); + MAKE_PROPERTY(suspension_compression, get_suspension_compression, set_suspension_compression); + MAKE_PROPERTY(suspension_damping, get_suspension_damping, set_suspension_damping); + MAKE_PROPERTY(max_suspension_travel_cm, get_max_suspension_travel_cm, set_max_suspension_travel_cm); + MAKE_PROPERTY(friction_slip, get_friction_slip, set_friction_slip); + MAKE_PROPERTY(max_suspension_force, get_max_suspension_force, set_max_suspension_force); + private: btRaycastVehicle::btVehicleTuning _; @@ -87,6 +94,12 @@ PUBLISHED: // Tuning INLINE BulletVehicleTuning &get_tuning(); + MAKE_PROPERTY(chassis, get_chassis); + MAKE_PROPERTY(current_speed_km_hour, get_current_speed_km_hour); + MAKE_PROPERTY(forward_vector, get_forward_vector); + MAKE_SEQ_PROPERTY(wheels, get_num_wheels, get_wheel); + MAKE_PROPERTY(tuning, get_tuning); + public: INLINE btRaycastVehicle *get_vehicle() const; diff --git a/panda/src/bullet/bulletWheel.h b/panda/src/bullet/bulletWheel.h index 2f3fcc2e71..2b6ecd8a80 100644 --- a/panda/src/bullet/bulletWheel.h +++ b/panda/src/bullet/bulletWheel.h @@ -39,6 +39,15 @@ PUBLISHED: INLINE LPoint3 get_hard_point_ws() const; INLINE PandaNode *get_ground_object() const; + MAKE_PROPERTY(in_contact, is_in_contact); + MAKE_PROPERTY(suspension_length, get_suspension_length); + MAKE_PROPERTY(contact_normal_ws, get_contact_normal_ws); + MAKE_PROPERTY(wheel_direction_ws, get_wheel_direction_ws); + MAKE_PROPERTY(wheel_axle_ws, get_wheel_axle_ws); + MAKE_PROPERTY(contact_point_ws, get_contact_point_ws); + MAKE_PROPERTY(hard_point_ws, get_hard_point_ws); + MAKE_PROPERTY(ground_object, get_ground_object); + public: BulletWheelRaycastInfo(btWheelInfo::RaycastInfo &info); @@ -105,6 +114,32 @@ PUBLISHED: PandaNode *get_node() const; BulletWheelRaycastInfo get_raycast_info() const; + MAKE_PROPERTY(raycast_info, get_raycast_info); + MAKE_PROPERTY(suspension_rest_length, get_suspension_rest_length); + MAKE_PROPERTY(suspension_stiffness, get_suspension_stiffness, set_suspension_stiffness); + MAKE_PROPERTY(max_suspension_travel_cm, get_max_suspension_travel_cm, set_max_suspension_travel_cm); + MAKE_PROPERTY(friction_slip, get_friction_slip, set_friction_slip); + MAKE_PROPERTY(max_suspension_force, get_max_suspension_force, set_max_suspension_force); + MAKE_PROPERTY(wheels_damping_compression, get_wheels_damping_compression, set_wheels_damping_compression); + MAKE_PROPERTY(wheels_damping_relaxation, get_wheels_damping_relaxation, set_wheels_damping_relaxation); + MAKE_PROPERTY(roll_influence, get_roll_influence, set_roll_influence); + MAKE_PROPERTY(wheel_radius, get_wheel_radius, set_wheel_radius); + MAKE_PROPERTY(steering, get_steering, set_steering); + MAKE_PROPERTY(rotation, get_rotation, set_rotation); + MAKE_PROPERTY(delta_rotation, get_delta_rotation, set_delta_rotation); + MAKE_PROPERTY(engine_force, get_engine_force, set_engine_force); + MAKE_PROPERTY(brake, get_brake, set_brake); + MAKE_PROPERTY(skid_info, get_skid_info, set_skid_info); + MAKE_PROPERTY(wheels_suspension_force, get_wheels_suspension_force, set_wheels_suspension_force); + MAKE_PROPERTY(suspension_relative_velocity, get_suspension_relative_velocity, set_suspension_relative_velocity); + MAKE_PROPERTY(clipped_inv_connection_point_cs, get_clipped_inv_connection_point_cs, set_clipped_inv_connection_point_cs); + MAKE_PROPERTY(chassis_connection_point_cs, get_chassis_connection_point_cs, set_chassis_connection_point_cs); + MAKE_PROPERTY(wheel_direction_cs, get_wheel_direction_cs, set_wheel_direction_cs); + MAKE_PROPERTY(wheel_axle_cs, get_wheel_axle_cs, set_wheel_axle_cs); + MAKE_PROPERTY(world_transform, get_world_transform, set_world_transform); + MAKE_PROPERTY(front_wheel, is_front_wheel, set_front_wheel); + MAKE_PROPERTY(node, get_node, set_node); + public: BulletWheel(btWheelInfo &info); diff --git a/panda/src/bullet/bulletWorld.I b/panda/src/bullet/bulletWorld.I index e93dc0d176..958376ec60 100644 --- a/panda/src/bullet/bulletWorld.I +++ b/panda/src/bullet/bulletWorld.I @@ -81,6 +81,15 @@ get_debug_node() const { return _debug; } +/** + * + */ +INLINE bool BulletWorld:: +has_debug_node() const { + + return _debug != NULL; +} + /** * */ diff --git a/panda/src/bullet/bulletWorld.h b/panda/src/bullet/bulletWorld.h index 8d39186bb0..b077e05f7a 100644 --- a/panda/src/bullet/bulletWorld.h +++ b/panda/src/bullet/bulletWorld.h @@ -65,6 +65,7 @@ PUBLISHED: INLINE void set_debug_node(BulletDebugNode *node); INLINE void clear_debug_node(); INLINE BulletDebugNode *get_debug_node() const; + INLINE bool has_debug_node() const; // AttachRemove void attach(TypedObject *object); @@ -159,6 +160,17 @@ PUBLISHED: FA_callback, }; + MAKE_PROPERTY(gravity, get_gravity, set_gravity); + MAKE_PROPERTY(world_info, get_world_info); + MAKE_PROPERTY2(debug_node, has_debug_node, get_debug_node, set_debug_node, clear_debug_node); + MAKE_SEQ_PROPERTY(ghosts, get_num_ghosts, get_ghost); + MAKE_SEQ_PROPERTY(rigid_bodies, get_num_rigid_bodies, get_rigid_body); + MAKE_SEQ_PROPERTY(soft_bodies, get_num_soft_bodies, get_soft_body); + MAKE_SEQ_PROPERTY(characters, get_num_characters, get_character); + MAKE_SEQ_PROPERTY(vehicles, get_num_vehicles, get_vehicle); + MAKE_SEQ_PROPERTY(constraints, get_num_constraints, get_constraint); + MAKE_SEQ_PROPERTY(manifolds, get_num_manifolds, get_manifold); + PUBLISHED: // Deprecated methods, will become private soon void attach_ghost(BulletGhostNode *node); void remove_ghost(BulletGhostNode *node); diff --git a/panda/src/char/characterJointEffect.cxx b/panda/src/char/characterJointEffect.cxx index ec0dec9de3..33441e35c2 100644 --- a/panda/src/char/characterJointEffect.cxx +++ b/panda/src/char/characterJointEffect.cxx @@ -122,8 +122,10 @@ void CharacterJointEffect:: cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState) &node_transform, CPT(RenderState) &) const { - CPT(TransformState) dummy_transform = TransformState::make_identity(); - adjust_transform(dummy_transform, node_transform, data.node()); + if (_character.is_valid_pointer()) { + _character->update(); + } + node_transform = data.node()->get_transform(); } /** @@ -147,7 +149,7 @@ has_adjust_transform() const { void CharacterJointEffect:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const { + const PandaNode *node) const { if (_character.is_valid_pointer()) { _character->update(); } diff --git a/panda/src/char/characterJointEffect.h b/panda/src/char/characterJointEffect.h index 031b75237c..0df4cea6fd 100644 --- a/panda/src/char/characterJointEffect.h +++ b/panda/src/char/characterJointEffect.h @@ -53,7 +53,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; protected: virtual int compare_to_impl(const RenderEffect *other) const; diff --git a/panda/src/collide/collisionLevelState.I b/panda/src/collide/collisionLevelState.I index 5ac7cb9063..5dc74aa691 100644 --- a/panda/src/collide/collisionLevelState.I +++ b/panda/src/collide/collisionLevelState.I @@ -111,10 +111,12 @@ any_in_bounds() { } #endif // NDEBUG - CPT(BoundingVolume) node_bv = node()->get_bounds(); + PandaNode *pnode = node(); + + CPT(BoundingVolume) node_bv = pnode->get_bounds(); if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) { - const GeometricBoundingVolume *node_gbv; - DCAST_INTO_R(node_gbv, node_bv, false); + const GeometricBoundingVolume *node_gbv = (const GeometricBoundingVolume *)node_bv.p(); + CollideMask this_mask = pnode->get_net_collide_mask(); int num_colliders = get_num_colliders(); for (int c = 0; c < num_colliders; c++) { @@ -125,10 +127,10 @@ any_in_bounds() { // Don't even bother testing the bounding volume if there are no // collide bits in common between our collider and this node. CollideMask from_mask = cnode->get_from_collide_mask() & _include_mask; - if (!(from_mask & node()->get_net_collide_mask()).is_zero()) { + if (!(from_mask & this_mask).is_zero()) { // Also don't test a node with itself, or with any of its // descendants. - if (node() == cnode) { + if (pnode == cnode) { #ifndef NDEBUG if (collide_cat.is_spam()) { indent(collide_cat.spam(false), indent_level) diff --git a/panda/src/collide/collisionLevelStateBase.h b/panda/src/collide/collisionLevelStateBase.h index bde70562c2..4c2abccb58 100644 --- a/panda/src/collide/collisionLevelStateBase.h +++ b/panda/src/collide/collisionLevelStateBase.h @@ -51,7 +51,7 @@ public: INLINE CollisionLevelStateBase(const NodePath &node_path); INLINE CollisionLevelStateBase(const CollisionLevelStateBase &parent, - PandaNode *child); + PandaNode *child); INLINE CollisionLevelStateBase(const CollisionLevelStateBase ©); INLINE void operator = (const CollisionLevelStateBase ©); diff --git a/panda/src/collide/collisionNode.cxx b/panda/src/collide/collisionNode.cxx index da5aa38cc6..9de94617b3 100644 --- a/panda/src/collide/collisionNode.cxx +++ b/panda/src/collide/collisionNode.cxx @@ -196,7 +196,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { if (respect_prev_transform) { // Determine the previous frame's position, relative to the current // position. - NodePath node_path = data._node_path.get_node_path(); + NodePath node_path = data.get_node_path(); CPT(TransformState) transform = node_path.get_net_transform()->invert_compose(node_path.get_net_prev_transform()); if (!transform->is_identity()) { diff --git a/panda/src/collide/collisionNode.h b/panda/src/collide/collisionNode.h index 6c95e6d435..db731f7bcf 100644 --- a/panda/src/collide/collisionNode.h +++ b/panda/src/collide/collisionNode.h @@ -93,6 +93,8 @@ private: typedef pvector< COWPT(CollisionSolid) > Solids; Solids _solids; + friend class CollisionTraverser; + public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); diff --git a/panda/src/collide/collisionTraverser.cxx b/panda/src/collide/collisionTraverser.cxx index 5934a5e541..74973d6764 100644 --- a/panda/src/collide/collisionTraverser.cxx +++ b/panda/src/collide/collisionTraverser.cxx @@ -57,7 +57,7 @@ public: inline bool operator () (int a, int b) const { const CollisionTraverser::OrderedColliderDef &ocd_a = _trav._ordered_colliders[a]; const CollisionTraverser::OrderedColliderDef &ocd_b = _trav._ordered_colliders[b]; - return DCAST(CollisionNode, ocd_a._node_path.node())->get_collider_sort() < DCAST(CollisionNode, ocd_b._node_path.node())->get_collider_sort(); + return ((const CollisionNode *)ocd_a._node_path.node())->get_collider_sort() < ((const CollisionNode *)ocd_b._node_path.node())->get_collider_sort(); } const CollisionTraverser &_trav; @@ -1117,31 +1117,45 @@ compare_collider_to_node(CollisionEntry &entry, } if (within_node_bounds) { + Thread *current_thread = Thread::get_current_thread(); + CollisionNode *cnode; DCAST_INTO_V(cnode, entry._into_node); + int num_solids = cnode->get_num_solids(); - collide_cat.spam() - << "Colliding against CollisionNode " << entry._into_node - << " which has " << num_solids << " collision solids.\n"; - for (int s = 0; s < num_solids; ++s) { - entry._into = cnode->get_solid(s); + if (collide_cat.is_spam()) { + collide_cat.spam() + << "Colliding against CollisionNode " << entry._into_node + << " which has " << num_solids << " collision solids.\n"; + } - // We should allow a collision test for solid into itself, because the - // solid might be simply instanced into multiple different - // CollisionNodes. We are already filtering out tests for a - // CollisionNode into itself. - CPT(BoundingVolume) solid_bv = entry._into->get_bounds(); - const GeometricBoundingVolume *solid_gbv = NULL; - if (num_solids > 1 && - solid_bv->is_of_type(GeometricBoundingVolume::get_class_type())) { - // Only bother to test against each solid's bounding volume if we have - // more than one solid in the node, as a slight optimization. (If the - // node contains just one solid, then the node's bounding volume, - // which we just tested, is the same as the solid's bounding volume.) - DCAST_INTO_V(solid_gbv, solid_bv); + // Only bother to test against each solid's bounding volume if we have + // more than one solid in the node, as a slight optimization. (If the + // node contains just one solid, then the node's bounding volume, which + // we just tested, is the same as the solid's bounding volume.) + if (num_solids == 1) { + entry._into = cnode->_solids[0].get_read_pointer(current_thread); + Colliders::const_iterator ci; + ci = _colliders.find(entry.get_from_node_path()); + nassertv(ci != _colliders.end()); + entry.test_intersection((*ci).second, this); + } else { + CollisionNode::Solids::const_iterator si; + for (si = cnode->_solids.begin(); si != cnode->_solids.end(); ++si) { + entry._into = (*si).get_read_pointer(current_thread); + + // We should allow a collision test for solid into itself, because the + // solid might be simply instanced into multiple different + // CollisionNodes. We are already filtering out tests for a + // CollisionNode into itself. + CPT(BoundingVolume) solid_bv = entry._into->get_bounds(); + const GeometricBoundingVolume *solid_gbv = nullptr; + if (solid_bv->is_of_type(GeometricBoundingVolume::get_class_type())) { + solid_gbv = (const GeometricBoundingVolume *)solid_bv.p(); + } + + compare_collider_to_solid(entry, from_node_gbv, solid_gbv); } - - compare_collider_to_solid(entry, from_node_gbv, solid_gbv); } } } diff --git a/panda/src/collide/collisionVisualizer.cxx b/panda/src/collide/collisionVisualizer.cxx index 19699b9d6f..d58137ce68 100644 --- a/panda/src/collide/collisionVisualizer.cxx +++ b/panda/src/collide/collisionVisualizer.cxx @@ -111,10 +111,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // its objects according to their appropriate net transform. xform_data._net_transform = TransformState::make_identity(); xform_data._view_frustum = trav->get_view_frustum(); - xform_data.apply_transform_and_state(trav, net_transform, - RenderState::make_empty(), - RenderEffects::make_empty(), - ClipPlaneAttrib::make()); + xform_data.apply_transform(net_transform); // Draw all the collision solids. Solids::const_iterator si; diff --git a/panda/src/cull/cullBinBackToFront.cxx b/panda/src/cull/cullBinBackToFront.cxx index e472d0811d..57168aa866 100644 --- a/panda/src/cull/cullBinBackToFront.cxx +++ b/panda/src/cull/cullBinBackToFront.cxx @@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinBackToFront:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinFixed.cxx b/panda/src/cull/cullBinFixed.cxx index 3db9b9f7fb..6bbce5ed78 100644 --- a/panda/src/cull/cullBinFixed.cxx +++ b/panda/src/cull/cullBinFixed.cxx @@ -70,10 +70,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinFixed:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinFrontToBack.cxx b/panda/src/cull/cullBinFrontToBack.cxx index 1800b5636a..a532fef811 100644 --- a/panda/src/cull/cullBinFrontToBack.cxx +++ b/panda/src/cull/cullBinFrontToBack.cxx @@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinFrontToBack:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinStateSorted.cxx b/panda/src/cull/cullBinStateSorted.cxx index c7ba58c295..07f3f9c9a3 100644 --- a/panda/src/cull/cullBinStateSorted.cxx +++ b/panda/src/cull/cullBinStateSorted.cxx @@ -69,10 +69,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinStateSorted:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinUnsorted.cxx b/panda/src/cull/cullBinUnsorted.cxx index e9de061fb1..c9a68401b6 100644 --- a/panda/src/cull/cullBinUnsorted.cxx +++ b/panda/src/cull/cullBinUnsorted.cxx @@ -54,10 +54,27 @@ add_object(CullableObject *object, Thread *current_thread) { void CullBinUnsorted:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi); - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/display/displayInformation.cxx b/panda/src/display/displayInformation.cxx index 9bda75e0de..d690544889 100644 --- a/panda/src/display/displayInformation.cxx +++ b/panda/src/display/displayInformation.cxx @@ -15,11 +15,13 @@ #include "displayInformation.h" // For __rdtsc +#if defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) #ifdef _MSC_VER #include #elif defined(__GNUC__) && !defined(__clang__) #include #endif +#endif /** * Returns true if these two DisplayModes are identical. @@ -529,6 +531,7 @@ get_cpu_frequency() { */ uint64_t DisplayInformation:: get_cpu_time() { +#if defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) #if defined(_MSC_VER) || (defined(__GNUC__) && !defined(__clang__)) return __rdtsc(); #else @@ -536,6 +539,9 @@ get_cpu_time() { __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); return ((uint64_t)hi << 32) | lo; #endif +#else + return 0; +#endif } /** diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index bb6fdae3a4..ad5d1aea62 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -28,6 +28,16 @@ #include #endif +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +// CPUID is only available on i386 and x86-64 architectures. +#if defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) + #if defined(__GNUC__) && !defined(__APPLE__) // GCC and Clang offer a useful cpuid.h header. #include @@ -38,13 +48,6 @@ #include #endif -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include -#endif - union cpuid_info { char str[16]; struct { @@ -85,6 +88,7 @@ static inline void get_cpuid(uint32_t leaf, cpuid_info &info) { : "0" (leaf)); #endif } +#endif #ifdef IS_LINUX /** @@ -123,6 +127,7 @@ GraphicsPipe() : _display_information = new DisplayInformation(); +#if defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) cpuid_info info; const uint32_t max_cpuid = get_cpuid_max(0); const uint32_t max_extended = get_cpuid_max(0x80000000); @@ -148,6 +153,7 @@ GraphicsPipe() : brand[48] = 0; _display_information->_cpu_brand_string = brand; } +#endif #if defined(IS_OSX) // macOS exposes a lot of useful information through sysctl. diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 5b46251ba8..e8ef03ce3b 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -903,16 +903,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_identity: { return &LMatrix4::ident_mat(); } - case Shader::SMO_window_size: { - t = LMatrix4::translate_mat(_current_display_region->get_pixel_width(), - _current_display_region->get_pixel_height(), - 0.0); - return &t; - } + case Shader::SMO_window_size: case Shader::SMO_pixel_size: { - t = LMatrix4::translate_mat(_current_display_region->get_pixel_width(), - _current_display_region->get_pixel_height(), - 0.0); + LVecBase2i pixel_size = _current_display_region->get_pixel_size(); + t = LMatrix4::translate_mat(pixel_size[0], pixel_size[1], 0); return &t; } case Shader::SMO_frame_time: { @@ -1049,7 +1043,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LColor const &c = lt->get_color(); LColor const &s = lt->get_specular_color(); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); LVecBase3 d = -(t.xform_vec(lt->get_direction())); d.normalize(); LVecBase3 h = d + LVecBase3(0,-1,0); @@ -1066,11 +1060,12 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LColor const &c = lt->get_color(); LColor const &s = lt->get_specular_color(); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); LVecBase3 p = (t.xform_point(lt->get_point())); LVecBase3 a = lt->get_attenuation(); - PN_stdfloat lnear = lt->get_lens(0)->get_near(); - PN_stdfloat lfar = lt->get_lens(0)->get_far(); + Lens *lens = lt->get_lens(0); + PN_stdfloat lnear = lens->get_near(); + PN_stdfloat lfar = lens->get_far(); t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],lnear,a[0],a[1],a[2],lfar); return &t; } @@ -1086,7 +1081,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LColor const &s = lt->get_specular_color(); PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f)); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); LVecBase3 p = t.xform_point(lens->get_nodal_point()); LVecBase3 d = -(t.xform_vec(lens->get_view_vector())); t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff); @@ -1109,7 +1104,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, Light *light_obj = light.node()->as_light(); nassertr(light_obj != (Light *)NULL, &LMatrix4::zeros_mat()); - if (light_obj->get_type() == AmbientLight::get_class_type()) { + if (light_obj->is_ambient_light()) { cur_ambient_light += light_obj->get_color(); } } @@ -1155,27 +1150,31 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_plane_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); - nassertr(np.node()->is_of_type(PlaneNode::get_class_type()), &LMatrix4::zeros_mat()); - LPlane p = DCAST(PlaneNode, np.node())->get_plane(); + const PlaneNode *plane_node; + DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); + LPlane p = plane_node->get_plane(); t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]); return &t; } case Shader::SMO_clipplane_x: { - const ClipPlaneAttrib *cpa = DCAST(ClipPlaneAttrib, _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot())); + const ClipPlaneAttrib *cpa; + _target_rs->get_attrib_def(cpa); int planenr = atoi(name->get_name().c_str()); if (planenr >= cpa->get_num_on_planes()) { return &LMatrix4::zeros_mat(); } const NodePath &np = cpa->get_on_plane(planenr); nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); - nassertr(np.node()->is_of_type(PlaneNode::get_class_type()), &LMatrix4::zeros_mat()); - LPlane p (DCAST(PlaneNode, np.node())->get_plane()); + const PlaneNode *plane_node; + DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); + LPlane p (plane_node->get_plane()); p.xform(np.get_net_transform()->get_mat()); // World-space t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]); return &t; } case Shader::SMO_apiview_clipplane_i: { - const ClipPlaneAttrib *cpa = DCAST(ClipPlaneAttrib, _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot())); + const ClipPlaneAttrib *cpa; + _target_rs->get_attrib_def(cpa); if (index >= cpa->get_num_on_planes()) { return &LMatrix4::zeros_mat(); } @@ -1186,7 +1185,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, DCAST_INTO_R(plane_node, plane.node(), &LMatrix4::zeros_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( plane.get_transform(_scene_setup->get_scene_root().get_parent())); LPlane xformed_plane = plane_node->get_plane() * transform->get_mat(); @@ -1206,24 +1205,24 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &t; } case Shader::SMO_world_to_view: { - return &(get_scene()->get_world_transform()->get_mat()); + return &(_scene_setup->get_world_transform()->get_mat()); break; } case Shader::SMO_view_to_world: { - return &(get_scene()->get_camera_transform()->get_mat()); + return &(_scene_setup->get_camera_transform()->get_mat()); } case Shader::SMO_model_to_view: { - return &(get_external_transform()->get_mat()); + return &(_inv_cs_transform->compose(_internal_transform)->get_mat()); } case Shader::SMO_model_to_apiview: { - return &(get_internal_transform()->get_mat()); + return &(_internal_transform->get_mat()); } case Shader::SMO_view_to_model: { - t = get_external_transform()->get_inverse()->get_mat(); + t = _internal_transform->invert_compose(_cs_transform)->get_mat(); return &t; } case Shader::SMO_apiview_to_model: { - t = get_internal_transform()->get_inverse()->get_mat(); + t = _internal_transform->get_inverse()->get_mat(); return &t; } case Shader::SMO_apiview_to_view: { @@ -1268,13 +1267,13 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_view_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = get_scene()->get_camera_transform()->get_mat() * + t = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat(); return &t; } @@ -1283,13 +1282,13 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, nassertr(!np.is_empty(), &LMatrix4::ident_mat()); t = LMatrix4::convert_mat(_internal_coordinate_system, _coordinate_system) * np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_apiview_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = (get_scene()->get_camera_transform()->get_mat() * + t = (_scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, _internal_coordinate_system)); return &t; @@ -1297,20 +1296,22 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_clip_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); t = lens->get_projection_mat_inv(_current_stereo_channel) * LMatrix4::convert_mat(lens->get_coordinate_system(), _coordinate_system) * np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_clip_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); - t = get_scene()->get_camera_transform()->get_mat() * + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); + t = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()) * lens->get_projection_mat(_current_stereo_channel); @@ -1319,20 +1320,22 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_apiclip_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); t = calc_projection_mat(lens)->get_inverse()->get_mat() * get_cs_transform_for(lens->get_coordinate_system())->get_inverse()->get_mat() * np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_apiclip_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); - t = get_scene()->get_camera_transform()->get_mat() * + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); + t = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * get_cs_transform_for(lens->get_coordinate_system())->get_mat() * calc_projection_mat(lens)->get_mat(); @@ -1383,7 +1386,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, Light *light_obj = light.node()->as_light(); nassertr(light_obj != (Light *)NULL, &LMatrix4::ident_mat()); - if (light_obj->get_type() != AmbientLight::get_class_type()) { + if (!light_obj->is_ambient_light()) { if (i++ == index) { return fetch_specified_member(light, name, t); } @@ -1430,7 +1433,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) static const CPT_InternalName IN_constantAttenuation("constantAttenuation"); static const CPT_InternalName IN_linearAttenuation("linearAttenuation"); static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation"); - static const CPT_InternalName IN_shadowMatrix("shadowMatrix"); + static const CPT_InternalName IN_shadowViewMatrix("shadowViewMatrix"); PandaNode *node = NULL; if (!np.is_empty()) { @@ -1454,7 +1457,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } Light *light = node->as_light(); nassertr(light != (Light *)NULL, &LMatrix4::ident_mat()); - if (node->is_of_type(AmbientLight::get_class_type())) { + if (node->is_ambient_light()) { LColor c = light->get_color(); c.componentwise_mult(_light_color_scale); t.set_row(3, c); @@ -1470,7 +1473,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } Light *light = node->as_light(); nassertr(light != (Light *)NULL, &LMatrix4::ones_mat()); - if (node->is_of_type(AmbientLight::get_class_type())) { + if (node->is_ambient_light()) { // Ambient light has no diffuse color. t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f)); } else { @@ -1493,7 +1496,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (np.is_empty()) { t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); return &t; - } else if (node->is_of_type(AmbientLight::get_class_type())) { + } else if (node->is_ambient_light()) { // Ambient light has no position. t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); return &t; @@ -1503,7 +1506,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); - dir *= get_scene()->get_cs_world_transform()->get_mat(); + dir *= _scene_setup->get_cs_world_transform()->get_mat(); t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0); return &t; } else { @@ -1513,7 +1516,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( np.get_transform(_scene_setup->get_scene_root().get_parent())); const LMatrix4 &light_mat = transform->get_mat(); @@ -1526,7 +1529,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (np.is_empty()) { t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); return &t; - } else if (node->is_of_type(AmbientLight::get_class_type())) { + } else if (node->is_ambient_light()) { // Ambient light has no half-vector. t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); return &t; @@ -1536,7 +1539,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); - dir *= get_scene()->get_cs_world_transform()->get_mat(); + dir *= _scene_setup->get_cs_world_transform()->get_mat(); dir.normalize(); dir += LVector3(0, 0, 1); dir.normalize(); @@ -1549,7 +1552,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( np.get_transform(_scene_setup->get_scene_root().get_parent())); const LMatrix4 &light_mat = transform->get_mat(); @@ -1565,7 +1568,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (node == (PandaNode *)NULL) { t.set_row(3, LVector3(0.0f, 0.0f, -1.0f)); return &t; - } else if (node->is_of_type(AmbientLight::get_class_type())) { + } else if (node->is_ambient_light()) { // Ambient light has no spot direction. t.set_row(3, LVector3(0.0f, 0.0f, 0.0f)); return &t; @@ -1576,7 +1579,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( np.get_transform(_scene_setup->get_scene_root().get_parent())); const LMatrix4 &light_mat = transform->get_mat(); @@ -1670,7 +1673,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) t.set_row(3, LVecBase4(light->get_attenuation()[2])); return &t; - } else if (attrib == IN_shadowMatrix) { + } else if (attrib == IN_shadowViewMatrix) { static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, @@ -1684,8 +1687,8 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) DCAST_INTO_R(lnode, node, &LMatrix4::ident_mat()); Lens *lens = lnode->get_lens(); - t = get_external_transform()->get_mat() * - get_scene()->get_camera_transform()->get_mat() * + t = _inv_cs_transform->get_mat() * + _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()); @@ -1785,7 +1788,7 @@ fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler, Light *light_obj = light.node()->as_light(); nassertr(light_obj != (Light *)NULL, NULL); - if (light_obj->get_type() != AmbientLight::get_class_type()) { + if (!light_obj->is_ambient_light()) { if (i++ == spec._stage) { PT(Texture) tex = get_shadow_map(light); if (tex != (Texture *)NULL) { @@ -2663,7 +2666,7 @@ do_issue_light() { _lighting_enabled = true; } - if (light_obj->get_type() == AmbientLight::get_class_type()) { + if (light_obj->is_ambient_light()) { // Ambient lights don't require specific light ids; simply add in the // ambient contribution to the current total cur_ambient_light += light_obj->get_color(); @@ -3143,11 +3146,12 @@ async_reload_texture(TextureContext *tc) { */ PT(Texture) GraphicsStateGuardian:: get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) { - nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) || - light_np.node()->is_of_type(PointLight::get_class_type()) || - light_np.node()->is_of_type(Spotlight::get_class_type()), NULL); + PandaNode *node = light_np.node(); + nassertr(node->is_of_type(DirectionalLight::get_class_type()) || + node->is_of_type(PointLight::get_class_type()) || + node->is_of_type(Spotlight::get_class_type()), NULL); - PT(LightLensNode) light = DCAST(LightLensNode, light_np.node()); + LightLensNode *light = (LightLensNode *)node; if (light == NULL || !light->_shadow_caster) { // TODO: return dummy shadow map (all white). return NULL; @@ -3177,11 +3181,12 @@ get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) { PT(Texture) GraphicsStateGuardian:: make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) { // Make sure everything is valid. - nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) || - light_np.node()->is_of_type(PointLight::get_class_type()) || - light_np.node()->is_of_type(Spotlight::get_class_type()), NULL); + PandaNode *node = light_np.node(); + nassertr(node->is_of_type(DirectionalLight::get_class_type()) || + node->is_of_type(PointLight::get_class_type()) || + node->is_of_type(Spotlight::get_class_type()), NULL); - PT(LightLensNode) light = DCAST(LightLensNode, light_np.node()); + LightLensNode *light = (LightLensNode *)node; if (light == NULL || !light->_shadow_caster) { return NULL; } diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index a5dbce4a11..a300771f1f 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -286,7 +286,7 @@ PUBLISHED: MAKE_PROPERTY(driver_shader_version_minor, get_driver_shader_version_minor); bool set_scene(SceneSetup *scene_setup); - virtual SceneSetup *get_scene() const; + virtual SceneSetup *get_scene() const FINAL; MAKE_PROPERTY(scene, get_scene, set_scene); public: diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index fd319031e6..1991bfc120 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/panda/src/distort/projectionScreen.cxx @@ -103,7 +103,7 @@ make_copy() const { bool ProjectionScreen:: cull_callback(CullTraverser *, CullTraverserData &data) { if (_auto_recompute) { - recompute_if_stale(data._node_path.get_node_path()); + recompute_if_stale(data.get_node_path()); } return true; } diff --git a/panda/src/dxgsg9/config_dxgsg9.cxx b/panda/src/dxgsg9/config_dxgsg9.cxx index 037d8dd919..64831d08c9 100644 --- a/panda/src/dxgsg9/config_dxgsg9.cxx +++ b/panda/src/dxgsg9/config_dxgsg9.cxx @@ -265,8 +265,3 @@ init_libdxgsg9() { PandaSystem *ps = PandaSystem::get_global_ptr(); ps->add_system("DirectX9"); } - -// Necessary to allow use of dxerr from MSVC 2015 -#if _MSC_VER >= 1900 -int (WINAPIV * __vsnprintf)(char *, size_t, const char*, va_list) = _vsnprintf; -#endif diff --git a/panda/src/dxgsg9/dxGeomMunger9.cxx b/panda/src/dxgsg9/dxGeomMunger9.cxx index aaadacb119..44729ae0cd 100644 --- a/panda/src/dxgsg9/dxGeomMunger9.cxx +++ b/panda/src/dxgsg9/dxGeomMunger9.cxx @@ -164,7 +164,7 @@ munge_format_impl(const GeomVertexFormat *orig, // Now go through the remaining arrays and make sure they are tightly // packed. If not, repack them. - for (int i = 0; i < new_format->get_num_arrays(); ++i) { + for (size_t i = 0; i < new_format->get_num_arrays(); ++i) { CPT(GeomVertexArrayFormat) orig_a = new_format->get_array(i); if (orig_a->count_unused_space() != 0) { PT(GeomVertexArrayFormat) new_a = new GeomVertexArrayFormat; @@ -267,7 +267,7 @@ premunge_format_impl(const GeomVertexFormat *orig) { // Now go through the remaining arrays and make sure they are tightly // packed. If not, repack them. - for (int i = 0; i < new_format->get_num_arrays(); ++i) { + for (size_t i = 0; i < new_format->get_num_arrays(); ++i) { CPT(GeomVertexArrayFormat) orig_a = new_format->get_array(i); if (orig_a->count_unused_space() != 0) { PT(GeomVertexArrayFormat) new_a = new GeomVertexArrayFormat; diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 4b5efc2b8c..2f47afe6cf 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -863,7 +863,7 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { dr->get_region_pixels_i(l, u, w, h); // Create the viewport - D3DVIEWPORT9 vp = { l, u, w, h, 0.0f, 1.0f }; + D3DVIEWPORT9 vp = { (DWORD)l, (DWORD)u, (DWORD)w, (DWORD)h, 0.0f, 1.0f }; _current_viewport = vp; HRESULT hr = _d3d_device->SetViewport(&_current_viewport); if (FAILED(hr)) { @@ -1185,7 +1185,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, const TransformTable *table = data_reader->get_transform_table(); if (table != (TransformTable *)NULL) { - for (int i = 0; i < table->get_num_transforms(); i++) { + for (size_t i = 0; i < table->get_num_transforms(); ++i) { LMatrix4 mat; table->get_transform(i)->mult_matrix(mat, _internal_transform->get_mat()); const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data(); diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.cxx b/panda/src/dxgsg9/dxIndexBufferContext9.cxx index 6cf6a78c84..a29dff17b3 100644 --- a/panda/src/dxgsg9/dxIndexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxIndexBufferContext9.cxx @@ -132,8 +132,7 @@ allocate_ibuffer(DXScreenData &scrn, dxgsg9_cat.debug() << "creating index buffer " << _ibuffer << ": " << reader->get_num_vertices() << " indices (" - << reader->get_vertices_reader()->get_array_format()->get_column(0)->get_numeric_type() - << ")\n"; + << reader->get_index_type() << ")\n"; } } } @@ -169,7 +168,7 @@ upload_data(const GeomPrimitivePipelineReader *reader, bool force) { if (data_pointer == NULL) { return false; } - int data_size = reader->get_data_size_bytes(); + size_t data_size = (size_t)reader->get_data_size_bytes(); if (reader->get_index_type() == GeomEnums::NT_uint8) { // We widen 8-bits indices to 16-bits. diff --git a/panda/src/egg2pg/eggSaver.cxx b/panda/src/egg2pg/eggSaver.cxx index 133bddc874..5eeb98f42c 100644 --- a/panda/src/egg2pg/eggSaver.cxx +++ b/panda/src/egg2pg/eggSaver.cxx @@ -940,6 +940,9 @@ apply_node_properties(EggGroup *egg_group, PandaNode *node, bool allow_backstage ModelNode *model_node = DCAST(ModelNode, node); switch (model_node->get_preserve_transform()) { case ModelNode::PT_none: + egg_group->set_model_flag(true); + break; + case ModelNode::PT_drop_node: break; diff --git a/panda/src/express/memoryUsage.I b/panda/src/express/memoryUsage.I index 619da5a736..f9de4f8c93 100644 --- a/panda/src/express/memoryUsage.I +++ b/panda/src/express/memoryUsage.I @@ -295,10 +295,13 @@ show_trend_ages() { */ INLINE MemoryUsage *MemoryUsage:: get_global_ptr() { - if (_global_ptr == (MemoryUsage *)NULL) { - init_memory_hook(); - _global_ptr = new MemoryUsage(*memory_hook); - memory_hook = _global_ptr; +#ifdef __GNUC__ + // Tell the compiler that this is an unlikely branch. + if (__builtin_expect(_global_ptr == nullptr, 0)) { +#else + if (_global_ptr == nullptr) { +#endif + init_memory_usage(); } return _global_ptr; diff --git a/panda/src/express/memoryUsage.cxx b/panda/src/express/memoryUsage.cxx index 1aea4fe825..a834da9dad 100644 --- a/panda/src/express/memoryUsage.cxx +++ b/panda/src/express/memoryUsage.cxx @@ -489,6 +489,16 @@ MemoryUsage(const MemoryHook ©) : MemoryHook(copy) { _total_size = 0; } +/** + * Initializes the global MemoryUsage pointer. + */ +void MemoryUsage:: +init_memory_usage() { + init_memory_hook(); + _global_ptr = new MemoryUsage(*memory_hook); + memory_hook = _global_ptr; +} + /** * This callback method is called whenever the total allocated heap size * exceeds _max_heap_size. It's mainly intended for reporting memory leaks, diff --git a/panda/src/express/memoryUsage.h b/panda/src/express/memoryUsage.h index b52f71f7ea..eb4cc6856e 100644 --- a/panda/src/express/memoryUsage.h +++ b/panda/src/express/memoryUsage.h @@ -95,6 +95,8 @@ private: MemoryUsage(const MemoryHook ©); INLINE static MemoryUsage *get_global_ptr(); + static void init_memory_usage(); + void ns_record_pointer(ReferenceCount *ptr); void ns_update_type(ReferenceCount *ptr, TypeHandle type); void ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr); diff --git a/panda/src/express/pointerToBase.I b/panda/src/express/pointerToBase.I index 296dc5d3bb..d57064967b 100644 --- a/panda/src/express/pointerToBase.I +++ b/panda/src/express/pointerToBase.I @@ -21,9 +21,7 @@ PointerToBase(To *ptr) { if (ptr != (To *)NULL) { ptr->ref(); #ifdef DO_MEMORY_USAGE - if (MemoryUsage::get_track_memory_usage()) { - update_type(ptr); - } + update_type(ptr); #endif } } @@ -38,11 +36,6 @@ PointerToBase(const PointerToBase ©) { if (_void_ptr != NULL) { To *ptr = (To *)_void_ptr; ptr->ref(); -#ifdef DO_MEMORY_USAGE - if (MemoryUsage::get_track_memory_usage()) { - update_type(ptr); - } -#endif } } @@ -108,17 +101,15 @@ reassign(To *ptr) { To *old_ptr = (To *)_void_ptr; _void_ptr = (void *)ptr; - if (ptr != (To *)NULL) { + if (ptr != nullptr) { ptr->ref(); #ifdef DO_MEMORY_USAGE - if (MemoryUsage::get_track_memory_usage()) { - update_type(ptr); - } + update_type(ptr); #endif } // Now delete the old pointer. - if (old_ptr != (To *)NULL) { + if (old_ptr != nullptr) { unref_delete(old_ptr); } } @@ -130,7 +121,24 @@ reassign(To *ptr) { template INLINE void PointerToBase:: reassign(const PointerToBase ©) { - reassign((To *)copy._void_ptr); + if (copy._void_ptr != _void_ptr) { + // First save the old pointer; we won't delete it until we have assigned + // the new one. We do this just in case there are cascading effects from + // deleting this pointer that might inadvertently delete the new one. + // (Don't laugh--it's happened!) + To *old_ptr = (To *)_void_ptr; + To *new_ptr = (To *)copy._void_ptr; + + _void_ptr = copy._void_ptr; + if (new_ptr != nullptr) { + new_ptr->ref(); + } + + // Now delete the old pointer. + if (old_ptr != nullptr) { + unref_delete(old_ptr); + } + } } #ifdef DO_MEMORY_USAGE @@ -139,15 +147,17 @@ reassign(const PointerToBase ©) { * object, if we know the type ourselves. */ template -void PointerToBase:: +INLINE void PointerToBase:: update_type(To *ptr) { - TypeHandle type = get_type_handle(To); - if (type == TypeHandle::none()) { - do_init_type(To); - type = get_type_handle(To); - } - if (type != TypeHandle::none()) { - MemoryUsage::update_type(ptr, type); + if (MemoryUsage::get_track_memory_usage()) { + TypeHandle type = get_type_handle(To); + if (type == TypeHandle::none()) { + do_init_type(To); + type = get_type_handle(To); + } + if (type != TypeHandle::none()) { + MemoryUsage::update_type(ptr, type); + } } } #endif // DO_MEMORY_USAGE diff --git a/panda/src/express/pointerToBase.h b/panda/src/express/pointerToBase.h index b85e6ec856..d19edd6b5c 100644 --- a/panda/src/express/pointerToBase.h +++ b/panda/src/express/pointerToBase.h @@ -45,7 +45,7 @@ protected: INLINE void reassign(const PointerToBase ©); #ifdef DO_MEMORY_USAGE - void update_type(To *ptr); + INLINE void update_type(To *ptr); #endif // DO_MEMORY_USAGE // No assignment or retrieval functions are declared in PointerToBase, diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 8497c7de71..329594eb38 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -399,6 +399,7 @@ unbind() { void CLP(CgShaderContext):: set_state_and_transform(const RenderState *target_rs, const TransformState *modelview_transform, + const TransformState *camera_transform, const TransformState *projection_transform) { if (!valid()) { @@ -410,6 +411,10 @@ set_state_and_transform(const RenderState *target_rs, if (_modelview_transform != modelview_transform) { _modelview_transform = modelview_transform; + altered |= (Shader::SSD_transform & ~Shader::SSD_view_transform); + } + if (_camera_transform != camera_transform) { + _camera_transform = camera_transform; altered |= Shader::SSD_transform; } if (_projection_transform != projection_transform) { diff --git a/panda/src/glstuff/glCgShaderContext_src.h b/panda/src/glstuff/glCgShaderContext_src.h index ae76989d77..49d451d442 100644 --- a/panda/src/glstuff/glCgShaderContext_src.h +++ b/panda/src/glstuff/glCgShaderContext_src.h @@ -25,7 +25,7 @@ class CLP(GraphicsStateGuardian); /** * xyz */ -class EXPCL_GL CLP(CgShaderContext) : public ShaderContext { +class EXPCL_GL CLP(CgShaderContext) FINAL : public ShaderContext { public: friend class CLP(GraphicsStateGuardian); @@ -39,7 +39,8 @@ public: void set_state_and_transform(const RenderState *state, const TransformState *modelview_transform, - const TransformState *projection_transform); + const TransformState *camera_transform, + const TransformState *projection_transform) OVERRIDE; void issue_parameters(int altered) OVERRIDE; void update_transform_table(const TransformTable *table); @@ -77,6 +78,7 @@ private: WCPT(RenderState) _state_rs; CPT(TransformState) _modelview_transform; + CPT(TransformState) _camera_transform; CPT(TransformState) _projection_transform; GLint _frame_number; @@ -93,10 +95,10 @@ public: register_type(_type_handle, CLASSPREFIX_QUOTED "CgShaderContext", ShaderContext::get_class_type()); } - virtual TypeHandle get_type() const { + virtual TypeHandle get_type() const OVERRIDE { return get_class_type(); } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + virtual TypeHandle force_init_type() OVERRIDE {init_type(); return get_class_type();} private: static TypeHandle _type_handle; diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 706bb03049..a4daaf3931 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -95,8 +95,7 @@ clear(Thread *current_thread) { return; } - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if (glgsg->_glClearBufferfv == NULL) { // We can't efficiently clear the buffer. Fall back to the inefficient @@ -254,8 +253,7 @@ begin_frame(FrameMode mode, Thread *current_thread) { // until we call glBlitFramebuffer. #ifndef OPENGLES_1 if (gl_enable_memory_barriers && _fbo_multisample == 0) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_R(glgsg, _gsg, false); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); TextureContexts::iterator it; for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) { @@ -285,8 +283,7 @@ begin_frame(FrameMode mode, Thread *current_thread) { */ bool CLP(GraphicsBuffer):: check_fbo() { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_R(glgsg, _gsg, false); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -341,8 +338,7 @@ rebuild_bitplanes() { return; } - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if (!_needs_rebuild) { if (_fbo_multisample != 0) { @@ -685,8 +681,7 @@ rebuild_bitplanes() { */ void CLP(GraphicsBuffer):: bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); Texture *tex = attach[slot]; @@ -1020,8 +1015,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, */ void CLP(GraphicsBuffer):: bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if ((_rbm[slot] != 0)&&(!rb_resize)) { return; @@ -1144,8 +1138,7 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, */ void CLP(GraphicsBuffer):: attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if (view >= attach->get_num_views()) { attach->set_num_views(view + 1); @@ -1215,8 +1208,7 @@ generate_mipmaps() { return; } - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); // PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector); @@ -1253,8 +1245,7 @@ end_frame(FrameMode mode, Thread *current_thread) { // Unbind the FBO. TODO: calling bind_fbo is slow, so we should probably // move this to begin_frame to prevent unnecessary calls. - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); glgsg->bind_fbo(0); _bound_tex_page = -1; @@ -1293,8 +1284,7 @@ void CLP(GraphicsBuffer):: select_target_tex_page(int page) { nassertv(page >= 0 && page < _fbo.size()); - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); bool switched_page = (_bound_tex_page != page); @@ -1689,8 +1679,7 @@ report_my_errors(int line, const char *file) { GLCAT.error() << file << ", line " << line << ": GL error " << (int)error_code << "\n"; } } else { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); glgsg->report_my_errors(line, file); } } @@ -1723,8 +1712,7 @@ void CLP(GraphicsBuffer):: resolve_multisamples() { nassertv(_fbo.size() > 0); - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); PStatGPUTimer timer(glgsg, _resolve_multisample_pcollector); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index c83c9e52c0..b147c9182e 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -929,7 +929,7 @@ reset() { #endif #ifndef OPENGLES - if (is_at_least_gl_version(3, 0)) { + if (is_at_least_gl_version(3, 1)) { _glTexBuffer = (PFNGLTEXBUFFERPROC)get_extension_func("glTexBuffer"); _supports_buffer_texture = true; @@ -9260,18 +9260,22 @@ get_internal_image_format(Texture *tex, bool force_sized) const { return GL_RGBA16F; } else #endif -#ifndef OPENGLES +#ifdef OPENGLES + { + // In OpenGL ES, the internal format must match the external format. + return _supports_bgr ? GL_BGRA : GL_RGBA; + } +#else if (tex->get_component_type() == Texture::T_unsigned_short) { return GL_RGBA16; } else if (tex->get_component_type() == Texture::T_short) { return GL_RGBA16_SNORM; } else if (tex->get_component_type() == Texture::T_byte) { return GL_RGBA8_SNORM; - } else -#endif - { + } else { return force_sized ? GL_RGBA8 : GL_RGBA; } +#endif case Texture::F_rgba4: return GL_RGBA4; @@ -10350,7 +10354,7 @@ set_state_and_transform(const RenderState *target, // Update all of the state that is bound to the shader program. if (_current_shader_context != NULL) { - _current_shader_context->set_state_and_transform(target, transform, _projection_mat); + _current_shader_context->set_state_and_transform(target, transform, _scene_setup->get_camera_transform(), _projection_mat); } #endif @@ -12702,6 +12706,9 @@ upload_simple_texture(CLP(TextureContext) *gtc) { _data_transferred_pcollector.add_level(image_size); #endif +#ifdef OPENGLES + internal_format = external_format; +#endif glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, external_format, component_type, image_ptr); diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 6947a39235..65a4a1c01c 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -874,7 +874,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { matrix_name.substr(0, 12) == "LightSource[" && sscanf(matrix_name.c_str(), "LightSource[%d].%s", &bind._index, name_buffer) == 2) { // A matrix member of a p3d_LightSource struct. - if (strncmp(name_buffer, "shadowMatrix", 127) == 0) { + if (strncmp(name_buffer, "shadowViewMatrix", 127) == 0) { if (inverse) { // Tack inverse back onto the end. strcpy(name_buffer + strlen(name_buffer), "Inverse"); @@ -884,7 +884,25 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._part[0] = Shader::SMO_light_source_i_attrib; bind._arg[0] = InternalName::make(name_buffer); bind._part[1] = Shader::SMO_identity; + bind._arg[1] = NULL; + } else if (strncmp(name_buffer, "shadowMatrix", 127) == 0) { + // Only supported for backward compatibility: includes the model + // matrix. Not very efficient to do this. + bind._func = Shader::SMF_compose; + bind._part[0] = Shader::SMO_model_to_apiview; + bind._arg[0] = NULL; + bind._part[1] = Shader::SMO_light_source_i_attrib; + bind._arg[1] = InternalName::make("shadowViewMatrix"); + + static bool warned = false; + if (!warned) { + warned = true; + GLCAT.warning() + << "p3d_LightSource[].shadowMatrix is deprecated; use " + "shadowViewMatrix instead, which transforms from view space " + "instead of model space.\n"; + } } else { GLCAT.error() << "p3d_LightSource struct does not provide a matrix named " << matrix_name << "!\n"; return; @@ -1163,11 +1181,16 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._index = index; bind._part[0] = Shader::SMO_light_source_i_attrib; bind._arg[0] = InternalName::make(member_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame | Shader::SSD_transform; + bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame; bind._part[1] = Shader::SMO_identity; bind._arg[1] = NULL; bind._dep[1] = Shader::SSD_NONE; + if (member_name == "position" || member_name == "halfVector" || + member_name == "spotDirection") { + bind._dep[0] |= Shader::SSD_view_transform; + } + switch (param_type) { case GL_FLOAT: bind._piece = Shader::SMP_row3x1; @@ -1250,7 +1273,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_compose; bind._part[0] = Shader::SMO_world_to_view; bind._part[1] = Shader::SMO_view_to_apiview; - bind._dep[0] = Shader::SSD_general | Shader::SSD_transform; + bind._dep[0] = Shader::SSD_general | Shader::SSD_view_transform; bind._dep[1] = Shader::SSD_general; _shader->_mat_spec.push_back(bind); _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; @@ -1262,7 +1285,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._part[0] = Shader::SMO_apiview_to_view; bind._part[1] = Shader::SMO_view_to_world; bind._dep[0] = Shader::SSD_general; - bind._dep[1] = Shader::SSD_general | Shader::SSD_transform; + bind._dep[1] = Shader::SSD_general | Shader::SSD_view_transform; _shader->_mat_spec.push_back(bind); _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; return; @@ -1383,22 +1406,43 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._id = arg_id; bind._piece = Shader::SMP_whole; bind._func = Shader::SMF_first; + bind._part[1] = Shader::SMO_identity; + bind._arg[1] = NULL; + bind._dep[1] = Shader::SSD_NONE; PT(InternalName) iname = InternalName::make(param_name); if (iname->get_parent() != InternalName::get_root()) { // It might be something like an attribute of a shader input, like a // light parameter. It might also just be a custom struct // parameter. We can't know yet, sadly. - bind._part[0] = Shader::SMO_mat_constant_x_attrib; - bind._arg[0] = InternalName::make(param_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_transform; + if (iname->get_basename() == "shadowMatrix") { + // Special exception for shadowMatrix, which is deprecated, + // because it includes the model transformation. It is far more + // efficient to do that in the shader instead. + static bool warned = false; + if (!warned) { + warned = true; + GLCAT.warning() + << "light.shadowMatrix inputs are deprecated; use " + "shadowViewMatrix instead, which transforms from view " + "space instead of model space.\n"; + } + bind._func = Shader::SMF_compose; + bind._part[0] = Shader::SMO_model_to_apiview; + bind._arg[0] = NULL; + bind._dep[0] = Shader::SSD_general | Shader::SSD_transform; + bind._part[1] = Shader::SMO_mat_constant_x_attrib; + bind._arg[1] = InternalName::make("shadowViewMatrix"); + bind._dep[1] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; + } else { + bind._part[0] = Shader::SMO_mat_constant_x_attrib; + bind._arg[0] = InternalName::make(param_name); + bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; + } } else { bind._part[0] = Shader::SMO_mat_constant_x; bind._arg[0] = InternalName::make(param_name); bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame; } - bind._part[1] = Shader::SMO_identity; - bind._arg[1] = NULL; - bind._dep[1] = Shader::SSD_NONE; _shader->_mat_spec.push_back(bind); _shader->_mat_deps |= bind._dep[0]; return; @@ -1430,9 +1474,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_vec_constant_x_attrib; bind._arg[0] = iname; - // We need SSD_transform since some attributes (eg. light position) - // have to be transformed to view space. - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_transform; + // We need SSD_view_transform since some attributes (eg. light + // position) have to be transformed to view space. + bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; bind._part[1] = Shader::SMO_identity; bind._arg[1] = NULL; bind._dep[1] = Shader::SSD_NONE; @@ -1822,6 +1866,7 @@ unbind() { void CLP(ShaderContext):: set_state_and_transform(const RenderState *target_rs, const TransformState *modelview_transform, + const TransformState *camera_transform, const TransformState *projection_transform) { // Find out which state properties have changed. @@ -1829,6 +1874,10 @@ set_state_and_transform(const RenderState *target_rs, if (_modelview_transform != modelview_transform) { _modelview_transform = modelview_transform; + altered |= (Shader::SSD_transform & ~Shader::SSD_view_transform); + } + if (_camera_transform != camera_transform) { + _camera_transform = camera_transform; altered |= Shader::SSD_transform; } if (_projection_transform != projection_transform) { @@ -2194,7 +2243,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { // Figure out which attributes to enable or disable. BitMask32 enabled_attribs = _enabled_attribs; if (_color_attrib_index != -1 && - color_attrib->get_type() != ColorAttrib::T_vertex) { + color_attrib->get_color_type() != ColorAttrib::T_vertex) { // Vertex colours are disabled. enabled_attribs.clear_bit(_color_attrib_index); @@ -2247,7 +2296,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { // Don't apply vertex colors if they are disabled with a ColorAttrib. int num_elements, element_stride, divisor; bool normalized; - if ((p != _color_attrib_index || color_attrib->get_type() == ColorAttrib::T_vertex) && + if ((p != _color_attrib_index || color_attrib->get_color_type() == ColorAttrib::T_vertex) && _glgsg->_data_reader->get_array_info(name, array_reader, num_values, numeric_type, normalized, start, stride, divisor, @@ -2440,17 +2489,17 @@ update_shader_texture_bindings(ShaderContext *prev) { const ParamTextureImage *param = NULL; Texture *tex; - const ShaderInput *sinp = _glgsg->_target_shader->get_shader_input(input._name); - switch (sinp->get_value_type()) { + const ShaderInput &sinp = _glgsg->_target_shader->get_shader_input(input._name); + switch (sinp.get_value_type()) { case ShaderInput::M_texture_image: - param = (const ParamTextureImage *)sinp->get_param(); + param = (const ParamTextureImage *)sinp.get_param(); tex = param->get_texture(); break; case ShaderInput::M_texture: // People find it convenient to be able to pass a texture without // further ado. - tex = sinp->get_texture(); + tex = sinp.get_texture(); break; case ShaderInput::M_invalid: diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index e143774ed6..97c9b5940c 100644 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -26,7 +26,7 @@ class CLP(GraphicsStateGuardian); /** * xyz */ -class EXPCL_GL CLP(ShaderContext) : public ShaderContext { +class EXPCL_GL CLP(ShaderContext) FINAL : public ShaderContext { public: friend class CLP(GraphicsStateGuardian); @@ -41,18 +41,19 @@ public: bool get_sampler_texture_type(int &out, GLenum param_type); INLINE bool valid(void); - void bind(); - void unbind(); + void bind() OVERRIDE; + void unbind() OVERRIDE; void set_state_and_transform(const RenderState *state, const TransformState *modelview_transform, - const TransformState *projection_transform); + const TransformState *camera_transform, + const TransformState *projection_transform) OVERRIDE; - void issue_parameters(int altered); + void issue_parameters(int altered) OVERRIDE; void update_transform_table(const TransformTable *table); void update_slider_table(const SliderTable *table); - void disable_shader_vertex_arrays(); - bool update_shader_vertex_arrays(ShaderContext *prev, bool force); + void disable_shader_vertex_arrays() OVERRIDE; + bool update_shader_vertex_arrays(ShaderContext *prev, bool force) OVERRIDE; void disable_shader_texture_bindings() OVERRIDE; void update_shader_texture_bindings(ShaderContext *prev) OVERRIDE; void update_shader_buffer_bindings(ShaderContext *prev) OVERRIDE; @@ -68,6 +69,7 @@ private: WCPT(RenderState) _state_rs; CPT(TransformState) _modelview_transform; + CPT(TransformState) _camera_transform; CPT(TransformState) _projection_transform; /* @@ -126,10 +128,10 @@ public: register_type(_type_handle, CLASSPREFIX_QUOTED "ShaderContext", ShaderContext::get_class_type()); } - virtual TypeHandle get_type() const { + virtual TypeHandle get_type() const OVERRIDE { return get_class_type(); } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + virtual TypeHandle force_init_type() OVERRIDE {init_type(); return get_class_type();} private: static TypeHandle _type_handle; diff --git a/panda/src/gobj/adaptiveLru.cxx b/panda/src/gobj/adaptiveLru.cxx index 8b68f0e9b2..a74fcfcb0d 100644 --- a/panda/src/gobj/adaptiveLru.cxx +++ b/panda/src/gobj/adaptiveLru.cxx @@ -114,12 +114,16 @@ update_page(AdaptiveLruPage *page) { update_frames = (_current_frame_identifier - page->_update_frame_identifier); if (update_frames > 0) { - PN_stdfloat update_average_frame_utilization = - (PN_stdfloat) (page->_update_total_usage) / (PN_stdfloat)update_frames; + if (page->_update_total_usage > 0) { + PN_stdfloat update_average_frame_utilization = + (PN_stdfloat) (page->_update_total_usage) / (PN_stdfloat)update_frames; - page->_average_frame_utilization = - calculate_exponential_moving_average(update_average_frame_utilization, - page->_average_frame_utilization); + page->_average_frame_utilization = + calculate_exponential_moving_average(update_average_frame_utilization, + page->_average_frame_utilization); + } else { + page->_average_frame_utilization *= 1.0f - _weight; + } target_priority = page->_priority; if (page->_average_frame_utilization >= 1.0f) { diff --git a/panda/src/gobj/geom.I b/panda/src/gobj/geom.I index 33132b3be5..3457a8b265 100644 --- a/panda/src/gobj/geom.I +++ b/panda/src/gobj/geom.I @@ -51,7 +51,7 @@ get_geom_rendering() const { INLINE CPT(GeomVertexData) Geom:: get_vertex_data(Thread *current_thread) const { CDReader cdata(_cycler, current_thread); - return cdata->_data.get_read_pointer(); + return cdata->_data.get_read_pointer(current_thread); } /** @@ -514,6 +514,18 @@ CData(const Geom::CData ©) : { } + +/** + * + */ +INLINE GeomPipelineReader:: +GeomPipelineReader(Thread *current_thread) : + _object(nullptr), + _current_thread(current_thread), + _cdata(nullptr) +{ +} + /** * */ @@ -531,34 +543,22 @@ GeomPipelineReader(const Geom *object, Thread *current_thread) : #endif // DO_PIPELINING } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomPipelineReader:: -GeomPipelineReader(const GeomPipelineReader &) { - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomPipelineReader:: -operator = (const GeomPipelineReader &) { - nassertv(false); -} - /** * */ INLINE GeomPipelineReader:: ~GeomPipelineReader() { #ifdef _DEBUG - nassertv(_object->test_ref_count_nonzero()); + if (_object != nullptr) { + nassertv(_object->test_ref_count_nonzero()); + } #endif // _DEBUG // _object->_cycler.release_read(_cdata); #ifdef DO_PIPELINING - unref_delete((CycleData *)_cdata); + if (_cdata != nullptr) { + unref_delete((CycleData *)_cdata); + } #endif // DO_PIPELINING #ifdef _DEBUG @@ -567,6 +567,30 @@ INLINE GeomPipelineReader:: #endif // _DEBUG } +/** + * + */ +INLINE void GeomPipelineReader:: +set_object(const Geom *object) { + if (object != _object) { + // _object->_cycler.release_read(_cdata); + +#ifdef DO_PIPELINING + if (_cdata != NULL) { + unref_delete((CycleData *)_cdata); + } +#endif // DO_PIPELINING + + _cdata = object->_cycler.read_unlocked(_current_thread); + +#ifdef DO_PIPELINING + _cdata->ref(); +#endif // DO_PIPELINING + + _object = object; + } +} + /** * */ diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 1d3e0a2a45..66d7c19e62 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -236,7 +236,7 @@ make_nonindexed(bool composite_only) { int num_changed = 0; CDWriter cdata(_cycler, true, current_thread); - CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(); + CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(current_thread); PT(GeomVertexData) new_data = new GeomVertexData(*orig_data); new_data->clear_rows(); @@ -247,7 +247,7 @@ make_nonindexed(bool composite_only) { Primitives new_prims; new_prims.reserve(cdata->_primitives.size()); for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - PT(GeomPrimitive) primitive = (*pi).get_read_pointer()->make_copy(); + PT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread)->make_copy(); new_prims.push_back(primitive.p()); // GeomPoints are considered "composite" for the purposes of making @@ -298,7 +298,7 @@ set_primitive(int i, const GeomPrimitive *primitive) { Thread *current_thread = Thread::get_current_thread(); CDWriter cdata(_cycler, true, current_thread); nassertv(i >= 0 && i < (int)cdata->_primitives.size()); - nassertv(primitive->check_valid(cdata->_data.get_read_pointer())); + nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread))); // All primitives within a particular Geom must have the same fundamental // primitive type (triangles, points, or lines). @@ -339,7 +339,7 @@ add_primitive(const GeomPrimitive *primitive) { Thread *current_thread = Thread::get_current_thread(); CDWriter cdata(_cycler, true, current_thread); - nassertv(primitive->check_valid(cdata->_data.get_read_pointer())); + nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread))); // All primitives within a particular Geom must have the same fundamental // primitive type (triangles, points, or lines). @@ -426,11 +426,11 @@ decompose_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->decompose(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->decompose(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -460,11 +460,11 @@ doubleside_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->doubleside(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->doubleside(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -494,11 +494,11 @@ reverse_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->reverse(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->reverse(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -528,11 +528,11 @@ rotate_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->rotate(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->rotate(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -596,7 +596,7 @@ unify_in_place(int max_indices, bool preserve_order) { Primitives::const_iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); + CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread); NewPrims::iterator npi = new_prims.find(primitive->get_type()); if (npi == new_prims.end()) { // This is the first primitive of this type. @@ -648,35 +648,79 @@ unify_in_place(int max_indices, bool preserve_order) { for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) { GeomPrimitive *prim = (*npi).second; - nassertv(prim->check_valid(cdata->_data.get_read_pointer())); + nassertv(prim->check_valid(cdata->_data.get_read_pointer(current_thread))); // Each new primitive, naturally, inherits the Geom's overall shade model. prim->set_shade_model(cdata->_shade_model); // Should we split it up again to satisfy max_indices? if (prim->get_num_vertices() > max_indices) { + // Copy prim into smaller prims, no one of which has more than + // max_indices vertices. + GeomPrimitivePipelineReader reader(prim, current_thread); + // Copy prim into smaller prims, no one of which has more than // max_indices vertices. int i = 0; + int num_primitives = reader.get_num_primitives(); + int num_vertices_per_primitive = prim->get_num_vertices_per_primitive(); + int num_unused_vertices_per_primitive = prim->get_num_unused_vertices_per_primitive(); + if (num_vertices_per_primitive != 0) { + // This is a simple primitive type like a triangle, where all the + // primitives share the same number of vertices. + int total_vertices_per_primitive = num_vertices_per_primitive + num_unused_vertices_per_primitive; + int max_primitives = max_indices / total_vertices_per_primitive; + const unsigned char *ptr = reader.get_read_pointer(true); + size_t stride = reader.get_index_stride(); - while (i < prim->get_num_primitives()) { - PT(GeomPrimitive) smaller = prim->make_copy(); - smaller->clear_vertices(); - while (i < prim->get_num_primitives() && - smaller->get_num_vertices() + prim->get_primitive_num_vertices(i) < max_indices) { - int start = prim->get_primitive_start(i); - int end = prim->get_primitive_end(i); - for (int n = start; n < end; ++n) { - smaller->add_vertex(prim->get_vertex(n)); + while (i < num_primitives) { + PT(GeomPrimitive) smaller = prim->make_copy(); + smaller->clear_vertices(); + + // Since the number of vertices is consistent, we can calculate how + // many primitives will fit, and copy them all in one go. + int copy_primitives = min((num_primitives - i), max_primitives); + int num_vertices = copy_primitives * total_vertices_per_primitive; + nassertv(num_vertices > 0); + { + GeomVertexArrayDataHandle writer(smaller->modify_vertices(), current_thread); + writer.unclean_set_num_rows(num_vertices); + memcpy(writer.get_write_pointer(), ptr, stride * (size_t)(num_vertices - num_unused_vertices_per_primitive)); } - smaller->close_primitive(); - ++i; + cdata->_primitives.push_back(smaller.p()); + + ptr += stride * (size_t)num_vertices; + i += copy_primitives; } + } else { + // This is a complex primitive type like a triangle strip. + CPTA_int ends = reader.get_ends(); + int start = 0; + int end = ends[0]; - cdata->_primitives.push_back(smaller.p()); + while (i < num_primitives) { + PT(GeomPrimitive) smaller = prim->make_copy(); + smaller->clear_vertices(); + + while (smaller->get_num_vertices() + (end - start) < max_indices) { + for (int n = start; n < end; ++n) { + smaller->add_vertex(reader.get_vertex(n)); + } + smaller->close_primitive(); + + ++i; + if (i >= num_primitives) { + break; + } + + start = end + num_unused_vertices_per_primitive; + end = ends[i]; + } + + cdata->_primitives.push_back(smaller.p()); + } } - } else { // The prim has few enough vertices; keep it. cdata->_primitives.push_back(prim); @@ -706,11 +750,11 @@ make_lines_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_lines(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_lines(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -740,11 +784,11 @@ make_points_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_points(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_points(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -774,11 +818,11 @@ make_patches_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_patches(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_patches(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -865,7 +909,9 @@ get_num_bytes() const { */ bool Geom:: request_resident() const { - CDReader cdata(_cycler); + Thread *current_thread = Thread::get_current_thread(); + + CDReader cdata(_cycler, current_thread); bool resident = true; @@ -873,7 +919,7 @@ request_resident() const { for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - if (!(*pi).get_read_pointer()->request_resident()) { + if (!(*pi).get_read_pointer(current_thread)->request_resident()) { resident = false; } } @@ -923,7 +969,8 @@ bool Geom:: check_valid() const { Thread *current_thread = Thread::get_current_thread(); GeomPipelineReader geom_reader(this, current_thread); - GeomVertexDataPipelineReader data_reader(geom_reader.get_vertex_data(), current_thread); + CPT(GeomVertexData) vertex_data = geom_reader.get_vertex_data(); + GeomVertexDataPipelineReader data_reader(vertex_data, current_thread); data_reader.check_array_readers(); return geom_reader.check_valid(&data_reader); } @@ -1197,7 +1244,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { int num_vertices = 0; // Get the vertex data, after animation. - CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(); + CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(current_thread); vertex_data = vertex_data->animate_vertices(true, current_thread); // Now actually compute the bounding volume. We do this by using @@ -1210,6 +1257,9 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { InternalName::get_vertex(), cdata, current_thread); + nassertv(!pmin.is_nan()); + nassertv(!pmax.is_nan()); + BoundingVolume::BoundsType btype = cdata->_bounds_type; if (btype == BoundingVolume::BT_default) { btype = bounds_type; @@ -1296,7 +1346,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); + CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread); num_vertices += prim->get_num_vertices(); } @@ -1327,7 +1377,7 @@ do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); + CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread); prim->calc_tight_bounds(min_point, max_point, sq_center_dist, found_any, vertex_data, got_mat, mat, column_name, current_thread); @@ -1345,7 +1395,7 @@ do_calc_sphere_radius(const LPoint3 ¢er, PN_stdfloat &sq_radius, for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); + CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread); prim->calc_sphere_radius(center, sq_radius, found_any, vertex_data, current_thread); } @@ -1469,8 +1519,10 @@ combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim, a_prim->append_unused_vertices(a_vertices, b_vertex); } - PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread); - CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread); + PT(GeomVertexArrayDataHandle) a_handle = + new GeomVertexArrayDataHandle(move(a_vertices), current_thread); + CPT(GeomVertexArrayDataHandle) b_handle = + new GeomVertexArrayDataHandle(move(b_vertices), current_thread); size_t orig_a_vertices = a_handle->get_num_rows(); @@ -1683,8 +1735,7 @@ check_valid(const GeomVertexDataPipelineReader *data_reader) const { for (pi = _cdata->_primitives.begin(); pi != _cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); - GeomPrimitivePipelineReader reader(primitive, _current_thread); + GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread); reader.check_minmax(); if (!reader.check_valid(data_reader)) { return false; @@ -1707,12 +1758,11 @@ draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, for (pi = _cdata->_primitives.begin(); pi != _cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); - GeomPrimitivePipelineReader reader(primitive, _current_thread); + GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread); if (reader.get_num_vertices() != 0) { reader.check_minmax(); nassertr(reader.check_valid(data_reader), false); - if (!primitive->draw(gsg, &reader, force)) { + if (!reader.draw(gsg, force)) { all_ok = false; } } diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index cd02493d79..a1408878d8 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -401,15 +401,17 @@ private: */ class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums { public: + INLINE GeomPipelineReader(Thread *current_thread); INLINE GeomPipelineReader(const Geom *object, Thread *current_thread); private: - INLINE GeomPipelineReader(const GeomPipelineReader ©); - INLINE void operator = (const GeomPipelineReader ©); + GeomPipelineReader(const GeomPipelineReader ©) DELETED; + GeomPipelineReader &operator = (const GeomPipelineReader ©) DELETED_ASSIGN; public: INLINE ~GeomPipelineReader(); ALLOC_DELETED_CHAIN(GeomPipelineReader); + INLINE void set_object(const Geom *object); INLINE const Geom *get_object() const; INLINE Thread *get_current_thread() const; diff --git a/panda/src/gobj/geomCacheEntry.cxx b/panda/src/gobj/geomCacheEntry.cxx index 27ab5a9e20..d16a7f6a08 100644 --- a/panda/src/gobj/geomCacheEntry.cxx +++ b/panda/src/gobj/geomCacheEntry.cxx @@ -95,8 +95,8 @@ PT(GeomCacheEntry) GeomCacheEntry:: erase() { nassertr(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL, NULL); - PT(GeomCacheEntry) keepme = this; - unref(); + PT(GeomCacheEntry) keepme; + keepme.cheat() = this; if (gobj_cat.is_debug()) { gobj_cat.debug() diff --git a/panda/src/gobj/geomPrimitive.I b/panda/src/gobj/geomPrimitive.I index 029063f864..9863701e21 100644 --- a/panda/src/gobj/geomPrimitive.I +++ b/panda/src/gobj/geomPrimitive.I @@ -124,8 +124,19 @@ get_vertex(int i) const { */ INLINE int GeomPrimitive:: get_num_primitives() const { - GeomPrimitivePipelineReader reader(this, Thread::get_current_thread()); - return reader.get_num_primitives(); + int num_vertices_per_primitive = get_num_vertices_per_primitive(); + + if (num_vertices_per_primitive == 0) { + // This is a complex primitive type like a triangle strip: each primitive + // uses a different number of vertices. + CDReader cdata(_cycler); + return cdata->_ends.size(); + + } else { + // This is a simple primitive type like a triangle: each primitive uses + // the same number of vertices. + return (get_num_vertices() / num_vertices_per_primitive); + } } /** @@ -235,6 +246,24 @@ get_vertices() const { return cdata->_vertices.get_read_pointer(); } +/** + * Equivalent to get_vertices().get_handle(). + */ +INLINE CPT(GeomVertexArrayDataHandle) GeomPrimitive:: +get_vertices_handle(Thread *current_thread) const { + CDReader cdata(_cycler, current_thread); + return new GeomVertexArrayDataHandle(cdata->_vertices.get_read_pointer(current_thread), current_thread); +} + +/** + * Equivalent to modify_vertices().get_handle(). + */ +INLINE PT(GeomVertexArrayDataHandle) GeomPrimitive:: +modify_vertices_handle(Thread *current_thread) { + CDWriter cdata(_cycler, true, current_thread); + return new GeomVertexArrayDataHandle(do_modify_vertices(cdata), current_thread); +} + /** * A convenience function to return the gap between successive index numbers, * in bytes, of the index data. @@ -414,38 +443,32 @@ CData(const GeomPrimitive::CData ©) : * */ INLINE GeomPrimitivePipelineReader:: -GeomPrimitivePipelineReader(const GeomPrimitive *object, +GeomPrimitivePipelineReader(CPT(GeomPrimitive) object, Thread *current_thread) : - _object(object), + _object(move(object)), _current_thread(current_thread), - _cdata(object->_cycler.read_unlocked(current_thread)), - _vertices_reader(NULL) +#ifndef CPPPARSER + _cdata(_object->_cycler.read_unlocked(current_thread)), +#endif + _vertices_cdata(NULL) { nassertv(_object->test_ref_count_nonzero()); #ifdef DO_PIPELINING _cdata->ref(); #endif // DO_PIPELINING + if (!_cdata->_vertices.is_null()) { - _vertices_reader = _cdata->_vertices.get_read_pointer()->get_handle(); + _vertices = _cdata->_vertices.get_read_pointer(current_thread); + _vertices_cdata = _vertices->_cycler.read_unlocked(current_thread); +#ifdef DO_PIPELINING + _vertices_cdata->ref(); +#endif // DO_PIPELINING + // We must grab the lock *after* we have incremented the reference count, + // above. + _vertices_cdata->_rw_lock.acquire(); } } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomPrimitivePipelineReader:: -GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &) { - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomPrimitivePipelineReader:: -operator = (const GeomPrimitivePipelineReader &) { - nassertv(false); -} - /** * */ @@ -460,8 +483,17 @@ INLINE GeomPrimitivePipelineReader:: unref_delete((CycleData *)_cdata); #endif // DO_PIPELINING + if (_vertices_cdata != nullptr) { + // We must release the lock *before* we decrement the reference count, + // below. + _vertices_cdata->_rw_lock.release(); + +#ifdef DO_PIPELINING + unref_delete((CycleData *)_vertices_cdata); +#endif // DO_PIPELINING + } + #ifdef _DEBUG - _vertices_reader = NULL; _object = NULL; _cdata = NULL; #endif // _DEBUG @@ -512,7 +544,7 @@ get_index_type() const { */ INLINE bool GeomPrimitivePipelineReader:: is_indexed() const { - return (!_cdata->_vertices.is_null()); + return (!_vertices.is_null()); } /** @@ -523,8 +555,10 @@ get_num_vertices() const { if (_cdata->_num_vertices != -1) { return _cdata->_num_vertices; } else { - nassertr(!_cdata->_vertices.is_null(), 0); - return _vertices_reader->get_num_rows(); + nassertr(!_vertices.is_null(), 0); + size_t stride = _vertices->_array_format->get_stride(); + nassertr(stride != 0, 0); + return get_data_size_bytes() / stride; } } @@ -551,7 +585,7 @@ get_max_vertex() const { */ INLINE int GeomPrimitivePipelineReader:: get_data_size_bytes() const { - return _vertices_reader->get_data_size_bytes(); + return _vertices_cdata->_buffer.get_size(); } /** @@ -568,15 +602,7 @@ get_modified() const { INLINE int GeomPrimitivePipelineReader:: get_index_stride() const { nassertr(is_indexed(), 0); - return _cdata->_vertices.get_read_pointer()->get_array_format()->get_stride(); -} - -/** - * - */ -INLINE const GeomVertexArrayDataHandle *GeomPrimitivePipelineReader:: -get_vertices_reader() const { - return _vertices_reader; + return _vertices->_array_format->get_stride(); } /** @@ -584,7 +610,8 @@ get_vertices_reader() const { */ INLINE const unsigned char *GeomPrimitivePipelineReader:: get_read_pointer(bool force) const { - return _vertices_reader->get_read_pointer(force); + ((GeomVertexArrayData *)_vertices.p())->mark_used(); + return _vertices_cdata->_buffer.get_read_pointer(force); } /** @@ -632,6 +659,14 @@ prepare_now(PreparedGraphicsObjects *prepared_objects, return ((GeomPrimitive *)_object.p())->prepare_now(prepared_objects, gsg); } +/** + * Calls the appropriate method on the GSG to draw the primitive. + */ +INLINE bool GeomPrimitivePipelineReader:: +draw(GraphicsStateGuardianBase *gsg, bool force) const { + return _object->draw(gsg, this, force); +} + INLINE ostream & operator << (ostream &out, const GeomPrimitive &obj) { obj.output(out); diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 6f918eefdb..23a905f8e3 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -165,16 +165,17 @@ add_vertex(int vertex) { consider_elevate_index_type(cdata, vertex); - int num_primitives = get_num_primitives(); - if (num_primitives > 0 && - requires_unused_vertices() && - get_num_vertices() == get_primitive_end(num_primitives - 1)) { - // If we are beginning a new primitive, give the derived class a chance to - // insert some degenerate vertices. - if (cdata->_vertices.is_null()) { - do_make_indexed(cdata); + if (requires_unused_vertices()) { + int num_primitives = get_num_primitives(); + if (num_primitives > 0 && + get_num_vertices() == get_primitive_end(num_primitives - 1)) { + // If we are beginning a new primitive, give the derived class a chance to + // insert some degenerate vertices. + if (cdata->_vertices.is_null()) { + do_make_indexed(cdata); + } + append_unused_vertices(cdata->_vertices.get_write_pointer(), vertex); } - append_unused_vertices(cdata->_vertices.get_write_pointer(), vertex); } if (cdata->_vertices.is_null()) { @@ -199,11 +200,28 @@ add_vertex(int vertex) { do_make_indexed(cdata); } - PT(GeomVertexArrayData) array_obj = cdata->_vertices.get_write_pointer(); - GeomVertexWriter index(array_obj, 0); - index.set_row_unsafe(array_obj->get_num_rows()); + { + GeomVertexArrayDataHandle handle(cdata->_vertices.get_write_pointer(), + Thread::get_current_thread()); + int num_rows = handle.get_num_rows(); + handle.set_num_rows(num_rows + 1); - index.add_data1i(vertex); + unsigned char *ptr = handle.get_write_pointer(); + switch (cdata->_index_type) { + case GeomEnums::NT_uint8: + ((uint8_t *)ptr)[num_rows] = vertex; + break; + case GeomEnums::NT_uint16: + ((uint16_t *)ptr)[num_rows] = vertex; + break; + case GeomEnums::NT_uint32: + ((uint32_t *)ptr)[num_rows] = vertex; + break; + default: + nassertv(false); + break; + } + } cdata->_modified = Geom::get_next_modified(); cdata->_got_minmax = false; @@ -888,21 +906,9 @@ make_points() const { // First, get a list of all of the vertices referenced by the original // primitive. BitArray bits; - int num_vertices = get_num_vertices(); - if (is_indexed()) { - CPT(GeomVertexArrayData) vertices = get_vertices(); - int strip_cut_index = get_strip_cut_index(); - GeomVertexReader index(vertices, 0); - for (int vi = 0; vi < num_vertices; ++vi) { - nassertr(!index.is_at_end(), NULL); - int vertex = index.get_data1i(); - if (vertex != strip_cut_index) { - bits.set_bit(vertex); - } - } - } else { - int first_vertex = get_first_vertex(); - bits.set_range(first_vertex, num_vertices); + { + GeomPrimitivePipelineReader reader(this, Thread::get_current_thread()); + reader.get_referenced_vertices(bits); } // Now construct a new index array with just those bits. @@ -1036,23 +1042,23 @@ get_num_bytes() const { * shortly; try again later. */ bool GeomPrimitive:: -request_resident() const { - CDReader cdata(_cycler); +request_resident(Thread *current_thread) const { + CDReader cdata(_cycler, current_thread); bool resident = true; if (!cdata->_vertices.is_null() && - !cdata->_vertices.get_read_pointer()->request_resident()) { + !cdata->_vertices.get_read_pointer(current_thread)->request_resident(current_thread)) { resident = false; } if (is_composite() && cdata->_got_minmax) { if (!cdata->_mins.is_null() && - !cdata->_mins.get_read_pointer()->request_resident()) { + !cdata->_mins.get_read_pointer(current_thread)->request_resident(current_thread)) { resident = false; } if (!cdata->_maxs.is_null() && - !cdata->_maxs.get_read_pointer()->request_resident()) { + !cdata->_maxs.get_read_pointer(current_thread)->request_resident(current_thread)) { resident = false; } } @@ -2178,14 +2184,17 @@ check_minmax() const { */ int GeomPrimitivePipelineReader:: get_first_vertex() const { - if (_cdata->_vertices.is_null()) { + if (_vertices.is_null()) { return _cdata->_first_vertex; - } else if (_vertices_reader->get_num_rows() == 0) { - return 0; - } else { - GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0); - return index.get_data1i(); } + + size_t size = _vertices_cdata->_buffer.get_size(); + if (size == 0) { + return 0; + } + + GeomVertexReader index(_vertices, 0); + return index.get_data1i(); } /** @@ -2193,13 +2202,25 @@ get_first_vertex() const { */ int GeomPrimitivePipelineReader:: get_vertex(int i) const { - if (!_cdata->_vertices.is_null()) { + if (!_vertices.is_null()) { // The indexed case. - nassertr(i >= 0 && i < _vertices_reader->get_num_rows(), -1); + nassertr(i >= 0 && i < get_num_vertices(), -1); - GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0); - index.set_row_unsafe(i); - return index.get_data1i(); + const unsigned char *ptr = get_read_pointer(true); + switch (_cdata->_index_type) { + case GeomEnums::NT_uint8: + return ((uint8_t *)ptr)[i]; + break; + case GeomEnums::NT_uint16: + return ((uint16_t *)ptr)[i]; + break; + case GeomEnums::NT_uint32: + return ((uint32_t *)ptr)[i]; + break; + default: + nassertr(false, -1); + return -1; + } } else { // The nonindexed case. @@ -2226,6 +2247,52 @@ get_num_primitives() const { } } +/** + * Turns on all the bits corresponding to the vertices that are referenced + * by this GeomPrimitive. + */ +void GeomPrimitivePipelineReader:: +get_referenced_vertices(BitArray &bits) const { + int num_vertices = get_num_vertices(); + + if (is_indexed()) { + int strip_cut_index = get_strip_cut_index(); + const unsigned char *ptr = get_read_pointer(true); + switch (get_index_type()) { + case GeomEnums::NT_uint8: + for (int vi = 0; vi < num_vertices; ++vi) { + int index = ((const uint8_t *)ptr)[vi]; + if (index != strip_cut_index) { + bits.set_bit(index); + } + } + break; + case GeomEnums::NT_uint16: + for (int vi = 0; vi < num_vertices; ++vi) { + int index = ((const uint16_t *)ptr)[vi]; + if (index != strip_cut_index) { + bits.set_bit(index); + } + } + break; + case GeomEnums::NT_uint32: + for (int vi = 0; vi < num_vertices; ++vi) { + int index = ((const uint32_t *)ptr)[vi]; + if (index != strip_cut_index) { + bits.set_bit(index); + } + } + break; + default: + nassertv(false); + break; + } + } else { + // Nonindexed case. + bits.set_range(get_first_vertex(), num_vertices); + } +} + /** * */ diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 9c24af0c45..eefaf1054c 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -142,7 +142,7 @@ PUBLISHED: MAKE_PROPERTY(data_size_bytes, get_data_size_bytes); MAKE_PROPERTY(modified, get_modified); - bool request_resident() const; + bool request_resident(Thread *current_thread = Thread::get_current_thread()) const; INLINE bool check_valid(const GeomVertexData *vertex_data) const; @@ -162,7 +162,9 @@ PUBLISHED: */ INLINE CPT(GeomVertexArrayData) get_vertices() const; + INLINE CPT(GeomVertexArrayDataHandle) get_vertices_handle(Thread *current_thread) const; PT(GeomVertexArrayData) modify_vertices(int num_vertices = -1); + INLINE PT(GeomVertexArrayDataHandle) modify_vertices_handle(Thread *current_thread); void set_vertices(const GeomVertexArrayData *vertices, int num_vertices = -1); void set_nonindexed_vertices(int first_vertex, int num_vertices); @@ -347,10 +349,10 @@ private: */ class EXPCL_PANDA_GOBJ GeomPrimitivePipelineReader : public GeomEnums { public: - INLINE GeomPrimitivePipelineReader(const GeomPrimitive *object, Thread *current_thread); + INLINE GeomPrimitivePipelineReader(CPT(GeomPrimitive) object, Thread *current_thread); private: - INLINE GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader ©); - INLINE void operator = (const GeomPrimitivePipelineReader ©); + GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader ©) DELETED; + GeomPrimitivePipelineReader &operator = (const GeomPrimitivePipelineReader ©) DELETED_ASSIGN; public: INLINE ~GeomPrimitivePipelineReader(); @@ -369,13 +371,13 @@ public: INLINE int get_num_vertices() const; int get_vertex(int i) const; int get_num_primitives() const; + void get_referenced_vertices(BitArray &bits) const; INLINE int get_min_vertex() const; INLINE int get_max_vertex() const; INLINE int get_data_size_bytes() const; INLINE UpdateSeq get_modified() const; bool check_valid(const GeomVertexDataPipelineReader *data_reader) const; INLINE int get_index_stride() const; - INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const; INLINE const unsigned char *get_read_pointer(bool force) const; INLINE int get_strip_cut_index() const; INLINE CPTA_int get_ends() const; @@ -384,13 +386,15 @@ public: INLINE IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg) const; + INLINE bool draw(GraphicsStateGuardianBase *gsg, bool force) const; private: CPT(GeomPrimitive) _object; Thread *_current_thread; const GeomPrimitive::CData *_cdata; - CPT(GeomVertexArrayDataHandle) _vertices_reader; + CPT(GeomVertexArrayData) _vertices; + const GeomVertexArrayData::CData *_vertices_cdata; public: static TypeHandle get_class_type() { diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index 3ee8d9311f..351f56cd53 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -130,9 +130,25 @@ get_modified() const { * back into memory shortly; try again later. */ INLINE bool GeomVertexArrayData:: -request_resident() const { - CPT(GeomVertexArrayDataHandle) handle = get_handle(); - return handle->request_resident(); +request_resident(Thread *current_thread) const { + const GeomVertexArrayData::CData *cdata = _cycler.read_unlocked(current_thread); + +#ifdef DO_PIPELINING + cdata->ref(); +#endif + + cdata->_rw_lock.acquire(); + + ((GeomVertexArrayData *)this)->mark_used(); + bool is_resident = (cdata->_buffer.get_read_pointer(false) != nullptr); + + cdata->_rw_lock.release(); + +#ifdef DO_PIPELINING + unref_delete((CycleData *)cdata); +#endif + + return is_resident; } /** @@ -143,9 +159,7 @@ request_resident() const { */ INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData:: get_handle(Thread *current_thread) const { - const CData *cdata = _cycler.read_unlocked(current_thread); - return new GeomVertexArrayDataHandle(this, current_thread, - cdata, false); + return new GeomVertexArrayDataHandle(this, current_thread); } /** @@ -156,9 +170,7 @@ get_handle(Thread *current_thread) const { */ INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData:: modify_handle(Thread *current_thread) { - CData *cdata = _cycler.write_upstream(true, current_thread); - return new GeomVertexArrayDataHandle(this, current_thread, - cdata, true); + return new GeomVertexArrayDataHandle(PT(GeomVertexArrayData)(this), current_thread); } /** @@ -202,6 +214,17 @@ set_lru_size(size_t lru_size) { } } +/** + */ +INLINE void GeomVertexArrayData:: +mark_used() { + if ((int)get_lru_size() <= vertex_data_small_size) { + SimpleLruPage::mark_used_lru(&_small_lru); + } else { + SimpleLruPage::mark_used_lru(&_independent_lru); + } +} + /** * */ @@ -234,18 +257,93 @@ operator = (const GeomVertexArrayData::CData ©) { _modified = copy._modified; } +/** + * + */ +INLINE GeomVertexArrayDataHandle:: +GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object, + Thread *current_thread) : + _current_thread(current_thread), + _cdata((GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)), + _writable(false) +{ + _object.swap(object); + +#ifdef _DEBUG + nassertv(_object->test_ref_count_nonzero()); +#endif // _DEBUG +#ifdef DO_PIPELINING + _cdata->ref(); +#endif // DO_PIPELINING + // We must grab the lock *after* we have incremented the reference count, + // above. + _cdata->_rw_lock.acquire(); +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, get_class_type()); +#endif +} + /** * */ INLINE GeomVertexArrayDataHandle:: GeomVertexArrayDataHandle(const GeomVertexArrayData *object, - Thread *current_thread, - const GeomVertexArrayData::CData *cdata, - bool writable) : + Thread *current_thread) : _object((GeomVertexArrayData *)object), _current_thread(current_thread), - _cdata((GeomVertexArrayData::CData *)cdata), - _writable(writable) + _cdata((GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)), + _writable(false) +{ +#ifdef _DEBUG + nassertv(_object->test_ref_count_nonzero()); +#endif // _DEBUG +#ifdef DO_PIPELINING + _cdata->ref(); +#endif // DO_PIPELINING + // We must grab the lock *after* we have incremented the reference count, + // above. + _cdata->_rw_lock.acquire(); +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, get_class_type()); +#endif +} + +/** + * + */ +INLINE GeomVertexArrayDataHandle:: +GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object, + Thread *current_thread) : + _current_thread(current_thread), + _cdata(object->_cycler.write_upstream(true, current_thread)), + _writable(true) +{ + _object.swap(object); + +#ifdef _DEBUG + nassertv(_object->test_ref_count_nonzero()); +#endif // _DEBUG +#ifdef DO_PIPELINING + _cdata->ref(); +#endif // DO_PIPELINING + // We must grab the lock *after* we have incremented the reference count, + // above. + _cdata->_rw_lock.acquire(); +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, get_class_type()); +#endif +} + +/** + * + */ +INLINE GeomVertexArrayDataHandle:: +GeomVertexArrayDataHandle(GeomVertexArrayData *object, + Thread *current_thread) : + _object(object), + _current_thread(current_thread), + _cdata(object->_cycler.write_upstream(true, current_thread)), + _writable(true) { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); @@ -265,7 +363,8 @@ GeomVertexArrayDataHandle(const GeomVertexArrayData *object, * Don't attempt to copy these objects. */ INLINE GeomVertexArrayDataHandle:: -GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle ©) { +GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle ©) + : _current_thread(copy._current_thread) { nassertv(false); } @@ -448,7 +547,7 @@ get_subdata(size_t start, size_t size) const { */ void GeomVertexArrayDataHandle:: mark_used() const { - _object->set_lru_size(_object->get_lru_size()); + _object->mark_used(); } INLINE ostream & diff --git a/panda/src/gobj/geomVertexArrayData.h b/panda/src/gobj/geomVertexArrayData.h index 9766a9cbd1..c16c5831d9 100644 --- a/panda/src/gobj/geomVertexArrayData.h +++ b/panda/src/gobj/geomVertexArrayData.h @@ -95,7 +95,7 @@ PUBLISHED: void output(ostream &out) const; void write(ostream &out, int indent_level = 0) const; - INLINE bool request_resident() const; + INLINE bool request_resident(Thread *current_thread = Thread::get_current_thread()) const; INLINE CPT(GeomVertexArrayDataHandle) get_handle(Thread *current_thread = Thread::get_current_thread()) const; INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread()); @@ -124,6 +124,7 @@ public: private: INLINE void set_lru_size(size_t lru_size); + INLINE void mark_used(); void clear_prepared(PreparedGraphicsObjects *prepared_objects); void reverse_data_endianness(unsigned char *dest, @@ -230,6 +231,7 @@ private: friend class GeomVertexData; friend class PreparedGraphicsObjects; friend class GeomVertexArrayDataHandle; + friend class GeomPrimitivePipelineReader; }; /** @@ -246,10 +248,14 @@ private: */ class EXPCL_PANDA_GOBJ GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums { private: + INLINE GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object, + Thread *current_thread); INLINE GeomVertexArrayDataHandle(const GeomVertexArrayData *object, - Thread *current_thread, - const GeomVertexArrayData::CData *_cdata, - bool writable); + Thread *current_thread); + INLINE GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object, + Thread *current_thread); + INLINE GeomVertexArrayDataHandle(GeomVertexArrayData *object, + Thread *current_thread); INLINE GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &); INLINE void operator = (const GeomVertexArrayDataHandle &); @@ -316,7 +322,7 @@ PUBLISHED: private: PT(GeomVertexArrayData) _object; - Thread *_current_thread; + Thread *const _current_thread; GeomVertexArrayData::CData *_cdata; bool _writable; @@ -333,6 +339,11 @@ public: private: static TypeHandle _type_handle; + friend class Geom; + friend class GeomPrimitive; + friend class GeomVertexData; + friend class GeomVertexDataPipelineReader; + friend class GeomVertexDataPipelineWriter; friend class GeomVertexArrayData; }; diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index dfb2138c1a..47fe0ef41b 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -147,6 +147,17 @@ get_array(int i) const { return cdata->_arrays[i].get_read_pointer(); } +/** + * Equivalent to get_array(i).get_handle(). + */ +INLINE CPT(GeomVertexArrayDataHandle) GeomVertexData:: +get_array_handle(int i) const { + Thread *current_thread = Thread::get_current_thread(); + CDReader cdata(_cycler, current_thread); + nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL); + return new GeomVertexArrayDataHandle(cdata->_arrays[i].get_read_pointer(), current_thread); +} + /** * Returns a modifiable pointer to the indicated vertex array, so that * application code may directly manipulate the data. You should avoid @@ -162,6 +173,16 @@ modify_array(int i) { return writer.modify_array(i); } +/** + * Equivalent to modify_array(i).modify_handle(). + */ +INLINE PT(GeomVertexArrayDataHandle) GeomVertexData:: +modify_array_handle(int i) { + Thread *current_thread = Thread::get_current_thread(); + GeomVertexDataPipelineWriter writer(this, true, current_thread); + return new GeomVertexArrayDataHandle(writer.modify_array(i), current_thread); +} + /** * Replaces the indicated vertex data array with a completely new array. You * should be careful that the new array has the same length and format as the @@ -575,6 +596,17 @@ CData(const GeomVertexData::CData ©) : { } +/** + * + */ +INLINE GeomVertexDataPipelineBase:: +GeomVertexDataPipelineBase(Thread *current_thread) : + _object(nullptr), + _current_thread(current_thread), + _cdata(nullptr) +{ +} + /** * */ @@ -600,11 +632,15 @@ GeomVertexDataPipelineBase(GeomVertexData *object, INLINE GeomVertexDataPipelineBase:: ~GeomVertexDataPipelineBase() { #ifdef _DEBUG - nassertv(_object->test_ref_count_nonzero()); + if (_object != nullptr) { + nassertv(_object->test_ref_count_nonzero()); + } #endif // _DEBUG #ifdef DO_PIPELINING - unref_delete((CycleData *)_cdata); + if (_cdata != nullptr) { + unref_delete((CycleData *)_cdata); + } #endif // DO_PIPELINING #ifdef _DEBUG @@ -694,6 +730,16 @@ get_modified() const { return _cdata->_modified; } +/** + * + */ +INLINE GeomVertexDataPipelineReader:: +GeomVertexDataPipelineReader(Thread *current_thread) : + GeomVertexDataPipelineBase(current_thread), + _got_array_readers(false) +{ +} + /** * */ @@ -706,33 +752,23 @@ GeomVertexDataPipelineReader(const GeomVertexData *object, { } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomVertexDataPipelineReader:: -GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader ©) : - GeomVertexDataPipelineBase(copy) -{ - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomVertexDataPipelineReader:: -operator = (const GeomVertexDataPipelineReader &) { - nassertv(false); -} - /** * */ -INLINE GeomVertexDataPipelineReader:: -~GeomVertexDataPipelineReader() { - if (_got_array_readers) { - delete_array_readers(); +INLINE void GeomVertexDataPipelineReader:: +set_object(const GeomVertexData *object) { +#ifdef DO_PIPELINING + if (_cdata != NULL) { + unref_delete((CycleData *)_cdata); } - // _object->_cycler.release_read(_cdata); +#endif // DO_PIPELINING + _array_readers.clear(); + + _object = (GeomVertexData *)object; + _cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread); + _got_array_readers = false; + + _cdata->ref(); } /** @@ -819,24 +855,6 @@ GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0, #endif // _DEBUG } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomVertexDataPipelineWriter:: -GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©) : - GeomVertexDataPipelineBase(copy) -{ - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomVertexDataPipelineWriter:: -operator = (const GeomVertexDataPipelineWriter &) { - nassertv(false); -} - /** * */ diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 6b73e4fe0f..cfa47d9949 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -516,9 +516,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, if (keep_data_objects) { // Copy the data, but keep the same GeomVertexArrayData object. - PT(GeomVertexArrayData) dest_data = modify_array(dest_i); - CPT(GeomVertexArrayData) source_data = source->get_array(source_i); - dest_data->modify_handle()->copy_data_from(source_data->get_handle()); + modify_array_handle(dest_i)->copy_data_from(source->get_array_handle(source_i)); } else { // Copy the GeomVertexArrayData object. if (get_array(dest_i) != source->get_array(source_i)) { @@ -533,13 +531,16 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, } // Now make sure the arrays we didn't share are all filled in. - reserve_num_rows(num_rows); - set_num_rows(num_rows); + { + GeomVertexDataPipelineWriter writer(this, true, Thread::get_current_thread()); + writer.check_array_writers(); + writer.reserve_num_rows(num_rows); + writer.set_num_rows(num_rows); + } // Now go back through and copy any data that's left over. for (source_i = 0; source_i < num_arrays; ++source_i) { - CPT(GeomVertexArrayData) array_obj = source->get_array(source_i); - CPT(GeomVertexArrayDataHandle) array_handle = array_obj->get_handle(); + CPT(GeomVertexArrayDataHandle) array_handle = source->get_array_handle(source_i); const unsigned char *array_data = array_handle->get_read_pointer(true); const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i); int num_columns = source_array_format->get_num_columns(); @@ -557,8 +558,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, if (dest_column->is_bytewise_equivalent(*source_column)) { // We can do a quick bytewise copy. - PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); bytewise_copy(dest_array_data + dest_column->get_start(), @@ -569,8 +569,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, } else if (dest_column->is_packed_argb() && source_column->is_uint8_rgba()) { // A common special case: OpenGL color to DirectX color. - PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); uint8_rgba_to_packed_argb @@ -582,8 +581,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, } else if (dest_column->is_uint8_rgba() && source_column->is_packed_argb()) { // Another common special case: DirectX color to OpenGL color. - PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); packed_argb_to_uint8_rgba @@ -700,12 +698,10 @@ copy_row_from(int dest_row, const GeomVertexData *source, int num_arrays = source_format->get_num_arrays(); for (int i = 0; i < num_arrays; ++i) { - PT(GeomVertexArrayData) dest_array_obj = modify_array(i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); - CPT(GeomVertexArrayData) source_array_obj = source->get_array(i); - CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle(); + CPT(GeomVertexArrayDataHandle) source_array_handle = source->get_array_handle(i); const unsigned char *source_array_data = source_array_handle->get_read_pointer(true); const GeomVertexArrayFormat *array_format = source_format->get_array(i); @@ -1144,8 +1140,7 @@ do_set_color(GeomVertexData *vdata, const LColor &color) { packer->set_data4f(buffer, color); #endif - PT(GeomVertexArrayDataHandle) handle = - vdata->modify_array(array_index)->modify_handle(); + PT(GeomVertexArrayDataHandle) handle = vdata->modify_array_handle(array_index); unsigned char *write_ptr = handle->get_write_pointer(); unsigned char *end_ptr = write_ptr + handle->get_data_size_bytes(); write_ptr += column->get_start(); @@ -1586,7 +1581,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) { } // Then apply the transforms. - CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer(); + CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer(current_thread); if (tb_table != (TransformBlendTable *)NULL) { // Recompute all the blends up front, so we don't have to test each one // for staleness at each vertex. @@ -1617,7 +1612,8 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) { if (blend_array_format->get_stride() == 2 && blend_array_format->get_column(0)->get_component_bytes() == 2) { // The blend indices are a table of ushorts. Optimize this common case. - CPT(GeomVertexArrayDataHandle) blend_array_handle = cdata->_arrays[blend_array_index].get_read_pointer()->get_handle(current_thread); + CPT(GeomVertexArrayDataHandle) blend_array_handle = + new GeomVertexArrayDataHandle(cdata->_arrays[blend_array_index].get_read_pointer(current_thread), current_thread); const unsigned short *blendt = (const unsigned short *)blend_array_handle->get_read_pointer(true); size_t ci; @@ -2399,24 +2395,12 @@ make_array_readers() { _array_readers.reserve(_cdata->_arrays.size()); GeomVertexData::Arrays::const_iterator ai; for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { - CPT(GeomVertexArrayData) array_obj = (*ai).get_read_pointer(); - _array_readers.push_back(array_obj->get_handle(_current_thread)); + _array_readers.push_back(new GeomVertexArrayDataHandle((*ai).get_read_pointer(_current_thread), _current_thread)); } _got_array_readers = true; } -/** - * - */ -void GeomVertexDataPipelineReader:: -delete_array_readers() { - nassertv(_got_array_readers); - - _array_readers.clear(); - _got_array_readers = false; -} - /** * */ @@ -2610,7 +2594,7 @@ set_array(int i, const GeomVertexArrayData *array) { _cdata->_animated_vertices_modified = UpdateSeq(); if (_got_array_writers) { - _array_writers[i] = _cdata->_arrays[i].get_write_pointer()->modify_handle(_current_thread); + _array_writers[i] = new GeomVertexArrayDataHandle(_cdata->_arrays[i].get_write_pointer(), _current_thread); } } @@ -2624,8 +2608,7 @@ make_array_writers() { _array_writers.reserve(_cdata->_arrays.size()); GeomVertexData::Arrays::iterator ai; for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { - PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer(); - _array_writers.push_back(array_obj->modify_handle(_current_thread)); + _array_writers.push_back(new GeomVertexArrayDataHandle((*ai).get_write_pointer(), _current_thread)); } _object->clear_cache_stage(); diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index cfb592529d..37839d98b8 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -107,8 +107,10 @@ PUBLISHED: INLINE int get_num_arrays() const; INLINE CPT(GeomVertexArrayData) get_array(int i) const; + INLINE CPT(GeomVertexArrayDataHandle) get_array_handle(int i) const; MAKE_SEQ(get_arrays, get_num_arrays, get_array); INLINE PT(GeomVertexArrayData) modify_array(int i); + INLINE PT(GeomVertexArrayDataHandle) modify_array_handle(int i); INLINE void set_array(int i, const GeomVertexArrayData *array); MAKE_SEQ_PROPERTY(arrays, get_num_arrays, get_array, set_array); @@ -402,10 +404,15 @@ private: */ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineBase : public GeomEnums { protected: + INLINE GeomVertexDataPipelineBase(Thread *current_thread); INLINE GeomVertexDataPipelineBase(GeomVertexData *object, Thread *current_thread, GeomVertexData::CData *cdata); +private: + GeomVertexDataPipelineBase(const GeomVertexDataPipelineBase ©) DELETED; + GeomVertexDataPipelineBase &operator = (const GeomVertexDataPipelineBase ©) DELETED_ASSIGN; + public: INLINE ~GeomVertexDataPipelineBase(); @@ -425,7 +432,7 @@ public: INLINE UpdateSeq get_modified() const; protected: - PT(GeomVertexData) _object; + GeomVertexData *_object; Thread *_current_thread; GeomVertexData::CData *_cdata; }; @@ -433,18 +440,17 @@ protected: /** * Encapsulates the data from a GeomVertexData, pre-fetched for one stage of * the pipeline. + * Does not hold a reference to the GeomVertexData, so make sure it does not + * go out of scope. */ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineReader : public GeomVertexDataPipelineBase { public: + INLINE GeomVertexDataPipelineReader(Thread *current_thread); INLINE GeomVertexDataPipelineReader(const GeomVertexData *object, Thread *current_thread); -private: - INLINE GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader ©); - INLINE void operator = (const GeomVertexDataPipelineReader ©); -public: - INLINE ~GeomVertexDataPipelineReader(); ALLOC_DELETED_CHAIN(GeomVertexDataPipelineReader); + INLINE void set_object(const GeomVertexData *object); INLINE const GeomVertexData *get_object() const; INLINE void check_array_readers() const; @@ -480,7 +486,6 @@ public: private: void make_array_readers(); - void delete_array_readers(); bool _got_array_readers; typedef pvector ArrayReaders; @@ -501,16 +506,14 @@ private: /** * Encapsulates the data from a GeomVertexData, pre-fetched for one stage of * the pipeline. + * Does not hold a reference to the GeomVertexData, so make sure it does not + * go out of scope. */ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineWriter : public GeomVertexDataPipelineBase { public: INLINE GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0, Thread *current_thread); -private: - INLINE GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©); - INLINE void operator = (const GeomVertexDataPipelineWriter ©); -public: INLINE ~GeomVertexDataPipelineWriter(); ALLOC_DELETED_CHAIN(GeomVertexDataPipelineWriter); diff --git a/panda/src/gobj/geomVertexWriter.cxx b/panda/src/gobj/geomVertexWriter.cxx index b80a30fe67..ef05c3bc44 100644 --- a/panda/src/gobj/geomVertexWriter.cxx +++ b/panda/src/gobj/geomVertexWriter.cxx @@ -14,7 +14,7 @@ #include "geomVertexWriter.h" -#ifndef NDEBUG +#ifdef _DEBUG // This is defined just for the benefit of having something non-NULL to // return from a nassertr() call. unsigned char GeomVertexWriter::empty_buffer[100] = { 0 }; diff --git a/panda/src/gobj/geomVertexWriter.h b/panda/src/gobj/geomVertexWriter.h index 815ca6435f..aaedaf565b 100644 --- a/panda/src/gobj/geomVertexWriter.h +++ b/panda/src/gobj/geomVertexWriter.h @@ -212,7 +212,7 @@ private: int _start_row; -#ifndef NDEBUG +#ifdef _DEBUG // This is defined just for the benefit of having something non-NULL to // return from a nassertr() call. static unsigned char empty_buffer[100]; diff --git a/panda/src/gobj/internalName.h b/panda/src/gobj/internalName.h index 7485e6f758..bc636eb1c9 100644 --- a/panda/src/gobj/internalName.h +++ b/panda/src/gobj/internalName.h @@ -178,6 +178,12 @@ private: static TypeHandle _texcoord_type_handle; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const InternalName &tcn); /** diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index 27a055a794..f0cb8e0506 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -390,8 +390,10 @@ cp_dependency(ShaderMatInput inp) { if ((inp == SMO_model_to_view) || (inp == SMO_view_to_model) || (inp == SMO_model_to_apiview) || - (inp == SMO_apiview_to_model) || - (inp == SMO_view_to_world) || + (inp == SMO_apiview_to_model)) { + dep |= SSD_transform; + } + if ((inp == SMO_view_to_world) || (inp == SMO_world_to_view) || (inp == SMO_view_x_to_view) || (inp == SMO_view_to_view_x) || @@ -404,7 +406,7 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_dlight_x) || (inp == SMO_plight_x) || (inp == SMO_slight_x)) { - dep |= SSD_transform; + dep |= SSD_view_transform; } if ((inp == SMO_texpad_x) || (inp == SMO_texpix_x) || @@ -449,7 +451,7 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_light_source_i_attrib)) { dep |= SSD_light; if (inp == SMO_light_source_i_attrib) { - dep |= SSD_transform; + dep |= SSD_view_transform; } } if ((inp == SMO_light_product_i_ambient) || diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index e7e843b9c6..2eb0bc910a 100644 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -287,7 +287,7 @@ public: enum ShaderStateDep { SSD_NONE = 0x000, SSD_general = 0x001, - SSD_transform = 0x002, + SSD_transform = 0x2002, SSD_color = 0x004, SSD_colorscale = 0x008, SSD_material = 0x010, @@ -299,6 +299,7 @@ public: SSD_frame = 0x400, SSD_projection = 0x800, SSD_texture = 0x1000, + SSD_view_transform= 0x2000, }; enum ShaderBug { diff --git a/panda/src/gobj/shaderContext.h b/panda/src/gobj/shaderContext.h index 7a5312faa2..a8d8add8ed 100644 --- a/panda/src/gobj/shaderContext.h +++ b/panda/src/gobj/shaderContext.h @@ -32,7 +32,10 @@ class EXPCL_PANDA_GOBJ ShaderContext: public SavedContext { public: INLINE ShaderContext(Shader *se); - INLINE virtual void set_state_and_transform(const RenderState *, const TransformState *, const TransformState*) {}; + virtual void set_state_and_transform(const RenderState *, + const TransformState *, + const TransformState *, + const TransformState *) {}; INLINE virtual bool valid() { return false; } INLINE virtual void bind() {}; diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index 47ce9e233f..29b1702280 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -1544,7 +1544,14 @@ INLINE size_t Texture:: get_ram_mipmap_image_size(int n) const { CDReader cdata(_cycler); if (n >= 0 && n < (int)cdata->_ram_images.size()) { - return cdata->_ram_images[n]._image.size(); + if (cdata->_ram_images[n]._pointer_image == nullptr) { + return cdata->_ram_images[n]._image.size(); + } else { + // Calculate it based on the given page size. + return do_get_ram_mipmap_page_size(cdata, n) * + do_get_expected_mipmap_z_size(cdata, n) * + cdata->_num_views; + } } return 0; } diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 115d9529bf..d3dd47dbb9 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -3441,8 +3441,8 @@ do_load_sub_image(CData *cdata, const PNMImage &image, int x, int y, int z, int nassertr(y >= 0 && y < tex_y_size, false); nassertr(z >= 0 && z < tex_z_size, false); - nassertr(image.get_x_size() + x < tex_x_size, false); - nassertr(image.get_y_size() + y < tex_y_size, false); + nassertr(image.get_x_size() + x <= tex_x_size, false); + nassertr(image.get_y_size() + y <= tex_y_size, false); // Flip y y = cdata->_y_size - (image.get_y_size() + y); diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.cxx b/panda/src/grutil/pipeOcclusionCullTraverser.cxx index 91ebeb6559..1052d5ace5 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.cxx +++ b/panda/src/grutil/pipeOcclusionCullTraverser.cxx @@ -464,42 +464,33 @@ void PipeOcclusionCullTraverser:: make_box() { PT(GeomVertexData) vdata = new GeomVertexData ("occlusion_box", GeomVertexFormat::get_v3(), Geom::UH_static); - GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + vdata->unclean_set_num_rows(8); - vertex.add_data3(0.0f, 0.0f, 0.0f); - vertex.add_data3(0.0f, 0.0f, 1.0f); - vertex.add_data3(0.0f, 1.0f, 0.0f); - vertex.add_data3(0.0f, 1.0f, 1.0f); - vertex.add_data3(1.0f, 0.0f, 0.0f); - vertex.add_data3(1.0f, 0.0f, 1.0f); - vertex.add_data3(1.0f, 1.0f, 0.0f); - vertex.add_data3(1.0f, 1.0f, 1.0f); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + vertex.set_data3(0.0f, 0.0f, 0.0f); + vertex.set_data3(0.0f, 0.0f, 1.0f); + vertex.set_data3(0.0f, 1.0f, 0.0f); + vertex.set_data3(0.0f, 1.0f, 1.0f); + vertex.set_data3(1.0f, 0.0f, 0.0f); + vertex.set_data3(1.0f, 0.0f, 1.0f); + vertex.set_data3(1.0f, 1.0f, 0.0f); + vertex.set_data3(1.0f, 1.0f, 1.0f); + } PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static); tris->add_vertices(0, 4, 5); - tris->close_primitive(); tris->add_vertices(0, 5, 1); - tris->close_primitive(); tris->add_vertices(4, 6, 7); - tris->close_primitive(); tris->add_vertices(4, 7, 5); - tris->close_primitive(); tris->add_vertices(6, 2, 3); - tris->close_primitive(); tris->add_vertices(6, 3, 7); - tris->close_primitive(); tris->add_vertices(2, 0, 1); - tris->close_primitive(); tris->add_vertices(2, 1, 3); - tris->close_primitive(); tris->add_vertices(1, 5, 7); - tris->close_primitive(); tris->add_vertices(1, 7, 3); - tris->close_primitive(); tris->add_vertices(2, 6, 4); - tris->close_primitive(); tris->add_vertices(2, 4, 0); - tris->close_primitive(); _box_geom = new Geom(vdata); _box_geom->add_primitive(tris); diff --git a/panda/src/grutil/shaderTerrainMesh.cxx b/panda/src/grutil/shaderTerrainMesh.cxx index 8c2d03cdd4..a7f6b1d8af 100644 --- a/panda/src/grutil/shaderTerrainMesh.cxx +++ b/panda/src/grutil/shaderTerrainMesh.cxx @@ -513,22 +513,22 @@ void ShaderTerrainMesh::add_for_draw(CullTraverser *trav, CullTraverserData &dat nassertv(current_shader_attrib != NULL); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.terrain_size", LVecBase2i(_size)) ); + ShaderInput("ShaderTerrainMesh.terrain_size", LVecBase2i(_size))); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.chunk_size", LVecBase2i(_chunk_size))); + ShaderInput("ShaderTerrainMesh.chunk_size", LVecBase2i(_chunk_size))); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.view_index", LVecBase2i(_current_view_index))); + ShaderInput("ShaderTerrainMesh.view_index", LVecBase2i(_current_view_index))); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.data_texture", _data_texture)); + ShaderInput("ShaderTerrainMesh.data_texture", _data_texture)); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.heightfield", _heightfield_tex)); + ShaderInput("ShaderTerrainMesh.heightfield", _heightfield_tex)); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_instance_count( traversal_data.emitted_chunks); state = state->set_attrib(current_shader_attrib, 10000); // Emit chunk - CullableObject *object = new CullableObject(_chunk_geom, state, modelview_transform); + CullableObject *object = new CullableObject(_chunk_geom, move(state), move(modelview_transform)); trav->get_cull_handler()->record_object(object, trav); // After rendering, increment the view index diff --git a/panda/src/mathutil/geometricBoundingVolume.I b/panda/src/mathutil/geometricBoundingVolume.I index 21a32c4b48..beef98f9ff 100644 --- a/panda/src/mathutil/geometricBoundingVolume.I +++ b/panda/src/mathutil/geometricBoundingVolume.I @@ -16,6 +16,9 @@ */ INLINE_MATHUTIL GeometricBoundingVolume:: GeometricBoundingVolume() { +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** diff --git a/panda/src/mathutil/geometricBoundingVolume.h b/panda/src/mathutil/geometricBoundingVolume.h index 90c794d832..cc48177f17 100644 --- a/panda/src/mathutil/geometricBoundingVolume.h +++ b/panda/src/mathutil/geometricBoundingVolume.h @@ -83,6 +83,12 @@ private: static TypeHandle _type_handle; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "geometricBoundingVolume.I" #endif diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index c799595888..365795adf7 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/panda/src/parametrics/ropeNode.cxx @@ -132,9 +132,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { if (curve != (NurbsCurveEvaluator *)NULL) { PT(NurbsCurveResult) result; if (has_matrix()) { - result = curve->evaluate(data._node_path.get_node_path(), get_matrix()); + result = curve->evaluate(data.get_node_path(), get_matrix()); } else { - result = curve->evaluate(data._node_path.get_node_path()); + result = curve->evaluate(data.get_node_path()); } if (result->get_num_segments() > 0) { diff --git a/panda/src/parametrics/sheetNode.cxx b/panda/src/parametrics/sheetNode.cxx index 34496bca68..b4e4cc5a4d 100644 --- a/panda/src/parametrics/sheetNode.cxx +++ b/panda/src/parametrics/sheetNode.cxx @@ -129,7 +129,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { if (get_num_u_subdiv() > 0 && get_num_v_subdiv() > 0) { NurbsSurfaceEvaluator *surface = get_surface(); if (surface != (NurbsSurfaceEvaluator *)NULL) { - PT(NurbsSurfaceResult) result = surface->evaluate(data._node_path.get_node_path()); + PT(NurbsSurfaceResult) result = surface->evaluate(data.get_node_path()); if (result->get_num_u_segments() > 0 && result->get_num_v_segments() > 0) { render_sheet(trav, data, result); diff --git a/panda/src/pgraph/billboardEffect.cxx b/panda/src/pgraph/billboardEffect.cxx index dad0638245..737b370c42 100644 --- a/panda/src/pgraph/billboardEffect.cxx +++ b/panda/src/pgraph/billboardEffect.cxx @@ -164,7 +164,7 @@ has_adjust_transform() const { void BillboardEffect:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *) const { + const PandaNode *) const { // A BillboardEffect can only affect the net transform when it is to a // particular node. A billboard to a camera is camera-dependent, of course, // so it has no effect in the absence of any particular camera viewing it. diff --git a/panda/src/pgraph/billboardEffect.h b/panda/src/pgraph/billboardEffect.h index 2d528453f9..284182ba91 100644 --- a/panda/src/pgraph/billboardEffect.h +++ b/panda/src/pgraph/billboardEffect.h @@ -60,7 +60,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; protected: virtual int compare_to_impl(const RenderEffect *other) const; diff --git a/panda/src/pgraph/compassEffect.cxx b/panda/src/pgraph/compassEffect.cxx index c1e0cf24a8..d972e7f45a 100644 --- a/panda/src/pgraph/compassEffect.cxx +++ b/panda/src/pgraph/compassEffect.cxx @@ -157,7 +157,7 @@ has_adjust_transform() const { void CompassEffect:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *) const { + const PandaNode *) const { if (_properties == 0) { // Nothing to do. return; diff --git a/panda/src/pgraph/compassEffect.h b/panda/src/pgraph/compassEffect.h index 60ec6d03e9..6600820bb1 100644 --- a/panda/src/pgraph/compassEffect.h +++ b/panda/src/pgraph/compassEffect.h @@ -78,7 +78,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; protected: virtual int compare_to_impl(const RenderEffect *other) const; diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 10b9fb04d3..f481a2aeb1 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -78,7 +78,6 @@ #include "scissorAttrib.h" #include "scissorEffect.h" #include "shadeModelAttrib.h" -#include "shaderInput.h" #include "shaderAttrib.h" #include "shader.h" #include "showBoundsEffect.h" @@ -449,7 +448,6 @@ init_libpgraph() { ScissorAttrib::init_type(); ScissorEffect::init_type(); ShadeModelAttrib::init_type(); - ShaderInput::init_type(); ShaderAttrib::init_type(); ShowBoundsEffect::init_type(); StateMunger::init_type(); @@ -502,7 +500,6 @@ init_libpgraph() { ScissorAttrib::register_with_read_factory(); ScissorEffect::register_with_read_factory(); ShadeModelAttrib::register_with_read_factory(); - ShaderInput::register_with_read_factory(); ShaderAttrib::register_with_read_factory(); ShowBoundsEffect::register_with_read_factory(); TexMatrixAttrib::register_with_read_factory(); diff --git a/panda/src/pgraph/cullPlanes.cxx b/panda/src/pgraph/cullPlanes.cxx index 782637c973..43a249403b 100644 --- a/panda/src/pgraph/cullPlanes.cxx +++ b/panda/src/pgraph/cullPlanes.cxx @@ -315,11 +315,10 @@ do_cull(int &result, CPT(RenderState) &state, result = BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some; - CPT(ClipPlaneAttrib) orig_cpa = DCAST(ClipPlaneAttrib, state->get_attrib(ClipPlaneAttrib::get_class_slot())); - CPT(CullPlanes) new_planes = this; - if (orig_cpa == (ClipPlaneAttrib *)NULL) { + const ClipPlaneAttrib *orig_cpa; + if (!state->get_attrib(orig_cpa)) { // If there are no clip planes in the state, the node is completely in // front of all zero of the clip planes. (This can happen if someone // directly changes the state during the traversal.) diff --git a/panda/src/pgraph/cullPlanes.h b/panda/src/pgraph/cullPlanes.h index 483eb2d30a..c091eebdc9 100644 --- a/panda/src/pgraph/cullPlanes.h +++ b/panda/src/pgraph/cullPlanes.h @@ -74,6 +74,12 @@ private: Occluders _occluders; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "cullPlanes.I" #endif diff --git a/panda/src/pgraph/cullTraverser.I b/panda/src/pgraph/cullTraverser.I index 180b94b37a..5da999d673 100644 --- a/panda/src/pgraph/cullTraverser.I +++ b/panda/src/pgraph/cullTraverser.I @@ -200,20 +200,14 @@ do_traverse(CullTraverserData &data) { if (is_in_view(data)) { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << "\n" << data._node_path + << "\n" << data.get_node_path() << " " << data._draw_mask << "\n"; } PandaNodePipelineReader *node_reader = data.node_reader(); int fancy_bits = node_reader->get_fancy_bits(); - if ((fancy_bits & (PandaNode::FB_transform | - PandaNode::FB_state | - PandaNode::FB_effects | - PandaNode::FB_tag | - PandaNode::FB_draw_mask | - PandaNode::FB_cull_callback)) == 0 && - data._cull_planes->is_empty()) { + if (fancy_bits == 0 && data._cull_planes->is_empty()) { // Nothing interesting in this node; just move on. } else { diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index 5d08b4e5dd..a796718828 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -113,10 +113,8 @@ traverse(const NodePath &root) { GeometricBoundingVolume *local_frustum = NULL; PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds(); - if (bv != (BoundingVolume *)NULL && - bv->is_of_type(GeometricBoundingVolume::get_class_type())) { - - local_frustum = DCAST(GeometricBoundingVolume, bv); + if (bv != nullptr) { + local_frustum = bv->as_geometric_bounding_volume(); } // This local_frustum is in camera space @@ -199,19 +197,18 @@ traverse_below(CullTraverserData &data) { PandaNode::Children children = node_reader->get_children(); node_reader->release(); int num_children = children.get_num_children(); - if (node->has_selective_visibility()) { + if (!node->has_selective_visibility()) { + for (int i = 0; i < num_children; ++i) { + CullTraverserData next_data(data, children.get_child(i)); + do_traverse(next_data); + } + } else { int i = node->get_first_visible_child(); while (i < num_children) { CullTraverserData next_data(data, children.get_child(i)); do_traverse(next_data); i = node->get_next_visible_child(i); } - - } else { - for (int i = 0; i < num_children; i++) { - CullTraverserData next_data(data, children.get_child(i)); - do_traverse(next_data); - } } } @@ -235,12 +232,12 @@ draw_bounding_volume(const BoundingVolume *vol, if (bounds_viz != (Geom *)NULL) { _geoms_pcollector.add_level(2); CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), + new CullableObject(move(bounds_viz), get_bounds_outer_viz_state(), internal_transform); _cull_handler->record_object(outer_viz, this); CullableObject *inner_viz = - new CullableObject(bounds_viz, get_bounds_inner_viz_state(), + new CullableObject(move(bounds_viz), get_bounds_inner_viz_state(), internal_transform); _cull_handler->record_object(inner_viz, this); } @@ -270,7 +267,7 @@ show_bounds(CullTraverserData &data, bool tight) { if (bounds_viz != (Geom *)NULL) { _geoms_pcollector.add_level(1); CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), + new CullableObject(move(bounds_viz), get_bounds_outer_viz_state(), internal_transform); _cull_handler->record_object(outer_viz, this); } @@ -281,7 +278,7 @@ show_bounds(CullTraverserData &data, bool tight) { if (node->is_geom_node()) { // Also show the bounding volumes of included Geoms. internal_transform = internal_transform->compose(node->get_transform()); - GeomNode *gnode = DCAST(GeomNode, node); + GeomNode *gnode = (GeomNode *)node; int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; ++i) { draw_bounding_volume(gnode->get_geom(i)->get_bounds(), @@ -334,29 +331,31 @@ make_bounds_viz(const BoundingVolume *vol) { const BoundingHexahedron *fvol = DCAST(BoundingHexahedron, vol); PT(GeomVertexData) vdata = new GeomVertexData - ("bounds", GeomVertexFormat::get_v3(), - Geom::UH_stream); - GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream); + vdata->unclean_set_num_rows(8); - for (int i = 0; i < 8; ++i ) { - vertex.add_data3(fvol->get_point(i)); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + for (int i = 0; i < 8; ++i) { + vertex.set_data3(fvol->get_point(i)); + } } PT(GeomLines) lines = new GeomLines(Geom::UH_stream); - lines->add_vertices(0, 1); lines->close_primitive(); - lines->add_vertices(1, 2); lines->close_primitive(); - lines->add_vertices(2, 3); lines->close_primitive(); - lines->add_vertices(3, 0); lines->close_primitive(); + lines->add_vertices(0, 1); + lines->add_vertices(1, 2); + lines->add_vertices(2, 3); + lines->add_vertices(3, 0); - lines->add_vertices(4, 5); lines->close_primitive(); - lines->add_vertices(5, 6); lines->close_primitive(); - lines->add_vertices(6, 7); lines->close_primitive(); - lines->add_vertices(7, 4); lines->close_primitive(); + lines->add_vertices(4, 5); + lines->add_vertices(5, 6); + lines->add_vertices(6, 7); + lines->add_vertices(7, 4); - lines->add_vertices(0, 4); lines->close_primitive(); - lines->add_vertices(1, 5); lines->close_primitive(); - lines->add_vertices(2, 6); lines->close_primitive(); - lines->add_vertices(3, 7); lines->close_primitive(); + lines->add_vertices(0, 4); + lines->add_vertices(1, 5); + lines->add_vertices(2, 6); + lines->add_vertices(3, 7); geom = new Geom(vdata); geom->add_primitive(lines); @@ -368,39 +367,29 @@ make_bounds_viz(const BoundingVolume *vol) { box.local_object(); PT(GeomVertexData) vdata = new GeomVertexData - ("bounds", GeomVertexFormat::get_v3(), - Geom::UH_stream); - GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream); + vdata->unclean_set_num_rows(8); - for (int i = 0; i < 8; ++i ) { - vertex.add_data3(box.get_point(i)); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + for (int i = 0; i < 8; ++i) { + vertex.set_data3(box.get_point(i)); + } } PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream); tris->add_vertices(0, 4, 5); - tris->close_primitive(); tris->add_vertices(0, 5, 1); - tris->close_primitive(); tris->add_vertices(4, 6, 7); - tris->close_primitive(); tris->add_vertices(4, 7, 5); - tris->close_primitive(); tris->add_vertices(6, 2, 3); - tris->close_primitive(); tris->add_vertices(6, 3, 7); - tris->close_primitive(); tris->add_vertices(2, 0, 1); - tris->close_primitive(); tris->add_vertices(2, 1, 3); - tris->close_primitive(); tris->add_vertices(1, 5, 7); - tris->close_primitive(); tris->add_vertices(1, 7, 3); - tris->close_primitive(); tris->add_vertices(2, 6, 4); - tris->close_primitive(); tris->add_vertices(2, 4, 0); - tris->close_primitive(); geom = new Geom(vdata); geom->add_primitive(tris); @@ -430,19 +419,21 @@ make_tight_bounds_viz(PandaNode *node) const { _current_thread); if (found_any) { PT(GeomVertexData) vdata = new GeomVertexData - ("bounds", GeomVertexFormat::get_v3(), - Geom::UH_stream); - GeomVertexWriter vertex(vdata, InternalName::get_vertex(), - _current_thread); + ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream); + vdata->unclean_set_num_rows(8); - vertex.add_data3(n[0], n[1], n[2]); - vertex.add_data3(n[0], n[1], x[2]); - vertex.add_data3(n[0], x[1], n[2]); - vertex.add_data3(n[0], x[1], x[2]); - vertex.add_data3(x[0], n[1], n[2]); - vertex.add_data3(x[0], n[1], x[2]); - vertex.add_data3(x[0], x[1], n[2]); - vertex.add_data3(x[0], x[1], x[2]); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex(), + _current_thread); + vertex.set_data3(n[0], n[1], n[2]); + vertex.set_data3(n[0], n[1], x[2]); + vertex.set_data3(n[0], x[1], n[2]); + vertex.set_data3(n[0], x[1], x[2]); + vertex.set_data3(x[0], n[1], n[2]); + vertex.set_data3(x[0], n[1], x[2]); + vertex.set_data3(x[0], x[1], n[2]); + vertex.set_data3(x[0], x[1], x[2]); + } PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream); diff --git a/panda/src/pgraph/cullTraverserData.I b/panda/src/pgraph/cullTraverserData.I index 4367d1608e..e2a9a64c95 100644 --- a/panda/src/pgraph/cullTraverserData.I +++ b/panda/src/pgraph/cullTraverserData.I @@ -20,7 +20,8 @@ CullTraverserData(const NodePath &start, const RenderState *state, GeometricBoundingVolume *view_frustum, Thread *current_thread) : - _node_path(start), + _next(nullptr), + _start(start._head), _node_reader(start.node(), current_thread), _net_transform(net_transform), _state(state), @@ -34,44 +35,16 @@ CullTraverserData(const NodePath &start, _node_reader.check_cached(check_bounds); } -/** - * - */ -INLINE CullTraverserData:: -CullTraverserData(const CullTraverserData ©) : - _node_path(copy._node_path), - _node_reader(copy._node_reader), - _net_transform(copy._net_transform), - _state(copy._state), - _view_frustum(copy._view_frustum), - _cull_planes(copy._cull_planes), - _draw_mask(copy._draw_mask), - _portal_depth(copy._portal_depth) -{ -} - -/** - * - */ -INLINE void CullTraverserData:: -operator = (const CullTraverserData ©) { - _node_path = copy._node_path; - _node_reader = copy._node_reader; - _net_transform = copy._net_transform; - _state = copy._state; - _view_frustum = copy._view_frustum; - _cull_planes = copy._cull_planes; - _draw_mask = copy._draw_mask; - _portal_depth = copy._portal_depth; -} - /** * This constructor creates a CullTraverserData object that reflects the next * node down in the traversal. */ INLINE CullTraverserData:: CullTraverserData(const CullTraverserData &parent, PandaNode *child) : - _node_path(parent._node_path, child), + _next(&parent), +#ifdef _DEBUG + _start(nullptr), +#endif _node_reader(child, parent._node_reader.get_current_thread()), _net_transform(parent._net_transform), _state(parent._state), @@ -86,19 +59,12 @@ CullTraverserData(const CullTraverserData &parent, PandaNode *child) : _node_reader.check_cached(check_bounds); } -/** - * - */ -INLINE CullTraverserData:: -~CullTraverserData() { -} - /** * Returns the node traversed to so far. */ INLINE PandaNode *CullTraverserData:: node() const { - return _node_path.node(); + return (PandaNode *)_node_reader.get_node(); } /** @@ -117,6 +83,18 @@ node_reader() const { return &_node_reader; } +/** + * Constructs and returns an actual NodePath that represents the same path we + * have just traversed. + */ +INLINE NodePath CullTraverserData:: +get_node_path() const { + NodePath result; + result._head = r_get_node_path(); + nassertr(result._head != nullptr, NodePath::fail()); + return result; +} + /** * Returns the modelview transform: the relative transform from the camera to * the model. diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index d5ad3cba4f..1a8280948f 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -46,25 +46,33 @@ apply_transform_and_state(CullTraverser *trav) { } _node_reader.compose_draw_mask(_draw_mask); - apply_transform_and_state(trav, _node_reader.get_transform(), - MOVE(node_state), _node_reader.get_effects(), - _node_reader.get_off_clip_planes()); + const RenderEffects *node_effects = _node_reader.get_effects(); + if (!node_effects->has_cull_callback()) { + apply_transform(_node_reader.get_transform()); + } else { + // The cull callback may decide to modify the node_transform. + CPT(TransformState) node_transform = _node_reader.get_transform(); + node_effects->cull_callback(trav, *this, node_transform, node_state); + apply_transform(node_transform); + } + + if (!node_state->is_empty()) { + _state = _state->compose(node_state); + } + + if (clip_plane_cull) { + _cull_planes = _cull_planes->apply_state(trav, this, + (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()), + (const ClipPlaneAttrib *)_node_reader.get_off_clip_planes(), + (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type())); + } } /** - * Applies the indicated transform and state changes (e.g. as extracted from - * a node) onto the current data. This also evaluates billboards, etc. + * Applies the indicated transform changes onto the current data. */ void CullTraverserData:: -apply_transform_and_state(CullTraverser *trav, - CPT(TransformState) node_transform, - CPT(RenderState) node_state, - CPT(RenderEffects) node_effects, - const RenderAttrib *off_clip_planes) { - if (node_effects->has_cull_callback()) { - node_effects->cull_callback(trav, *this, node_transform, node_state); - } - +apply_transform(const TransformState *node_transform) { if (!node_transform->is_identity()) { _net_transform = _net_transform->compose(node_transform); @@ -95,15 +103,40 @@ apply_transform_and_state(CullTraverser *trav, } } } +} - _state = _state->compose(node_state); - - if (clip_plane_cull) { - _cull_planes = _cull_planes->apply_state(trav, this, - (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()), - DCAST(ClipPlaneAttrib, off_clip_planes), - (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type())); +/** + * The private, recursive implementation of get_node_path(), this returns the + * NodePathComponent representing the NodePath. + */ +PT(NodePathComponent) CullTraverserData:: +r_get_node_path() const { + if (_next == nullptr) { + nassertr(_start != nullptr, nullptr); + return _start; } + +#ifdef _DEBUG + nassertr(_start == nullptr, nullptr); +#endif + nassertr(node() != nullptr, nullptr); + + PT(NodePathComponent) comp = _next->r_get_node_path(); + nassertr(comp != nullptr, nullptr); + + Thread *current_thread = Thread::get_current_thread(); + int pipeline_stage = current_thread->get_pipeline_stage(); + PT(NodePathComponent) result = + PandaNode::get_component(comp, node(), pipeline_stage, current_thread); + if (result == nullptr) { + // This means we found a disconnected chain in the CullTraverserData's + // ancestry: the node above this node isn't connected. In this case, + // don't attempt to go higher; just truncate the NodePath at the bottom of + // the disconnect. + return PandaNode::get_top_component(node(), true, pipeline_stage, current_thread); + } + + return result; } /** @@ -121,7 +154,7 @@ is_in_view_impl() { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << _node_path << " cull result = " << hex << result << dec << "\n"; + << get_node_path() << " cull result = " << hex << result << dec << "\n"; } if (result == BoundingVolume::IF_no_intersection) { @@ -136,8 +169,7 @@ is_in_view_impl() { // If we have fake view-frustum culling enabled, instead of actually // culling an object we simply force it to be drawn in red wireframe. _view_frustum = (GeometricBoundingVolume *)NULL; - CPT(RenderState) fake_state = get_fake_view_frustum_cull_state(); - _state = _state->compose(fake_state); + _state = _state->compose(get_fake_view_frustum_cull_state()); #endif } else if ((result & BoundingVolume::IF_all) != 0) { @@ -170,7 +202,7 @@ is_in_view_impl() { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << _node_path << " cull planes cull result = " << hex + << get_node_path() << " cull planes cull result = " << hex << result << dec << "\n"; _cull_planes->write(pgraph_cat.spam(false)); } @@ -182,7 +214,7 @@ is_in_view_impl() { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << _node_path << " is_final, cull planes disabled, state:\n"; + << get_node_path() << " is_final, cull planes disabled, state:\n"; _state->write(pgraph_cat.spam(false), 2); } } @@ -196,8 +228,7 @@ is_in_view_impl() { return false; } _cull_planes = CullPlanes::make_empty(); - CPT(RenderState) fake_state = get_fake_view_frustum_cull_state(); - _state = _state->compose(fake_state); + _state = _state->compose(get_fake_view_frustum_cull_state()); #endif } else if ((result & BoundingVolume::IF_all) != 0) { @@ -215,15 +246,15 @@ is_in_view_impl() { * Returns a RenderState for rendering stuff in red wireframe, strictly for * the fake_view_frustum_cull effect. */ -CPT(RenderState) CullTraverserData:: +const RenderState *CullTraverserData:: get_fake_view_frustum_cull_state() { #ifdef NDEBUG - return NULL; + return nullptr; #else // Once someone asks for this pointer, we hold its reference count and never // free it. - static CPT(RenderState) state = (const RenderState *)NULL; - if (state == (const RenderState *)NULL) { + static CPT(RenderState) state; + if (state == nullptr) { state = RenderState::make (ColorAttrib::make_flat(LColor(1.0f, 0.0f, 0.0f, 1.0f)), TextureAttrib::make_all_off(), diff --git a/panda/src/pgraph/cullTraverserData.h b/panda/src/pgraph/cullTraverserData.h index 80d523fe0c..e275dcfd93 100644 --- a/panda/src/pgraph/cullTraverserData.h +++ b/panda/src/pgraph/cullTraverserData.h @@ -44,11 +44,8 @@ public: const RenderState *state, GeometricBoundingVolume *view_frustum, Thread *current_thread); - INLINE CullTraverserData(const CullTraverserData ©); - INLINE void operator = (const CullTraverserData ©); INLINE CullTraverserData(const CullTraverserData &parent, PandaNode *child); - INLINE ~CullTraverserData(); PUBLISHED: INLINE PandaNode *node() const; @@ -57,6 +54,8 @@ public: INLINE PandaNodePipelineReader *node_reader(); INLINE const PandaNodePipelineReader *node_reader() const; + INLINE NodePath get_node_path() const; + PUBLISHED: INLINE CPT(TransformState) get_modelview_transform(const CullTraverser *trav) const; INLINE CPT(TransformState) get_internal_transform(const CullTraverser *trav) const; @@ -66,14 +65,15 @@ PUBLISHED: INLINE bool is_this_node_hidden(const DrawMask &camera_mask) const; void apply_transform_and_state(CullTraverser *trav); - void apply_transform_and_state(CullTraverser *trav, - CPT(TransformState) node_transform, - CPT(RenderState) node_state, - CPT(RenderEffects) node_effects, - const RenderAttrib *off_clip_planes); + void apply_transform(const TransformState *node_transform); + +private: + // We store a chain leading all the way to the root, so that we can compose + // a NodePath. We may be able to eliminate this requirement in the future. + const CullTraverserData *_next; + NodePathComponent *_start; public: - WorkingNodePath _node_path; PandaNodePipelineReader _node_reader; CPT(TransformState) _net_transform; CPT(RenderState) _state; @@ -83,8 +83,10 @@ public: int _portal_depth; private: + PT(NodePathComponent) r_get_node_path() const; + bool is_in_view_impl(); - static CPT(RenderState) get_fake_view_frustum_cull_state(); + static const RenderState *get_fake_view_frustum_cull_state(); }; /* okcircular */ diff --git a/panda/src/pgraph/cullableObject.I b/panda/src/pgraph/cullableObject.I index 242496587f..2aae972296 100644 --- a/panda/src/pgraph/cullableObject.I +++ b/panda/src/pgraph/cullableObject.I @@ -26,11 +26,11 @@ CullableObject() { * render state and transform. */ INLINE CullableObject:: -CullableObject(const Geom *geom, const RenderState *state, - const TransformState *internal_transform) : - _geom(geom), - _state(state), - _internal_transform(internal_transform) +CullableObject(CPT(Geom) geom, CPT(RenderState) state, + CPT(TransformState) internal_transform) : + _geom(move(geom)), + _state(move(state)), + _internal_transform(move(internal_transform)) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); @@ -135,6 +135,21 @@ draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) _geom->draw(gsg, _munger, _munged_data, force, current_thread); } +/** + * Invokes the draw callback, assuming one is set. Crashes if not. + */ +INLINE void CullableObject:: +draw_callback(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) { + gsg->clear_before_callback(); + gsg->set_state_and_transform(_state, _internal_transform); + GeomDrawCallbackData cbdata(this, gsg, force); + _draw_callback->do_callback(&cbdata); + if (cbdata.get_lost_state()) { + // Tell the GSG to forget its state. + gsg->clear_state_and_transform(); + } +} + /** * */ diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index 82fd0df3a5..aa4a3af3c2 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -46,8 +46,8 @@ class EXPCL_PANDA_PGRAPH CullableObject { public: INLINE CullableObject(); - INLINE CullableObject(const Geom *geom, const RenderState *state, - const TransformState *internal_transform); + INLINE CullableObject(CPT(Geom) geom, CPT(RenderState) state, + CPT(TransformState) internal_transform); INLINE CullableObject(const CullableObject ©); INLINE void operator = (const CullableObject ©); @@ -63,6 +63,11 @@ public: INLINE void set_draw_callback(CallbackObject *draw_callback); + INLINE void draw_inline(GraphicsStateGuardianBase *gsg, + bool force, Thread *current_thread); + INLINE void draw_callback(GraphicsStateGuardianBase *gsg, + bool force, Thread *current_thread); + public: ALLOC_DELETED_CHAIN(CullableObject); @@ -82,9 +87,6 @@ private: static CPT(RenderState) get_flash_cpu_state(); static CPT(RenderState) get_flash_hardware_state(); - INLINE void draw_inline(GraphicsStateGuardianBase *gsg, - bool force, Thread *current_thread); - private: // This class is used internally by munge_points_to_quads(). class PointData { diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index f0000d4ebb..7b850fafc6 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -515,7 +515,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { CPT(TransformState) internal_transform = data.get_internal_transform(trav); for (int i = 0; i < num_geoms; i++) { - const Geom *geom = geoms.get_geom(i); + CPT(Geom) geom = geoms.get_geom(i); if (geom->is_empty()) { continue; } @@ -558,7 +558,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { } CullableObject *object = - new CullableObject(geom, state, internal_transform); + new CullableObject(move(geom), move(state), internal_transform); trav->get_cull_handler()->record_object(object, trav); } } diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 10648b7686..65c1ca6c80 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -151,7 +151,7 @@ transform_vertices(GeomNode *node, const LMatrix4 &mat) { GeomNode::GeomEntry &entry = (*gi); PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy(); if (transform_vertices(new_geom, mat)) { - entry._geom = new_geom; + entry._geom = move(new_geom); any_changed = true; } } @@ -1243,16 +1243,14 @@ apply_collect_changes() { void GeomTransformer::NewCollectedData:: append_vdata(const GeomVertexData *vdata, int vertex_offset) { for (int i = 0; i < vdata->get_num_arrays(); ++i) { - PT(GeomVertexArrayData) new_array = _new_data->modify_array(i); - CPT(GeomVertexArrayData) old_array = vdata->get_array(i); + PT(GeomVertexArrayDataHandle) new_handle = _new_data->modify_array_handle(i); + CPT(GeomVertexArrayDataHandle) old_handle = vdata->get_array_handle(i); size_t stride = (size_t)_new_format->get_array(i)->get_stride(); size_t start_byte = (size_t)vertex_offset * stride; - size_t copy_bytes = old_array->get_data_size_bytes(); - nassertv(start_byte + copy_bytes <= new_array->get_data_size_bytes()); + size_t copy_bytes = old_handle->get_data_size_bytes(); + nassertv(start_byte + copy_bytes <= new_handle->get_data_size_bytes()); - new_array->modify_handle()->copy_subdata_from - (start_byte, copy_bytes, - old_array->get_handle(), 0, copy_bytes); + new_handle->copy_subdata_from(start_byte, copy_bytes, old_handle, 0, copy_bytes); } // Also, copy the animation data (if any). This means combining transform @@ -1441,13 +1439,8 @@ remove_unused_vertices(const GeomVertexData *vdata) { any_referenced = true; int num_primitives = geom->get_num_primitives(); for (int i = 0; i < num_primitives; ++i) { - CPT(GeomPrimitive) prim = geom->get_primitive(i); - - GeomPrimitivePipelineReader reader(prim, current_thread); - int num_vertices = reader.get_num_vertices(); - for (int vi = 0; vi < num_vertices; ++vi) { - referenced_vertices.set_bit(reader.get_vertex(vi)); - } + GeomPrimitivePipelineReader reader(geom->get_primitive(i), current_thread); + reader.get_referenced_vertices(referenced_vertices); } } diff --git a/panda/src/pgraph/nodePath.I b/panda/src/pgraph/nodePath.I index cfcef09112..efe133c215 100644 --- a/panda/src/pgraph/nodePath.I +++ b/panda/src/pgraph/nodePath.I @@ -1080,7 +1080,7 @@ get_sa() const { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1088,7 +1088,7 @@ set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1096,7 +1096,7 @@ set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_int &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1104,7 +1104,7 @@ set_shader_input(CPT_InternalName id, const PTA_int &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1112,7 +1112,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } @@ -1121,7 +1121,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1129,7 +1129,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1137,7 +1137,7 @@ set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1145,7 +1145,7 @@ set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1153,7 +1153,7 @@ set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1161,7 +1161,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase4i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } @@ -1170,7 +1170,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase3i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1178,7 +1178,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase2i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase4i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1186,7 +1186,7 @@ set_shader_input(CPT_InternalName id, const LVecBase4i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase3i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1194,7 +1194,7 @@ set_shader_input(CPT_InternalName id, const LVecBase3i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase2i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1202,7 +1202,7 @@ set_shader_input(CPT_InternalName id, const LVecBase2i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1210,7 +1210,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1218,7 +1218,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1226,7 +1226,7 @@ set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1234,7 +1234,7 @@ set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, int priority) { - set_shader_input(new ShaderInput(id, tex, priority)); + set_shader_input(ShaderInput(move(id), tex, priority)); } /** @@ -1242,7 +1242,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, int priority) { - set_shader_input(new ShaderInput(id, tex, sampler, priority)); + set_shader_input(ShaderInput(move(id), tex, sampler, priority)); } /** @@ -1250,7 +1250,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z, int n, int priority) { - set_shader_input(new ShaderInput(id, tex, read, write, z, n, priority)); + set_shader_input(ShaderInput(move(id), tex, read, write, z, n, priority)); } /** @@ -1258,7 +1258,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority) { - set_shader_input(new ShaderInput(id, buf, priority)); + set_shader_input(ShaderInput(move(id), buf, priority)); } /** @@ -1266,7 +1266,7 @@ set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const NodePath &np, int priority) { - set_shader_input(new ShaderInput(id, np, priority)); + set_shader_input(ShaderInput(move(id), np, priority)); } /** @@ -1274,7 +1274,7 @@ set_shader_input(CPT_InternalName id, const NodePath &np, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, int n1, int n2, int n3, int n4, int priority) { - set_shader_input(new ShaderInput(id, LVecBase4i(n1, n2, n3, n4), priority)); + set_shader_input(ShaderInput(move(id), LVecBase4i(n1, n2, n3, n4), priority)); } /** @@ -1282,7 +1282,7 @@ set_shader_input(CPT_InternalName id, int n1, int n2, int n3, int n4, int priori */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, PN_stdfloat n1, PN_stdfloat n2, PN_stdfloat n3, PN_stdfloat n4, int priority) { - set_shader_input(new ShaderInput(id, LVecBase4(n1, n2, n3, n4), priority)); + set_shader_input(ShaderInput(move(id), LVecBase4(n1, n2, n3, n4), priority)); } /** diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index de0cf7c4fb..f0056e703f 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -697,8 +697,10 @@ get_state(const NodePath &other, Thread *current_thread) const { return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty()); } +#if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS)) nassertr(verify_complete(current_thread), RenderState::make_empty()); nassertr(other.verify_complete(current_thread), RenderState::make_empty()); +#endif int a_count, b_count; if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { @@ -767,8 +769,10 @@ get_transform(const NodePath &other, Thread *current_thread) const { return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity()); } +#if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS)) nassertr(verify_complete(current_thread), TransformState::make_identity()); nassertr(other.verify_complete(current_thread), TransformState::make_identity()); +#endif int a_count, b_count; if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { @@ -852,8 +856,10 @@ get_prev_transform(const NodePath &other, Thread *current_thread) const { return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity()); } +#if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS)) nassertr(verify_complete(current_thread), TransformState::make_identity()); nassertr(other.verify_complete(current_thread), TransformState::make_identity()); +#endif int a_count, b_count; if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { @@ -3255,35 +3261,36 @@ get_shader() const { * */ void NodePath:: -set_shader_input(const ShaderInput *inp) { +set_shader_input(ShaderInput inp) { nassertv_always(!is_empty()); + PandaNode *pnode = node(); const RenderAttrib *attrib = - node()->get_attrib(ShaderAttrib::get_class_slot()); - if (attrib != (const RenderAttrib *)NULL) { - const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); - node()->set_attrib(sa->set_shader_input(inp)); + pnode->get_attrib(ShaderAttrib::get_class_slot()); + if (attrib != nullptr) { + const ShaderAttrib *sa = (const ShaderAttrib *)attrib; + pnode->set_attrib(sa->set_shader_input(inp)); } else { // Create a new ShaderAttrib for this node. CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); - node()->set_attrib(sa->set_shader_input(inp)); + pnode->set_attrib(sa->set_shader_input(inp)); } } /** * */ -const ShaderInput *NodePath:: +ShaderInput NodePath:: get_shader_input(CPT_InternalName id) const { - nassertr_always(!is_empty(), NULL); + nassertr_always(!is_empty(), ShaderInput::get_blank()); const RenderAttrib *attrib = node()->get_attrib(ShaderAttrib::get_class_slot()); - if (attrib != (const RenderAttrib *)NULL) { - const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); + if (attrib != nullptr) { + const ShaderAttrib *sa = (const ShaderAttrib *)attrib; return sa->get_shader_input(id); } - return NULL; + return ShaderInput::get_blank(); } /** @@ -5786,17 +5793,22 @@ r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const { if (comp == (NodePathComponent *)NULL) { return TransformState::make_identity(); } else { + PandaNode *node = comp->get_node(); int pipeline_stage = current_thread->get_pipeline_stage(); CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread); - PandaNode *node = comp->get_node(); - CPT(TransformState) transform = node->get_transform(current_thread); - CPT(RenderEffects) effects = node->get_effects(current_thread); - if (effects->has_adjust_transform()) { - effects->adjust_transform(net_transform, transform, node); + PandaNode::CDReader node_cdata(node->_cycler, current_thread); + if (!node_cdata->_effects->has_adjust_transform()) { + if (node_cdata->_transform->is_identity()) { + return net_transform; + } else { + return net_transform->compose(node_cdata->_transform); + } + } else { + CPT(TransformState) transform = node_cdata->_transform.p(); + node_cdata->_effects->adjust_transform(net_transform, transform, node); + return net_transform->compose(transform); } - - return net_transform->compose(transform); } } @@ -5814,16 +5826,21 @@ r_get_partial_transform(NodePathComponent *comp, int n, if (n == 0 || comp == (NodePathComponent *)NULL) { return TransformState::make_identity(); } else { - if (comp->get_node()->get_effects(current_thread)->has_adjust_transform()) { + PandaNode *node = comp->get_node(); + PandaNode::CDReader node_cdata(node->_cycler, current_thread); + if (node_cdata->_effects->has_adjust_transform()) { return NULL; } - CPT(TransformState) transform = comp->get_node()->get_transform(current_thread); int pipeline_stage = current_thread->get_pipeline_stage(); CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread); if (partial == (const TransformState *)NULL) { return NULL; } - return partial->compose(transform); + if (node_cdata->_transform->is_identity()) { + return partial; + } else { + return partial->compose(node_cdata->_transform); + } } } diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 6aeeda6d01..e6eaca10cd 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -629,7 +629,7 @@ PUBLISHED: void set_shader_auto(BitMask32 shader_switch, int priority=0); void clear_shader(); - void set_shader_input(const ShaderInput *inp); + void set_shader_input(ShaderInput input); INLINE void set_shader_input(CPT_InternalName id, Texture *tex, int priority=0); INLINE void set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, int priority=0); INLINE void set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0); @@ -665,7 +665,7 @@ PUBLISHED: void set_instance_count(int instance_count); const Shader *get_shader() const; - const ShaderInput *get_shader_input(CPT_InternalName id) const; + ShaderInput get_shader_input(CPT_InternalName id) const; int get_instance_count() const; void set_tex_transform(TextureStage *stage, const TransformState *transform); @@ -1029,6 +1029,7 @@ private: friend class NodePathCollection; friend class WorkingNodePath; friend class WeakNodePath; + friend class CullTraverserData; }; INLINE ostream &operator << (ostream &out, const NodePath &node_path); diff --git a/panda/src/pgraph/nodePathComponent.I b/panda/src/pgraph/nodePathComponent.I index fa16ebe2b9..d3abe36c07 100644 --- a/panda/src/pgraph/nodePathComponent.I +++ b/panda/src/pgraph/nodePathComponent.I @@ -75,6 +75,15 @@ has_key() const { return (_key != 0); } +/** + * Returns the next component in the path. + */ +INLINE NodePathComponent *NodePathComponent:: +get_next(int pipeline_stage, Thread *current_thread) const { + CDStageReader cdata(_cycler, pipeline_stage, current_thread); + return cdata->_next; +} + INLINE ostream &operator << (ostream &out, const NodePathComponent &comp) { comp.output(out); return out; diff --git a/panda/src/pgraph/nodePathComponent.cxx b/panda/src/pgraph/nodePathComponent.cxx index 4dbacc4539..a9f8a38788 100644 --- a/panda/src/pgraph/nodePathComponent.cxx +++ b/panda/src/pgraph/nodePathComponent.cxx @@ -92,17 +92,6 @@ get_length(int pipeline_stage, Thread *current_thread) const { return cdata->_length; } -/** - * Returns the next component in the path. - */ -NodePathComponent *NodePathComponent:: -get_next(int pipeline_stage, Thread *current_thread) const { - CDStageReader cdata(_cycler, pipeline_stage, current_thread); - NodePathComponent *next = cdata->_next; - - return next; -} - /** * Checks that the length indicated by the component is one more than the * length of its predecessor. If this is broken, fixes it and returns true diff --git a/panda/src/pgraph/nodePathComponent.h b/panda/src/pgraph/nodePathComponent.h index fbe4625c14..b0ed69a389 100644 --- a/panda/src/pgraph/nodePathComponent.h +++ b/panda/src/pgraph/nodePathComponent.h @@ -39,7 +39,7 @@ * graph, and the NodePathComponents are stored in the nodes themselves to * allow the nodes to keep these up to date as the scene graph is manipulated. */ -class EXPCL_PANDA_PGRAPH NodePathComponent : public ReferenceCount { +class EXPCL_PANDA_PGRAPH NodePathComponent FINAL : public ReferenceCount { private: NodePathComponent(PandaNode *node, NodePathComponent *next, int pipeline_stage, Thread *current_thread); @@ -55,7 +55,7 @@ public: int get_key() const; bool is_top_node(int pipeline_stage, Thread *current_thread) const; - NodePathComponent *get_next(int pipeline_stage, Thread *current_thread) const; + INLINE NodePathComponent *get_next(int pipeline_stage, Thread *current_thread) const; int get_length(int pipeline_stage, Thread *current_thread) const; bool fix_length(int pipeline_stage, Thread *current_thread); @@ -125,6 +125,12 @@ private: friend class NodePath; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const NodePathComponent &comp); #include "nodePathComponent.I" diff --git a/panda/src/pgraph/nodePath_ext.cxx b/panda/src/pgraph/nodePath_ext.cxx index 60cbe19a1c..1d1449b423 100644 --- a/panda/src/pgraph/nodePath_ext.cxx +++ b/panda/src/pgraph/nodePath_ext.cxx @@ -278,7 +278,7 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { } CPT_InternalName name(string(buffer, length)); - ShaderInput *input = nullptr; + ShaderInput input(nullptr, 0); if (PyTuple_CheckExact(value)) { // A tuple is interpreted as a vector. @@ -300,13 +300,13 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { for (Py_ssize_t i = 0; i < size; ++i) { vec[i] = (PN_stdfloat)PyFloat_AsDouble(PyTuple_GET_ITEM(value, i)); } - input = new ShaderInput(name, vec); + input = ShaderInput(move(name), vec); } else { LVecBase4i vec(0); for (Py_ssize_t i = 0; i < size; ++i) { vec[i] = (int)PyLong_AsLong(PyTuple_GET_ITEM(value, i)); } - input = new ShaderInput(name, vec); + input = ShaderInput(move(name), vec); } } else if (DtoolCanThisBeAPandaInstance(value)) { @@ -314,91 +314,91 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { void *ptr; if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_Texture))) { - input = new ShaderInput(name, (Texture *)ptr); + input = ShaderInput(move(name), (Texture *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_NodePath))) { - input = new ShaderInput(name, *(const NodePath *)ptr); + input = ShaderInput(move(name), *(const NodePath *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_float))) { - input = new ShaderInput(name, *(const PTA_float *)ptr); + input = ShaderInput(move(name), *(const PTA_float *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_double))) { - input = new ShaderInput(name, *(const PTA_double *)ptr); + input = ShaderInput(move(name), *(const PTA_double *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_int))) { - input = new ShaderInput(name, *(const PTA_int *)ptr); + input = ShaderInput(move(name), *(const PTA_int *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4f))) { - input = new ShaderInput(name, *(const PTA_LVecBase4f *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase4f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3f))) { - input = new ShaderInput(name, *(const PTA_LVecBase3f *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase3f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2f))) { - input = new ShaderInput(name, *(const PTA_LVecBase2f *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase2f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4f))) { - input = new ShaderInput(name, *(const PTA_LMatrix4f *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix4f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3f))) { - input = new ShaderInput(name, *(const PTA_LMatrix3f *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix3f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4d))) { - input = new ShaderInput(name, *(const PTA_LVecBase4d *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase4d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3d))) { - input = new ShaderInput(name, *(const PTA_LVecBase3d *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase3d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2d))) { - input = new ShaderInput(name, *(const PTA_LVecBase2d *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase2d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4d))) { - input = new ShaderInput(name, *(const PTA_LMatrix4d *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix4d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3d))) { - input = new ShaderInput(name, *(const PTA_LMatrix3d *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix3d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4i))) { - input = new ShaderInput(name, *(const PTA_LVecBase4i *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase4i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3i))) { - input = new ShaderInput(name, *(const PTA_LVecBase3i *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase3i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2i))) { - input = new ShaderInput(name, *(const PTA_LVecBase2i *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase2i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4f))) { - input = new ShaderInput(name, *(const LVecBase4f *)ptr); + input = ShaderInput(move(name), *(const LVecBase4f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3f))) { - input = new ShaderInput(name, *(const LVecBase3f *)ptr); + input = ShaderInput(move(name), *(const LVecBase3f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2f))) { - input = new ShaderInput(name, *(const LVecBase2f *)ptr); + input = ShaderInput(move(name), *(const LVecBase2f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4d))) { - input = new ShaderInput(name, *(const LVecBase4d *)ptr); + input = ShaderInput(move(name), *(const LVecBase4d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3d))) { - input = new ShaderInput(name, *(const LVecBase3d *)ptr); + input = ShaderInput(move(name), *(const LVecBase3d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2d))) { - input = new ShaderInput(name, *(const LVecBase2d *)ptr); + input = ShaderInput(move(name), *(const LVecBase2d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4i))) { - input = new ShaderInput(name, *(const LVecBase4i *)ptr); + input = ShaderInput(move(name), *(const LVecBase4i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3i))) { - input = new ShaderInput(name, *(const LVecBase3i *)ptr); + input = ShaderInput(move(name), *(const LVecBase3i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2i))) { - input = new ShaderInput(name, *(const LVecBase2i *)ptr); + input = ShaderInput(move(name), *(const LVecBase2i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ShaderBuffer))) { - input = new ShaderInput(name, (ShaderBuffer *)ptr); + input = ShaderInput(move(name), (ShaderBuffer *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ParamValueBase))) { - input = new ShaderInput(name, (ParamValueBase *)ptr); + input = ShaderInput(move(name), (ParamValueBase *)ptr); } else { Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs"); @@ -406,22 +406,22 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { } } else if (PyFloat_Check(value)) { - input = new ShaderInput(name, LVecBase4(PyFloat_AS_DOUBLE(value), 0, 0, 0)); + input = ShaderInput(move(name), LVecBase4(PyFloat_AS_DOUBLE(value), 0, 0, 0)); #if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(value)) { - input = new ShaderInput(name, LVecBase4i((int)PyInt_AS_LONG(value), 0, 0, 0)); + input = ShaderInput(move(name), LVecBase4i((int)PyInt_AS_LONG(value), 0, 0, 0)); #endif } else if (PyLong_Check(value)) { - input = new ShaderInput(name, LVecBase4i((int)PyLong_AsLong(value), 0, 0, 0)); + input = ShaderInput(move(name), LVecBase4i((int)PyLong_AsLong(value), 0, 0, 0)); } else { Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs"); return; } - attrib->_inputs[move(name)] = input; + attrib->_inputs[input.get_name()] = move(input); } node->set_attrib(ShaderAttrib::return_new(attrib)); diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index 747f322a36..ecff479445 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -1482,7 +1482,7 @@ get_net_collide_mask() const { * Returns a ClipPlaneAttrib which represents the union of all of the clip * planes that have been turned *off* at this level and below. */ -INLINE CPT(RenderAttrib) PandaNodePipelineReader:: +INLINE const RenderAttrib *PandaNodePipelineReader:: get_off_clip_planes() const { nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_off_clip_planes); return _cdata->_off_clip_planes; @@ -1493,7 +1493,7 @@ get_off_clip_planes() const { * contains the user bounding volume, the internal bounding volume, and all of * the children's bounding volumes. */ -INLINE CPT(BoundingVolume) PandaNodePipelineReader:: +INLINE const BoundingVolume *PandaNodePipelineReader:: get_bounds() const { nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_external_bounds); return _cdata->_external_bounds; diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index e9f3204ccd..b55f160588 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -827,6 +827,7 @@ private: friend class PandaNodePipelineReader; friend class EggLoader; friend class Extension; + friend class CullTraverserData; }; /** @@ -877,8 +878,8 @@ public: INLINE bool has_tag(const string &key) const; INLINE CollideMask get_net_collide_mask() const; - INLINE CPT(RenderAttrib) get_off_clip_planes() const; - INLINE CPT(BoundingVolume) get_bounds() const; + INLINE const RenderAttrib *get_off_clip_planes() const; + INLINE const BoundingVolume *get_bounds() const; INLINE int get_nested_vertices() const; INLINE bool is_final() const; INLINE int get_fancy_bits() const; @@ -906,6 +907,12 @@ private: }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const PandaNode &node) { node.output(out); return out; diff --git a/panda/src/pgraph/polylightEffect.cxx b/panda/src/pgraph/polylightEffect.cxx index f2c49b7f91..acbd41b18f 100644 --- a/panda/src/pgraph/polylightEffect.cxx +++ b/panda/src/pgraph/polylightEffect.cxx @@ -136,9 +136,9 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran if (light->is_enabled()) { // if enabled get all the properties PN_stdfloat light_radius = light->get_radius(); // Calculate the distance of the node from the light dist = - // light_iter->second->get_distance(data->_node_path.get_node_path()); + // light_iter->second->get_distance(data->get_node_path()); const NodePath lightnp = *light_iter; - LPoint3 relative_point = data->_node_path.get_node_path().get_relative_point(lightnp, light->get_pos()); + LPoint3 relative_point = data->get_node_path().get_relative_point(lightnp, light->get_pos()); if (_effect_center[2]) { dist = (relative_point - _effect_center).length(); // this counts height difference @@ -155,7 +155,7 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran // LPoint3 camera_position = camera.get_relative_point(lightnp, // light->get_pos()); LPoint3 camera_position = lightnp.get_relative_point(camera, LPoint3(0,0,0)); - LPoint3 avatar_position = lightnp.get_relative_point(data->_node_path.get_node_path(), LPoint3(0,0,0)); + LPoint3 avatar_position = lightnp.get_relative_point(data->get_node_path(), LPoint3(0,0,0)); LVector3 light_camera = camera_position - light_position; LVector3 light_avatar = avatar_position - light_position; light_camera.normalize(); @@ -263,7 +263,7 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran if (num_lights) { // was_under_polylight = true; - // data->_node_path.get_node_path().set_color_scale_off(); + // data->get_node_path().set_color_scale_off(); if (polylight_info) pgraph_cat.debug() << "num lights = " << num_lights << endl; @@ -320,8 +320,8 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran else { if (was_under_polylight) { // under no polylight influence...so clear the color scale - // data->_node_path.get_node_path().clear_color_scale(); - // data->_node_path.get_node_path().set_color_scale(scene_color); + // data->get_node_path().clear_color_scale(); + // data->get_node_path().set_color_scale(scene_color); was_under_polylight = false; } } diff --git a/panda/src/pgraph/portalClipper.h b/panda/src/pgraph/portalClipper.h index a1c8f5b179..b6cee9e3a7 100644 --- a/panda/src/pgraph/portalClipper.h +++ b/panda/src/pgraph/portalClipper.h @@ -119,7 +119,7 @@ private: LPoint2 _reduced_viewport_max; CPT(RenderState) _clip_state; // each portal node needs to know the clip state of its "parent" portal Node - PortalNode *_portal_node; // current working portal for dereference ease + const PortalNode *_portal_node; // current working portal for dereference ease // int _num_vert; LVertex _coords[4]; diff --git a/panda/src/pgraph/portalNode.cxx b/panda/src/pgraph/portalNode.cxx index d70eacd17e..dccfef23c4 100644 --- a/panda/src/pgraph/portalNode.cxx +++ b/panda/src/pgraph/portalNode.cxx @@ -213,7 +213,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { portal_viewer->get_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max); PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum(); - if (portal_viewer->prepare_portal(data._node_path.get_node_path())) { + if (portal_viewer->prepare_portal(data.get_node_path())) { if ((reduced_frustum = portal_viewer->get_reduced_frustum())) { // remember current clip state, we might change it CPT(RenderState) old_clip_state = portal_viewer->get_clip_state(); @@ -241,7 +241,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // camera space to this portal node's space (because the clip planes // are attached to this node) PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy()); - CPT(TransformState) temp_frustum_transform = data._node_path.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); + CPT(TransformState) temp_frustum_transform = data.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); portal_cat.spam() << "clipping plane frustum transform " << *temp_frustum_transform << endl; portal_cat.spam() << "frustum before transform " << *temp_bh << endl; diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 334898a510..3a7b511381 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -22,7 +22,7 @@ LightReMutex *RenderAttrib::_attribs_lock = NULL; RenderAttrib::Attribs *RenderAttrib::_attribs = NULL; TypeHandle RenderAttrib::_type_handle; -int RenderAttrib::_garbage_index = 0; +size_t RenderAttrib::_garbage_index = 0; PStatCollector RenderAttrib::_garbage_collect_pcollector("*:State Cache:Garbage Collect"); @@ -195,8 +195,8 @@ list_attribs(ostream &out) { LightReMutexHolder holder(*_attribs_lock); out << _attribs->get_num_entries() << " attribs:\n"; - int size = _attribs->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _attribs->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_attribs->has_element(si)) { continue; } @@ -219,7 +219,9 @@ garbage_collect() { PStatTimer timer(_garbage_collect_pcollector); int orig_size = _attribs->get_num_entries(); +#ifdef _DEBUG nassertr(_attribs->validate(), 0); +#endif // How many elements to process this pass? int size = _attribs->get_size(); @@ -230,11 +232,9 @@ garbage_collect() { num_this_pass = min(num_this_pass, size); int stop_at_element = (_garbage_index + num_this_pass) % size; - int num_elements = 0; - int si = _garbage_index; + size_t si = _garbage_index; do { if (_attribs->has_element(si)) { - ++num_elements; RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si); if (attrib->get_ref_count() == 1) { // This attrib has recently been unreffed to 1 (the one we added when @@ -250,9 +250,12 @@ garbage_collect() { si = (si + 1) % size; } while (si != stop_at_element); _garbage_index = si; - nassertr(_attribs->validate(), 0); - int new_size = _attribs->get_num_entries(); +#ifdef _DEBUG + nassertr(_attribs->validate(), 0); +#endif + + size_t new_size = _attribs->get_num_entries(); return orig_size - new_size; } @@ -272,8 +275,8 @@ validate_attribs() { pgraph_cat.error() << "RenderAttrib::_attribs cache is invalid!\n"; - int size = _attribs->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _attribs->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_attribs->has_element(si)) { continue; } @@ -285,14 +288,14 @@ validate_attribs() { return false; } - int size = _attribs->get_size(); - int si = 0; + size_t size = _attribs->get_size(); + size_t si = 0; while (si < size && !_attribs->has_element(si)) { ++si; } nassertr(si < size, false); nassertr(_attribs->get_key(si)->get_ref_count() >= 0, false); - int snext = si; + size_t snext = si; ++snext; while (snext < size && !_attribs->has_element(snext)) { ++snext; diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index 12dd33b720..9d6ed83a1a 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -196,7 +196,7 @@ private: // This keeps track of our current position through the garbage collection // cycle. - static int _garbage_index; + static size_t _garbage_index; static PStatCollector _garbage_collect_pcollector; diff --git a/panda/src/pgraph/renderEffect.cxx b/panda/src/pgraph/renderEffect.cxx index ceada3a109..09572cc445 100644 --- a/panda/src/pgraph/renderEffect.cxx +++ b/panda/src/pgraph/renderEffect.cxx @@ -160,7 +160,7 @@ has_adjust_transform() const { */ void RenderEffect:: adjust_transform(CPT(TransformState) &, CPT(TransformState) &, - PandaNode *) const { + const PandaNode *) const { } /** diff --git a/panda/src/pgraph/renderEffect.h b/panda/src/pgraph/renderEffect.h index f8a55de869..d739f5cee7 100644 --- a/panda/src/pgraph/renderEffect.h +++ b/panda/src/pgraph/renderEffect.h @@ -68,7 +68,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; PUBLISHED: INLINE int compare_to(const RenderEffect &other) const; diff --git a/panda/src/pgraph/renderEffects.cxx b/panda/src/pgraph/renderEffects.cxx index 18c7565a3f..639f11be9b 100644 --- a/panda/src/pgraph/renderEffects.cxx +++ b/panda/src/pgraph/renderEffects.cxx @@ -492,7 +492,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data, void RenderEffects:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const { + const PandaNode *node) const { Effects::const_iterator ei; for (ei = _effects.begin(); ei != _effects.end(); ++ei) { (*ei)._effect->adjust_transform(net_transform, node_transform, node); diff --git a/panda/src/pgraph/renderEffects.h b/panda/src/pgraph/renderEffects.h index e1ece7d2b3..6ccf7eb05f 100644 --- a/panda/src/pgraph/renderEffects.h +++ b/panda/src/pgraph/renderEffects.h @@ -102,7 +102,7 @@ public: INLINE bool has_adjust_transform() const; void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; static void init_states(); diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index c6d0520ec4..75b6f1070a 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -522,7 +522,8 @@ INLINE void RenderState:: check_hash() const { // This pretends to be a const function, even though it's not, because it // only updates a transparent cache value. - if ((_flags & F_hash_known) == 0) { + if ((_flags & F_hash_known) != 0) { + } else { ((RenderState *)this)->calc_hash(); } } diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index de3a58b2ba..e92f284cc1 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -40,7 +40,7 @@ LightReMutex *RenderState::_states_lock = NULL; RenderState::States *RenderState::_states = NULL; const RenderState *RenderState::_empty_state = NULL; UpdateSeq RenderState::_last_cycle_detect; -int RenderState::_garbage_index = 0; +size_t RenderState::_garbage_index = 0; PStatCollector RenderState::_cache_update_pcollector("*:State Cache:Update"); PStatCollector RenderState::_garbage_collect_pcollector("*:State Cache:Garbage Collect"); @@ -75,6 +75,10 @@ RenderState() : _cache_stats.add_num_states(1); _read_overrides = NULL; _generated_shader = NULL; + +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** @@ -97,6 +101,10 @@ RenderState(const RenderState ©) : _cache_stats.add_num_states(1); _read_overrides = NULL; _generated_shader = NULL; + +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** @@ -617,7 +625,7 @@ adjust_all_priorities(int adjustment) const { */ bool RenderState:: unref() const { - if (!state_cache || garbage_collect_states) { + if (garbage_collect_states || !state_cache) { // If we're not using the cache at all, or if we're relying on garbage // collection, just allow the pointer to unref normally. return ReferenceCount::unref(); @@ -774,8 +782,8 @@ get_num_unused_states() { typedef pmap StateCount; StateCount state_count; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -871,8 +879,8 @@ clear_cache() { TempStates temp_states; temp_states.reserve(orig_size); - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -938,27 +946,30 @@ garbage_collect() { if (_states == (States *)NULL || !garbage_collect_states) { return num_attribs; } + + bool break_and_uniquify = (auto_break_cycles && uniquify_transforms); + LightReMutexHolder holder(*_states_lock); PStatTimer timer(_garbage_collect_pcollector); int orig_size = _states->get_num_entries(); // How many elements to process this pass? - int size = _states->get_size(); - int num_this_pass = int(size * garbage_collect_states_rate); - if (num_this_pass <= 0) { + size_t size = _states->get_size(); + size_t num_this_pass = int((int)size * garbage_collect_states_rate); + if (size <= 0 || num_this_pass <= 0) { return num_attribs; } - num_this_pass = min(num_this_pass, size); - int stop_at_element = (_garbage_index + num_this_pass) % size; - int num_elements = 0; - int si = _garbage_index; + size_t si = _garbage_index; + + num_this_pass = min(num_this_pass, size); + size_t stop_at_element = (si + num_this_pass) % (size - 1); + do { if (_states->has_element(si)) { - ++num_elements; RenderState *state = (RenderState *)_states->get_key(si); - if (auto_break_cycles && uniquify_states) { + if (break_and_uniquify) { if (state->get_cache_ref_count() > 0 && state->get_ref_count() == state->get_cache_ref_count()) { // If we have removed all the references to this state not in the @@ -982,10 +993,13 @@ garbage_collect() { } } - si = (si + 1) % size; + si = (si + 1) & (size - 1); } while (si != stop_at_element); _garbage_index = si; + +#ifdef _DEBUG nassertr(_states->validate(), 0); +#endif int new_size = _states->get_num_entries(); return orig_size - new_size + num_attribs; @@ -999,8 +1013,8 @@ void RenderState:: clear_munger_cache() { LightReMutexHolder holder(*_states_lock); - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1034,8 +1048,8 @@ list_cycles(ostream &out) { VisitedStates visited; CompositionCycleDesc cycle_desc; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1113,8 +1127,8 @@ list_states(ostream &out) { out << _states->get_num_entries() << " states:\n"; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1148,14 +1162,14 @@ validate_states() { return false; } - int size = _states->get_size(); - int si = 0; + size_t size = _states->get_size(); + size_t si = 0; while (si < size && !_states->has_element(si)) { ++si; } nassertr(si < size, false); nassertr(_states->get_key(si)->get_ref_count() >= 0, false); - int snext = si; + size_t snext = si; ++snext; while (snext < size && !_states->has_element(snext)) { ++snext; diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index c15efe68ad..f91f02cd3e 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -278,7 +278,7 @@ private: // This keeps track of our current position through the garbage collection // cycle. - static int _garbage_index; + static size_t _garbage_index; static PStatCollector _cache_update_pcollector; static PStatCollector _garbage_collect_pcollector; @@ -368,6 +368,12 @@ private: friend class Extension; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const RenderState &state) { state.output(out); return out; diff --git a/panda/src/pgraph/shaderAttrib.I b/panda/src/pgraph/shaderAttrib.I index f3667b27d9..6513604ae9 100644 --- a/panda/src/pgraph/shaderAttrib.I +++ b/panda/src/pgraph/shaderAttrib.I @@ -110,7 +110,7 @@ has_shader_input(CPT_InternalName id) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -118,7 +118,7 @@ set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -126,7 +126,7 @@ set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -134,7 +134,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) cons */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } @@ -143,7 +143,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) cons */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -151,7 +151,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) cons */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -159,7 +159,7 @@ set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -167,7 +167,7 @@ set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -175,7 +175,7 @@ set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -183,7 +183,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) const */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -191,7 +191,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) const */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -199,7 +199,7 @@ set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -207,7 +207,7 @@ set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, Texture *tex, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), tex, priority)); + return set_shader_input(ShaderInput(move(id), tex, priority)); } /** @@ -215,7 +215,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const NodePath &np, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), np, priority)); + return set_shader_input(ShaderInput(move(id), np, priority)); } /** @@ -223,7 +223,7 @@ set_shader_input(CPT_InternalName id, const NodePath &np, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, double n1, double n2, double n3, double n4, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), LVecBase4((PN_stdfloat)n1, (PN_stdfloat)n2, (PN_stdfloat)n3, (PN_stdfloat)n4), priority)); + return set_shader_input(ShaderInput(move(id), LVecBase4((PN_stdfloat)n1, (PN_stdfloat)n2, (PN_stdfloat)n3, (PN_stdfloat)n4), priority)); } INLINE bool ShaderAttrib:: diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index 2e6ac7cd77..6435ceed5d 100644 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -193,13 +193,13 @@ clear_flag(int flag) const { * */ CPT(RenderAttrib) ShaderAttrib:: -set_shader_input(const ShaderInput *input) const { +set_shader_input(ShaderInput input) const { ShaderAttrib *result = new ShaderAttrib(*this); - Inputs::iterator i = result->_inputs.find(input->get_name()); + Inputs::iterator i = result->_inputs.find(input.get_name()); if (i == result->_inputs.end()) { - result->_inputs.insert(Inputs::value_type(input->get_name(), input)); + result->_inputs.insert(Inputs::value_type(input.get_name(), move(input))); } else { - i->second = input; + i->second = move(input); } return return_new(result); } @@ -248,13 +248,13 @@ clear_all_shader_inputs() const { * Returns the ShaderInput of the given name. If no such name is found, this * function does not return NULL --- it returns the "blank" ShaderInput. */ -const ShaderInput *ShaderAttrib:: +const ShaderInput &ShaderAttrib:: get_shader_input(const InternalName *id) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - return ShaderInput::get_blank(); - } else { + if (i != _inputs.end()) { return (*i).second; + } else { + return ShaderInput::get_blank(); } } @@ -262,7 +262,7 @@ get_shader_input(const InternalName *id) const { * Returns the ShaderInput of the given name. If no such name is found, this * function does not return NULL --- it returns the "blank" ShaderInput. */ -const ShaderInput *ShaderAttrib:: +const ShaderInput &ShaderAttrib:: get_shader_input(const string &id) const { return get_shader_input(InternalName::make(id)); } @@ -275,20 +275,21 @@ const NodePath &ShaderAttrib:: get_shader_input_nodepath(const InternalName *id) const { static NodePath resfail; Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return resfail; - } else { - const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_nodepath) { + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; + if (p.get_value_type() == ShaderInput::M_nodepath) { + return ((const ParamNodePath *)p.get_value())->get_value(); + } else { ostringstream strm; strm << "Shader input " << id->get_name() << " is not a nodepath.\n"; nassert_raise(strm.str()); return resfail; } - return p->get_nodepath(); + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return resfail; } // Satisfy compiler. @@ -303,19 +304,14 @@ LVecBase4 ShaderAttrib:: get_shader_input_vector(InternalName *id) const { static LVecBase4 resfail(0,0,0,0); Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return resfail; - } else { - const ShaderInput *p = (*i).second; + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; - if (p->get_value_type() == ShaderInput::M_vector) { - return p->get_vector(); + if (p.get_value_type() == ShaderInput::M_vector) { + return p.get_vector(); - } else if (p->get_value_type() == ShaderInput::M_numeric && p->get_ptr()._size <= 4) { - const Shader::ShaderPtrData &ptr = p->get_ptr(); + } else if (p.get_value_type() == ShaderInput::M_numeric && p.get_ptr()._size <= 4) { + const Shader::ShaderPtrData &ptr = p.get_ptr(); switch (ptr._type) { case Shader::SPT_float: @@ -339,19 +335,23 @@ get_shader_input_vector(InternalName *id) const { } } - } else if (p->get_value_type() == ShaderInput::M_param) { + } else if (p.get_value_type() == ShaderInput::M_param) { // Temporary solution until the new param system - ParamValueBase *param = p->get_param(); + TypedWritableReferenceCount *param = p.get_value(); if (param != NULL && param->is_of_type(ParamVecBase4::get_class_type())) { - return ((const ParamVecBase4 *) param)->get_value(); + return ((const ParamVecBase4 *)param)->get_value(); } } ostringstream strm; strm << "Shader input " << id->get_name() << " is not a vector.\n"; nassert_raise(strm.str()); - return resfail; + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); } + return resfail; } /** @@ -361,21 +361,21 @@ get_shader_input_vector(InternalName *id) const { const Shader::ShaderPtrData *ShaderAttrib:: get_shader_input_ptr(const InternalName *id) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return NULL; - } else { - const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_numeric && - p->get_value_type() != ShaderInput::M_vector) { + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; + if (p.get_value_type() != ShaderInput::M_numeric && + p.get_value_type() != ShaderInput::M_vector) { ostringstream strm; strm << "Shader input " << id->get_name() << " is not a PTA(float/double) type.\n"; nassert_raise(strm.str()); return NULL; } - return &(p->get_ptr()); + return &(p.get_ptr()); + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return NULL; } } @@ -389,24 +389,39 @@ get_shader_input_ptr(const InternalName *id) const { Texture *ShaderAttrib:: get_shader_input_texture(const InternalName *id, SamplerState *sampler) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return NULL; - } else { - const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_texture && - p->get_value_type() != ShaderInput::M_texture_sampler) { + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; + switch (p.get_value_type()) { + case ShaderInput::M_texture: + { + Texture *tex = (Texture *)p.get_value(); + if (sampler) { + *sampler = tex->get_default_sampler(); + } + return tex; + } + + case ShaderInput::M_texture_sampler: + { + const ParamTextureSampler *param = (const ParamTextureSampler *)p.get_value(); + if (sampler) { + *sampler = param->get_sampler(); + } + return param->get_texture(); + } + + default: ostringstream strm; strm << "Shader input " << id->get_name() << " is not a texture.\n"; nassert_raise(strm.str()); return NULL; } - if (sampler != NULL) { - *sampler = p->get_sampler(); - } - return p->get_texture(); + + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return NULL; } } @@ -417,22 +432,17 @@ get_shader_input_texture(const InternalName *id, SamplerState *sampler) const { const LMatrix4 &ShaderAttrib:: get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return LMatrix4::ident_mat(); - } else { - const ShaderInput *p = (*i).second; + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; - if (p->get_value_type() == ShaderInput::M_nodepath) { - const NodePath &np = p->get_nodepath(); + if (p.get_value_type() == ShaderInput::M_nodepath) { + const NodePath &np = p.get_nodepath(); nassertr(!np.is_empty(), LMatrix4::ident_mat()); return np.get_transform()->get_mat(); - } else if (p->get_value_type() == ShaderInput::M_numeric && - p->get_ptr()._size >= 16 && (p->get_ptr()._size & 15) == 0) { - const Shader::ShaderPtrData &ptr = p->get_ptr(); + } else if (p.get_value_type() == ShaderInput::M_numeric && + p.get_ptr()._size >= 16 && (p.get_ptr()._size & 15) == 0) { + const Shader::ShaderPtrData &ptr = p.get_ptr(); switch (ptr._type) { case Shader::SPT_float: { @@ -460,6 +470,11 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const { strm << "Shader input " << id->get_name() << " is not a NodePath, LMatrix4 or PTA_LMatrix4.\n"; nassert_raise(strm.str()); return LMatrix4::ident_mat(); + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return LMatrix4::ident_mat(); } } @@ -476,11 +491,11 @@ get_shader_input_buffer(const InternalName *id) const { nassert_raise(strm.str()); return NULL; } else { - const ShaderInput *p = (*i).second; + const ShaderInput &p = (*i).second; - if (p->get_value_type() == ShaderInput::M_buffer) { + if (p.get_value_type() == ShaderInput::M_buffer) { ShaderBuffer *value; - DCAST_INTO_R(value, p->_value, NULL); + DCAST_INTO_R(value, p._value, NULL); return value; } @@ -615,8 +630,7 @@ get_hash_impl() const { Inputs::const_iterator ii; for (ii = _inputs.begin(); ii != _inputs.end(); ++ii) { - hash = pointer_hash::add_hash(hash, (*ii).first); - hash = pointer_hash::add_hash(hash, (*ii).second); + hash = (*ii).second.add_hash(hash); } return hash; @@ -649,13 +663,13 @@ compose_impl(const RenderAttrib *other) const { Inputs::const_iterator iover; for (iover=over->_inputs.begin(); iover!=over->_inputs.end(); ++iover) { const InternalName *id = (*iover).first; - const ShaderInput *dover = (*iover).second; + const ShaderInput &dover = (*iover).second; Inputs::iterator iattr = attr->_inputs.find(id); if (iattr == attr->_inputs.end()) { attr->_inputs.insert(Inputs::value_type(id,dover)); } else { - const ShaderInput *dattr = (*iattr).second; - if (dattr->get_priority() <= dover->get_priority()) { + const ShaderInput &dattr = (*iattr).second; + if (dattr.get_priority() <= dover.get_priority()) { iattr->second = iover->second; } } diff --git a/panda/src/pgraph/shaderAttrib.h b/panda/src/pgraph/shaderAttrib.h index ebdcca499c..719106c0b6 100644 --- a/panda/src/pgraph/shaderAttrib.h +++ b/panda/src/pgraph/shaderAttrib.h @@ -71,7 +71,7 @@ PUBLISHED: CPT(RenderAttrib) clear_shader() const; // Shader Inputs - CPT(RenderAttrib) set_shader_input(const ShaderInput *inp) const; + CPT(RenderAttrib) set_shader_input(ShaderInput input) const; INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, Texture *tex, int priority=0) const; INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, const NodePath &np, int priority=0) const; @@ -104,8 +104,8 @@ PUBLISHED: INLINE bool has_shader_input(CPT_InternalName id) const; const Shader *get_shader() const; - const ShaderInput *get_shader_input(const InternalName *id) const; - const ShaderInput *get_shader_input(const string &id) const; + const ShaderInput &get_shader_input(const InternalName *id) const; + const ShaderInput &get_shader_input(const string &id) const; const NodePath &get_shader_input_nodepath(const InternalName *id) const; LVecBase4 get_shader_input_vector(InternalName *id) const; @@ -145,7 +145,9 @@ private: bool _auto_ramp_on; bool _auto_shadow_on; - typedef pmap Inputs; + // We don't keep a reference to the InternalName, since this is also already + // stored on the ShaderInput object. + typedef pmap Inputs; Inputs _inputs; friend class Extension; diff --git a/panda/src/pgraph/shaderInput.I b/panda/src/pgraph/shaderInput.I index 7344717e47..30d1bab97a 100644 --- a/panda/src/pgraph/shaderInput.I +++ b/panda/src/pgraph/shaderInput.I @@ -13,13 +13,6 @@ * @date 2010-04-06 */ -/** - * - */ -INLINE ShaderInput:: -~ShaderInput() { -} - /** * */ @@ -424,6 +417,81 @@ ShaderInput(CPT_InternalName name, const LVecBase2i &vec, int priority) : { } +/** + * + */ +INLINE bool ShaderInput:: +operator == (const ShaderInput &other) const { + if (_type != other._type || _name != other._name || _priority != other._priority) { + return false; + } + switch (_type) { + case M_invalid: + return true; + + case M_vector: + return _stored_vector == other._stored_vector; + + case M_numeric: + return _stored_ptr._ptr == other._stored_ptr._ptr; + + default: + return _value == other._value; + } +} + +/** + * + */ +INLINE bool ShaderInput:: +operator != (const ShaderInput &other) const { + if (_type != other._type || _name != other._name || _priority != other._priority) { + return true; + } + switch (_type) { + case M_invalid: + return false; + + case M_vector: + return _stored_vector != other._stored_vector; + + case M_numeric: + return _stored_ptr._ptr != other._stored_ptr._ptr; + + default: + return _value != other._value; + } +} + +/** + * + */ +INLINE bool ShaderInput:: +operator < (const ShaderInput &other) const { + if (_type != other._type) { + return (_type < other._type); + } + if (_name != other._name) { + return (_name < other._name); + } + if (_priority != other._priority) { + return (_priority < other._priority); + } + switch (_type) { + case M_invalid: + return false; + + case M_vector: + return _stored_vector < other._stored_vector; + + case M_numeric: + return _stored_ptr._ptr < other._stored_ptr._ptr; + + default: + return _value < other._value; + } +} + /** * */ @@ -471,3 +539,11 @@ INLINE ParamValueBase *ShaderInput:: get_param() const { return DCAST(ParamValueBase, _value); } + +/** + * + */ +INLINE TypedWritableReferenceCount *ShaderInput:: +get_value() const { + return _value.p(); +} diff --git a/panda/src/pgraph/shaderInput.cxx b/panda/src/pgraph/shaderInput.cxx index 3ee38ef70a..44fb91cf23 100644 --- a/panda/src/pgraph/shaderInput.cxx +++ b/panda/src/pgraph/shaderInput.cxx @@ -15,18 +15,13 @@ #include "paramNodePath.h" #include "paramTexture.h" -TypeHandle ShaderInput::_type_handle; - /** * Returns a static ShaderInput object with name NULL, priority zero, type * INVALID, and all value-fields cleared. */ -const ShaderInput *ShaderInput:: +const ShaderInput &ShaderInput:: get_blank() { - static CPT(ShaderInput) blank; - if (blank == 0) { - blank = new ShaderInput(NULL, 0); - } + static ShaderInput blank(nullptr, 0); return blank; } @@ -66,6 +61,30 @@ ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, in { } +/** + * + */ +size_t ShaderInput:: +add_hash(size_t hash) const { + hash = int_hash::add_hash(hash, _type); + hash = pointer_hash::add_hash(hash, _name); + hash = int_hash::add_hash(hash, _priority); + + switch (_type) { + case M_invalid: + return hash; + + case M_vector: + return _stored_vector.add_hash(hash); + + case M_numeric: + return pointer_hash::add_hash(hash, _stored_ptr._ptr); + + default: + return pointer_hash::add_hash(hash, _value); + } +} + /** * Warning: no error checking is done. This *will* crash if get_value_type() * is not M_nodepath. diff --git a/panda/src/pgraph/shaderInput.h b/panda/src/pgraph/shaderInput.h index c91c790618..ebf630fcaa 100644 --- a/panda/src/pgraph/shaderInput.h +++ b/panda/src/pgraph/shaderInput.h @@ -17,7 +17,6 @@ #define SHADERINPUT_H #include "pandabase.h" -#include "typedWritableReferenceCount.h" #include "pointerTo.h" #include "internalName.h" #include "paramValue.h" @@ -37,10 +36,7 @@ * This is a small container class that can hold any one of the value types * that can be passed as input to a shader. */ -class EXPCL_PANDA_PGRAPH ShaderInput : public TypedWritableReferenceCount { -public: - INLINE ~ShaderInput(); - +class EXPCL_PANDA_PGRAPH ShaderInput { PUBLISHED: // Used when binding texture images. enum AccessFlags { @@ -49,7 +45,7 @@ PUBLISHED: A_layered = 0x04, }; - static const ShaderInput *get_blank(); + static const ShaderInput &get_blank(); INLINE ShaderInput(CPT_InternalName name, int priority=0); INLINE ShaderInput(CPT_InternalName name, Texture *tex, int priority=0); INLINE ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority=0); @@ -102,6 +98,12 @@ PUBLISHED: M_buffer, }; + INLINE bool operator == (const ShaderInput &other) const; + INLINE bool operator != (const ShaderInput &other) const; + INLINE bool operator < (const ShaderInput &other) const; + + size_t add_hash(size_t hash) const; + INLINE const InternalName *get_name() const; INLINE int get_value_type() const; @@ -114,7 +116,10 @@ PUBLISHED: const SamplerState &get_sampler() const; public: + ShaderInput() DEFAULT_CTOR; + INLINE ParamValueBase *get_param() const; + INLINE TypedWritableReferenceCount *get_value() const; static void register_with_read_factory(); @@ -127,26 +132,8 @@ private: int _type; friend class ShaderAttrib; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - TypedWritableReferenceCount::init_type(); - register_type(_type_handle, "ShaderInput", - TypedWritableReferenceCount::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 "shaderInput.I" #endif // SHADERINPUT_H diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 4d1aade0ec..be1ed4a15a 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -29,7 +29,7 @@ TransformState::States *TransformState::_states = NULL; CPT(TransformState) TransformState::_identity_state; CPT(TransformState) TransformState::_invalid_state; UpdateSeq TransformState::_last_cycle_detect; -int TransformState::_garbage_index = 0; +size_t TransformState::_garbage_index = 0; bool TransformState::_uniquify_matrix = true; PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update"); @@ -62,6 +62,10 @@ TransformState() : _lock("TransformState") { _flags = F_is_identity | F_singular_known | F_is_2d; _inv_mat = (LMatrix4 *)NULL; _cache_stats.add_num_states(1); + +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** @@ -608,33 +612,74 @@ compose(const TransformState *other) const { return do_compose(other); } - // Is this composition already cached? - CPT(TransformState) result; - { - LightReMutexHolder holder(*_states_lock); - int index = _composition_cache.find(other); - if (index != -1) { - const Composition &comp = _composition_cache.get_data(index); - result = comp._result; - } - if (result != (TransformState *)NULL) { - _cache_stats.inc_hits(); - } - } + LightReMutexHolder holder(*_states_lock); - if (result != (TransformState *)NULL) { - // Success! - return result; + // Is this composition already cached? + int index = _composition_cache.find(other); + if (index != -1) { + const Composition &comp = _composition_cache.get_data(index); + if (comp._result != nullptr) { + // Success! + _cache_stats.inc_hits(); + return comp._result; + } } // Not in the cache. Compute a new result. It's important that we don't // hold the lock while we do this, or we lose the benefit of // parallelization. - result = do_compose(other); + CPT(TransformState) result = do_compose(other); - // It's OK to cast away the constness of this pointer, because the cache is - // a transparent property of the class. - return ((TransformState *)this)->store_compose(other, result); + if (index != -1) { + Composition &comp = _composition_cache.modify_data(index); + // Well, it wasn't cached already, but we already had an entry (probably + // created for the reverse direction), so use the same entry to store + // the new result. + comp._result = result; + + if (result != (const TransformState *)this) { + // See the comments below about the need to up the reference count + // only when the result is not the same as this. + result->cache_ref(); + } + // Here's the cache! + _cache_stats.inc_hits(); + return result; + } + _cache_stats.inc_misses(); + + // We need to make a new cache entry, both in this object and in the other + // object. We make both records so the other TransformState object will + // know to delete the entry from this object when it destructs, and vice- + // versa. + + // The cache entry in this object is the only one that indicates the result; + // the other will be NULL for now. + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(_composition_cache.get_size() == 0); + + _composition_cache[other]._result = result; + + if (other != this) { + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(other->_composition_cache.get_size() == 0); + other->_composition_cache[this]._result = NULL; + } + + if (result != (TransformState *)this) { + // If the result of do_compose() is something other than this, explicitly + // increment the reference count. We have to be sure to decrement it + // again later, when the composition entry is removed from the cache. + result->cache_ref(); + + // (If the result was just this again, we still store the result, but we + // don't increment the reference count, since that would be a self- + // referential leak.) + } + + _cache_stats.maybe_report("TransformState"); + + return result; } /** @@ -676,32 +721,69 @@ invert_compose(const TransformState *other) const { LightReMutexHolder holder(*_states_lock); - CPT(TransformState) result; - { - LightReMutexHolder holder(*_states_lock); - int index = _invert_composition_cache.find(other); - if (index != -1) { - const Composition &comp = _invert_composition_cache.get_data(index); - result = comp._result; - } - if (result != (TransformState *)NULL) { + int index = _invert_composition_cache.find(other); + if (index != -1) { + const Composition &comp = _invert_composition_cache.get_data(index); + if (comp._result != nullptr) { + // Success! _cache_stats.inc_hits(); + return comp._result; } } - if (result != (TransformState *)NULL) { - // Success! - return result; - } - // Not in the cache. Compute a new result. It's important that we don't // hold the lock while we do this, or we lose the benefit of // parallelization. - result = do_invert_compose(other); + CPT(TransformState) result = do_invert_compose(other); - // It's OK to cast away the constness of this pointer, because the cache is - // a transparent property of the class. - return ((TransformState *)this)->store_invert_compose(other, result); + // Is this composition already cached? + if (index != -1) { + Composition &comp = _invert_composition_cache.modify_data(index); + // Well, it wasn't cached already, but we already had an entry (probably + // created for the reverse direction), so use the same entry to store + // the new result. + comp._result = result; + + if (result != (const TransformState *)this) { + // See the comments below about the need to up the reference count + // only when the result is not the same as this. + result->cache_ref(); + } + // Here's the cache! + _cache_stats.inc_hits(); + return result; + } + _cache_stats.inc_misses(); + + // We need to make a new cache entry, both in this object and in the other + // object. We make both records so the other TransformState object will + // know to delete the entry from this object when it destructs, and vice- + // versa. + + // The cache entry in this object is the only one that indicates the result; + // the other will be NULL for now. + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0); + _invert_composition_cache[other]._result = result; + + if (other != this) { + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0); + other->_invert_composition_cache[this]._result = NULL; + } + + if (result != (TransformState *)this) { + // If the result of compose() is something other than this, explicitly + // increment the reference count. We have to be sure to decrement it + // again later, when the composition entry is removed from the cache. + result->cache_ref(); + + // (If the result was just this again, we still store the result, but we + // don't increment the reference count, since that would be a self- + // referential leak.) + } + + return result; } /** @@ -712,7 +794,7 @@ invert_compose(const TransformState *other) const { */ bool TransformState:: unref() const { - if (!transform_cache || garbage_collect_states) { + if (garbage_collect_states || !transform_cache) { // If we're not using the cache at all, or if we're relying on garbage // collection, just allow the pointer to unref normally. return ReferenceCount::unref(); @@ -760,8 +842,8 @@ bool TransformState:: validate_composition_cache() const { LightReMutexHolder holder(*_states_lock); - int size = _composition_cache.get_size(); - for (int i = 0; i < size; ++i) { + size_t size = _composition_cache.get_size(); + for (size_t i = 0; i < size; ++i) { if (!_composition_cache.has_element(i)) { continue; } @@ -955,15 +1037,15 @@ get_num_unused_states() { typedef pmap StateCount; StateCount state_count; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } const TransformState *state = _states->get_key(si); - int i; - int cache_size = state->_composition_cache.get_size(); + size_t i; + size_t cache_size = state->_composition_cache.get_size(); for (i = 0; i < cache_size; ++i) { if (state->_composition_cache.has_element(i)) { const TransformState *result = state->_composition_cache.get_data(i)._result; @@ -1053,8 +1135,8 @@ clear_cache() { TempStates temp_states; temp_states.reserve(orig_size); - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1116,27 +1198,30 @@ garbage_collect() { if (_states == (States *)NULL || !garbage_collect_states) { return 0; } + + bool break_and_uniquify = (auto_break_cycles && uniquify_transforms); + LightReMutexHolder holder(*_states_lock); PStatTimer timer(_garbage_collect_pcollector); - int orig_size = _states->get_num_entries(); + size_t orig_size = _states->get_num_entries(); // How many elements to process this pass? - int size = _states->get_size(); - int num_this_pass = int(size * garbage_collect_states_rate); - if (num_this_pass <= 0) { + size_t size = _states->get_size(); + size_t num_this_pass = int(size * garbage_collect_states_rate); + if (size <= 0 || num_this_pass <= 0) { return 0; } - num_this_pass = min(num_this_pass, size); - int stop_at_element = (_garbage_index + num_this_pass) % size; - int num_elements = 0; - int si = _garbage_index; + size_t si = _garbage_index; + + num_this_pass = min(num_this_pass, size); + size_t stop_at_element = (si + num_this_pass) & (size - 1); + do { if (_states->has_element(si)) { - ++num_elements; TransformState *state = (TransformState *)_states->get_key(si); - if (auto_break_cycles && uniquify_transforms) { + if (break_and_uniquify) { if (state->get_cache_ref_count() > 0 && state->get_ref_count() == state->get_cache_ref_count()) { // If we have removed all the references to this state not in the @@ -1160,10 +1245,13 @@ garbage_collect() { } } - si = (si + 1) % size; + si = (si + 1) & (size - 1); } while (si != stop_at_element); _garbage_index = si; + +#ifdef _DEBUG nassertr(_states->validate(), 0); +#endif int new_size = _states->get_num_entries(); return orig_size - new_size; @@ -1193,8 +1281,8 @@ list_cycles(ostream &out) { VisitedStates visited; CompositionCycleDesc cycle_desc; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1272,8 +1360,8 @@ list_states(ostream &out) { out << _states->get_num_entries() << " states:\n"; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1307,14 +1395,14 @@ validate_states() { return false; } - int size = _states->get_size(); - int si = 0; + size_t size = _states->get_size(); + size_t si = 0; while (si < size && !_states->has_element(si)) { ++si; } nassertr(si < size, false); nassertr(_states->get_key(si)->get_ref_count() >= 0, false); - int snext = si; + size_t snext = si; ++snext; while (snext < size && !_states->has_element(snext)) { ++snext; @@ -1533,150 +1621,6 @@ do_compose(const TransformState *other) const { } } -/** - * Stores the result of a composition in the cache. Returns the stored result - * (it may be a different object than the one passed in, due to another thread - * having computed the composition first). - */ -CPT(TransformState) TransformState:: -store_compose(const TransformState *other, const TransformState *result) { - // Identity should have already been screened. - nassertr(!is_identity(), other); - nassertr(!other->is_identity(), this); - - // So should have validity. - nassertr(!is_invalid(), this); - nassertr(!other->is_invalid(), other); - - LightReMutexHolder holder(*_states_lock); - - // Is this composition already cached? - int index = _composition_cache.find(other); - if (index != -1) { - Composition &comp = _composition_cache.modify_data(index); - if (comp._result == (const TransformState *)NULL) { - // Well, it wasn't cached already, but we already had an entry (probably - // created for the reverse direction), so use the same entry to store - // the new result. - comp._result = result; - - if (result != (const TransformState *)this) { - // See the comments below about the need to up the reference count - // only when the result is not the same as this. - result->cache_ref(); - } - } - // Here's the cache! - _cache_stats.inc_hits(); - return comp._result; - } - _cache_stats.inc_misses(); - - // We need to make a new cache entry, both in this object and in the other - // object. We make both records so the other TransformState object will - // know to delete the entry from this object when it destructs, and vice- - // versa. - - // The cache entry in this object is the only one that indicates the result; - // the other will be NULL for now. - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(_composition_cache.get_size() == 0); - - _composition_cache[other]._result = result; - - if (other != this) { - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(other->_composition_cache.get_size() == 0); - ((TransformState *)other)->_composition_cache[this]._result = NULL; - } - - if (result != (TransformState *)this) { - // If the result of do_compose() is something other than this, explicitly - // increment the reference count. We have to be sure to decrement it - // again later, when the composition entry is removed from the cache. - result->cache_ref(); - - // (If the result was just this again, we still store the result, but we - // don't increment the reference count, since that would be a self- - // referential leak.) - } - - _cache_stats.maybe_report("TransformState"); - - return result; -} - -/** - * Stores the result of a composition in the cache. Returns the stored result - * (it may be a different object than the one passed in, due to another thread - * having computed the composition first). - */ -CPT(TransformState) TransformState:: -store_invert_compose(const TransformState *other, const TransformState *result) { - // Identity should have already been screened. - nassertr(!is_identity(), other); - - // So should have validity. - nassertr(!is_invalid(), this); - nassertr(!other->is_invalid(), other); - - nassertr(other != this, make_identity()); - - LightReMutexHolder holder(*_states_lock); - - // Is this composition already cached? - int index = _invert_composition_cache.find(other); - if (index != -1) { - Composition &comp = ((TransformState *)this)->_invert_composition_cache.modify_data(index); - if (comp._result == (const TransformState *)NULL) { - // Well, it wasn't cached already, but we already had an entry (probably - // created for the reverse direction), so use the same entry to store - // the new result. - comp._result = result; - - if (result != (const TransformState *)this) { - // See the comments below about the need to up the reference count - // only when the result is not the same as this. - result->cache_ref(); - } - } - // Here's the cache! - _cache_stats.inc_hits(); - return comp._result; - } - _cache_stats.inc_misses(); - - // We need to make a new cache entry, both in this object and in the other - // object. We make both records so the other TransformState object will - // know to delete the entry from this object when it destructs, and vice- - // versa. - - // The cache entry in this object is the only one that indicates the result; - // the other will be NULL for now. - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0); - _invert_composition_cache[other]._result = result; - - if (other != this) { - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0); - ((TransformState *)other)->_invert_composition_cache[this]._result = NULL; - } - - if (result != (TransformState *)this) { - // If the result of compose() is something other than this, explicitly - // increment the reference count. We have to be sure to decrement it - // again later, when the composition entry is removed from the cache. - result->cache_ref(); - - // (If the result was just this again, we still store the result, but we - // don't increment the reference count, since that would be a self- - // referential leak.) - } - - return result; -} - /** * The private implemention of invert_compose(). */ diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 3287fb1853..3fd628be7c 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -234,9 +234,7 @@ private: static CPT(TransformState) return_unique(TransformState *state); CPT(TransformState) do_compose(const TransformState *other) const; - CPT(TransformState) store_compose(const TransformState *other, const TransformState *result); CPT(TransformState) do_invert_compose(const TransformState *other) const; - CPT(TransformState) store_invert_compose(const TransformState *other, const TransformState *result); void detect_and_break_cycles(); static bool r_detect_cycles(const TransformState *start_state, const TransformState *current_state, @@ -288,8 +286,8 @@ private: }; typedef SimpleHashMap CompositionCache; - CompositionCache _composition_cache; - CompositionCache _invert_composition_cache; + mutable CompositionCache _composition_cache; + mutable CompositionCache _invert_composition_cache; // This is used to mark nodes as we visit them to detect cycles. UpdateSeq _cycle_detect; @@ -297,7 +295,7 @@ private: // This keeps track of our current position through the garbage collection // cycle. - static int _garbage_index; + static size_t _garbage_index; static bool _uniquify_matrix; @@ -408,6 +406,12 @@ private: friend class Extension; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const TransformState &state) { state.output(out); return out; diff --git a/panda/src/pgraph/workingNodePath.I b/panda/src/pgraph/workingNodePath.I index 83010f2009..b74921827b 100644 --- a/panda/src/pgraph/workingNodePath.I +++ b/panda/src/pgraph/workingNodePath.I @@ -43,10 +43,10 @@ WorkingNodePath(const WorkingNodePath ©) : * traversal to the next node. */ INLINE WorkingNodePath:: -WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) { - _next = &parent; - _start = (NodePathComponent *)NULL; - _node = child; +WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) : + _next(&parent), + _start(nullptr), + _node(child) { nassertv(_node != _next->_node); } diff --git a/panda/src/pgraphnodes/ambientLight.h b/panda/src/pgraphnodes/ambientLight.h index e52122bdde..23623d7afe 100644 --- a/panda/src/pgraphnodes/ambientLight.h +++ b/panda/src/pgraphnodes/ambientLight.h @@ -33,7 +33,7 @@ protected: public: virtual PandaNode *make_copy() const; virtual void write(ostream &out, int indent_level) const; - virtual bool is_ambient_light() const; + virtual bool is_ambient_light() const FINAL; PUBLISHED: virtual int get_class_priority() const; diff --git a/panda/src/pgraphnodes/directionalLight.cxx b/panda/src/pgraphnodes/directionalLight.cxx index 127f994fbb..f0d84ffb9a 100644 --- a/panda/src/pgraphnodes/directionalLight.cxx +++ b/panda/src/pgraphnodes/directionalLight.cxx @@ -59,6 +59,7 @@ DirectionalLight(const string &name) : LightLensNode(name, new OrthographicLens()), _has_specular_color(false) { + _lenses[0]._lens->set_interocular_distance(0); } /** diff --git a/panda/src/pgraphnodes/fadeLodNode.cxx b/panda/src/pgraphnodes/fadeLodNode.cxx index 5f1f8d15ec..de952457e8 100644 --- a/panda/src/pgraphnodes/fadeLodNode.cxx +++ b/panda/src/pgraphnodes/fadeLodNode.cxx @@ -93,7 +93,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { consider_verify_lods(trav, data); Camera *camera = trav->get_scene()->get_camera_node(); - NodePath this_np = data._node_path.get_node_path(); + NodePath this_np = data.get_node_path(); FadeLODNodeData *ldata = DCAST(FadeLODNodeData, camera->get_aux_scene_data(this_np)); diff --git a/panda/src/pgraphnodes/lightLensNode.I b/panda/src/pgraphnodes/lightLensNode.I index ddb2808e86..8fff5b2533 100644 --- a/panda/src/pgraphnodes/lightLensNode.I +++ b/panda/src/pgraphnodes/lightLensNode.I @@ -15,7 +15,7 @@ * Returns whether this light is configured to cast shadows or not. */ INLINE bool LightLensNode:: -is_shadow_caster() { +is_shadow_caster() const { return _shadow_caster; } diff --git a/panda/src/pgraphnodes/lightLensNode.h b/panda/src/pgraphnodes/lightLensNode.h index d4e0c7385d..0c4b329b16 100644 --- a/panda/src/pgraphnodes/lightLensNode.h +++ b/panda/src/pgraphnodes/lightLensNode.h @@ -34,7 +34,7 @@ PUBLISHED: LightLensNode(const string &name, Lens *lens = new PerspectiveLens()); virtual ~LightLensNode(); - INLINE bool is_shadow_caster(); + INLINE bool is_shadow_caster() const; INLINE void set_shadow_caster(bool caster); INLINE void set_shadow_caster(bool caster, int buffer_xsize, int buffer_ysize, int sort = -10); diff --git a/panda/src/pgraphnodes/lodNode.cxx b/panda/src/pgraphnodes/lodNode.cxx index 5936b0634b..4c2ca87528 100644 --- a/panda/src/pgraphnodes/lodNode.cxx +++ b/panda/src/pgraphnodes/lodNode.cxx @@ -330,7 +330,7 @@ compute_child(CullTraverser *trav, CullTraverserData &data) { * trav->get_scene()->get_camera_node()->get_lod_scale())) { if (pgraph_cat.is_debug()) { pgraph_cat.debug() - << data._node_path << " at distance " << sqrt(dist2) + << data.get_node_path() << " at distance " << sqrt(dist2) << ", selected child " << index << "\n"; } @@ -340,7 +340,7 @@ compute_child(CullTraverser *trav, CullTraverserData &data) { if (pgraph_cat.is_debug()) { pgraph_cat.debug() - << data._node_path << " at distance " << sqrt(dist2) + << data.get_node_path() << " at distance " << sqrt(dist2) << ", no children in range.\n"; } @@ -393,20 +393,14 @@ show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data) { // And draw the spindle in this color. CullTraverserData next_data2(data, sw.get_spindle_viz()); - next_data2.apply_transform_and_state(trav, viz_transform, - RenderState::make_empty(), - RenderEffects::make_empty(), - ClipPlaneAttrib::make()); + next_data2.apply_transform(viz_transform); trav->traverse(next_data2); } // Draw the rings for this switch level. We do this after we have drawn // the geometry and the spindle. CullTraverserData next_data(data, sw.get_ring_viz()); - next_data.apply_transform_and_state(trav, viz_transform, - RenderState::make_empty(), - RenderEffects::make_empty(), - ClipPlaneAttrib::make()); + next_data.apply_transform(viz_transform); trav->traverse(next_data); } } @@ -650,7 +644,7 @@ do_auto_verify_lods(CullTraverser *trav, CullTraverserData &data) { const Switch &sw = cdata->_switch_vector[index]; ostringstream strm; strm - << "Level " << index << " geometry of " << data._node_path + << "Level " << index << " geometry of " << data.get_node_path() << " is larger than its switch radius; suggest radius of " << suggested_radius << " instead of " << sw.get_in() << " (configure verify-lods 0 to ignore this error)"; diff --git a/panda/src/pgraphnodes/nodeCullCallbackData.cxx b/panda/src/pgraphnodes/nodeCullCallbackData.cxx index d0bf763e98..b0cbd9d980 100644 --- a/panda/src/pgraphnodes/nodeCullCallbackData.cxx +++ b/panda/src/pgraphnodes/nodeCullCallbackData.cxx @@ -41,7 +41,7 @@ void NodeCullCallbackData:: upcall() { PandaNode *node = _data.node(); if (node->is_of_type(CallbackNode::get_class_type())) { - CallbackNode *cbnode = DCAST(CallbackNode, _data.node()); + CallbackNode *cbnode = (CallbackNode *)node; // OK, render this node. Rendering a CallbackNode means creating a // CullableObject for the draw_callback, if any. We don't need to pass diff --git a/panda/src/pgraphnodes/pointLight.cxx b/panda/src/pgraphnodes/pointLight.cxx index 564116ecac..d3f7192248 100644 --- a/panda/src/pgraphnodes/pointLight.cxx +++ b/panda/src/pgraphnodes/pointLight.cxx @@ -66,21 +66,27 @@ PointLight(const string &name) : { PT(Lens) lens; lens = new PerspectiveLens(90, 90); + lens->set_interocular_distance(0); lens->set_view_vector(1, 0, 0, 0, -1, 0); set_lens(0, lens); lens = new PerspectiveLens(90, 90); + lens->set_interocular_distance(0); lens->set_view_vector(-1, 0, 0, 0, -1, 0); set_lens(1, lens); lens = new PerspectiveLens(90, 90); + lens->set_interocular_distance(0); lens->set_view_vector(0, 1, 0, 0, 0, 1); set_lens(2, lens); lens = new PerspectiveLens(90, 90); + lens->set_interocular_distance(0); lens->set_view_vector(0, -1, 0, 0, 0, -1); set_lens(3, lens); lens = new PerspectiveLens(90, 90); + lens->set_interocular_distance(0); lens->set_view_vector(0, 0, 1, 0, -1, 0); set_lens(4, lens); lens = new PerspectiveLens(90, 90); + lens->set_interocular_distance(0); lens->set_view_vector(0, 0, -1, 0, -1, 0); set_lens(5, lens); } diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 2c840e46ee..63973c6bc3 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -284,7 +284,7 @@ analyze_renderstate(const RenderState *rs) { PandaNode *light_obj = light.node(); nassertv(light_obj != (PandaNode *)NULL); - if (light_obj->get_type() == AmbientLight::get_class_type()) { + if (light_obj->is_ambient_light()) { if (_material->has_ambient()) { LColor a = _material->get_ambient(); if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) { @@ -298,7 +298,7 @@ analyze_renderstate(const RenderState *rs) { } else if (light_obj->is_of_type(LightLensNode::get_class_type())) { _lights_np.push_back(light); _lights.push_back((LightLensNode *)light_obj); - if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) { + if (((const LightLensNode *)light_obj)->is_shadow_caster()) { _shadows = true; } _lighting = true; diff --git a/panda/src/pgraphnodes/spotlight.cxx b/panda/src/pgraphnodes/spotlight.cxx index 638f89f93c..badf4544d9 100644 --- a/panda/src/pgraphnodes/spotlight.cxx +++ b/panda/src/pgraphnodes/spotlight.cxx @@ -68,6 +68,7 @@ Spotlight(const string &name) : LightLensNode(name), _has_specular_color(false) { + _lenses[0]._lens->set_interocular_distance(0); } /** diff --git a/panda/src/pipeline/pipelineCyclerTrueImpl.I b/panda/src/pipeline/pipelineCyclerTrueImpl.I index 2c393d0546..9b078a6a30 100644 --- a/panda/src/pipeline/pipelineCyclerTrueImpl.I +++ b/panda/src/pipeline/pipelineCyclerTrueImpl.I @@ -231,6 +231,8 @@ read_stage_unlocked(int pipeline_stage) const { TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage_unlocked(int)", " ", TAU_USER); #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif return _data[pipeline_stage]._cdata; } @@ -248,6 +250,8 @@ read_stage(int pipeline_stage, Thread *current_thread) const { TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage(int, Thread *)", " ", TAU_USER); #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif _lock.acquire(current_thread); return _data[pipeline_stage]._cdata; @@ -278,6 +282,8 @@ elevate_read_stage(int pipeline_stage, const CycleData *pointer, #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); nassertr(_data[pipeline_stage]._cdata == pointer, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif CycleData *new_pointer = write_stage(pipeline_stage, current_thread); _lock.release(); @@ -296,6 +302,8 @@ elevate_read_stage_upstream(int pipeline_stage, const CycleData *pointer, #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); nassertr(_data[pipeline_stage]._cdata == pointer, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif CycleData *new_pointer = write_stage_upstream(pipeline_stage, force_to_0, current_thread); @@ -313,6 +321,8 @@ release_write_stage(int pipeline_stage, CycleData *pointer) { nassertv(pipeline_stage >= 0 && pipeline_stage < _num_stages); nassertv(_data[pipeline_stage]._cdata == pointer); nassertv(_data[pipeline_stage]._writes_outstanding > 0); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif --(_data[pipeline_stage]._writes_outstanding); _lock.release(); diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index b721486c72..321d24da6a 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -73,7 +73,16 @@ get_unique_id() const { */ INLINE int Thread:: get_pipeline_stage() const { +#if !defined(_DEBUG) && defined(__has_builtin) && __has_builtin(__builtin_assume) + // Because this is a signed int, this results in a sign extend on x86-64. + // However, since we guarantee that this is never less than zero, clang + // offers a nice way to avoid that. + int pipeline_stage = _pipeline_stage; + __builtin_assume(pipeline_stage >= 0); + return pipeline_stage; +#else return _pipeline_stage; +#endif } /** diff --git a/panda/src/putil/copyOnWriteObject.h b/panda/src/putil/copyOnWriteObject.h index 12ea5baf24..37302ea44a 100644 --- a/panda/src/putil/copyOnWriteObject.h +++ b/panda/src/putil/copyOnWriteObject.h @@ -161,6 +161,12 @@ private: static TypeHandle _type_handle; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "copyOnWriteObject.I" #endif diff --git a/panda/src/putil/copyOnWritePointer.I b/panda/src/putil/copyOnWritePointer.I index a44731bcbc..9e996355fa 100644 --- a/panda/src/putil/copyOnWritePointer.I +++ b/panda/src/putil/copyOnWritePointer.I @@ -166,7 +166,7 @@ operator < (const CopyOnWritePointer &other) const { * This flavor of the method is written for the non-threaded case. */ INLINE const CopyOnWriteObject *CopyOnWritePointer:: -get_read_pointer() const { +get_read_pointer(Thread *current_thread) const { return _cow_object; } #endif // COW_THREADED @@ -362,8 +362,14 @@ operator = (PointerTo &&from) NOEXCEPT { */ template INLINE CPT(TYPENAME CopyOnWritePointerTo::To) CopyOnWritePointerTo:: -get_read_pointer() const { - return (const To *)(CopyOnWritePointer::get_read_pointer().p()); +get_read_pointer(Thread *current_thread) const { + // This is necessary because we don't currently have a way to cast between + // two compatible PointerTo types without losing the reference count. + CPT(TYPENAME CopyOnWritePointerTo::To) to; + CPT(CopyOnWriteObject) from = CopyOnWritePointer::get_read_pointer(current_thread); + to.cheat() = (const To *)from.p(); + from.cheat() = nullptr; + return to; } #else // COW_THREADED /** @@ -371,8 +377,8 @@ get_read_pointer() const { */ template INLINE const TYPENAME CopyOnWritePointerTo::To *CopyOnWritePointerTo:: -get_read_pointer() const { - return (const To *)CopyOnWritePointer::get_read_pointer(); +get_read_pointer(Thread *current_thread) const { + return (const To *)CopyOnWritePointer::get_read_pointer(current_thread); } #endif // COW_THREADED #endif // CPPPARSER @@ -385,7 +391,13 @@ get_read_pointer() const { template INLINE PT(TYPENAME CopyOnWritePointerTo::To) CopyOnWritePointerTo:: get_write_pointer() { - return (To *)(CopyOnWritePointer::get_write_pointer().p()); + // This is necessary because we don't currently have a way to cast between + // two compatible PointerTo types without losing the reference count. + PT(TYPENAME CopyOnWritePointerTo::To) to; + PT(CopyOnWriteObject) from = CopyOnWritePointer::get_write_pointer(); + to.cheat() = (To *)from.p(); + from.cheat() = nullptr; + return to; } #else // COW_THREADED /** diff --git a/panda/src/putil/copyOnWritePointer.cxx b/panda/src/putil/copyOnWritePointer.cxx index e2396e84a9..03ed76e24b 100644 --- a/panda/src/putil/copyOnWritePointer.cxx +++ b/panda/src/putil/copyOnWritePointer.cxx @@ -23,13 +23,11 @@ * This flavor of the method is written for the threaded case. */ CPT(CopyOnWriteObject) CopyOnWritePointer:: -get_read_pointer() const { +get_read_pointer(Thread *current_thread) const { if (_cow_object == (CopyOnWriteObject *)NULL) { return NULL; } - Thread *current_thread = Thread::get_current_thread(); - MutexHolder holder(_cow_object->_lock_mutex); while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) { if (_cow_object->_locking_thread == current_thread) { diff --git a/panda/src/putil/copyOnWritePointer.h b/panda/src/putil/copyOnWritePointer.h index 1a7f0e099d..2178b6b433 100644 --- a/panda/src/putil/copyOnWritePointer.h +++ b/panda/src/putil/copyOnWritePointer.h @@ -48,10 +48,10 @@ public: INLINE bool operator < (const CopyOnWritePointer &other) const; #ifdef COW_THREADED - CPT(CopyOnWriteObject) get_read_pointer() const; + CPT(CopyOnWriteObject) get_read_pointer(Thread *current_thread) const; PT(CopyOnWriteObject) get_write_pointer(); #else - INLINE const CopyOnWriteObject *get_read_pointer() const; + INLINE const CopyOnWriteObject *get_read_pointer(Thread *current_thread) const; INLINE CopyOnWriteObject *get_write_pointer(); #endif // COW_THREADED @@ -93,10 +93,10 @@ public: #endif #ifdef COW_THREADED - INLINE CPT(To) get_read_pointer() const; + INLINE CPT(To) get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const; INLINE PT(To) get_write_pointer(); #else - INLINE const To *get_read_pointer() const; + INLINE const To *get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const; INLINE To *get_write_pointer(); #endif // COW_THREADED diff --git a/panda/src/putil/simpleHashMap.I b/panda/src/putil/simpleHashMap.I index d68fae9542..74245fd606 100644 --- a/panda/src/putil/simpleHashMap.I +++ b/panda/src/putil/simpleHashMap.I @@ -235,8 +235,8 @@ get_size() const { */ template INLINE bool SimpleHashMap:: -has_element(int n) const { - nassertr(n >= 0 && n < (int)_table_size, false); +has_element(size_t n) const { + nassertr(n < _table_size, false); return (get_exists_array()[n] != 0); } @@ -249,7 +249,7 @@ has_element(int n) const { */ template INLINE const Key &SimpleHashMap:: -get_key(int n) const { +get_key(size_t n) const { nassertr(has_element(n), _table[n]._key); return _table[n]._key; } @@ -263,7 +263,7 @@ get_key(int n) const { */ template INLINE const Value &SimpleHashMap:: -get_data(int n) const { +get_data(size_t n) const { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -277,7 +277,7 @@ get_data(int n) const { */ template INLINE Value &SimpleHashMap:: -modify_data(int n) { +modify_data(size_t n) { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -291,7 +291,7 @@ modify_data(int n) { */ template INLINE void SimpleHashMap:: -set_data(int n, const Value &data) { +set_data(size_t n, const Value &data) { nassertv(has_element(n)); _table[n]._data = data; } @@ -305,7 +305,7 @@ set_data(int n, const Value &data) { */ template void SimpleHashMap:: -remove_element(int n) { +remove_element(size_t n) { nassertv(has_element(n)); clear_element(n); @@ -314,7 +314,7 @@ remove_element(int n) { // Now we have put a hole in the table. If there was a hash conflict in the // slot following this one, we have to move it down to close the hole. - size_t i = (size_t)n; + size_t i = n; i = (i + 1) & (_table_size - 1); while (has_element(i)) { size_t wants_index = get_hash(_table[i]._key); @@ -403,12 +403,14 @@ bool SimpleHashMap:: validate() const { size_t count = 0; + const unsigned char *exists_array = get_exists_array(); + for (size_t i = 0; i < _table_size; ++i) { - if (has_element(i)) { + if (exists_array[i] != 0) { ++count; size_t ideal_index = get_hash(_table[i]._key); size_t wants_index = ideal_index; - while (wants_index != i && has_element(wants_index)) { + while (wants_index != i && exists_array[wants_index] != 0) { wants_index = (wants_index + 1) & (_table_size - 1); } if (wants_index != i) { @@ -455,7 +457,7 @@ get_hash(const Key &key) const { */ template INLINE bool SimpleHashMap:: -is_element(int n, const Key &key) const { +is_element(size_t n, const Key &key) const { nassertr(has_element(n), false); return _comp.is_equal(_table[n]._key, key); } @@ -466,7 +468,7 @@ is_element(int n, const Key &key) const { */ template INLINE void SimpleHashMap:: -store_new_element(int n, const Key &key, const Value &data) { +store_new_element(size_t n, const Key &key, const Value &data) { new(&_table[n]) TableEntry(key, data); get_exists_array()[n] = true; } @@ -476,7 +478,7 @@ store_new_element(int n, const Key &key, const Value &data) { */ template INLINE void SimpleHashMap:: -clear_element(int n) { +clear_element(size_t n) { _table[n].~TableEntry(); get_exists_array()[n] = false; } diff --git a/panda/src/putil/simpleHashMap.h b/panda/src/putil/simpleHashMap.h index 7954cd943e..c1a25fc7f9 100644 --- a/panda/src/putil/simpleHashMap.h +++ b/panda/src/putil/simpleHashMap.h @@ -42,12 +42,12 @@ public: INLINE Value &operator [] (const Key &key); INLINE size_t get_size() const; - INLINE bool has_element(int n) const; - INLINE const Key &get_key(int n) const; - INLINE const Value &get_data(int n) const; - INLINE Value &modify_data(int n); - INLINE void set_data(int n, const Value &data); - void remove_element(int n); + INLINE bool has_element(size_t n) const; + INLINE const Key &get_key(size_t n) const; + INLINE const Value &get_data(size_t n) const; + INLINE Value &modify_data(size_t n); + INLINE void set_data(size_t n, const Value &data); + void remove_element(size_t n); INLINE size_t get_num_entries() const; INLINE bool is_empty() const; @@ -61,9 +61,9 @@ private: INLINE size_t get_hash(const Key &key) const; - INLINE bool is_element(int n, const Key &key) const; - INLINE void store_new_element(int n, const Key &key, const Value &data); - INLINE void clear_element(int n); + INLINE bool is_element(size_t n, const Key &key) const; + INLINE void store_new_element(size_t n, const Key &key, const Value &data); + INLINE void clear_element(size_t n); INLINE unsigned char *get_exists_array() const; void new_table(); diff --git a/panda/src/putil/typedWritableReferenceCount.h b/panda/src/putil/typedWritableReferenceCount.h index 97d7d90029..51803d7b36 100644 --- a/panda/src/putil/typedWritableReferenceCount.h +++ b/panda/src/putil/typedWritableReferenceCount.h @@ -61,6 +61,11 @@ private: static TypeHandle _type_handle; }; +#ifdef DO_MEMORY_USAGE +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "typedWritableReferenceCount.I" #endif diff --git a/panda/src/putil/weakKeyHashMap.I b/panda/src/putil/weakKeyHashMap.I index b4b007f998..f894411f24 100644 --- a/panda/src/putil/weakKeyHashMap.I +++ b/panda/src/putil/weakKeyHashMap.I @@ -234,8 +234,8 @@ get_size() const { */ template INLINE bool WeakKeyHashMap:: -has_element(int n) const { - nassertr(n >= 0 && n < (int)_table_size, false); +has_element(size_t n) const { + nassertr(n < _table_size, false); return (get_exists_array()[n] != 0 && !_table[n]._key.was_deleted()); } @@ -248,7 +248,7 @@ has_element(int n) const { */ template INLINE const Key *WeakKeyHashMap:: -get_key(int n) const { +get_key(size_t n) const { nassertr(has_element(n), _table[n]._key); return _table[n]._key; } @@ -262,7 +262,7 @@ get_key(int n) const { */ template INLINE const Value &WeakKeyHashMap:: -get_data(int n) const { +get_data(size_t n) const { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -276,7 +276,7 @@ get_data(int n) const { */ template INLINE Value &WeakKeyHashMap:: -modify_data(int n) { +modify_data(size_t n) { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -290,7 +290,7 @@ modify_data(int n) { */ template INLINE void WeakKeyHashMap:: -set_data(int n, const Value &data) { +set_data(size_t n, const Value &data) { nassertv(has_element(n)); _table[n]._data = data; } @@ -305,7 +305,7 @@ set_data(int n, const Value &data) { */ template INLINE void WeakKeyHashMap:: -set_data(int n, Value &&data) { +set_data(size_t n, Value &&data) { nassertv(has_element(n)); _table[n]._data = move(data); } @@ -320,7 +320,7 @@ set_data(int n, Value &&data) { */ template void WeakKeyHashMap:: -remove_element(int n) { +remove_element(size_t n) { nassertv(get_exists_array()[n] != 0); clear_element(n); @@ -329,7 +329,7 @@ remove_element(int n) { // Now we have put a hole in the table. If there was a hash conflict in the // slot following this one, we have to move it down to close the hole. - size_t i = (size_t)n; + size_t i = n; i = (i + 1) & (_table_size - 1); while (get_exists_array()[i] != 0) { if (_table[i]._key.was_deleted()) { @@ -430,15 +430,17 @@ bool WeakKeyHashMap:: validate() const { size_t count = 0; + const unsigned char *exists_array = get_exists_array(); + for (size_t i = 0; i < _table_size; ++i) { - if (get_exists_array()[i] != 0) { + if (exists_array[i] != 0) { ++count; if (_table[i]._key.was_deleted()) { continue; } size_t ideal_index = get_hash(_table[i]._key.get_orig()); size_t wants_index = ideal_index; - while (wants_index != i && get_exists_array()[i] != 0) { + while (wants_index != i && exists_array[wants_index] != 0) { wants_index = (wants_index + 1) & (_table_size - 1); } if (wants_index != i) { @@ -485,7 +487,7 @@ get_hash(const Key *key) const { */ template INLINE bool WeakKeyHashMap:: -is_element(int n, const Key *key) const { +is_element(size_t n, const Key *key) const { nassertr(has_element(n), false); return _table[n]._key == key; } @@ -496,7 +498,7 @@ is_element(int n, const Key *key) const { */ template INLINE void WeakKeyHashMap:: -store_new_element(int n, const Key *key, const Value &data) { +store_new_element(size_t n, const Key *key, const Value &data) { if (get_exists_array()[n] != 0) { // There was already an element in this spot. This can happen if it was a // pointer that had already been deleted. @@ -513,7 +515,7 @@ store_new_element(int n, const Key *key, const Value &data) { */ template INLINE void WeakKeyHashMap:: -clear_element(int n) { +clear_element(size_t n) { _table[n].~TableEntry(); get_exists_array()[n] = false; } diff --git a/panda/src/putil/weakKeyHashMap.h b/panda/src/putil/weakKeyHashMap.h index 98a8863ee2..bbb7077998 100644 --- a/panda/src/putil/weakKeyHashMap.h +++ b/panda/src/putil/weakKeyHashMap.h @@ -45,15 +45,15 @@ public: INLINE Value &operator [] (const Key *key); INLINE size_t get_size() const; - INLINE bool has_element(int n) const; - INLINE const Key *get_key(int n) const; - INLINE const Value &get_data(int n) const; - INLINE Value &modify_data(int n); - INLINE void set_data(int n, const Value &data); + INLINE bool has_element(size_t n) const; + INLINE const Key *get_key(size_t n) const; + INLINE const Value &get_data(size_t n) const; + INLINE Value &modify_data(size_t n); + INLINE void set_data(size_t n, const Value &data); #ifdef USE_MOVE_SEMANTICS - INLINE void set_data(int n, Value &&data); + INLINE void set_data(size_t n, Value &&data); #endif - void remove_element(int n); + void remove_element(size_t n); INLINE size_t get_num_entries() const; INLINE bool is_empty() const; @@ -65,9 +65,9 @@ public: private: INLINE size_t get_hash(const Key *key) const; - INLINE bool is_element(int n, const Key *key) const; - INLINE void store_new_element(int n, const Key *key, const Value &data); - INLINE void clear_element(int n); + INLINE bool is_element(size_t n, const Key *key) const; + INLINE void store_new_element(size_t n, const Key *key, const Value &data); + INLINE void clear_element(size_t n); INLINE unsigned char *get_exists_array() const; void new_table(); diff --git a/panda/src/text/config_text.cxx b/panda/src/text/config_text.cxx index 4790c5ecf7..36ef375afe 100644 --- a/panda/src/text/config_text.cxx +++ b/panda/src/text/config_text.cxx @@ -48,6 +48,12 @@ ConfigVariableBool text_dynamic_merge "operation. Usually it's a performance " "advantage to keep this true. See TextNode::set_flatten_flags().")); +ConfigVariableBool text_kerning +("text-kerning", false, + PRC_DESC("Set this true to enable kerning when the font provides kerning " + "tables. This can result in more aesthetically pleasing spacing " + "between individual glyphs.")); + ConfigVariableInt text_anisotropic_degree ("text-anisotropic-degree", 1, PRC_DESC("This is the default anisotropic-degree that is set on dynamic " diff --git a/panda/src/text/config_text.h b/panda/src/text/config_text.h index 5c50af6a52..4e5ca1a6ed 100644 --- a/panda/src/text/config_text.h +++ b/panda/src/text/config_text.h @@ -30,6 +30,7 @@ NotifyCategoryDecl(text, EXPCL_PANDA_TEXT, EXPTP_PANDA_TEXT); extern ConfigVariableBool text_flatten; extern ConfigVariableBool text_dynamic_merge; +extern ConfigVariableBool text_kerning; extern ConfigVariableInt text_anisotropic_degree; extern ConfigVariableInt text_texture_margin; extern ConfigVariableDouble text_poly_margin; diff --git a/panda/src/text/dynamicTextFont.cxx b/panda/src/text/dynamicTextFont.cxx index 09369a12b9..f066e07c35 100644 --- a/panda/src/text/dynamicTextFont.cxx +++ b/panda/src/text/dynamicTextFont.cxx @@ -278,6 +278,32 @@ get_glyph(int character, CPT(TextGlyph) &glyph) { return (glyph_index != 0); } +/** + * Returns the amount by which to offset the second glyph when it directly + * follows the first glyph. This is an additional offset that is added on top + * of the advance. + */ +PN_stdfloat DynamicTextFont:: +get_kerning(int first, int second) const { + if (!_is_valid) { + return 0; + } + + FT_Face face = acquire_face(); + if (!FT_HAS_KERNING(face)) { + release_face(face); + return 0; + } + + int first_index = FT_Get_Char_Index(face, first); + int second_index = FT_Get_Char_Index(face, second); + + FT_Vector delta; + FT_Get_Kerning(face, first_index, second_index, FT_KERNING_DEFAULT, &delta); + release_face(face); + + return delta.x / (_font_pixels_per_unit * 64); +} /** * Called from both constructors to set up some initial values. diff --git a/panda/src/text/dynamicTextFont.h b/panda/src/text/dynamicTextFont.h index c418ea34c3..26433deef6 100644 --- a/panda/src/text/dynamicTextFont.h +++ b/panda/src/text/dynamicTextFont.h @@ -123,6 +123,7 @@ PUBLISHED: public: virtual bool get_glyph(int character, CPT(TextGlyph) &glyph); + virtual PN_stdfloat get_kerning(int first, int second) const; private: void initialize(); diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index 4829576407..7b8470116b 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -609,6 +609,8 @@ assemble_text() { * Returns the width of a single character, according to its associated font. * This also correctly calculates the width of cheesy ligatures and accented * characters, which may not exist in the font as such. + * + * This does not take kerning into account, however. */ PN_stdfloat TextAssembler:: calc_width(wchar_t character, const TextProperties &properties) { @@ -1142,7 +1144,6 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { } else { tris->set_index_type(GeomEnums::NT_uint16); } - PT(GeomVertexArrayData) indices = tris->modify_vertices(); int i = 0; @@ -1150,9 +1151,10 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { // bottleneck. So, I've written this out the hard way instead. Two // versions of the loop: one for 32-bit indices, one for 16-bit. { - PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array(0)->modify_handle(); + PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array_handle(0); vtx_handle->unclean_set_num_rows(quads.size() * 4); + Thread *current_thread = Thread::get_current_thread(); unsigned char *write_ptr = vtx_handle->get_write_pointer(); size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float32); @@ -1163,7 +1165,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { if (tris->get_index_type() == GeomEnums::NT_uint32) { // 32-bit index case. - PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle(); + PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread); idx_handle->unclean_set_num_rows(quads.size() * 6); uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer(); @@ -1219,7 +1221,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { } } else { // 16-bit index case. - PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle(); + PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread); idx_handle->unclean_set_num_rows(quads.size() * 6); uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer(); @@ -1399,6 +1401,9 @@ assemble_row(TextAssembler::TextRow &row, PN_stdfloat xpos = 0.0f; align = TextProperties::A_left; + // Remember previous character, for kerning. + int prev_char = -1; + bool underscore = false; PN_stdfloat underscore_start = 0.0f; const TextProperties *underscore_properties = NULL; @@ -1450,11 +1455,13 @@ assemble_row(TextAssembler::TextRow &row, if (character == ' ') { // A space is a special case. xpos += properties->get_glyph_scale() * properties->get_text_scale() * font->get_space_advance(); + prev_char = -1; } else if (character == '\t') { // So is a tab character. PN_stdfloat tab_width = properties->get_tab_width(); xpos = (floor(xpos / tab_width) + 1.0f) * tab_width; + prev_char = -1; } else if (character == text_soft_hyphen_key) { // And so is the 'soft-hyphen' key character. @@ -1493,6 +1500,7 @@ assemble_row(TextAssembler::TextRow &row, placed_glyphs.push_back(placement); xpos += advance * glyph_scale; + prev_char = -1; } else { // A printable character. @@ -1521,13 +1529,22 @@ assemble_row(TextAssembler::TextRow &row, << "\n"; } + glyph_scale *= properties->get_glyph_scale() * properties->get_text_scale(); + + // Add the kerning delta. + if (text_kerning) { + if (prev_char != -1) { + xpos += font->get_kerning(prev_char, character) * glyph_scale; + } + prev_char = character; + } + // Build up a GlyphPlacement, indicating all of the Geoms that go into // this character. Normally, there is only one Geom per character, but // it may involve multiple Geoms if we need to add cheesy accents or // ligatures. GlyphPlacement placement; - glyph_scale *= properties->get_glyph_scale() * properties->get_text_scale(); placement._glyph = NULL; placement._scale = glyph_scale; placement._xpos = xpos; diff --git a/panda/src/text/textFont.cxx b/panda/src/text/textFont.cxx index 70ca9a74d5..add86483bd 100644 --- a/panda/src/text/textFont.cxx +++ b/panda/src/text/textFont.cxx @@ -54,6 +54,16 @@ TextFont:: ~TextFont() { } +/** + * Returns the amount by which to offset the second glyph when it directly + * follows the first glyph. This is an additional offset that is added on top + * of the advance. + */ +PN_stdfloat TextFont:: +get_kerning(int first, int second) const { + return 0; +} + /** * */ diff --git a/panda/src/text/textFont.h b/panda/src/text/textFont.h index 1249e7b817..7cea63e391 100644 --- a/panda/src/text/textFont.h +++ b/panda/src/text/textFont.h @@ -74,6 +74,8 @@ PUBLISHED: INLINE CPT(TextGlyph) get_glyph(int character); + virtual PN_stdfloat get_kerning(int first, int second) const; + virtual void write(ostream &out, int indent_level) const; public: diff --git a/pandatool/src/maxegg/maxEgg.rc b/pandatool/src/maxegg/maxEgg.rc index 161b0ec456..a037734218 100644 --- a/pandatool/src/maxegg/maxEgg.rc +++ b/pandatool/src/maxegg/maxEgg.rc @@ -7,7 +7,8 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include "WinResrc.h" +#define IDC_STATIC -1 ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS diff --git a/pandatool/src/maxprogs/maxImportRes.rc b/pandatool/src/maxprogs/maxImportRes.rc index a8041e52d7..b4f2e778e9 100644 --- a/pandatool/src/maxprogs/maxImportRes.rc +++ b/pandatool/src/maxprogs/maxImportRes.rc @@ -7,8 +7,8 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" - +#include "WinResrc.h" +#define IDC_STATIC -1 //////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS diff --git a/pandatool/src/mayaprogs/mayapath.cxx b/pandatool/src/mayaprogs/mayapath.cxx index aac472759d..428e4ba128 100644 --- a/pandatool/src/mayaprogs/mayapath.cxx +++ b/pandatool/src/mayaprogs/mayapath.cxx @@ -98,6 +98,7 @@ struct MayaVerInfo maya_versions[] = { { "MAYA2015", "2015"}, { "MAYA2016", "2016"}, { "MAYA20165", "2016.5"}, + { "MAYA2017", "2017"}, { 0, 0 }, };