Forráskód Böngészése

Merge branch 'master' into input-overhaul

rdb 7 éve
szülő
commit
14042faa3d

+ 38 - 6
README.md

@@ -43,8 +43,9 @@ Building Panda3D
 Windows
 -------
 
-We currently build using the Microsoft Visual C++ 2015 compiler.  You will
-also need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk),
+You can build Panda3D with the Microsoft Visual C++ 2015 or 2017 compiler,
+which can be downloaded for free from the [Visual Studio site](https://visualstudio.microsoft.com/downloads/).
+You will also need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk),
 and if you intend to target Windows XP, you will also need the
 [Windows 7.1 SDK](https://www.microsoft.com/en-us/download/details.aspx?id=8279).
 
@@ -58,11 +59,12 @@ http://rdb.name/thirdparty-vc14-x64.7z
 http://rdb.name/thirdparty-vc14.7z
 
 After acquiring these dependencies, you may simply build Panda3D from the
-command prompt using the following command.  (Add the `--windows-sdk=10`
-option if you don't need to support Windows XP.)
+command prompt using the following command.  (Change `14.1` to `14` if you are
+using Visual C++ 2015 instead of 2017.  Add the `--windows-sdk=10` option if
+you don't need to support Windows XP and did not install the Windows 7.1 SDK.)
 
 ```bash
-makepanda\makepanda.bat --everything --installer --no-eigen --threads=2
+makepanda\makepanda.bat --everything --installer --msvc-version=14.1 --no-eigen --threads=2
 ```
 
 When the build succeeds, it will produce an .exe file that you can use to
@@ -101,7 +103,7 @@ If you are on Ubuntu, this command should cover the most frequently
 used third-party packages:
 
 ```bash
-sudo apt-get install build-essential pkg-config python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev
+sudo apt-get install build-essential pkg-config python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev libassimp-dev libopenexr-dev
 ```
 
 Once Panda3D has built, you can either install the .deb or .rpm package that
@@ -163,6 +165,36 @@ python3.6 makepanda/makepanda.py --everything --installer --no-egl --no-gles --n
 If successful, this will produce a .pkg file in the root of the source
 directory which you can install using `pkg install`.
 
+Android
+-------
+
+Note: building on Android is very experimental and not guaranteed to work.
+
+You can experimentally build the Android Python runner via the [termux](https://termux.com/)
+shell.  You will need to install [Termux](https://play.google.com/store/apps/details?id=com.termux)
+and [Termux API](https://play.google.com/store/apps/details?id=com.termux.api)
+from the Play Store.  Many of the dependencies can be installed by running the
+following command in the Termux shell:
+
+```bash
+pkg install python-dev termux-tools ndk-stl ndk-sysroot clang libvorbis-dev libopus-dev opusfile-dev openal-soft-dev freetype-dev harfbuzz-dev libpng-dev ecj4.6 dx patchelf aapt apksigner libcrypt-dev
+```
+
+Then, you can build and install the .apk right away using these commands:
+
+```bash
+python makepanda/makepanda.py --everything --target android-21 --installer
+xdg-open panda3d.apk
+```
+
+To launch a Python program from Termux, you can use the `run_python.sh` script
+inside the `panda/src/android` directory.  It will launch Python in a separate
+activity, load it with the Python script you passed as argument, and use a
+socket for returning the command-line output to the Termux shell.  Do note
+that this requires the Python application to reside on the SD card and that
+Termux needs to be set up with access to the SD card (using the
+`termux-setup-storage` command).
+
 Running Tests
 =============
 

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

@@ -2943,7 +2943,7 @@ define_method(CPPInstance *function, InterrogateType &itype,
   // specifically flag get_class_type() as published.
   bool force_publish = false;
   if (function->get_simple_name() == "get_class_type" &&
-      (function->_storage_class && CPPInstance::SC_static) != 0 &&
+      (function->_storage_class & CPPInstance::SC_static) != 0 &&
       function->_vis <= V_public) {
     force_publish = true;
   }

+ 2 - 2
dtool/src/interrogatedb/py_panda.cxx

@@ -235,8 +235,8 @@ PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute) {
     "'%.100s' object has no attribute '%.200s'",
     Py_TYPE(obj)->tp_name, attribute);
 
-  Py_INCREF(PyExc_TypeError);
-  PyErr_Restore(PyExc_TypeError, message, nullptr);
+  Py_INCREF(PyExc_AttributeError);
+  PyErr_Restore(PyExc_AttributeError, message, nullptr);
   return nullptr;
 }
 

+ 5 - 0
makepanda/confauto.in

@@ -21,6 +21,11 @@
 
 load-file-type egg pandaegg
 
+# If we built with Assimp support, we can enable the Assimp loader,
+# which allows us to load many model formats natively.
+
+load-file-type p3assimp
+
 # These entries work very similar to load-file-type, except they are
 # used by the MovieVideo and MovieAudio code to determine which module
 # should be loaded in order to decode files of the given extension.

+ 3 - 0
makepanda/makepanda.py

@@ -2884,6 +2884,9 @@ else:
     # otherwise, disable it.
     confautoprc = confautoprc.replace('#st#', '#')
 
+if PkgSkip("ASSIMP"):
+    confautoprc = confautoprc.replace("load-file-type p3assimp", "#load-file-type p3assimp")
+
 if (os.path.isfile("makepanda/myconfig.in")):
     configprc = ReadFile("makepanda/myconfig.in")
 else:

+ 9 - 2
panda/src/display/graphicsEngine.cxx

@@ -593,8 +593,7 @@ remove_all_windows() {
   Windows old_windows;
   old_windows.swap(_windows);
   Windows::iterator wi;
-  for (wi = old_windows.begin(); wi != old_windows.end(); ++wi) {
-    GraphicsOutput *win = (*wi);
+  for (GraphicsOutput *win : old_windows) {
     nassertv(win != nullptr);
     do_remove_window(win, current_thread);
     GraphicsStateGuardian *gsg = win->get_gsg();
@@ -605,6 +604,14 @@ remove_all_windows() {
 
   {
     MutexHolder new_windows_holder(_new_windows_lock, current_thread);
+    for (GraphicsOutput *win : _new_windows) {
+      nassertv(win != nullptr);
+      do_remove_window(win, current_thread);
+      GraphicsStateGuardian *gsg = win->get_gsg();
+      if (gsg != nullptr) {
+        gsg->release_all();
+      }
+    }
     _new_windows.clear();
   }
 

+ 22 - 1
panda/src/display/standardMunger.cxx

@@ -36,7 +36,8 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
   _munge_color(false),
   _munge_color_scale(false),
   _auto_shader(false),
-  _shader_skinning(false)
+  _shader_skinning(false),
+  _remove_material(false)
 {
   const ShaderAttrib *shader_attrib;
   state->get_attrib_def(shader_attrib);
@@ -94,6 +95,19 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
       // effort to detect this contrived situation and handle it correctly.
     }
   }
+
+  // If we have no lights but do have a material, we will need to remove it so
+  // that it won't appear when we enable color scale via lighting.
+  const LightAttrib *light_attrib;
+  const MaterialAttrib *material_attrib;
+  if (get_gsg()->get_color_scale_via_lighting() &&
+      (!state->get_attrib(light_attrib) || !light_attrib->has_any_on_light()) &&
+      state->get_attrib(material_attrib) &&
+      material_attrib->get_material() != nullptr &&
+      shader_attrib->get_shader() == nullptr) {
+    _remove_material = true;
+    _should_munge_state = true;
+  }
 }
 
 /**
@@ -291,6 +305,9 @@ compare_to_impl(const GeomMunger *other) const {
   if (_auto_shader != om->_auto_shader) {
     return (int)_auto_shader - (int)om->_auto_shader;
   }
+  if (_remove_material != om->_remove_material) {
+    return (int)_remove_material - (int)om->_remove_material;
+  }
 
   return StateMunger::compare_to_impl(other);
 }
@@ -344,5 +361,9 @@ munge_state_impl(const RenderState *state) {
     munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
   }
 
+  if (_remove_material) {
+    munged_state = munged_state->remove_attrib(MaterialAttrib::get_class_slot());
+  }
+
   return munged_state;
 }

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

@@ -55,6 +55,7 @@ private:
   bool _munge_color_scale;
   bool _auto_shader;
   bool _shader_skinning;
+  bool _remove_material;
 
   LColor _color;
   LVecBase4 _color_scale;

+ 21 - 0
panda/src/event/asyncTask.h

@@ -99,6 +99,27 @@ PUBLISHED:
 
   virtual void output(std::ostream &out) const;
 
+PUBLISHED:
+  MAKE_PROPERTY(state, get_state);
+  MAKE_PROPERTY(alive, is_alive);
+  MAKE_PROPERTY(manager, get_manager);
+
+  // The name of this task.
+  MAKE_PROPERTY(name, get_name, set_name);
+
+  // This is a number guaranteed to be unique for each different AsyncTask
+  // object in the universe.
+  MAKE_PROPERTY(id, get_task_id);
+
+  MAKE_PROPERTY(task_chain, get_task_chain, set_task_chain);
+  MAKE_PROPERTY(sort, get_sort, set_sort);
+  MAKE_PROPERTY(priority, get_priority, set_priority);
+  MAKE_PROPERTY(done_event, get_done_event, set_done_event);
+
+  MAKE_PROPERTY(dt, get_dt);
+  MAKE_PROPERTY(max_dt, get_max_dt);
+  MAKE_PROPERTY(average_dt, get_average_dt);
+
 protected:
   void jump_to_task_chain(AsyncTaskManager *manager);
   DoneStatus unlock_and_do_task();

+ 0 - 7
panda/src/event/pythonTask.h

@@ -61,9 +61,6 @@ PUBLISHED:
   int __clear__();
 
 PUBLISHED:
-  // The name of this task.
-  MAKE_PROPERTY(name, get_name, set_name);
-
   // The amount of seconds that have elapsed since the task was started,
   // according to the task manager's clock.
   MAKE_PROPERTY(time, get_elapsed_time);
@@ -88,10 +85,6 @@ PUBLISHED:
   // according to the task manager's clock.
   MAKE_PROPERTY(frame, get_elapsed_frames);
 
-  // This is a number guaranteed to be unique for each different AsyncTask
-  // object in the universe.
-  MAKE_PROPERTY(id, get_task_id);
-
   // This is a special variable to hold the instance dictionary in which
   // custom variables may be stored.
   PyObject *__dict__;

+ 7 - 0
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -283,6 +283,13 @@ begin_frame(FrameMode mode, Thread *current_thread) {
     rebuild_bitplanes();
   }
 
+  // The host window may not have had sRGB enabled, so we need to do this.
+#ifndef OPENGLES
+  if (get_fb_properties().get_srgb_color()) {
+    glEnable(GL_FRAMEBUFFER_SRGB);
+  }
+#endif
+
   _gsg->set_current_properties(&get_fb_properties());
   report_my_gl_errors();
   return true;

+ 6 - 8
panda/src/mathutil/mersenne.h

@@ -69,14 +69,12 @@ PUBLISHED:
   };
 
 private:
-  enum {
-    // Period parameters
-    N = 624,
-    M = 397,
-    MATRIX_A = 0x9908b0dfUL,   // constant vector a
-    UPPER_MASK = 0x80000000UL, // most significant w-r bits
-    LOWER_MASK = 0x7fffffffUL, // least significant r bits
-  };
+  // Period parameters
+  static const unsigned long N = 624;
+  static const unsigned long M = 397;
+  static const unsigned long MATRIX_A = 0x9908b0dfUL;   // constant vector a
+  static const unsigned long UPPER_MASK = 0x80000000UL; // most significant w-r bits
+  static const unsigned long LOWER_MASK = 0x7fffffffUL; // least significant r bits
 
   unsigned long mt[N]; // the array for the state vector
   unsigned int mti; // mti==N+1 means mt[N] is not initialized

+ 2 - 0
panda/src/movies/movieTypeRegistry.cxx

@@ -12,10 +12,12 @@
  */
 
 #include "movieTypeRegistry.h"
+
 #include "string_utils.h"
 #include "config_movies.h"
 #include "config_putil.h"
 #include "load_dso.h"
+#include "reMutexHolder.h"
 
 using std::endl;
 using std::string;

+ 271 - 0
tests/display/test_color_buffer.py

@@ -0,0 +1,271 @@
+from panda3d import core
+import pytest
+
+TEST_COLOR = core.LColor(1, 127/255.0, 0, 127/255.0)
+TEST_COLOR_SCALE = core.LVecBase4(0.5, 0.5, 0.5, 0.5)
+TEST_SCALED_COLOR = core.LColor(TEST_COLOR)
+TEST_SCALED_COLOR.componentwise_mult(TEST_COLOR_SCALE)
+FUZZ = 0.02
+
+
[email protected](scope='session', params=[False, True], ids=["shader:off", "shader:auto"])
+def shader_attrib(request):
+    """Returns two ShaderAttribs: one with auto shader, one without."""
+    if request.param:
+        return core.ShaderAttrib.make_default().set_shader_auto(True)
+    else:
+        return core.ShaderAttrib.make_off()
+
+
[email protected](scope='session', params=["mat:off", "mat:empty", "mat:amb", "mat:diff", "mat:both"])
+def material_attrib(request):
+    """Returns two MaterialAttribs: one with material, one without.  It
+    shouldn't really matter what we set them to, since the tests in here do
+    not use lighting, and therefore the material should be ignored."""
+
+    if request.param == "mat:off":
+        return core.MaterialAttrib.make_off()
+
+    elif request.param == "mat:empty":
+        return core.MaterialAttrib.make(core.Material())
+
+    elif request.param == "mat:amb":
+        mat = core.Material()
+        mat.ambient = (0.1, 1, 0.5, 1)
+        return core.MaterialAttrib.make(mat)
+
+    elif request.param == "mat:diff":
+        mat = core.Material()
+        mat.diffuse = (0.1, 1, 0.5, 1)
+        return core.MaterialAttrib.make(mat)
+
+    elif request.param == "mat:both":
+        mat = core.Material()
+        mat.diffuse = (0.1, 1, 0.5, 1)
+        mat.ambient = (0.1, 1, 0.5, 1)
+        return core.MaterialAttrib.make(mat)
+
+
[email protected](scope='module', params=[False, True], ids=["srgb:off", "srgb:on"])
+def color_region(request, graphics_pipe):
+    """Creates and returns a DisplayRegion with a depth buffer."""
+
+    engine = core.GraphicsEngine()
+    engine.set_threading_model("")
+
+    host_fbprops = core.FrameBufferProperties()
+    host_fbprops.force_hardware = True
+
+    host = engine.make_output(
+        graphics_pipe,
+        'host',
+        0,
+        host_fbprops,
+        core.WindowProperties.size(32, 32),
+        core.GraphicsPipe.BF_refuse_window,
+    )
+    engine.open_windows()
+
+    if host is None:
+        pytest.skip("GraphicsPipe cannot make offscreen buffers")
+
+    fbprops = core.FrameBufferProperties()
+    fbprops.force_hardware = True
+    fbprops.set_rgba_bits(8, 8, 8, 8)
+    fbprops.srgb_color = request.param
+
+    buffer = engine.make_output(
+        graphics_pipe,
+        'buffer',
+        0,
+        fbprops,
+        core.WindowProperties.size(32, 32),
+        core.GraphicsPipe.BF_refuse_window,
+        host.gsg,
+        host
+    )
+    engine.open_windows()
+
+    if buffer is None:
+        pytest.skip("Cannot make color buffer")
+
+    if fbprops.srgb_color != buffer.get_fb_properties().srgb_color:
+        pytest.skip("Cannot make buffer with required srgb_color setting")
+
+    buffer.set_clear_color_active(True)
+    buffer.set_clear_color((0, 0, 0, 1))
+
+    yield buffer.make_display_region()
+
+    if buffer is not None:
+        engine.remove_window(buffer)
+
+
+def render_color_pixel(region, state, vertex_color=None):
+    """Renders a fragment using the specified render settings, and returns the
+    resulting color value."""
+
+    # Set up the scene with a blank card rendering at specified distance.
+    scene = core.NodePath("root")
+    scene.set_attrib(core.DepthTestAttrib.make(core.RenderAttrib.M_always))
+
+    camera = scene.attach_new_node(core.Camera("camera"))
+    camera.node().get_lens(0).set_near_far(1, 3)
+    camera.node().set_cull_bounds(core.OmniBoundingVolume())
+
+    cm = core.CardMaker("card")
+    cm.set_frame(-1, 1, -1, 1)
+
+    if vertex_color is not None:
+        cm.set_color(vertex_color)
+
+    card = scene.attach_new_node(cm.generate())
+    card.set_state(state)
+    card.set_pos(0, 2, 0)
+    card.set_scale(60)
+
+    region.active = True
+    region.camera = camera
+
+    color_texture = core.Texture("color")
+    region.window.add_render_texture(color_texture,
+                                     core.GraphicsOutput.RTM_copy_ram,
+                                     core.GraphicsOutput.RTP_color)
+
+    region.window.engine.render_frame()
+    region.window.clear_render_textures()
+
+    col = core.LColor()
+    color_texture.peek().lookup(col, 0.5, 0.5)
+    return col
+
+
+def test_color_write_mask(color_region):
+    state = core.RenderState.make(
+        core.ColorWriteAttrib.make(core.ColorWriteAttrib.C_green),
+    )
+    result = render_color_pixel(color_region, state)
+    assert result == (0, 1, 0, 1)
+
+
+def test_color_empty(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state)
+    assert result == (1, 1, 1, 1)
+
+
+def test_color_off(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        core.ColorAttrib.make_off(),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state)
+    assert result == (1, 1, 1, 1)
+
+
+def test_color_flat(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        core.ColorAttrib.make_flat(TEST_COLOR),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state)
+    assert result.almost_equal(TEST_COLOR, FUZZ)
+
+
+def test_color_vertex(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        core.ColorAttrib.make_vertex(),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
+    assert result.almost_equal(TEST_COLOR, FUZZ)
+
+
+def test_color_empty_vertex(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
+    assert result.almost_equal(TEST_COLOR, FUZZ)
+
+
+def test_color_off_vertex(color_region, shader_attrib, material_attrib):
+    #XXX This behaviour is really odd.
+    state = core.RenderState.make(
+        core.ColorAttrib.make_off(),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
+    assert result.almost_equal(TEST_COLOR, FUZZ)
+
+
+def test_scaled_color_empty(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state)
+    assert result == (1, 1, 1, 1)
+
+
+def test_scaled_color_off(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        core.ColorAttrib.make_off(),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state)
+    assert result == (1, 1, 1, 1)
+
+
+def test_scaled_color_flat(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        core.ColorAttrib.make_flat(TEST_COLOR),
+        core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state)
+    assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
+
+
+def test_scaled_color_vertex(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        core.ColorAttrib.make_vertex(),
+        core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
+    assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
+
+
+def test_scaled_color_empty_vertex(color_region, shader_attrib, material_attrib):
+    state = core.RenderState.make(
+        core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
+    assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
+
+
+def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib):
+    #XXX This behaviour is really odd.
+    state = core.RenderState.make(
+        core.ColorAttrib.make_off(),
+        core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
+        shader_attrib,
+        material_attrib,
+    )
+    result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
+    assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
+

+ 0 - 2
tests/display/test_depth_buffer.py

@@ -91,8 +91,6 @@ def render_depth_pixel(region, distance, near, far, clear=None, write=True):
     region.window.engine.render_frame()
     region.window.clear_render_textures()
 
-    depth_texture.write("test2.png")
-
     col = core.LColor()
     depth_texture.peek().lookup(col, 0.5, 0.5)
     return col[0]