Browse Source

Merge branch 'master' into deploy-ng

Mitchell Stokes 7 years ago
parent
commit
ebe2588a50

+ 48 - 57
direct/src/showbase/PythonUtil.py

@@ -10,7 +10,7 @@ __all__ = ['indent',
 'bound', 'clamp', 'lerp', 'average', 'addListsByValue',
 'bound', 'clamp', 'lerp', 'average', 'addListsByValue',
 'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic',
 'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic',
 'findPythonModule', 'mostDerivedLast',
 'findPythonModule', 'mostDerivedLast',
-'weightedChoice', 'randFloat', 'normalDistrib',
+'clampScalar', 'weightedChoice', 'randFloat', 'normalDistrib',
 'weightedRand', 'randUint31', 'randInt32',
 'weightedRand', 'randUint31', 'randInt32',
 'SerialNumGen', 'serialNum', 'uniqueName', 'Enum', 'Singleton',
 'SerialNumGen', 'serialNum', 'uniqueName', 'Enum', 'Singleton',
 'SingletonError', 'printListEnum', 'safeRepr',
 'SingletonError', 'printListEnum', 'safeRepr',
@@ -178,27 +178,6 @@ class Queue:
     def __len__(self):
     def __len__(self):
         return len(self.__list)
         return len(self.__list)
 
 
-if __debug__ and __name__ == '__main__':
-    q = Queue()
-    assert q.isEmpty()
-    q.clear()
-    assert q.isEmpty()
-    q.push(10)
-    assert not q.isEmpty()
-    q.push(20)
-    assert not q.isEmpty()
-    assert len(q) == 2
-    assert q.front() == 10
-    assert q.back() == 20
-    assert q.top() == 10
-    assert q.top() == 10
-    assert q.pop() == 10
-    assert len(q) == 1
-    assert not q.isEmpty()
-    assert q.pop() == 20
-    assert len(q) == 0
-    assert q.isEmpty()
-
 
 
 def indent(stream, numIndents, str):
 def indent(stream, numIndents, str):
     """
     """
@@ -1130,6 +1109,23 @@ def findPythonModule(module):
 
 
     return None
     return None
 
 
+def clampScalar(value, a, b):
+    # calling this ought to be faster than calling both min and max
+    if a < b:
+        if value < a:
+            return a
+        elif value > b:
+            return b
+        else:
+            return value
+    else:
+        if value < b:
+            return b
+        elif value > a:
+            return a
+        else:
+            return value
+
 def weightedChoice(choiceList, rng=random.random, sum=None):
 def weightedChoice(choiceList, rng=random.random, sum=None):
     """given a list of (weight, item) pairs, chooses an item based on the
     """given a list of (weight, item) pairs, chooses an item based on the
     weights. rng must return 0..1. if you happen to have the sum of the
     weights. rng must return 0..1. if you happen to have the sum of the
@@ -2313,36 +2309,6 @@ def flywheel(*args, **kArgs):
         pass
         pass
     return flywheel
     return flywheel
 
 
-if __debug__ and __name__ == '__main__':
-    f = flywheel(['a','b','c','d'], countList=[11,20,3,4])
-    obj2count = {}
-    for obj in f:
-        obj2count.setdefault(obj, 0)
-        obj2count[obj] += 1
-    assert obj2count['a'] == 11
-    assert obj2count['b'] == 20
-    assert obj2count['c'] == 3
-    assert obj2count['d'] == 4
-
-    f = flywheel([1,2,3,4], countFunc=lambda x: x*2)
-    obj2count = {}
-    for obj in f:
-        obj2count.setdefault(obj, 0)
-        obj2count[obj] += 1
-    assert obj2count[1] == 2
-    assert obj2count[2] == 4
-    assert obj2count[3] == 6
-    assert obj2count[4] == 8
-
-    f = flywheel([1,2,3,4], countFunc=lambda x: x, scale = 3)
-    obj2count = {}
-    for obj in f:
-        obj2count.setdefault(obj, 0)
-        obj2count[obj] += 1
-    assert obj2count[1] == 1 * 3
-    assert obj2count[2] == 2 * 3
-    assert obj2count[3] == 3 * 3
-    assert obj2count[4] == 4 * 3
 
 
 if __debug__:
 if __debug__:
     def quickProfile(name="unnamed"):
     def quickProfile(name="unnamed"):
@@ -2687,11 +2653,36 @@ def unescapeHtmlString(s):
         result += char
         result += char
     return result
     return result
 
 
-if __debug__ and __name__ == '__main__':
-    assert unescapeHtmlString('asdf') == 'asdf'
-    assert unescapeHtmlString('as+df') == 'as df'
-    assert unescapeHtmlString('as%32df') == 'as2df'
-    assert unescapeHtmlString('asdf%32') == 'asdf2'
+class PriorityCallbacks:
+    """ manage a set of prioritized callbacks, and allow them to be invoked in order of priority """
+    def __init__(self):
+        self._callbacks = []
+
+    def clear(self):
+        del self._callbacks[:]
+
+    def add(self, callback, priority=None):
+        if priority is None:
+            priority = 0
+        callbacks = self._callbacks
+        lo = 0
+        hi = len(callbacks)
+        while lo < hi:
+            mid = (lo + hi) // 2
+            if priority < callbacks[mid][0]:
+                hi = mid
+            else:
+                lo = mid + 1
+        item = (priority, callback)
+        callbacks.insert(lo, item)
+        return item
+
+    def remove(self, item):
+        self._callbacks.remove(item)
+
+    def __call__(self):
+        for priority, callback in self._callbacks:
+            callback()
 
 
 builtins.Functor = Functor
 builtins.Functor = Functor
 builtins.Stack = Stack
 builtins.Stack = Stack

+ 3 - 2
makepanda/makepanda.py

@@ -615,6 +615,7 @@ if (COMPILER == "MSVC"):
     PkgDisable("EGL")
     PkgDisable("EGL")
     PkgDisable("CARBON")
     PkgDisable("CARBON")
     PkgDisable("COCOA")
     PkgDisable("COCOA")
+    DefSymbol("FLEX", "YY_NO_UNISTD_H")
     if (PkgSkip("PYTHON")==0):
     if (PkgSkip("PYTHON")==0):
         IncDirectory("ALWAYS", SDK["PYTHON"] + "/include")
         IncDirectory("ALWAYS", SDK["PYTHON"] + "/include")
         LibDirectory("ALWAYS", SDK["PYTHON"] + "/libs")
         LibDirectory("ALWAYS", SDK["PYTHON"] + "/libs")
@@ -890,7 +891,7 @@ if (COMPILER=="GCC"):
         SmartPkgEnable("EIGEN",     "eigen3",    (), ("Eigen/Dense",), target_pkg = 'ALWAYS')
         SmartPkgEnable("EIGEN",     "eigen3",    (), ("Eigen/Dense",), target_pkg = 'ALWAYS')
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
         SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
         SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
-        SmartPkgEnable("ASSIMP",    "assimp", ("assimp"), "assimp")
+        SmartPkgEnable("ASSIMP",    "",          ("assimp"), "assimp")
         SmartPkgEnable("FFMPEG",    ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h"))
         SmartPkgEnable("FFMPEG",    ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h"))
         SmartPkgEnable("SWSCALE",   "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
         SmartPkgEnable("SWSCALE",   "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
         SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
         SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
@@ -1460,7 +1461,7 @@ def CompileBison(wobj, wsrc, opts):
         CopyFile(wdsth, GetOutputDir()+"/tmp/"+ifile+".h")
         CopyFile(wdsth, GetOutputDir()+"/tmp/"+ifile+".h")
 
 
     # Finally, compile the generated source file.
     # Finally, compile the generated source file.
-    CompileCxx(wobj,wdstc,opts)
+    CompileCxx(wobj, wdstc, opts + ["FLEX"])
 
 
 ########################################################################
 ########################################################################
 ##
 ##

+ 6 - 1
panda/src/bullet/bulletWorld.cxx

@@ -1052,7 +1052,7 @@ BulletPersistentManifold *BulletWorld::
 get_manifold(int idx) const {
 get_manifold(int idx) const {
   LightMutexHolder holder(get_global_lock());
   LightMutexHolder holder(get_global_lock());
 
 
-  nassertr(idx < get_num_manifolds(), NULL);
+  nassertr(idx < _dispatcher->getNumManifolds(), NULL);
 
 
   btPersistentManifold *ptr = _dispatcher->getManifoldByIndexInternal(idx);
   btPersistentManifold *ptr = _dispatcher->getManifoldByIndexInternal(idx);
   return (ptr) ? new BulletPersistentManifold(ptr) : NULL;
   return (ptr) ? new BulletPersistentManifold(ptr) : NULL;
@@ -1186,7 +1186,12 @@ tick_callback(btDynamicsWorld *world, btScalar timestep) {
   CallbackObject *obj = w->_tick_callback_obj;
   CallbackObject *obj = w->_tick_callback_obj;
   if (obj) {
   if (obj) {
     BulletTickCallbackData cbdata(timestep);
     BulletTickCallbackData cbdata(timestep);
+    // Release the global lock that we are holding during the tick callback
+    // and allow interactions with bullet world in the user callback
+    get_global_lock().release();
     obj->do_callback(&cbdata);
     obj->do_callback(&cbdata);
+    // Acquire the global lock again and protect the execution
+    get_global_lock().acquire();
   }
   }
 }
 }
 
 

+ 17 - 0
panda/src/downloader/httpChannel.I

@@ -426,6 +426,23 @@ get_max_updates_per_second() const {
   return _max_updates_per_second;
   return _max_updates_per_second;
 }
 }
 
 
+/**
+ * Specifies the Content-Type header, useful for applications that require
+ * different types of content, such as JSON.
+ */
+INLINE void HTTPChannel::
+set_content_type(string content_type) {
+  _content_type = content_type;
+}
+
+/**
+ * Returns the value of the Content-Type header.
+ */
+INLINE string HTTPChannel::
+get_content_type() const {
+  return _content_type;
+}
+
 /**
 /**
  * This may be called immediately after a call to get_document() or some
  * This may be called immediately after a call to get_document() or some
  * related function to specify the expected size of the document we are
  * related function to specify the expected size of the document we are

+ 2 - 1
panda/src/downloader/httpChannel.cxx

@@ -100,6 +100,7 @@ HTTPChannel(HTTPClient *client) :
   _response_type = RT_none;
   _response_type = RT_none;
   _http_version = _client->get_http_version();
   _http_version = _client->get_http_version();
   _http_version_string = _client->get_http_version_string();
   _http_version_string = _client->get_http_version_string();
+  _content_type = "application/x-www-form-urlencoded";
   _state = S_new;
   _state = S_new;
   _done_state = S_new;
   _done_state = S_new;
   _started_download = false;
   _started_download = false;
@@ -3624,7 +3625,7 @@ make_header() {
 
 
   if (!_body.empty()) {
   if (!_body.empty()) {
     stream
     stream
-      << "Content-Type: application/x-www-form-urlencoded\r\n"
+      << "Content-Type: " << _content_type << "\r\n"
       << "Content-Length: " << _body.length() << "\r\n";
       << "Content-Length: " << _body.length() << "\r\n";
   }
   }
 
 

+ 4 - 0
panda/src/downloader/httpChannel.h

@@ -143,6 +143,9 @@ PUBLISHED:
   INLINE void set_max_updates_per_second(double max_updates_per_second);
   INLINE void set_max_updates_per_second(double max_updates_per_second);
   INLINE double get_max_updates_per_second() const;
   INLINE double get_max_updates_per_second() const;
 
 
+  INLINE void set_content_type(string content_type);
+  INLINE string get_content_type() const;
+
   INLINE void set_expected_file_size(size_t file_size);
   INLINE void set_expected_file_size(size_t file_size);
   streamsize get_file_size() const;
   streamsize get_file_size() const;
   INLINE bool is_file_size_known() const;
   INLINE bool is_file_size_known() const;
@@ -336,6 +339,7 @@ private:
   string request_path;
   string request_path;
   string _header;
   string _header;
   string _body;
   string _body;
+  string _content_type;
   bool _want_ssl;
   bool _want_ssl;
   bool _proxy_serves_document;
   bool _proxy_serves_document;
   bool _proxy_tunnel_now;
   bool _proxy_tunnel_now;

+ 2 - 1
panda/src/event/asyncTaskChain.cxx

@@ -477,6 +477,7 @@ do_remove(AsyncTask *task, bool upon_death) {
     {
     {
       int index = find_task_on_heap(_sleeping, task);
       int index = find_task_on_heap(_sleeping, task);
       nassertr(index != -1, false);
       nassertr(index != -1, false);
+      PT(AsyncTask) hold_task = task;
       _sleeping.erase(_sleeping.begin() + index);
       _sleeping.erase(_sleeping.begin() + index);
       make_heap(_sleeping.begin(), _sleeping.end(), AsyncTaskSortWakeTime());
       make_heap(_sleeping.begin(), _sleeping.end(), AsyncTaskSortWakeTime());
       cleanup_task(task, upon_death, false);
       cleanup_task(task, upon_death, false);
@@ -486,6 +487,7 @@ do_remove(AsyncTask *task, bool upon_death) {
   case AsyncTask::S_active:
   case AsyncTask::S_active:
     {
     {
       // Active, but not being serviced, easy.
       // Active, but not being serviced, easy.
+      PT(AsyncTask) hold_task = task;
       int index = find_task_on_heap(_active, task);
       int index = find_task_on_heap(_active, task);
       if (index != -1) {
       if (index != -1) {
         _active.erase(_active.begin() + index);
         _active.erase(_active.begin() + index);
@@ -769,7 +771,6 @@ cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit) {
   }
   }
 
 
   nassertv(task->_chain == this);
   nassertv(task->_chain == this);
-  PT(AsyncTask) hold_task = task;
 
 
   task->_state = AsyncTask::S_inactive;
   task->_state = AsyncTask::S_inactive;
   task->_chain = nullptr;
   task->_chain = nullptr;

+ 19 - 9
panda/src/putil/datagramInputFile.cxx

@@ -138,35 +138,45 @@ get_datagram(Datagram &data) {
     return true;
     return true;
   }
   }
 
 
-  streamsize num_bytes = (streamsize)num_bytes_32;
+  size_t num_bytes = (size_t)num_bytes_32;
   if (num_bytes_32 == (uint32_t)-1) {
   if (num_bytes_32 == (uint32_t)-1) {
     // Another special case for a value larger than 32 bits.
     // Another special case for a value larger than 32 bits.
-    num_bytes = reader.get_uint64();
-  }
+    uint64_t num_bytes_64 = reader.get_uint64();
 
 
-  // Make sure we have a reasonable datagram size for putting into memory.
-  nassertr(num_bytes == (size_t)num_bytes, false);
+    if (_in->fail() || _in->eof()) {
+      _error = true;
+      return false;
+    }
+
+    num_bytes = (size_t)num_bytes_64;
+
+    // Make sure we have a reasonable datagram size for putting into memory.
+    if (num_bytes_64 != (uint64_t)num_bytes) {
+      _error = true;
+      return false;
+    }
+  }
 
 
   // Now, read the datagram itself. We construct an empty datagram, use
   // Now, read the datagram itself. We construct an empty datagram, use
   // pad_bytes to make it big enough, and read *directly* into the datagram's
   // pad_bytes to make it big enough, and read *directly* into the datagram's
   // internal buffer. Doing this saves us a copy operation.
   // internal buffer. Doing this saves us a copy operation.
   data = Datagram();
   data = Datagram();
 
 
-  streamsize bytes_read = 0;
+  size_t bytes_read = 0;
   while (bytes_read < num_bytes) {
   while (bytes_read < num_bytes) {
-    streamsize bytes_left = num_bytes - bytes_read;
+    size_t bytes_left = num_bytes - bytes_read;
 
 
     // Hold up a second - datagrams >4MB are pretty large by bam/network
     // Hold up a second - datagrams >4MB are pretty large by bam/network
     // standards. Let's take it 4MB at a time just in case the length is
     // standards. Let's take it 4MB at a time just in case the length is
     // corrupt, so we don't allocate potentially a few GBs of RAM only to
     // corrupt, so we don't allocate potentially a few GBs of RAM only to
     // find a truncated file.
     // find a truncated file.
-    bytes_left = min(bytes_left, (streamsize)4*1024*1024);
+    bytes_left = min(bytes_left, (size_t)4*1024*1024);
 
 
     PTA_uchar buffer = data.modify_array();
     PTA_uchar buffer = data.modify_array();
     buffer.resize(buffer.size() + bytes_left);
     buffer.resize(buffer.size() + bytes_left);
     unsigned char *ptr = &buffer.p()[bytes_read];
     unsigned char *ptr = &buffer.p()[bytes_read];
 
 
-    _in->read((char *)ptr, bytes_left);
+    _in->read((char *)ptr, (streamsize)bytes_left);
     if (_in->fail() || _in->eof()) {
     if (_in->fail() || _in->eof()) {
       _error = true;
       _error = true;
       return false;
       return false;

+ 2 - 2
pandatool/src/flt/fltBeadID.cxx

@@ -78,8 +78,8 @@ extract_record(FltRecordReader &reader) {
 bool FltBeadID::
 bool FltBeadID::
 extract_ancillary(FltRecordReader &reader) {
 extract_ancillary(FltRecordReader &reader) {
   if (reader.get_opcode() == FO_long_id) {
   if (reader.get_opcode() == FO_long_id) {
-    vector_uchar s = reader.get_iterator().get_remaining_bytes();
-    _id.assign((const char *)s.data(), strnlen((const char *)s.data(), s.size()));
+    DatagramIterator &di = reader.get_iterator();
+    _id = di.get_fixed_string(di.get_remaining_size());
     return true;
     return true;
   }
   }
 
 

+ 2 - 2
pandatool/src/flt/fltRecord.cxx

@@ -621,8 +621,8 @@ extract_record(FltRecordReader &) {
 bool FltRecord::
 bool FltRecord::
 extract_ancillary(FltRecordReader &reader) {
 extract_ancillary(FltRecordReader &reader) {
   if (reader.get_opcode() == FO_comment) {
   if (reader.get_opcode() == FO_comment) {
-    vector_uchar s = reader.get_iterator().get_remaining_bytes();
-    _comment.assign((const char *)s.data(), strnlen((const char *)s.data(), s.size()));
+    DatagramIterator &di = reader.get_iterator();
+    _comment = di.get_fixed_string(di.get_remaining_size());
     return true;
     return true;
   }
   }
 
 

+ 2 - 2
tests/bullet/test_bullet_bam.py

@@ -88,8 +88,8 @@ def test_minkowski_sum_shape():
     assert type(shape) is type(shape2)
     assert type(shape) is type(shape2)
     assert shape.margin == shape2.margin
     assert shape.margin == shape2.margin
     assert shape.name == shape2.name
     assert shape.name == shape2.name
-    assert shape.transform_a.compare_to(shape2.transform_a, True) == 0
-    assert shape.transform_b.compare_to(shape2.transform_b, True) == 0
+    assert shape.transform_a.mat.compare_to(shape2.transform_a.mat, 0.001) == 0
+    assert shape.transform_b.mat.compare_to(shape2.transform_b.mat, 0.001) == 0
     assert type(shape.shape_a) == type(shape2.shape_a)
     assert type(shape.shape_a) == type(shape2.shape_a)
     assert type(shape.shape_b) == type(shape2.shape_b)
     assert type(shape.shape_b) == type(shape2.shape_b)
 
 

+ 105 - 0
tests/showbase/test_PythonUtil.py

@@ -0,0 +1,105 @@
+from direct.showbase import PythonUtil
+
+
+def test_queue():
+    q = PythonUtil.Queue()
+    assert q.isEmpty()
+    q.clear()
+    assert q.isEmpty()
+    q.push(10)
+    assert not q.isEmpty()
+    q.push(20)
+    assert not q.isEmpty()
+    assert len(q) == 2
+    assert q.front() == 10
+    assert q.back() == 20
+    assert q.top() == 10
+    assert q.top() == 10
+    assert q.pop() == 10
+    assert len(q) == 1
+    assert not q.isEmpty()
+    assert q.pop() == 20
+    assert len(q) == 0
+    assert q.isEmpty()
+
+
+def test_flywheel():
+    f = PythonUtil.flywheel(['a','b','c','d'], countList=[11,20,3,4])
+    obj2count = {}
+    for obj in f:
+        obj2count.setdefault(obj, 0)
+        obj2count[obj] += 1
+    assert obj2count['a'] == 11
+    assert obj2count['b'] == 20
+    assert obj2count['c'] == 3
+    assert obj2count['d'] == 4
+
+    f = PythonUtil.flywheel([1,2,3,4], countFunc=lambda x: x*2)
+    obj2count = {}
+    for obj in f:
+        obj2count.setdefault(obj, 0)
+        obj2count[obj] += 1
+    assert obj2count[1] == 2
+    assert obj2count[2] == 4
+    assert obj2count[3] == 6
+    assert obj2count[4] == 8
+
+    f = PythonUtil.flywheel([1,2,3,4], countFunc=lambda x: x, scale = 3)
+    obj2count = {}
+    for obj in f:
+        obj2count.setdefault(obj, 0)
+        obj2count[obj] += 1
+    assert obj2count[1] == 1 * 3
+    assert obj2count[2] == 2 * 3
+    assert obj2count[3] == 3 * 3
+    assert obj2count[4] == 4 * 3
+
+
+def test_unescape_html_string():
+    assert PythonUtil.unescapeHtmlString('asdf') == 'asdf'
+    assert PythonUtil.unescapeHtmlString('as+df') == 'as df'
+    assert PythonUtil.unescapeHtmlString('as%32df') == 'as2df'
+    assert PythonUtil.unescapeHtmlString('asdf%32') == 'asdf2'
+
+
+def test_priority_callbacks():
+    l = []
+    def a(l=l):
+        l.append('a')
+    def b(l=l):
+        l.append('b')
+    def c(l=l):
+        l.append('c')
+
+    pc = PythonUtil.PriorityCallbacks()
+    pc.add(a)
+    pc()
+    assert l == ['a']
+
+    del l[:]
+    bItem = pc.add(b)
+    pc()
+    assert 'a' in l
+    assert 'b' in l
+    assert len(l) == 2
+
+    del l[:]
+    pc.remove(bItem)
+    pc()
+    assert l == ['a']
+
+    del l[:]
+    pc.add(c, 2)
+    bItem = pc.add(b, 10)
+    pc()
+    assert l == ['a', 'c', 'b']
+
+    del l[:]
+    pc.remove(bItem)
+    pc()
+    assert l == ['a', 'c']
+
+    del l[:]
+    pc.clear()
+    pc()
+    assert len(l) == 0