Merge branch 'release/1.10.x'

This commit is contained in:
rdb 2021-03-24 13:01:28 +01:00
commit eb6eb9f1dd
31 changed files with 445 additions and 117 deletions

View File

@ -216,7 +216,8 @@ class build_apps(setuptools.Command):
'libpthread.so.*', 'libc.so.*', 'ld-linux-x86-64.so.*',
'libgl.so.*', 'libx11.so.*', 'libncursesw.so.*', 'libz.so.*',
'librt.so.*', 'libutil.so.*', 'libnsl.so.1', 'libXext.so.6',
'libXrender.so.1', 'libICE.so.6', 'libSM.so.6',
'libXrender.so.1', 'libICE.so.6', 'libSM.so.6', 'libEGL.so.1',
'libOpenGL.so.0', 'libGLdispatch.so.0', 'libGLX.so.0',
'libgobject-2.0.so.0', 'libgthread-2.0.so.0', 'libglib-2.0.so.0',
# macOS

View File

@ -1199,18 +1199,24 @@ class SerialNumGen:
if start is None:
start = 0
self.__counter = start-1
def next(self):
self.__counter += 1
return self.__counter
__next__ = next
class SerialMaskedGen(SerialNumGen):
def __init__(self, mask, start=None):
self._mask = mask
SerialNumGen.__init__(self, start)
def next(self):
v = SerialNumGen.next(self)
return v & self._mask
__next__ = next
_serialGen = SerialNumGen()
def serialNum():
global _serialGen
@ -2447,6 +2453,7 @@ class AlphabetCounter:
# object that produces 'A', 'B', 'C', ... 'AA', 'AB', etc.
def __init__(self):
self._curCounter = ['A']
def next(self):
result = ''.join([c for c in self._curCounter])
index = -1
@ -2470,6 +2477,8 @@ class AlphabetCounter:
break
return result
__next__ = next
if __debug__ and __name__ == '__main__':
def testAlphabetCounter():
tempList = []

View File

@ -1059,6 +1059,14 @@ if not PkgSkip("EIGEN"):
# will turn them into runtime assertions.
DefSymbol("ALWAYS", "EIGEN_NO_STATIC_ASSERT")
if not PkgSkip("EGL"):
DefSymbol('EGL', 'HAVE_EGL', '')
if PkgSkip("X11"):
DefSymbol('EGL', 'EGL_NO_X11', '')
if not PkgSkip("X11"):
DefSymbol('X11', 'USE_X11', '')
########################################################################
##
## Give a Status Report on Command-Line Options
@ -2832,6 +2840,8 @@ configprc = configprc.replace('\r\n', '\n')
if (GetTarget() == 'windows'):
configprc = configprc.replace("$XDG_CACHE_HOME/panda3d", "$USER_APPDATA/Panda3D-%s" % MAJOR_VERSION)
elif not PkgSkip("X11") and not PkgSkip("GL") and not PkgSkip("EGL") and not GetLinkAllStatic():
configprc = configprc.replace("#load-display pandadx9", "aux-display p3headlessgl")
else:
configprc = configprc.replace("aux-display pandadx9", "")
@ -3172,9 +3182,10 @@ elif GetTarget() == 'darwin':
elif GetTarget() == 'android':
CopyAllHeaders('panda/src/android')
CopyAllHeaders('panda/src/androiddisplay')
else:
if not PkgSkip('X11'):
CopyAllHeaders('panda/src/x11display')
CopyAllHeaders('panda/src/glxdisplay')
if not PkgSkip('GL'):
CopyAllHeaders('panda/src/glxdisplay')
CopyAllHeaders('panda/src/egldisplay')
CopyAllHeaders('panda/metalibs/pandagl')
CopyAllHeaders('panda/metalibs/pandagles')
@ -4587,7 +4598,6 @@ if GetTarget() == 'windows' and not PkgSkip("GL"):
# If we're not compiling with any windowing system at all, but we do have EGL,
# we can use that to create a headless libpandagl instead.
if not PkgSkip("EGL") and not PkgSkip("GL") and PkgSkip("X11") and GetTarget() not in ('windows', 'darwin'):
DefSymbol('EGL', 'HAVE_EGL', '')
OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGL', 'GL', 'EGL']
TargetAdd('pandagl_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx')
OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'GL', 'EGL']
@ -4599,13 +4609,27 @@ if not PkgSkip("EGL") and not PkgSkip("GL") and PkgSkip("X11") and GetTarget() n
TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS)
TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'EGL', 'CGGL'])
elif not PkgSkip("EGL") and not PkgSkip("GL") and GetTarget() not in ('windows', 'darwin'):
# As a temporary solution for #1086, build this module, which we can use as a
# fallback to OpenGL for headless systems.
OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGL', 'GL', 'EGL']
TargetAdd('p3headlessgl_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx')
OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'GL', 'EGL']
TargetAdd('p3headlessgl_pandagl.obj', opts=OPTS, input='pandagl.cxx')
TargetAdd('libp3headlessgl.dll', input='p3headlessgl_pandagl.obj')
TargetAdd('libp3headlessgl.dll', input='p3glgsg_config_glgsg.obj')
TargetAdd('libp3headlessgl.dll', input='p3glgsg_glgsg.obj')
TargetAdd('libp3headlessgl.dll', input='p3headlessgl_egldisplay_composite1.obj')
TargetAdd('libp3headlessgl.dll', input=COMMON_PANDA_LIBS)
TargetAdd('libp3headlessgl.dll', opts=['MODULE', 'GL', 'EGL', 'CGGL'])
#
# DIRECTORY: panda/src/egldisplay/
#
if not PkgSkip("EGL") and not PkgSkip("GLES"):
DefSymbol('GLES', 'OPENGLES_1', '')
OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES', 'GLES', 'EGL']
OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES', 'GLES', 'EGL', 'X11']
TargetAdd('pandagles_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx')
OPTS=['DIR:panda/metalibs/pandagles', 'BUILDING:PANDAGLES', 'GLES', 'EGL']
TargetAdd('pandagles_pandagles.obj', opts=OPTS, input='pandagles.cxx')
@ -4624,7 +4648,7 @@ if not PkgSkip("EGL") and not PkgSkip("GLES"):
if not PkgSkip("EGL") and not PkgSkip("GLES2"):
DefSymbol('GLES2', 'OPENGLES_2', '')
OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES2', 'GLES2', 'EGL']
OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES2', 'GLES2', 'EGL', 'X11']
TargetAdd('pandagles2_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx')
OPTS=['DIR:panda/metalibs/pandagles2', 'BUILDING:PANDAGLES2', 'GLES2', 'EGL']
TargetAdd('pandagles2_pandagles2.obj', opts=OPTS, input='pandagles2.cxx')

