mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-27 23:34:57 -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:
|
This example demonstrates its use:
|
||||||
|
|
||||||
import direct.directbase.DirectStart
|
import direct.directbase.DirectStart
|
||||||
run()
|
base.run()
|
||||||
|
|
||||||
While it may be considered useful for quick prototyping in the interactive
|
While it may be considered useful for quick prototyping in the interactive
|
||||||
Python shell, using it in applications is not considered good style.
|
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()):
|
for moduleName, module in list(self.mf.modules.items()):
|
||||||
if module.__code__:
|
if module.__code__:
|
||||||
origPathname = module.__code__.co_filename
|
origPathname = module.__code__.co_filename
|
||||||
replace_paths.append((origPathname, moduleName))
|
if origPathname:
|
||||||
|
replace_paths.append((origPathname, moduleName))
|
||||||
self.mf.replace_paths = replace_paths
|
self.mf.replace_paths = replace_paths
|
||||||
|
|
||||||
# Now that we have built up the replacement mapping, go back
|
# 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={},
|
def generateRuntimeFromStub(self, target, stub_file, use_console, fields={},
|
||||||
log_append=False):
|
log_append=False):
|
||||||
|
self.__replacePaths()
|
||||||
|
|
||||||
# We must have a __main__ module to make an exe file.
|
# We must have a __main__ module to make an exe file.
|
||||||
if not self.__writingModule('__main__'):
|
if not self.__writingModule('__main__'):
|
||||||
message = "Can't generate an executable without a __main__ module."
|
message = "Can't generate an executable without a __main__ module."
|
||||||
|
@ -260,6 +260,7 @@ class ConnectionRepository(
|
|||||||
searchPath = getModelPath().getValue()
|
searchPath = getModelPath().getValue()
|
||||||
for dcFileName in dcFileNames:
|
for dcFileName in dcFileNames:
|
||||||
pathname = Filename(dcFileName)
|
pathname = Filename(dcFileName)
|
||||||
|
vfs = VirtualFileSystem.getGlobalPtr()
|
||||||
vfs.resolveFilename(pathname, searchPath)
|
vfs.resolveFilename(pathname, searchPath)
|
||||||
readResult = dcFile.read(pathname)
|
readResult = dcFile.read(pathname)
|
||||||
if not readResult:
|
if not readResult:
|
||||||
|
@ -225,6 +225,7 @@ class ServerRepository:
|
|||||||
searchPath = getModelPath().getValue()
|
searchPath = getModelPath().getValue()
|
||||||
for dcFileName in dcFileNames:
|
for dcFileName in dcFileNames:
|
||||||
pathname = Filename(dcFileName)
|
pathname = Filename(dcFileName)
|
||||||
|
vfs = VirtualFileSystem.getGlobalPtr()
|
||||||
vfs.resolveFilename(pathname, searchPath)
|
vfs.resolveFilename(pathname, searchPath)
|
||||||
readResult = dcFile.read(pathname)
|
readResult = dcFile.read(pathname)
|
||||||
if not readResult:
|
if not readResult:
|
||||||
|
@ -24,14 +24,14 @@ class Loader(DirectObject):
|
|||||||
|
|
||||||
_loadedPythonFileTypes = False
|
_loadedPythonFileTypes = False
|
||||||
|
|
||||||
class Callback:
|
class _Callback:
|
||||||
"""Returned by loadModel when used asynchronously. This class is
|
"""Returned by loadModel when used asynchronously. This class is
|
||||||
modelled after Future, and can be awaited."""
|
modelled after Future, and can be awaited."""
|
||||||
|
|
||||||
# This indicates that this class behaves like a Future.
|
# This indicates that this class behaves like a Future.
|
||||||
_asyncio_future_blocking = False
|
_asyncio_future_blocking = False
|
||||||
|
|
||||||
class ResultAwaiter(object):
|
class _ResultAwaiter(object):
|
||||||
"""Reinvents generators because of PEP 479, sigh. See #513."""
|
"""Reinvents generators because of PEP 479, sigh. See #513."""
|
||||||
|
|
||||||
__slots__ = 'requestList', 'index'
|
__slots__ = 'requestList', 'index'
|
||||||
@ -126,9 +126,9 @@ class Loader(DirectObject):
|
|||||||
self._asyncio_future_blocking = True
|
self._asyncio_future_blocking = True
|
||||||
|
|
||||||
if self.gotList:
|
if self.gotList:
|
||||||
return self.ResultAwaiter([self])
|
return self._ResultAwaiter([self])
|
||||||
else:
|
else:
|
||||||
return self.ResultAwaiter(self.requestList)
|
return self._ResultAwaiter(self.requestList)
|
||||||
|
|
||||||
def __aiter__(self):
|
def __aiter__(self):
|
||||||
""" This allows using `async for` to iterate asynchronously over
|
""" This allows using `async for` to iterate asynchronously over
|
||||||
@ -138,7 +138,7 @@ class Loader(DirectObject):
|
|||||||
requestList = self.requestList
|
requestList = self.requestList
|
||||||
assert requestList is not None, "Request was cancelled."
|
assert requestList is not None, "Request was cancelled."
|
||||||
|
|
||||||
return self.ResultAwaiter(requestList)
|
return self._ResultAwaiter(requestList)
|
||||||
|
|
||||||
# special methods
|
# special methods
|
||||||
def __init__(self, base):
|
def __init__(self, base):
|
||||||
@ -308,7 +308,7 @@ class Loader(DirectObject):
|
|||||||
# requested models have been loaded, we'll invoke the
|
# requested models have been loaded, we'll invoke the
|
||||||
# callback (passing it the models on the parameter list).
|
# 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
|
i = 0
|
||||||
for modelPath in modelList:
|
for modelPath in modelList:
|
||||||
request = self.loader.makeAsyncRequest(Filename(modelPath), loaderOptions)
|
request = self.loader.makeAsyncRequest(Filename(modelPath), loaderOptions)
|
||||||
@ -476,7 +476,7 @@ class Loader(DirectObject):
|
|||||||
# requested models have been saved, we'll invoke the
|
# requested models have been saved, we'll invoke the
|
||||||
# callback (passing it the models on the parameter list).
|
# 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
|
i = 0
|
||||||
for modelPath, node in modelList:
|
for modelPath, node in modelList:
|
||||||
request = self.loader.makeAsyncSaveRequest(Filename(modelPath), loaderOptions, node)
|
request = self.loader.makeAsyncSaveRequest(Filename(modelPath), loaderOptions, node)
|
||||||
@ -1013,7 +1013,7 @@ class Loader(DirectObject):
|
|||||||
# requested sounds have been loaded, we'll invoke the
|
# requested sounds have been loaded, we'll invoke the
|
||||||
# callback (passing it the sounds on the parameter list).
|
# 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):
|
for i, soundPath in enumerate(soundList):
|
||||||
request = AudioLoadRequest(manager, soundPath, positional)
|
request = AudioLoadRequest(manager, soundPath, positional)
|
||||||
request.setDoneEvent(self.hook)
|
request.setDoneEvent(self.hook)
|
||||||
@ -1078,7 +1078,7 @@ class Loader(DirectObject):
|
|||||||
callback = self.__asyncFlattenDone
|
callback = self.__asyncFlattenDone
|
||||||
gotList = True
|
gotList = True
|
||||||
|
|
||||||
cb = Loader.Callback(self, len(modelList), gotList, callback, extraArgs)
|
cb = Loader._Callback(self, len(modelList), gotList, callback, extraArgs)
|
||||||
i = 0
|
i = 0
|
||||||
for model in modelList:
|
for model in modelList:
|
||||||
request = ModelFlattenRequest(model.node())
|
request = ModelFlattenRequest(model.node())
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""This defines the Messenger class, which is responsible for most of the
|
"""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']
|
__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
|
for opening a graphical display, setting up input devices and creating
|
||||||
the scene graph.
|
the scene graph.
|
||||||
|
|
||||||
@ -19,14 +19,15 @@ Built-in global variables
|
|||||||
Some key variables used in all Panda3D scripts are actually attributes of the
|
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
|
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
|
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
|
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,
|
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.
|
to whom it may not be obvious where these variables are originating.
|
||||||
|
|
||||||
Some of these built-in variables are documented further in the
|
Refer to the :mod:`builtins` page for a listing of the variables written to the
|
||||||
:mod:`~direct.showbase.ShowBaseGlobal` module.
|
built-in scope.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__all__ = ['ShowBase', 'WindowControls']
|
__all__ = ['ShowBase', 'WindowControls']
|
||||||
@ -2016,7 +2017,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||||||
def enableAllAudio(self):
|
def enableAllAudio(self):
|
||||||
"""
|
"""
|
||||||
Reenables the SFX and music managers that were active at the time
|
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.
|
audio focus.
|
||||||
"""
|
"""
|
||||||
self.AppHasAudioFocus = 1
|
self.AppHasAudioFocus = 1
|
||||||
|
@ -2,9 +2,14 @@
|
|||||||
:class:`~.ShowBase.ShowBase` instance, as an alternative to using the builtin
|
:class:`~.ShowBase.ShowBase` instance, as an alternative to using the builtin
|
||||||
scope.
|
scope.
|
||||||
|
|
||||||
Note that you cannot directly import `base` from this module since ShowBase
|
Many of the variables contained in this module are also automatically written
|
||||||
may not have been created yet; instead, ShowBase dynamically adds itself to
|
to the :mod:`builtins` module when ShowBase is instantiated, making them
|
||||||
this module's scope when instantiated."""
|
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__ = []
|
__all__ = []
|
||||||
|
|
||||||
@ -17,8 +22,8 @@ from . import DConfig as config
|
|||||||
|
|
||||||
__dev__ = config.GetBool('want-dev', __debug__)
|
__dev__ = config.GetBool('want-dev', __debug__)
|
||||||
|
|
||||||
#: The global instance of the :class:`~panda3d.core.VirtualFileSystem`, as
|
#: The global instance of the :ref:`virtual-file-system`, as obtained using
|
||||||
#: obtained using :meth:`panda3d.core.VirtualFileSystem.getGlobalPtr()`.
|
#: :meth:`panda3d.core.VirtualFileSystem.getGlobalPtr()`.
|
||||||
vfs = VirtualFileSystem.getGlobalPtr()
|
vfs = VirtualFileSystem.getGlobalPtr()
|
||||||
|
|
||||||
#: The default Panda3D output stream for notifications and logging, as
|
#: The default Panda3D output stream for notifications and logging, as
|
||||||
|
@ -351,7 +351,7 @@ cnan(double v) {
|
|||||||
#if __FINITE_MATH_ONLY__
|
#if __FINITE_MATH_ONLY__
|
||||||
// GCC's isnan breaks when using -ffast-math.
|
// GCC's isnan breaks when using -ffast-math.
|
||||||
union { double d; uint64_t x; } u = { v };
|
union { double d; uint64_t x; } u = { v };
|
||||||
return ((u.x << 1) > 0xff70000000000000ull);
|
return ((u.x << 1) > 0xffe0000000000000ull);
|
||||||
#elif !defined(_WIN32)
|
#elif !defined(_WIN32)
|
||||||
return std::isnan(v);
|
return std::isnan(v);
|
||||||
#else
|
#else
|
||||||
@ -383,7 +383,7 @@ cinf(double v) {
|
|||||||
#if __FINITE_MATH_ONLY__
|
#if __FINITE_MATH_ONLY__
|
||||||
// GCC's isinf breaks when using -ffast-math.
|
// GCC's isinf breaks when using -ffast-math.
|
||||||
union { double d; uint64_t x; } u = { v };
|
union { double d; uint64_t x; } u = { v };
|
||||||
return ((u.x << 1) == 0xff70000000000000ull);
|
return ((u.x << 1) == 0xffe0000000000000ull);
|
||||||
#elif !defined(_WIN32)
|
#elif !defined(_WIN32)
|
||||||
return std::isinf(v);
|
return std::isinf(v);
|
||||||
#else
|
#else
|
||||||
|
@ -150,7 +150,11 @@ triangulate() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int attempts = 0;
|
||||||
|
|
||||||
while (construct_trapezoids(num_segments) != 0) {
|
while (construct_trapezoids(num_segments) != 0) {
|
||||||
|
nassertv_always(attempts++ < 100);
|
||||||
|
|
||||||
// If there's an error, re-shuffle the index and try again.
|
// If there's an error, re-shuffle the index and try again.
|
||||||
Randomizer randomizer;
|
Randomizer randomizer;
|
||||||
for (i = 0; i < num_segments; ++i) {
|
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
|
// Combine in alpha, which bypasses lighting calculations. Use of lerp
|
||||||
// here is a workaround for a radeon driver bug.
|
// here is a workaround for a radeon driver bug.
|
||||||
if (key._calc_primary_alpha) {
|
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";
|
text << "\t result.a = l_color.a;\n";
|
||||||
} else if (key._color_type == ColorAttrib::T_flat) {
|
} else if (key._color_type == ColorAttrib::T_flat) {
|
||||||
text << "\t result.a = attr_color.a;\n";
|
text << "\t result.a = attr_color.a;\n";
|
||||||
|
@ -203,6 +203,11 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
|
|
||||||
ButtonHandle button = param.get_button();
|
ButtonHandle button = param.get_button();
|
||||||
|
|
||||||
|
if (button == KeyboardButton::tab()) {
|
||||||
|
// Tab. Ignore the entry.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (button == MouseButton::one() ||
|
if (button == MouseButton::one() ||
|
||||||
button == MouseButton::two() ||
|
button == MouseButton::two() ||
|
||||||
button == MouseButton::three() ||
|
button == MouseButton::three() ||
|
||||||
|
@ -46,6 +46,16 @@ def material_attrib(request):
|
|||||||
return core.MaterialAttrib.make(mat)
|
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"])
|
@pytest.fixture(scope='module', params=[False, True], ids=["srgb:off", "srgb:on"])
|
||||||
def color_region(request, graphics_pipe):
|
def color_region(request, graphics_pipe):
|
||||||
"""Creates and returns a DisplayRegion with a depth buffer."""
|
"""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)
|
result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
|
||||||
assert result.almost_equal(TEST_COLOR_SCALE, FUZZ)
|
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__)
|
path = pathlib.Path(__file__)
|
||||||
fn = Filename(path)
|
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():
|
def test_perspectivelens_extrude():
|
||||||
@ -75,3 +75,25 @@ def test_perspectivelens_project():
|
|||||||
|
|
||||||
assert lens.project((100, 100, 0), point)
|
assert lens.project((100, 100, 0), point)
|
||||||
assert point.almost_equal((1, 0), 0.001)
|
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(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(1, 0)) == -1
|
||||||
assert Vec2(0, 1).compare_to(Vec2(0, 1)) == 0
|
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