mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-27 07:03:36 -04:00
Merge branch 'release/1.10.x'
This commit is contained in:
commit
b655aa86c5
@ -4,7 +4,7 @@ opening a graphical window and setting up the scene graph.
|
||||
This example demonstrates its use:
|
||||
|
||||
import direct.directbase.DirectStart
|
||||
run()
|
||||
base.run()
|
||||
|
||||
While it may be considered useful for quick prototyping in the interactive
|
||||
Python shell, using it in applications is not considered good style.
|
||||
|
5
direct/src/dist/FreezeTool.py
vendored
5
direct/src/dist/FreezeTool.py
vendored
@ -1333,7 +1333,8 @@ class Freezer:
|
||||
for moduleName, module in list(self.mf.modules.items()):
|
||||
if module.__code__:
|
||||
origPathname = module.__code__.co_filename
|
||||
replace_paths.append((origPathname, moduleName))
|
||||
if origPathname:
|
||||
replace_paths.append((origPathname, moduleName))
|
||||
self.mf.replace_paths = replace_paths
|
||||
|
||||
# Now that we have built up the replacement mapping, go back
|
||||
@ -1721,6 +1722,8 @@ class Freezer:
|
||||
|
||||
def generateRuntimeFromStub(self, target, stub_file, use_console, fields={},
|
||||
log_append=False):
|
||||
self.__replacePaths()
|
||||
|
||||
# We must have a __main__ module to make an exe file.
|
||||
if not self.__writingModule('__main__'):
|
||||
message = "Can't generate an executable without a __main__ module."
|
||||
|
@ -260,6 +260,7 @@ class ConnectionRepository(
|
||||
searchPath = getModelPath().getValue()
|
||||
for dcFileName in dcFileNames:
|
||||
pathname = Filename(dcFileName)
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
vfs.resolveFilename(pathname, searchPath)
|
||||
readResult = dcFile.read(pathname)
|
||||
if not readResult:
|
||||
|
@ -225,6 +225,7 @@ class ServerRepository:
|
||||
searchPath = getModelPath().getValue()
|
||||
for dcFileName in dcFileNames:
|
||||
pathname = Filename(dcFileName)
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
vfs.resolveFilename(pathname, searchPath)
|
||||
readResult = dcFile.read(pathname)
|
||||
if not readResult:
|
||||
|
@ -24,14 +24,14 @@ class Loader(DirectObject):
|
||||
|
||||
_loadedPythonFileTypes = False
|
||||
|
||||
class Callback:
|
||||
class _Callback:
|
||||
"""Returned by loadModel when used asynchronously. This class is
|
||||
modelled after Future, and can be awaited."""
|
||||
|
||||
# This indicates that this class behaves like a Future.
|
||||
_asyncio_future_blocking = False
|
||||
|
||||
class ResultAwaiter(object):
|
||||
class _ResultAwaiter(object):
|
||||
"""Reinvents generators because of PEP 479, sigh. See #513."""
|
||||
|
||||
__slots__ = 'requestList', 'index'
|
||||
@ -126,9 +126,9 @@ class Loader(DirectObject):
|
||||
self._asyncio_future_blocking = True
|
||||
|
||||
if self.gotList:
|
||||
return self.ResultAwaiter([self])
|
||||
return self._ResultAwaiter([self])
|
||||
else:
|
||||
return self.ResultAwaiter(self.requestList)
|
||||
return self._ResultAwaiter(self.requestList)
|
||||
|
||||
def __aiter__(self):
|
||||
""" This allows using `async for` to iterate asynchronously over
|
||||
@ -138,7 +138,7 @@ class Loader(DirectObject):
|
||||
requestList = self.requestList
|
||||
assert requestList is not None, "Request was cancelled."
|
||||
|
||||
return self.ResultAwaiter(requestList)
|
||||
return self._ResultAwaiter(requestList)
|
||||
|
||||
# special methods
|
||||
def __init__(self, base):
|
||||
@ -308,7 +308,7 @@ class Loader(DirectObject):
|
||||
# requested models have been loaded, we'll invoke the
|
||||
# callback (passing it the models on the parameter list).
|
||||
|
||||
cb = Loader.Callback(self, len(modelList), gotList, callback, extraArgs)
|
||||
cb = Loader._Callback(self, len(modelList), gotList, callback, extraArgs)
|
||||
i = 0
|
||||
for modelPath in modelList:
|
||||
request = self.loader.makeAsyncRequest(Filename(modelPath), loaderOptions)
|
||||
@ -476,7 +476,7 @@ class Loader(DirectObject):
|
||||
# requested models have been saved, we'll invoke the
|
||||
# callback (passing it the models on the parameter list).
|
||||
|
||||
cb = Loader.Callback(self, len(modelList), gotList, callback, extraArgs)
|
||||
cb = Loader._Callback(self, len(modelList), gotList, callback, extraArgs)
|
||||
i = 0
|
||||
for modelPath, node in modelList:
|
||||
request = self.loader.makeAsyncSaveRequest(Filename(modelPath), loaderOptions, node)
|
||||
@ -1013,7 +1013,7 @@ class Loader(DirectObject):
|
||||
# requested sounds have been loaded, we'll invoke the
|
||||
# callback (passing it the sounds on the parameter list).
|
||||
|
||||
cb = Loader.Callback(self, len(soundList), gotList, callback, extraArgs)
|
||||
cb = Loader._Callback(self, len(soundList), gotList, callback, extraArgs)
|
||||
for i, soundPath in enumerate(soundList):
|
||||
request = AudioLoadRequest(manager, soundPath, positional)
|
||||
request.setDoneEvent(self.hook)
|
||||
@ -1078,7 +1078,7 @@ class Loader(DirectObject):
|
||||
callback = self.__asyncFlattenDone
|
||||
gotList = True
|
||||
|
||||
cb = Loader.Callback(self, len(modelList), gotList, callback, extraArgs)
|
||||
cb = Loader._Callback(self, len(modelList), gotList, callback, extraArgs)
|
||||
i = 0
|
||||
for model in modelList:
|
||||
request = ModelFlattenRequest(model.node())
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""This defines the Messenger class, which is responsible for most of the
|
||||
event handling that happens on the Python side.
|
||||
:ref:`event handling <event-handlers>` that happens on the Python side.
|
||||
"""
|
||||
|
||||
__all__ = ['Messenger']
|
||||
|
@ -1,4 +1,4 @@
|
||||
""" This module contains ShowBase, an application framework responsible
|
||||
""" This module contains `.ShowBase`, an application framework responsible
|
||||
for opening a graphical display, setting up input devices and creating
|
||||
the scene graph.
|
||||
|
||||
@ -19,14 +19,15 @@ Built-in global variables
|
||||
Some key variables used in all Panda3D scripts are actually attributes of the
|
||||
ShowBase instance. When creating an instance of this class, it will write many
|
||||
of these variables to the built-in scope of the Python interpreter, so that
|
||||
they are accessible to any Python module.
|
||||
they are accessible to any Python module, without the need fors extra imports.
|
||||
|
||||
While these are handy for prototyping, we do not recommend using them in bigger
|
||||
projects, as it can make the code confusing to read to other Python developers,
|
||||
to whom it may not be obvious where these variables are originating.
|
||||
|
||||
Some of these built-in variables are documented further in the
|
||||
:mod:`~direct.showbase.ShowBaseGlobal` module.
|
||||
Refer to the :mod:`builtins` page for a listing of the variables written to the
|
||||
built-in scope.
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ['ShowBase', 'WindowControls']
|
||||
@ -2016,7 +2017,7 @@ class ShowBase(DirectObject.DirectObject):
|
||||
def enableAllAudio(self):
|
||||
"""
|
||||
Reenables the SFX and music managers that were active at the time
|
||||
`disableAllAudio() was called. Meant to be called when the app regains
|
||||
`disableAllAudio()` was called. Meant to be called when the app regains
|
||||
audio focus.
|
||||
"""
|
||||
self.AppHasAudioFocus = 1
|
||||
|
@ -2,9 +2,14 @@
|
||||
:class:`~.ShowBase.ShowBase` instance, as an alternative to using the builtin
|
||||
scope.
|
||||
|
||||
Note that you cannot directly import `base` from this module since ShowBase
|
||||
may not have been created yet; instead, ShowBase dynamically adds itself to
|
||||
this module's scope when instantiated."""
|
||||
Many of the variables contained in this module are also automatically written
|
||||
to the :mod:`builtins` module when ShowBase is instantiated, making them
|
||||
available to any Python code. Importing them from this module instead can make
|
||||
it easier to see where these variables are coming from.
|
||||
|
||||
Note that you cannot directly import :data:`~builtins.base` from this module
|
||||
since ShowBase may not have been created yet; instead, ShowBase dynamically
|
||||
adds itself to this module's scope when instantiated."""
|
||||
|
||||
__all__ = []
|
||||
|
||||
@ -17,8 +22,8 @@ from . import DConfig as config
|
||||
|
||||
__dev__ = config.GetBool('want-dev', __debug__)
|
||||
|
||||
#: The global instance of the :class:`~panda3d.core.VirtualFileSystem`, as
|
||||
#: obtained using :meth:`panda3d.core.VirtualFileSystem.getGlobalPtr()`.
|
||||
#: The global instance of the :ref:`virtual-file-system`, as obtained using
|
||||
#: :meth:`panda3d.core.VirtualFileSystem.getGlobalPtr()`.
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
|
||||
#: The default Panda3D output stream for notifications and logging, as
|
||||
|
@ -351,7 +351,7 @@ cnan(double v) {
|
||||
#if __FINITE_MATH_ONLY__
|
||||
// GCC's isnan breaks when using -ffast-math.
|
||||
union { double d; uint64_t x; } u = { v };
|
||||
return ((u.x << 1) > 0xff70000000000000ull);
|
||||
return ((u.x << 1) > 0xffe0000000000000ull);
|
||||
#elif !defined(_WIN32)
|
||||
return std::isnan(v);
|
||||
#else
|
||||
@ -383,7 +383,7 @@ cinf(double v) {
|
||||
#if __FINITE_MATH_ONLY__
|
||||
// GCC's isinf breaks when using -ffast-math.
|
||||
union { double d; uint64_t x; } u = { v };
|
||||
return ((u.x << 1) == 0xff70000000000000ull);
|
||||
return ((u.x << 1) == 0xffe0000000000000ull);
|
||||
#elif !defined(_WIN32)
|
||||
return std::isinf(v);
|
||||
#else
|
||||
|
@ -150,7 +150,11 @@ triangulate() {
|
||||
}
|
||||
*/
|
||||
|
||||
int attempts = 0;
|
||||
|
||||
while (construct_trapezoids(num_segments) != 0) {
|
||||
nassertv_always(attempts++ < 100);
|
||||
|
||||
// If there's an error, re-shuffle the index and try again.
|
||||
Randomizer randomizer;
|
||||
for (i = 0; i < num_segments; ++i) {
|
||||
|
@ -1485,7 +1485,9 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
|
||||
// Combine in alpha, which bypasses lighting calculations. Use of lerp
|
||||
// here is a workaround for a radeon driver bug.
|
||||
if (key._calc_primary_alpha) {
|
||||
if (key._color_type == ColorAttrib::T_vertex) {
|
||||
if (key._material_flags & Material::F_diffuse) {
|
||||
text << "\t result.a = attr_material[1].w;\n";
|
||||
} else if (key._color_type == ColorAttrib::T_vertex) {
|
||||
text << "\t result.a = l_color.a;\n";
|
||||
} else if (key._color_type == ColorAttrib::T_flat) {
|
||||
text << "\t result.a = attr_color.a;\n";
|
||||
|
@ -203,6 +203,11 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
||||
|
||||
ButtonHandle button = param.get_button();
|
||||
|
||||
if (button == KeyboardButton::tab()) {
|
||||
// Tab. Ignore the entry.
|
||||
return;
|
||||
}
|
||||
|
||||
if (button == MouseButton::one() ||
|
||||
button == MouseButton::two() ||
|
||||
button == MouseButton::three() ||
|
||||
|
@ -46,6 +46,16 @@ def material_attrib(request):
|
||||
return core.MaterialAttrib.make(mat)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def light_attrib():
|
||||
light = core.AmbientLight('amb')
|
||||
light.color = (1, 1, 1, 1)
|
||||
light_attrib = core.LightAttrib.make()
|
||||
light_attrib = light_attrib.add_on_light(core.NodePath(light))
|
||||
|
||||
return light_attrib
|
||||
|
||||
|
||||
@pytest.fixture(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."""
|
||||
@ -297,3 +307,63 @@ def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib):
|
||||
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||
assert result.almost_equal(TEST_COLOR_SCALE, FUZZ)
|
||||
|
||||
|
||||
def test_color_transparency(color_region, shader_attrib, light_attrib):
|
||||
mat = core.Material()
|
||||
mat.diffuse = (1, 1, 1, 0.75)
|
||||
material_attrib = core.MaterialAttrib.make(mat)
|
||||
|
||||
state = core.RenderState.make(
|
||||
core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
|
||||
light_attrib,
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result.x == pytest.approx(0.75, 0.1)
|
||||
|
||||
|
||||
def test_color_transparency_flat(color_region, shader_attrib, light_attrib):
|
||||
mat = core.Material()
|
||||
mat.diffuse = (1, 1, 1, 0.75)
|
||||
material_attrib = core.MaterialAttrib.make(mat)
|
||||
|
||||
state = core.RenderState.make(
|
||||
core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
|
||||
core.ColorAttrib.make_flat(TEST_COLOR),
|
||||
light_attrib,
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result.x == pytest.approx(0.75, 0.1)
|
||||
|
||||
|
||||
def test_color_transparency_vertex(color_region, shader_attrib, light_attrib):
|
||||
mat = core.Material()
|
||||
mat.diffuse = (1, 1, 1, 0.75)
|
||||
material_attrib = core.MaterialAttrib.make(mat)
|
||||
|
||||
state = core.RenderState.make(
|
||||
core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
|
||||
core.ColorAttrib.make_vertex(),
|
||||
light_attrib,
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state, vertex_color=(1, 1, 1, 0.5))
|
||||
assert result.x == pytest.approx(0.75, 0.1)
|
||||
|
||||
|
||||
def test_color_transparency_no_light(color_region, shader_attrib):
|
||||
mat = core.Material()
|
||||
mat.diffuse = (1, 1, 1, 0.75)
|
||||
material_attrib = core.MaterialAttrib.make(mat)
|
||||
|
||||
state = core.RenderState.make(
|
||||
core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
|
||||
shader_attrib,
|
||||
material_attrib,
|
||||
)
|
||||
result = render_color_pixel(color_region, state)
|
||||
assert result.x == pytest.approx(1.0, 0.1)
|
||||
|
@ -20,4 +20,4 @@ def test_filename_ctor_pathlib():
|
||||
|
||||
path = pathlib.Path(__file__)
|
||||
fn = Filename(path)
|
||||
assert fn.to_os_specific_w() == str(path)
|
||||
assert fn.to_os_specific_w().lower() == str(path).lower()
|
||||
|
@ -1,4 +1,4 @@
|
||||
from panda3d.core import PerspectiveLens, Point3, Point2
|
||||
from panda3d.core import PerspectiveLens, Point3, Point2, CS_zup_right
|
||||
|
||||
|
||||
def test_perspectivelens_extrude():
|
||||
@ -75,3 +75,25 @@ def test_perspectivelens_project():
|
||||
|
||||
assert lens.project((100, 100, 0), point)
|
||||
assert point.almost_equal((1, 0), 0.001)
|
||||
|
||||
|
||||
def test_perspectivelens_far_inf():
|
||||
lens = PerspectiveLens()
|
||||
lens.set_fov(90, 90)
|
||||
lens.set_near_far(2, float("inf"))
|
||||
lens.coordinate_system = CS_zup_right
|
||||
|
||||
mat = lens.get_projection_mat()
|
||||
assert mat[1][2] == 1
|
||||
assert mat[3][2] == -4
|
||||
|
||||
|
||||
def test_perspectivelens_near_inf():
|
||||
lens = PerspectiveLens()
|
||||
lens.set_fov(90, 90)
|
||||
lens.set_near_far(float("inf"), 2)
|
||||
lens.coordinate_system = CS_zup_right
|
||||
|
||||
mat = lens.get_projection_mat()
|
||||
assert mat[1][2] == -1
|
||||
assert mat[3][2] == 4
|
||||
|
@ -89,3 +89,31 @@ def test_vec2_compare():
|
||||
assert Vec2(1, 0).compare_to(Vec2(0, 1)) == 1
|
||||
assert Vec2(0, 1).compare_to(Vec2(1, 0)) == -1
|
||||
assert Vec2(0, 1).compare_to(Vec2(0, 1)) == 0
|
||||
|
||||
|
||||
def test_vec2_nan():
|
||||
nan = float("nan")
|
||||
inf = float("inf")
|
||||
assert not Vec2F(0, 0).is_nan()
|
||||
assert not Vec2F(1, 0).is_nan()
|
||||
assert Vec2F(nan, 0).is_nan()
|
||||
assert Vec2F(0, nan).is_nan()
|
||||
assert Vec2F(nan, nan).is_nan()
|
||||
assert Vec2F(-nan, 0).is_nan()
|
||||
assert Vec2F(-nan, nan).is_nan()
|
||||
assert Vec2F(inf, nan).is_nan()
|
||||
assert not Vec2F(inf, 0).is_nan()
|
||||
assert not Vec2F(inf, inf).is_nan()
|
||||
assert not Vec2F(-inf, 0).is_nan()
|
||||
|
||||
assert not Vec2D(0, 0).is_nan()
|
||||
assert not Vec2D(1, 0).is_nan()
|
||||
assert Vec2D(nan, 0).is_nan()
|
||||
assert Vec2D(0, nan).is_nan()
|
||||
assert Vec2D(nan, nan).is_nan()
|
||||
assert Vec2D(-nan, 0).is_nan()
|
||||
assert Vec2D(-nan, nan).is_nan()
|
||||
assert Vec2D(inf, nan).is_nan()
|
||||
assert not Vec2D(inf, 0).is_nan()
|
||||
assert not Vec2D(inf, inf).is_nan()
|
||||
assert not Vec2D(-inf, 0).is_nan()
|
||||
|
Loading…
x
Reference in New Issue
Block a user