View File

@ -82,7 +82,7 @@ ABI_TAG = get_abi_tag()
EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", ".sln"]
# Plug-ins to install.
PLUGIN_LIBS = ["pandagl", "pandagles", "pandagles2", "pandadx9", "p3tinydisplay", "p3ptloader", "p3assimp", "p3ffmpeg", "p3openal_audio", "p3fmod_audio"]
PLUGIN_LIBS = ["pandagl", "pandagles", "pandagles2", "pandadx9", "p3tinydisplay", "p3ptloader", "p3assimp", "p3ffmpeg", "p3openal_audio", "p3fmod_audio", "p3headlessgl"]
# Libraries included in manylinux ABI that should be ignored. See PEP 513/571/599.
MANYLINUX_LIBS = [
@ -95,6 +95,7 @@ MANYLINUX_LIBS = [
# These are not mentioned in manylinux1 spec but should nonetheless always
# be excluded.
"linux-vdso.so.1", "linux-gate.so.1", "ld-linux.so.2", "libdrm.so.2",
"libEGL.so.1", "libOpenGL.so.0", "libGLX.so.0", "libGLdispatch.so.0",
]
# Binaries to never scan for dependencies on non-Windows systems.

View File

@ -23,7 +23,7 @@
#include "glxGraphicsPipe.h"
#endif
#if defined(HAVE_EGL) && !defined(HAVE_X11)
#ifdef HAVE_EGL
#include "config_egldisplay.h"
#include "eglGraphicsPipe.h"
#endif
@ -54,7 +54,7 @@ init_libpandagl() {
init_libglxdisplay();
#endif
#if defined(HAVE_EGL) && !defined(HAVE_X11)
#ifdef HAVE_EGL
init_libegldisplay();
#endif
}
@ -77,9 +77,16 @@ get_pipe_type_pandagl() {
return glxGraphicsPipe::get_class_type().get_index();
#endif
#if defined(HAVE_EGL) && !defined(HAVE_X11)
#ifdef HAVE_EGL
return eglGraphicsPipe::get_class_type().get_index();
#endif
return 0;
}
#if defined(HAVE_EGL) && !defined(USE_X11)
int
get_pipe_type_p3headlessgl() {
return eglGraphicsPipe::get_class_type().get_index();
}
#endif

View File

@ -12,4 +12,8 @@
EXPCL_PANDAGL void init_libpandagl();
extern "C" EXPCL_PANDAGL int get_pipe_type_pandagl();
#if defined(HAVE_EGL) && !defined(USE_X11)
extern "C" EXPCL_PANDAGL int get_pipe_type_p3headlessgl();
#endif
#endif

View File

@ -20,6 +20,12 @@ add_metalib(pandagles ${MODULE_TYPE}
COMPONENTS p3egldisplay_gles1 p3glesgsg p3glstuff p3x11display)
unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
if(HAVE_X11)
target_compile_definitions(pandagles PUBLIC USE_X11)
else()
target_compile_definitions(pandagles PRIVATE EGL_NO_X11)
endif()
install(TARGETS pandagles
EXPORT OpenGLES1 COMPONENT OpenGLES1
DESTINATION ${MODULE_DESTINATION}

View File

@ -10,6 +10,12 @@ add_metalib(pandagles2 ${MODULE_TYPE}
COMPONENTS p3egldisplay_gles2 p3gles2gsg p3glstuff p3x11display)
unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
if(HAVE_X11)
target_compile_definitions(pandagles2 PUBLIC USE_X11)
else()
target_compile_definitions(pandagles2 PRIVATE EGL_NO_X11)
endif()
install(TARGETS pandagles2
EXPORT OpenGLES2 COMPONENT OpenGLES2
DESTINATION ${MODULE_DESTINATION}

View File

@ -35,6 +35,12 @@ if(HAVE_GLES1)
target_link_libraries(p3egldisplay_gles1 p3glesgsg p3x11display
PKG::EGL PKG::GLES1)
if(HAVE_X11)
target_compile_definitions(p3egldisplay_gles1 PUBLIC USE_X11)
else()
target_compile_definitions(p3egldisplay_gles1 PRIVATE EGL_NO_X11)
endif()
if(NOT BUILD_METALIBS)
install(TARGETS p3egldisplay_gles1
EXPORT OpenGLES1 COMPONENT OpenGLES1
@ -55,6 +61,12 @@ if(HAVE_GLES2)
target_link_libraries(p3egldisplay_gles2 p3gles2gsg p3x11display
PKG::EGL PKG::GLES2)
if(HAVE_X11)
target_compile_definitions(p3egldisplay_gles2 PUBLIC USE_X11)
else()
target_compile_definitions(p3egldisplay_gles2 PRIVATE EGL_NO_X11)
endif()
if(NOT BUILD_METALIBS)
install(TARGETS p3egldisplay_gles2
EXPORT OpenGLES2 COMPONENT OpenGLES2

View File

@ -48,7 +48,7 @@ init_libegldisplay() {
eglGraphicsBuffer::init_type();
eglGraphicsPipe::init_type();
#ifdef HAVE_X11
#ifdef USE_X11
eglGraphicsPixmap::init_type();
eglGraphicsWindow::init_type();
#endif

View File

@ -53,7 +53,7 @@ eglGraphicsPipe() {
//NB. if the X11 display failed to open, _display will be 0, which is a valid
// input to eglGetDisplay - it means to open the default display.
#ifdef HAVE_X11
#ifdef USE_X11
_egl_display = eglGetDisplay((NativeDisplayType) _display);
#else
_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@ -207,7 +207,7 @@ make_output(const std::string &name,
// First thing to try: an eglGraphicsWindow
if (retry == 0) {
#ifdef HAVE_X11
#ifdef USE_X11
if (!_display) {
return nullptr;
}
@ -290,7 +290,7 @@ make_output(const std::string &name,
// Fourth thing to try: an eglGraphicsPixmap.
if (retry == 3) {
#ifdef HAVE_X11
#ifdef USE_X11
if (!_display) {
return nullptr;
}

View File

@ -16,12 +16,14 @@
#include "pandabase.h"
#ifdef HAVE_X11
#ifdef USE_X11
#include "x11GraphicsPipe.h"
typedef x11GraphicsPipe BaseGraphicsPipe;
#else
#include "graphicsPipe.h"
typedef GraphicsPipe BaseGraphicsPipe;
#undef EGL_NO_X11
#define EGL_NO_X11 1
#endif
#ifdef OPENGLES_2

View File

@ -13,7 +13,7 @@
#include "eglGraphicsPixmap.h"
#ifdef HAVE_X11
#ifdef USE_X11
#include "eglGraphicsWindow.h"
#include "eglGraphicsStateGuardian.h"
@ -245,4 +245,4 @@ open_buffer() {
return true;
}
#endif // HAVE_X11
#endif // USE_X11

View File

@ -16,7 +16,7 @@
#include "pandabase.h"
#ifdef HAVE_X11
#ifdef USE_X11
#include "eglGraphicsPipe.h"
#include "graphicsBuffer.h"
@ -69,6 +69,6 @@ private:
static TypeHandle _type_handle;
};
#endif // HAVE_X11
#endif // USE_X11
#endif

View File

@ -187,7 +187,7 @@ choose_pixel_format(const FrameBufferProperties &properties,
best_props = fbprops;
}
}
#ifdef HAVE_X11
#ifdef USE_X11
X11_Display *display = egl_pipe->get_display();
if (display) {
int screen = egl_pipe->get_screen();
@ -233,7 +233,7 @@ choose_pixel_format(const FrameBufferProperties &properties,
int err = eglGetError();
if (_context && err == EGL_SUCCESS) {
#ifdef HAVE_X11
#ifdef USE_X11
if (!display || _visual)
#endif
{
@ -262,7 +262,7 @@ choose_pixel_format(const FrameBufferProperties &properties,
<< get_egl_error_string(err) << "\n";
_fbconfig = 0;
_context = 0;
#ifdef HAVE_X11
#ifdef USE_X11
_visual = 0;
#endif
}
@ -306,7 +306,7 @@ egl_is_at_least_version(int major_version, int minor_version) const {
*/
void eglGraphicsStateGuardian::
gl_flush() const {
#ifdef HAVE_X11
#ifdef USE_X11
// This call requires synchronization with X.
LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
#endif
@ -318,7 +318,7 @@ gl_flush() const {
*/
GLenum eglGraphicsStateGuardian::
gl_get_error() const {
#ifdef HAVE_X11
#ifdef USE_X11
// This call requires synchronization with X.
LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
#endif

View File

@ -17,7 +17,7 @@
#include "pandabase.h"
#include "eglGraphicsPipe.h"
#ifdef HAVE_X11
#ifdef USE_X11
#include "get_x11.h"
#endif
@ -55,7 +55,7 @@ public:
EGLContext _share_context;
EGLContext _context;
EGLDisplay _egl_display;
#ifdef HAVE_X11
#ifdef USE_X11
XVisualInfo *_visual = nullptr;
#endif
EGLConfig _fbconfig;

View File

@ -13,7 +13,7 @@
#include "eglGraphicsWindow.h"
#ifdef HAVE_X11
#ifdef USE_X11
#include "eglGraphicsStateGuardian.h"
#include "config_egldisplay.h"
@ -279,4 +279,4 @@ open_window() {
return true;
}
#endif // HAVE_X11
#endif // USE_X11

View File

@ -16,7 +16,7 @@
#include "pandabase.h"
#ifdef HAVE_X11
#ifdef USE_X11
#include "eglGraphicsPipe.h"
#include "x11GraphicsWindow.h"
@ -67,6 +67,6 @@ private:
#include "eglGraphicsWindow.I"
#endif // HAVE_X11
#endif // USE_X11
#endif

View File

@ -28,6 +28,10 @@ add_component_library(p3glxdisplay SYMBOL BUILDING_PANDA_GLXDISPLAY
${P3GLXDISPLAY_HEADERS} ${P3GLXDISPLAY_SOURCES})
target_link_libraries(p3glxdisplay p3glgsg p3x11display)
if(HAVE_X11)
target_compile_definitions(p3glxdisplay PRIVATE USE_X11)
endif()
if(NOT BUILD_METALIBS)
install(TARGETS p3glxdisplay EXPORT OpenGL COMPONENT OpenGL DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()

View File

@ -542,16 +542,49 @@ offset_vertices(int offset, int begin_row, int end_row) {
consider_elevate_index_type(cdata, max_vertex + offset);
GeomVertexRewriter index(do_modify_vertices(cdata), 0);
index.set_row_unsafe(begin_row);
for (int j = begin_row; j < end_row; ++j) {
int vertex = index.get_data1i();
if (vertex != strip_cut_index) {
index.set_data1i(vertex + offset);
{
GeomVertexArrayDataHandle handle(cdata->_vertices.get_write_pointer(),
Thread::get_current_thread());
unsigned char *ptr = handle.get_write_pointer();
switch (cdata->_index_type) {
case GeomEnums::NT_uint8:
for (int i = begin_row; i < end_row; ++i) {
uint8_t &v = ((uint8_t *)ptr)[i];
if (v != 0xff) {
v += offset;
}
}
break;
case GeomEnums::NT_uint16:
for (int i = begin_row; i < end_row; ++i) {
uint16_t &v = ((uint16_t *)ptr)[i];
if (v != 0xffff) {
v += offset;
}
}
break;
case GeomEnums::NT_uint32:
for (int i = begin_row; i < end_row; ++i) {
uint32_t &v = ((uint32_t *)ptr)[i];
if (v != 0xffffffff) {
v += offset;
}
}
break;
default:
nassert_raise("unsupported index type");
break;
}
}
} else {
cdata->_modified = Geom::get_next_modified();
cdata->_got_minmax = false;
}
else {
// The supplied values cover all vertices, so we don't need to make it
// indexed.
CDWriter cdata(_cycler, true);

View File

@ -56,3 +56,11 @@ INLINE bool TexturePeeker::
has_pixel(int x, int y) const {
return x >= 0 && y >= 0 && x < _x_size && y < _y_size;
}
/**
* Returns whether a given coordinate is inside of the texture dimensions.
*/
INLINE bool TexturePeeker::
has_pixel(int x, int y, int z) const {
return x >= 0 && y >= 0 && z >= 0 && x < _x_size && y < _y_size && z < _z_size;
}

View File

@ -74,56 +74,42 @@ static double get_signed_int_i(const unsigned char *&p) {
*/
TexturePeeker::
TexturePeeker(Texture *tex, Texture::CData *cdata) {
if (cdata->_texture_type == Texture::TT_cube_map) {
// Cube map texture. We'll need to map from (u, v, w) to (u, v) within
// the appropriate page, where w indicates the page.
// Simple ram images are possible if it is a 2-d texture.
if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
// Get the regular RAM image if it is available.
_image = tex->do_get_ram_image(cdata);
_x_size = cdata->_x_size;
_y_size = cdata->_y_size;
_z_size = cdata->_z_size;
_pixel_width = cdata->_component_width * cdata->_num_components;
_format = cdata->_format;
_component_type = cdata->_component_type;
}
else if (!cdata->_simple_ram_image._image.empty()) {
// Get the simple RAM image if *that* is available.
_image = cdata->_simple_ram_image._image;
_x_size = cdata->_simple_x_size;
_y_size = cdata->_simple_y_size;
_z_size = 1;
// TODO: handle cube maps.
return;
} else {
// Regular 1-d, 2-d, or 3-d texture. The coordinates map directly.
// Simple ram images are possible if it is a 2-d texture.
if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
// Get the regular RAM image if it is available.
_image = tex->do_get_ram_image(cdata);
_x_size = cdata->_x_size;
_y_size = cdata->_y_size;
_z_size = cdata->_z_size;
_component_width = cdata->_component_width;
_num_components = cdata->_num_components;
_format = cdata->_format;
_component_type = cdata->_component_type;
} else if (!cdata->_simple_ram_image._image.empty()) {
// Get the simple RAM image if *that* is available.
_image = cdata->_simple_ram_image._image;
_x_size = cdata->_simple_x_size;
_y_size = cdata->_simple_y_size;
_z_size = 1;
_component_width = 1;
_num_components = 4;
_format = Texture::F_rgba;
_component_type = Texture::T_unsigned_byte;
} else {
// Failing that, reload and get the uncompressed RAM image.
_image = tex->do_get_uncompressed_ram_image(cdata);
_x_size = cdata->_x_size;
_y_size = cdata->_y_size;
_z_size = cdata->_z_size;
_component_width = cdata->_component_width;
_num_components = cdata->_num_components;
_format = cdata->_format;
_component_type = cdata->_component_type;
}
_pixel_width = 4;
_format = Texture::F_rgba;
_component_type = Texture::T_unsigned_byte;
}
else {
// Failing that, reload and get the uncompressed RAM image.
_image = tex->do_get_uncompressed_ram_image(cdata);
_x_size = cdata->_x_size;
_y_size = cdata->_y_size;
_z_size = cdata->_z_size;
_pixel_width = cdata->_component_width * cdata->_num_components;
_format = cdata->_format;
_component_type = cdata->_component_type;
}
if (_image.is_null()) {
return;
}
_pixel_width = _component_width * _num_components;
if (Texture::is_integer(_format)) {
switch (_component_type) {
@ -291,8 +277,10 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
_image.clear();
return;
}
}
_is_cube = (cdata->_texture_type == Texture::TT_cube_map ||
cdata->_texture_type == Texture::TT_cube_map_array);
}
/**
* Fills "color" with the RGBA color of the texel at point (u, v).
@ -304,22 +292,95 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
*/
void TexturePeeker::
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
fetch_pixel(color, x, y);
if (!_is_cube) {
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
fetch_pixel(color, x, y);
}
else {
lookup(color, u, v, 0);
}
}
/**
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
* coordinates are used.
* Fills "color" with the RGBA color of the texel at point (u, v, w).
*
* The texel color is determined via nearest-point sampling (no filtering of
* adjacent pixels), regardless of the filter type associated with the
* texture. u, v, and w will wrap around regardless of the texture's wrap
* mode.
*/
void TexturePeeker::
fetch_pixel(LColor& color, int x, int y) const {
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const {
if (!_is_cube) {
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
int z = int((w - cfloor(w)) * (PN_stdfloat)_z_size) % _z_size;
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size &&
z >= 0 && z < _z_size);
const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
(*_get_texel)(color, p, _get_component);
}
else {
PN_stdfloat absu = fabs(u),
absv = fabs(v),
absw = fabs(w);
PN_stdfloat magnitude;
PN_stdfloat u2d, v2d;
int z;
// The following was pulled from:
// https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/
if (absw >= absu && absw >= absv) {
z = 4 + (w < 0.0);
magnitude = 0.5 / absw;
u2d = w < 0.0 ? -u : u;
v2d = -v;
}
else if (absv >= absu) {
z = 2 + (v < 0.0);
magnitude = 0.5 / absv;
u2d = u;
v2d = v < 0.0 ? -w : w;
}
else {
z = 0 + (u < 0.0);
magnitude = 0.5 / absu;
u2d = u < 0.0 ? w : -w;
v2d = -v;
}
u2d = u2d * magnitude + 0.5;
v2d = v2d * magnitude + 0.5;
int x = int((u2d - cfloor(u2d)) * (PN_stdfloat)_x_size) % _x_size;
int y = int((v2d - cfloor(v2d)) * (PN_stdfloat)_y_size) % _y_size;
fetch_pixel(color, x, y, z);
}
}
/**
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
* coordinates are used.
*/
void TexturePeeker::
fetch_pixel(LColor &color, int x, int y) const {
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
(*_get_texel)(color, p, _get_component);
}
/**
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
* coordinates are used.
*/
void TexturePeeker::
fetch_pixel(LColor &color, int x, int y, int z) const {
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size && z >= 0 && z < _z_size);
const unsigned char *p = _image.p() + ((z * _y_size + y) * _x_size + x) * _pixel_width;
(*_get_texel)(color, p, _get_component);
}
/**
* Performs a bilinear lookup to retrieve the color value stored at the uv
@ -370,27 +431,6 @@ lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
return true;
}
/**
* Fills "color" with the RGBA color of the texel at point (u, v, w).
*
* The texel color is determined via nearest-point sampling (no filtering of
* adjacent pixels), regardless of the filter type associated with the
* texture. u, v, and w will wrap around regardless of the texture's wrap
* mode.
*/
void TexturePeeker::
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const {
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
int z = int((w - cfloor(w)) * (PN_stdfloat)_z_size) % _z_size;
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size &&
z >= 0 && z < _z_size);
const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
(*_get_texel)(color, p, _get_component);
}
/**
* Fills "color" with the average RGBA color of the texels within the
* rectangle defined by the specified coordinate range.

View File

@ -37,9 +37,11 @@ PUBLISHED:
INLINE int get_z_size() const;
INLINE bool has_pixel(int x, int y) const;
INLINE bool has_pixel(int x, int y, int z) const;
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const;
void fetch_pixel(LColor &color, int x, int y) const;
void fetch_pixel(LColor &color, int x, int y, int z) const;
bool lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
void filter_rect(LColor &color,
PN_stdfloat min_u, PN_stdfloat min_v,
@ -86,8 +88,8 @@ private:
int _x_size;
int _y_size;
int _z_size;
int _component_width;
int _num_components;
int _is_cube;
int _unused1;
int _pixel_width;
Texture::Format _format;
Texture::ComponentType _component_type;

View File

@ -375,6 +375,13 @@ ConfigVariableBool allow_live_flatten
"only has an effect when Panda is not compiled for a release "
"build."));
ConfigVariableBool filled_wireframe_apply_shader
("filled-wireframe-apply-shader", false,
PRC_DESC("Set this true to apply any shader configured on nodes onto the "
"filled wireframe overlay. The wireframe color is multiplied with "
"the result of the fragment shader. This is helpful when the shader "
"alters the position of the vertices and makes the overlay wrong."));
/**
* Initializes the library. This must be called at least once before any of
* the functions or classes in this library can be used. Normally it will be

View File

@ -74,6 +74,8 @@ extern ConfigVariableString default_model_extension;
extern ConfigVariableBool allow_live_flatten;
extern ConfigVariableBool filled_wireframe_apply_shader;
extern EXPCL_PANDA_PGRAPH void init_libpgraph();
#endif

View File

@ -28,6 +28,7 @@
#include "config_pgraph.h"
#include "depthOffsetAttrib.h"
#include "colorBlendAttrib.h"
#include "shaderAttrib.h"
TypeHandle CullResult::_type_handle;
@ -133,7 +134,9 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
if (object->_state->get_attrib(rmode)) {
if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) {
CullableObject *wireframe_part = new CullableObject(*object);
wireframe_part->_state = get_wireframe_overlay_state(rmode);
const ShaderAttrib *shader = nullptr;
object->_state->get_attrib(shader);
wireframe_part->_state = get_wireframe_overlay_state(rmode, shader);
if (wireframe_part->munge_geom
(_gsg, _gsg->get_geom_munger(wireframe_part->_state, current_thread),
@ -521,13 +524,36 @@ get_wireframe_filled_state() {
*/
CPT(RenderState) CullResult::
get_wireframe_overlay_state(const RenderModeAttrib *rmode) {
return RenderState::make(
return get_wireframe_overlay_state(rmode, nullptr);
}
/**
* Returns a RenderState that renders only the wireframe part of an
* M_filled_wireframe model.
* If a shader attrib is provided, a constant color is used in ColorBlendAttrib
* to emulate the flat color.
*/
CPT(RenderState) CullResult::
get_wireframe_overlay_state(const RenderModeAttrib *rmode, const ShaderAttrib *shader) {
CPT(RenderState) state = RenderState::make(
DepthOffsetAttrib::make(1, 0, 0.99999f),
ColorAttrib::make_flat(rmode->get_wireframe_color()),
ColorBlendAttrib::make(ColorBlendAttrib::M_add,
ColorBlendAttrib::O_incoming_alpha,
ColorBlendAttrib::O_one_minus_incoming_alpha),
RenderModeAttrib::make(RenderModeAttrib::M_wireframe,
rmode->get_thickness(),
rmode->get_perspective()));
if (filled_wireframe_apply_shader) {
state = state->add_attrib(ColorBlendAttrib::make(ColorBlendAttrib::M_add,
ColorBlendAttrib::O_zero,
ColorBlendAttrib::O_constant_color,
ColorBlendAttrib::M_add,
ColorBlendAttrib::O_one,
ColorBlendAttrib::O_one_minus_incoming_alpha,
rmode->get_wireframe_color()));
state = state->add_attrib(shader);
} else {
state = state->add_attrib(ColorBlendAttrib::make(ColorBlendAttrib::M_add,
ColorBlendAttrib::O_incoming_alpha,
ColorBlendAttrib::O_one_minus_incoming_alpha));
state = state->add_attrib(ColorAttrib::make_flat(rmode->get_wireframe_color()));
}
return state;
}

View File

@ -78,6 +78,7 @@ private:
static const RenderState *get_dual_opaque_state();
static const RenderState *get_wireframe_filled_state();
static CPT(RenderState) get_wireframe_overlay_state(const RenderModeAttrib *rmode);
static CPT(RenderState) get_wireframe_overlay_state(const RenderModeAttrib *rmode, const ShaderAttrib *shader);
GraphicsStateGuardianBase *_gsg;
PStatCollector _draw_region_pcollector;

View File

@ -20,6 +20,7 @@ class ShaderTerrainDemo(ShowBase):
textures-power-2 none
gl-coordinate-system default
window-title Panda3D ShaderTerrainMesh Demo
filled-wireframe-apply-shader true
# As an optimization, set this to the maximum number of cameras
# or lights that will be rendering the terrain at any given time.

View File

@ -101,3 +101,65 @@ def test_geom_linestrips_adjacency():
3, 4, 5, 6,
4, 5, 6, 6,
)
def test_geom_linestrips_offset_indexed():
prim = core.GeomLinestrips(core.GeomEnums.UH_static)
prim.add_vertex(0)
prim.add_vertex(1)
prim.close_primitive()
prim.add_vertex(1)
prim.add_vertex(2)
prim.add_vertex(3)
prim.close_primitive()
prim.add_vertex(3)
prim.add_vertex(4)
prim.add_vertex(5)
prim.add_vertex(6)
prim.close_primitive()
prim.offset_vertices(100)
verts = prim.get_vertex_list()
cut = prim.strip_cut_index
assert tuple(verts) == (
100, 101,
cut,
101, 102, 103,
cut,
103, 104, 105, 106,
)
prim.offset_vertices(-100)
verts = prim.get_vertex_list()
cut = prim.strip_cut_index
assert tuple(verts) == (
0, 1,
cut,
1, 2, 3,
cut,
3, 4, 5, 6,
)
prim.offset_vertices(100, 4, 9)
verts = prim.get_vertex_list()
cut = prim.strip_cut_index
assert tuple(verts) == (
0, 1,
cut,
1, 102, 103,
cut,
103, 104, 5, 6,
)
# Automatically upgrade to uint32
prim.offset_vertices(100000)
assert prim.index_type == core.GeomEnums.NT_uint32
verts = prim.get_vertex_list()
cut = prim.strip_cut_index
assert tuple(verts) == (
100000, 100001,
cut,
100001, 100102, 100103,
cut,
100103, 100104, 100005, 100006,
)

View File

@ -158,3 +158,51 @@ def test_texture_peek_int_i():
col = LColor()
peeker.fetch_pixel(col, 0, 0)
assert col == (minval, -1, 0, maxval)
def test_texture_peek_cube():
maxval = 255
data_list = []
for z in range(6):
for y in range(3):
for x in range(3):
data_list += [z, y, x, maxval]
data = array('B', data_list)
tex = Texture("")
tex.setup_cube_map(3, Texture.T_unsigned_byte, Texture.F_rgba8i)
tex.set_ram_image(data)
peeker = tex.peek()
assert peeker.has_pixel(0, 0)
assert peeker.has_pixel(0, 0, 0)
# If no z is specified, face 0 is used by default
col = LColor()
peeker.fetch_pixel(col, 1, 2)
assert col == (1, 2, 0, maxval)
# Now try each face
for faceidx in range(6):
col = LColor()
peeker.fetch_pixel(col, 0, 0, faceidx)
assert col == (0, 0, faceidx, maxval)
# Try some vector lookups.
def lookup(*vec):
col = LColor()
peeker.lookup(col, *vec)
return col
assert lookup(1, 0, 0) == (1, 1, 0, maxval)
assert lookup(-1, 0, 0) == (1, 1, 1, maxval)
assert lookup(0, 1, 0) == (1, 1, 2, maxval)
assert lookup(0, -1, 0) == (1, 1, 3, maxval)
assert lookup(0, 0, 1) == (1, 1, 4, maxval)
assert lookup(0, 0, -1) == (1, 1, 5, maxval)
# Magnitude shouldn't matter
assert lookup(0, 2, 0) == (1, 1, 2, maxval)
assert lookup(0, 0, -0.5) == (1, 1, 5, maxval)
# Sample in corner (slight bias to disambiguate which face is selected)
assert lookup(1.00001, 1, 1) == (0, 0, 0, maxval)
assert lookup(1.00001, 1, 0) == (1, 0, 0, maxval)
assert lookup(1, 1.00001, 0) == (2, 1, 2, maxval)

View File

@ -157,3 +157,25 @@ def test_weighted_choice():
# When subtracting that number by each weight, it will reach 0
# by the time it hits 'item6' in the iteration.
assert item == items[5]
def test_serial():
gen = PythonUtil.SerialNumGen()
assert gen.next() == 0
assert next(gen) == 1
assert next(gen) == 2
assert gen.next() == 3
def test_alphabet_counter():
counter = PythonUtil.AlphabetCounter()
assert next(counter) == 'A'
assert counter.next() == 'B'
assert counter.next() == 'C'
assert next(counter) == 'D'
for i in range(26 - 4):
next(counter)
assert next(counter) == 'AA'
assert next(counter) == 'AB'