From 28f49ffd0b2d472f752bc122638ffde1705424f2 Mon Sep 17 00:00:00 2001 From: LD Date: Tue, 1 Sep 2020 20:25:18 +0200 Subject: [PATCH 01/23] cocoadisplay: Use [event charactersIgnoringModifiers] when UCKeyTranslate() can not translate the input key --- panda/src/cocoadisplay/cocoaGraphicsWindow.mm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm index 49857a4d14..ace8a4973b 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm @@ -1762,6 +1762,19 @@ handle_key_event(NSEvent *event) { return; } + // If UCKeyTranslate could not map the key into a valid unicode character or + // reserved symbol (See NSEvent.h), it returns 0x10 as translated character. + // This happens e.g.e with the combination Fn+F1.. keys. + // In that case, as fallback, we use charactersIgnoringModifiers to retrieve + // the character without modifiers. + if (c == 0x10) { + NSString *str = [event charactersIgnoringModifiers]; + if (str == nil || [str length] != 1) { + return; + } + c = [str characterAtIndex: 0]; + } + ButtonHandle button = map_key(c); if (button == ButtonHandle::none()) { From cca84131dfc7c4a7b959c2aa2cabb37c5d3c8776 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 6 Sep 2020 09:19:51 +0200 Subject: [PATCH 02/23] gles2gsg: squelch warning about missing #version line in shader --- panda/src/glstuff/glGraphicsStateGuardian_src.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 28297ba464..f6c795636d 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -170,6 +170,7 @@ static const string default_vshader = "out vec2 texcoord;\n" "out vec4 color;\n" #else + "#version 100\n" "precision mediump float;\n" "attribute vec4 p3d_Vertex;\n" "attribute vec4 p3d_Color;\n" @@ -240,6 +241,7 @@ static const string default_fshader = "uniform sampler2D p3d_Texture0;\n" "uniform vec4 p3d_TexAlphaOnly;\n" #else + "#version 100\n" "precision mediump float;\n" "varying vec2 texcoord;\n" "varying lowp vec4 color;\n" From 40842ef2177d64b76de021b72891f454b37b8318 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 6 Sep 2020 09:20:34 +0200 Subject: [PATCH 03/23] gles2gsg: fix sRGB texture support --- panda/src/gles2gsg/gles2gsg.h | 5 ++-- .../glstuff/glGraphicsStateGuardian_src.cxx | 23 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/panda/src/gles2gsg/gles2gsg.h b/panda/src/gles2gsg/gles2gsg.h index 363baad0ca..729ee6e589 100644 --- a/panda/src/gles2gsg/gles2gsg.h +++ b/panda/src/gles2gsg/gles2gsg.h @@ -100,9 +100,7 @@ typedef char GLchar; #define GL_RGBA16F GL_RGBA16F_EXT #define GL_RGB32F GL_RGB32F_EXT #define GL_RGBA32F GL_RGBA32F_EXT -#define GL_SRGB GL_SRGB_EXT #define GL_SRGB_ALPHA GL_SRGB_ALPHA_EXT -#define GL_SRGB8_ALPHA8 GL_SRGB8_ALPHA8_EXT #define GL_RGBA8 GL_RGBA8_OES #define GL_R8 GL_R8_EXT #define GL_RG8 GL_RG8_EXT @@ -194,6 +192,9 @@ typedef char GLchar; #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB8_ALPHA8 0x8C43 #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_RED_INTEGER 0x8D94 #define GL_RGB_INTEGER 0x8D98 diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index f6c795636d..dd29bda619 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -10314,11 +10314,9 @@ get_internal_image_format(Texture *tex, bool force_sized) const { #ifndef OPENGLES_1 case Texture::F_srgb: -#ifndef OPENGLES - return GL_SRGB8; -#endif + return _supports_texture_srgb ? GL_SRGB8 : GL_RGB8; case Texture::F_srgb_alpha: - return GL_SRGB8_ALPHA8; + return _supports_texture_srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8; #endif #ifndef OPENGLES case Texture::F_sluminance: @@ -12807,11 +12805,20 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { int num_levels = 1; CPTA_uchar image = tex->get_ram_mipmap_image(mipmap_bias); + bool can_generate = _supports_generate_mipmap; +#if defined(OPENGLES) && !defined(OPENGLES_1) + // OpenGL ES doesn't support generating mipmaps for sRGB textures, so we + // have to do this on the CPU, unless we have a special extension. + if (internal_format == GL_SRGB8 || internal_format == GL_SRGB8_ALPHA8) { + can_generate = has_extension("GL_NV_generate_mipmap_sRGB"); + } +#endif + if (image.is_null()) { // We don't even have a RAM image, so we have no choice but to let // mipmaps be generated on the GPU. if (uses_mipmaps) { - if (_supports_generate_mipmap) { + if (can_generate) { num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias; gtc->_generate_mipmaps = true; } else { @@ -12827,7 +12834,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { if (num_levels <= 1) { // No RAM mipmap levels available. Should we generate some? - if (!_supports_generate_mipmap || !driver_generate_mipmaps || + if (!can_generate || !driver_generate_mipmaps || image_compression != Texture::CM_off) { // Yes, the GL can't or won't generate them, so we need to. Note // that some drivers (nVidia) will *corrupt memory* if you ask @@ -12840,7 +12847,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { if (num_levels <= 1) { // We don't have mipmap levels in RAM. Ask the GL to generate them // if it can. - if (_supports_generate_mipmap) { + if (can_generate) { num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias; gtc->_generate_mipmaps = true; } else { @@ -14106,9 +14113,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { #ifndef OPENGLES_1 case GL_SRGB: -#ifndef OPENGLES case GL_SRGB8: -#endif format = Texture::F_srgb; break; case GL_SRGB_ALPHA: From 24fb2a2c8815580ebbf2f4e3021478d52d76bfa8 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 6 Sep 2020 09:21:21 +0200 Subject: [PATCH 04/23] egldisplay: Fix invalid software/hardware detection on Mesa --- .../src/egldisplay/eglGraphicsStateGuardian.cxx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/panda/src/egldisplay/eglGraphicsStateGuardian.cxx b/panda/src/egldisplay/eglGraphicsStateGuardian.cxx index 31c1069d46..f31040bd87 100644 --- a/panda/src/egldisplay/eglGraphicsStateGuardian.cxx +++ b/panda/src/egldisplay/eglGraphicsStateGuardian.cxx @@ -120,9 +120,9 @@ get_properties(FrameBufferProperties &properties, properties.set_depth_bits(depth_size); properties.set_multisamples(samples); - // Set both hardware and software bits, indicating not-yet-known. - properties.set_force_software(1); - properties.set_force_hardware(1); + // "slow" likely indicates no hardware acceleration. + properties.set_force_software(slow); + properties.set_force_hardware(!slow); } /** @@ -255,17 +255,9 @@ reset() { GLESGraphicsStateGuardian::reset(); #endif - // If "Mesa" is present, assume software. However, if "Mesa DRI" is found, - // it's actually a Mesa-based OpenGL layer running over a hardware driver. - if (_gl_renderer == "Software Rasterizer" || - (_gl_renderer.find("Mesa") != std::string::npos && - _gl_renderer.find("Mesa DRI") == std::string::npos)) { - // It's Mesa, therefore probably a software context. + if (_gl_renderer == "Software Rasterizer") { _fbprops.set_force_software(1); _fbprops.set_force_hardware(0); - } else { - _fbprops.set_force_hardware(1); - _fbprops.set_force_software(0); } } From 005d187ac4ba01a4e9cf449d67b41a3c93d6c11b Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 6 Sep 2020 10:14:28 +0200 Subject: [PATCH 05/23] egldisplay: Support creating a window with sRGB framebuffer --- .../egldisplay/eglGraphicsStateGuardian.cxx | 14 ++++++++++++++ panda/src/egldisplay/eglGraphicsWindow.cxx | 19 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/panda/src/egldisplay/eglGraphicsStateGuardian.cxx b/panda/src/egldisplay/eglGraphicsStateGuardian.cxx index f31040bd87..ae3867feec 100644 --- a/panda/src/egldisplay/eglGraphicsStateGuardian.cxx +++ b/panda/src/egldisplay/eglGraphicsStateGuardian.cxx @@ -223,6 +223,20 @@ choose_pixel_format(const FrameBufferProperties &properties, int err = eglGetError(); if (_context && err == EGL_SUCCESS) { if (_visual) { + // This is set during window creation, but for now we have to pretend + // that we can honor the request, if we support the extension. + if (properties.get_srgb_color()) { + const char *extensions = eglQueryString(_egl_display, EGL_EXTENSIONS); + if (extensions != nullptr) { + vector_string tokens; + extract_words(extensions, tokens); + + if (std::find(tokens.begin(), tokens.end(), "EGL_KHR_gl_colorspace") != tokens.end()) { + best_props.set_srgb_color(true); + } + } + } + _fbprops = best_props; delete[] configs; return; diff --git a/panda/src/egldisplay/eglGraphicsWindow.cxx b/panda/src/egldisplay/eglGraphicsWindow.cxx index 89deb47deb..8827325ce0 100644 --- a/panda/src/egldisplay/eglGraphicsWindow.cxx +++ b/panda/src/egldisplay/eglGraphicsWindow.cxx @@ -27,6 +27,14 @@ #include "nativeWindowHandle.h" #include "get_x11.h" +#ifndef EGL_GL_COLORSPACE_KHR +#define EGL_GL_COLORSPACE_KHR 0x309D +#endif + +#ifndef EGL_GL_COLORSPACE_SRGB_KHR +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#endif + TypeHandle eglGraphicsWindow::_type_handle; /** @@ -233,7 +241,16 @@ open_window() { return false; } - _egl_surface = eglCreateWindowSurface(_egl_display, eglgsg->_fbconfig, (NativeWindowType) _xwindow, nullptr); + EGLint attribs[4]; + EGLint *attribs_p = nullptr; + if (eglgsg->get_fb_properties().get_srgb_color()) { + attribs[0] = EGL_GL_COLORSPACE_KHR; + attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; + attribs[2] = EGL_NONE; + attribs[3] = EGL_NONE; + attribs_p = attribs; + } + _egl_surface = eglCreateWindowSurface(_egl_display, eglgsg->_fbconfig, (NativeWindowType) _xwindow, attribs_p); if (eglGetError() != EGL_SUCCESS) { egldisplay_cat.error() << "Failed to create window surface.\n"; From f7375e215e104815111e19db029365ccca8a735e Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 6 Sep 2020 13:30:02 +0200 Subject: [PATCH 06/23] filter: Add built-in sRGB encoding filter --- direct/src/filter/CommonFilters.py | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/direct/src/filter/CommonFilters.py b/direct/src/filter/CommonFilters.py index 1ba9ec91d4..d24b25b791 100644 --- a/direct/src/filter/CommonFilters.py +++ b/direct/src/filter/CommonFilters.py @@ -341,6 +341,11 @@ class CommonFilters: elif gamma != 1.0: text += " o_color.rgb = pow(o_color.rgb, %ff);\n" % (gamma) + if ("SrgbEncode" in configuration): + text += " o_color.r = (o_color.r < 0.0031308) ? (o_color.r * 12.92) : (1.055 * pow(o_color.r, 0.41666) - 0.055);\n" + text += " o_color.g = (o_color.g < 0.0031308) ? (o_color.g * 12.92) : (1.055 * pow(o_color.g, 0.41666) - 0.055);\n" + text += " o_color.b = (o_color.b < 0.0031308) ? (o_color.b * 12.92) : (1.055 * pow(o_color.b, 0.41666) - 0.055);\n" + if ("Inverted" in configuration): text += " o_color = float4(1, 1, 1, 1) - o_color;\n" text += "}\n" @@ -547,6 +552,32 @@ class CommonFilters: return self.reconfigure((old_gamma != 1.0), "GammaAdjust") return True + def setSrgbEncode(self, force=False): + """ Applies the inverse sRGB EOTF to the output, unless the window + already has an sRGB framebuffer, in which case this filter refuses to + apply, to prevent accidental double-application. + + Set the force argument to True to force it to be applied in all cases. + + .. versionadded:: 1.10.7 + """ + new_enable = force or not self.manager.win.getFbProperties().getSrgbColor() + old_enable = self.configuration.get("SrgbEncode", False) + if new_enable and not old_enable: + self.configuration["SrgbEncode"] = True + return self.reconfigure(True, "SrgbEncode") + elif not new_enable and old_enable: + del self.configuration["SrgbEncode"] + return new_enable + + def delSrgbEncode(self): + """ Reverses the effects of setSrgbEncode. """ + if ("SrgbEncode" in self.configuration): + old_enable = self.configuration["SrgbEncode"] + del self.configuration["SrgbEncode"] + return self.reconfigure(old_enable, "SrgbEncode") + return True + #snake_case alias: del_cartoon_ink = delCartoonInk set_half_pixel_shift = setHalfPixelShift @@ -555,7 +586,6 @@ class CommonFilters: del_inverted = delInverted del_view_glow = delViewGlow set_volumetric_lighting = setVolumetricLighting - del_gamma_adjust = delGammaAdjust set_bloom = setBloom set_view_glow = setViewGlow set_ambient_occlusion = setAmbientOcclusion @@ -566,3 +596,6 @@ class CommonFilters: del_blur_sharpen = delBlurSharpen del_volumetric_lighting = delVolumetricLighting set_gamma_adjust = setGammaAdjust + del_gamma_adjust = delGammaAdjust + set_srgb_encode = setSrgbEncode + del_srgb_encode = delSrgbEncode From cd435ecec8208ac1ee56cd2e0e7222e261174556 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 6 Sep 2020 14:23:33 +0200 Subject: [PATCH 07/23] filter: Support HDR in CommonFilters (using ACES tonemap) --- direct/src/filter/CommonFilters.py | 84 +++++++++++++++++++++++++++++- direct/src/filter/FilterManager.py | 6 ++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/direct/src/filter/CommonFilters.py b/direct/src/filter/CommonFilters.py index d24b25b791..18e62afc22 100644 --- a/direct/src/filter/CommonFilters.py +++ b/direct/src/filter/CommonFilters.py @@ -27,6 +27,7 @@ from panda3d.core import LVecBase4, LPoint2 from panda3d.core import Filename from panda3d.core import AuxBitplaneAttrib from panda3d.core import Texture, Shader, ATSNone +from panda3d.core import FrameBufferProperties import os CARTOON_BODY=""" @@ -177,7 +178,15 @@ class CommonFilters: self.textures[tex].setWrapU(Texture.WMClamp) self.textures[tex].setWrapV(Texture.WMClamp) - self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits) + fbprops = None + clamping = None + if "HighDynamicRange" in configuration: + fbprops = FrameBufferProperties() + fbprops.setFloatColor(True) + fbprops.setSrgbColor(False) + clamping = False + + self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits, fbprops=fbprops, clamping=clamping) if (self.finalQuad == None): self.cleanup() return False @@ -255,6 +264,17 @@ class CommonFilters: texcoordSets = list(enumerate(texcoordPadding.keys())) text = "//Cg\n" + if "HighDynamicRange" in configuration: + text += "static const float3x3 aces_input_mat = {\n" + text += " {0.59719, 0.35458, 0.04823},\n" + text += " {0.07600, 0.90834, 0.01566},\n" + text += " {0.02840, 0.13383, 0.83777},\n" + text += "};\n" + text += "static const float3x3 aces_output_mat = {\n" + text += " { 1.60475, -0.53108, -0.07367},\n" + text += " {-0.10208, 1.10813, -0.00605},\n" + text += " {-0.00327, -0.07276, 1.07602},\n" + text += "};\n" text += "void vshader(float4 vtx_position : POSITION,\n" text += " out float4 l_position : POSITION,\n" @@ -301,6 +321,10 @@ class CommonFilters: if ("VolumetricLighting" in configuration): text += " uniform float4 k_casterpos,\n" text += " uniform float4 k_vlparams,\n" + + if ("ExposureAdjust" in configuration): + text += " uniform float k_exposure,\n" + text += " out float4 o_color : COLOR)\n" text += "{\n" text += " o_color = tex2D(k_txcolor, %s);\n" % (texcoords["color"]) @@ -332,6 +356,14 @@ class CommonFilters: text += " }\n" text += " o_color += float4(vlcolor * k_vlparams.z, 1);\n" + if ("ExposureAdjust" in configuration): + text += " o_color.rgb *= k_exposure;\n" + + # With thanks to Stephen Hill! + if ("HighDynamicRange" in configuration): + text += " float3 aces_color = mul(aces_input_mat, o_color.rgb);\n" + text += " o_color.rgb = saturate(mul(aces_output_mat, (aces_color * (aces_color + 0.0245786f) - 0.000090537f) / (aces_color * (0.983729f * aces_color + 0.4329510f) + 0.238081f)));\n" + if ("GammaAdjust" in configuration): gamma = configuration["GammaAdjust"] if gamma == 0.5: @@ -391,6 +423,11 @@ class CommonFilters: self.ssao[0].setShaderInput("params1", config.numsamples, -float(config.amount) / config.numsamples, config.radius, 0) self.ssao[0].setShaderInput("params2", config.strength, config.falloff, 0, 0) + if (changed == "ExposureAdjust") or fullrebuild: + if ("ExposureAdjust" in configuration): + stops = configuration["ExposureAdjust"] + self.finalQuad.setShaderInput("exposure", 2 ** stops) + self.update() return True @@ -578,6 +615,47 @@ class CommonFilters: return self.reconfigure(old_enable, "SrgbEncode") return True + def setHighDynamicRange(self): + """ Enables HDR rendering by using a floating-point framebuffer, + disabling color clamping on the main scene, and applying a tone map + operator (ACES). + + It may also be necessary to use setExposureAdjust to perform exposure + compensation on the scene, depending on the lighting intensity. + + .. versionadded:: 1.10.7 + """ + + fullrebuild = (("HighDynamicRange" in self.configuration) is False) + self.configuration["HighDynamicRange"] = 1 + return self.reconfigure(fullrebuild, "HighDynamicRange") + + def delHighDynamicRange(self): + if ("HighDynamicRange" in self.configuration): + del self.configuration["HighDynamicRange"] + return self.reconfigure(True, "HighDynamicRange") + return True + + def setExposureAdjust(self, stops): + """ Sets a relative exposure adjustment to multiply with the result of + rendering the scene, in stops. A value of 0 means no adjustment, a + positive value will result in a brighter image. Useful in conjunction + with HDR, see setHighDynamicRange. + + .. versionadded:: 1.10.7 + """ + old_stops = self.configuration.get("ExposureAdjust") + if old_stops != stops: + self.configuration["ExposureAdjust"] = stops + return self.reconfigure(old_stops is None, "ExposureAdjust") + return True + + def delExposureAdjust(self): + if ("ExposureAdjust" in self.configuration): + del self.configuration["ExposureAdjust"] + return self.reconfigure(True, "ExposureAdjust") + return True + #snake_case alias: del_cartoon_ink = delCartoonInk set_half_pixel_shift = setHalfPixelShift @@ -599,3 +677,7 @@ class CommonFilters: del_gamma_adjust = delGammaAdjust set_srgb_encode = setSrgbEncode del_srgb_encode = delSrgbEncode + set_exposure_adjust = setExposureAdjust + del_exposure_adjust = delExposureAdjust + set_high_dynamic_range = setHighDynamicRange + del_high_dynamic_range = delHighDynamicRange diff --git a/direct/src/filter/FilterManager.py b/direct/src/filter/FilterManager.py index c20cbed139..88b151ec89 100644 --- a/direct/src/filter/FilterManager.py +++ b/direct/src/filter/FilterManager.py @@ -22,6 +22,7 @@ from panda3d.core import WindowProperties, FrameBufferProperties from panda3d.core import Camera from panda3d.core import OrthographicLens from panda3d.core import AuxBitplaneAttrib +from panda3d.core import LightRampAttrib from direct.directnotify.DirectNotifyGlobal import * from direct.showbase.DirectObject import DirectObject @@ -124,7 +125,7 @@ class FilterManager(DirectObject): return winx,winy - def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None): + def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None, clamping=None): """ Causes the scene to be rendered into the supplied textures instead of into the original window. Puts a fullscreen quad @@ -207,6 +208,9 @@ class FilterManager(DirectObject): #cs.setShaderAuto() if (auxbits): cs.setAttrib(AuxBitplaneAttrib.make(auxbits)) + if clamping is False: + # Disables clamping in the shader generator. + cs.setAttrib(LightRampAttrib.make_identity()) self.camera.node().setInitialState(cs.getState()) quadcamnode = Camera("filter-quad-cam") From ad0e634292209b8b5163bc45da94000ffd74cfd5 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 6 Sep 2020 14:44:44 +0200 Subject: [PATCH 08/23] egg: Add (discouraged) way to specify sRGB texture format (#924) This should NOT be used by exporters, but is provided only for the sake of round-trippability of .bam files. --- panda/src/egg/eggTexture.cxx | 10 ++++++++++ panda/src/egg/eggTexture.h | 5 ++++- panda/src/egg2pg/eggLoader.cxx | 9 +++++++++ panda/src/egg2pg/eggSaver.cxx | 6 ++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/panda/src/egg/eggTexture.cxx b/panda/src/egg/eggTexture.cxx index eb2cfa7342..a4fb06b62e 100644 --- a/panda/src/egg/eggTexture.cxx +++ b/panda/src/egg/eggTexture.cxx @@ -509,6 +509,7 @@ has_alpha_channel(int num_components) const { case F_rgb8: case F_rgb5: case F_rgb332: + case F_srgb: // These formats never use alpha, regardless of the number of components // we have. return false; @@ -525,6 +526,7 @@ has_alpha_channel(int num_components) const { case F_rgba8: case F_rgba4: case F_rgba5: + case F_srgb_alpha: case F_unspecified: // These formats use alpha if the image had alpha. return (num_components == 2 || num_components == 4); @@ -690,6 +692,8 @@ EggTexture::Format EggTexture:: string_format(const string &string) { if (cmp_nocase_uh(string, "rgba") == 0) { return F_rgba; + } else if (cmp_nocase_uh(string, "srgb_alpha") == 0) { + return F_srgb_alpha; } else if (cmp_nocase_uh(string, "rgbm") == 0) { return F_rgbm; } else if (cmp_nocase_uh(string, "rgba12") == 0) { @@ -701,6 +705,8 @@ string_format(const string &string) { } else if (cmp_nocase_uh(string, "rgb") == 0) { return F_rgb; + } else if (cmp_nocase_uh(string, "srgb") == 0) { + return F_srgb; } else if (cmp_nocase_uh(string, "rgb12") == 0) { return F_rgb12; } else if (cmp_nocase_uh(string, "rgb8") == 0) { @@ -1137,6 +1143,8 @@ ostream &operator << (ostream &out, EggTexture::Format format) { return out << "rgba8"; case EggTexture::F_rgba4: return out << "rgba4"; + case EggTexture::F_srgb_alpha: + return out << "srgb_alpha"; case EggTexture::F_rgb: return out << "rgb"; @@ -1150,6 +1158,8 @@ ostream &operator << (ostream &out, EggTexture::Format format) { return out << "rgba5"; case EggTexture::F_rgb332: return out << "rgb332"; + case EggTexture::F_srgb: + return out << "srgb"; case EggTexture::F_red: return out << "red"; diff --git a/panda/src/egg/eggTexture.h b/panda/src/egg/eggTexture.h index 55f56f4b3d..ac15293140 100644 --- a/panda/src/egg/eggTexture.h +++ b/panda/src/egg/eggTexture.h @@ -60,7 +60,10 @@ PUBLISHED: F_rgba, F_rgbm, F_rgba12, F_rgba8, F_rgba4, F_rgba5, F_rgb, F_rgb12, F_rgb8, F_rgb5, F_rgb332, F_red, F_green, F_blue, F_alpha, F_luminance, - F_luminance_alpha, F_luminance_alphamask + F_luminance_alpha, F_luminance_alphamask, + + // Only for compatibility with .bam, use is discouraged! + F_srgb, F_srgb_alpha }; enum CompressionMode { CM_default, CM_off, CM_on, diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 66a9ea44c6..170cc6f7ae 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -900,6 +900,7 @@ load_texture(TextureDef &def, EggTexture *egg_tex) { case EggTexture::F_rgb8: case EggTexture::F_rgb5: case EggTexture::F_rgb332: + case EggTexture::F_srgb: wanted_channels = 3; wanted_alpha = false; break; @@ -910,6 +911,7 @@ load_texture(TextureDef &def, EggTexture *egg_tex) { case EggTexture::F_rgba8: case EggTexture::F_rgba4: case EggTexture::F_rgba5: + case EggTexture::F_srgb_alpha: wanted_channels = 4; wanted_alpha = true; break; @@ -1259,6 +1261,10 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { case EggTexture::F_rgb332: tex->set_format(Texture::F_rgb332); break; + case EggTexture::F_srgb: + case EggTexture::F_srgb_alpha: + tex->set_format(Texture::F_srgb); + break; case EggTexture::F_unspecified: break; @@ -1296,6 +1302,9 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { case EggTexture::F_rgba5: tex->set_format(Texture::F_rgba5); break; + case EggTexture::F_srgb_alpha: + tex->set_format(Texture::F_srgb_alpha); + break; case EggTexture::F_unspecified: break; diff --git a/panda/src/egg2pg/eggSaver.cxx b/panda/src/egg2pg/eggSaver.cxx index dc7be82d7d..da4273d3a3 100644 --- a/panda/src/egg2pg/eggSaver.cxx +++ b/panda/src/egg2pg/eggSaver.cxx @@ -1420,6 +1420,12 @@ get_egg_texture(Texture *tex) { case Texture::F_luminance_alphamask: temp.set_format(EggTexture::F_luminance_alphamask); break; + case Texture::F_srgb: + temp.set_format(EggTexture::F_srgb); + break; + case Texture::F_srgb_alpha: + temp.set_format(EggTexture::F_srgb_alpha); + break; default: break; } From f8cb1499bee96d09f0f498e4c4f74e8d3263ba6b Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Sep 2020 17:59:31 +0200 Subject: [PATCH 09/23] rplight: various API documentation fixes --- contrib/src/rplight/rpLight.I | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/contrib/src/rplight/rpLight.I b/contrib/src/rplight/rpLight.I index c0e2422651..c405437906 100644 --- a/contrib/src/rplight/rpLight.I +++ b/contrib/src/rplight/rpLight.I @@ -148,7 +148,7 @@ inline void RPLight::assign_slot(int slot) { * changed. This will cause all shadow sources to be updated, emitting a * shadow update. Be careful when calling this method if you don't want all * sources to get updated. If you only have to invalidate a single shadow source, - * use get_shadow_source(n)->set_needs_update(true). + * use `get_shadow_source(n)->set_needs_update(true)`. */ inline void RPLight::invalidate_shadows() { for (size_t i = 0; i < _shadow_sources.size(); ++i) { @@ -296,14 +296,14 @@ inline bool RPLight::get_casts_shadows() const { } /** - * @brief Sets the lights shadow map resolution - * @details This sets the lights shadow map resolution. This has no effect + * @brief Sets the light's shadow map resolution + * @details This sets the light's shadow map resolution. This has no effect * when the light is not told to cast shadows (Use RPLight::set_casts_shadows). * - * When calling this on a light with multiple shadow sources (e.g. PointLight), - * this controls the resolution of each source. If the light has 6 shadow sources, - * and you use a resolution of 512x512, the lights shadow map will occur a - * space of 6 * 512x512 maps in the shadow atlas. + * When calling this on a light with multiple shadow sources (e.g. + * RPPointLight), this controls the resolution of each source. If the light + * has 6 shadow sources, and you use a resolution of 512x512, the light's + * shadow map will occupy a space of 6 * 512x512 maps in the shadow atlas. * * @param resolution Resolution of the shadow map in pixels */ @@ -326,14 +326,14 @@ inline size_t RPLight::get_shadow_map_resolution() const { } /** - * @brief Sets the ies profile + * @brief Sets the IES profile * @details This sets the ies profile of the light. The parameter should be a * handle previously returned by RenderPipeline.load_ies_profile. Using a * value of -1 indicates no ies profile. * - * Notice that for ies profiles which cover a whole range, you should use - * PointLights, whereas for ies profiles which only cover the lower hemisphere - * you should use SpotLights for the best performance. + * Notice that for IES profiles which cover a whole range, you should use an + * RPPointLight, whereas for ies profiles which only cover the lower + * hemisphere you should use an RPSpotLight for the best performance. * * @param profile IES Profile handle */ @@ -343,8 +343,8 @@ inline void RPLight::set_ies_profile(int profile) { } /** - * @brief Returns the lights ies profile - * @details This returns the ies profile of a light, previously set with + * @brief Returns the light's IES profile + * @details This returns the IES profile of a light, previously set with * RPLight::set_ies_profile. In case no ies profile was set, returns -1. * * @return IES Profile handle @@ -354,20 +354,20 @@ inline int RPLight::get_ies_profile() const { } /** - * @brief Returns whether the light has an ies profile assigned - * @details This returns whether the light has an ies profile assigned, + * @brief Returns whether the light has an IES profile assigned + * @details This returns whether the light has an IES profile assigned, * previously done with RPLight::set_ies_profile. * - * @return true if the light has an ies profile assigned, false otherwise + * @return true if the light has an IES profile assigned, false otherwise */ inline bool RPLight::has_ies_profile() const { return _ies_profile >= 0; } /** - * @brief Clears the ies profile - * @details This clears the ies profile of the light, telling it to no longer - * use an ies profile, and instead use the default attenuation. + * @brief Clears the IES profile + * @details This clears the IES profile of the light, telling it to no longer + * use an IES profile, and instead use the default attenuation. */ inline void RPLight::clear_ies_profile() { set_ies_profile(-1); @@ -377,7 +377,7 @@ inline void RPLight::clear_ies_profile() { * @brief Sets the near plane of the light * @details This sets the near plane of all shadow sources of the light. It has * no effects if the light does not cast shadows. This prevents artifacts from - * objects near to the light. It behaves like Lens::set_near_plane. + * objects near to the light. It behaves like Lens::set_near(). * * It can also help increasing shadow map precision, low near planes will * cause the precision to suffer. Try setting the near plane as big as possible. @@ -394,7 +394,7 @@ inline void RPLight::set_near_plane(float near_plane) { /** * @brief Returns the near plane of the light - * @details This returns the lights near plane, previously set with + * @details This returns the light's near plane, previously set with * RPLight::set_near_plane. If the light does not cast shadows, this value * is meaningless. * From 4d20b36098d3bc14713b56053fb62a7123183348 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Sep 2020 17:59:53 +0200 Subject: [PATCH 10/23] doxygen: exclude directscripts directory building C++ API reference --- direct/src/directscripts/Doxyfile.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/direct/src/directscripts/Doxyfile.cxx b/direct/src/directscripts/Doxyfile.cxx index db71c81b3b..11d5fc9bc2 100644 --- a/direct/src/directscripts/Doxyfile.cxx +++ b/direct/src/directscripts/Doxyfile.cxx @@ -789,6 +789,7 @@ RECURSIVE = YES EXCLUDE = dtool/src/parser-inc \ dtool/src/cppparser \ dtool/src/interrogate \ + direct/src/directscripts \ direct/src/plugin \ direct/src/plugin_standalone \ direct/src/plugin_npapi \ From 3daf1ae1b1876ecaf4c2e0e79e2ae310d945f665 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Sep 2020 18:03:49 +0200 Subject: [PATCH 11/23] general: Assorted API reference fixes --- dtool/src/prc/configPageManager.I | 12 ++++++------ dtool/src/prc/configVariableManager.cxx | 4 ++-- panda/src/audio/audioManager.h | 12 +++++------- panda/src/audio/audioSound.cxx | 6 +++--- panda/src/audio/audioSound.h | 4 ++-- panda/src/downloader/httpClient.cxx | 2 +- panda/src/linmath/lmatrix4_src.I | 2 +- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/dtool/src/prc/configPageManager.I b/dtool/src/prc/configPageManager.I index 30e6c64950..2d27874573 100644 --- a/dtool/src/prc/configPageManager.I +++ b/dtool/src/prc/configPageManager.I @@ -12,7 +12,7 @@ */ /** - * Returns true if the implicit *.prc files have already been loaded, false + * Returns true if the implicit `*.prc` files have already been loaded, false * otherwise. Normally this will only be false briefly before startup. */ INLINE bool ConfigPageManager:: @@ -21,7 +21,7 @@ loaded_implicit_pages() const { } /** - * Searches the PRC_DIR and/or PRC_PATH directories for *.prc files and loads + * Searches the PRC_DIR and/or PRC_PATH directories for `*.prc` files and loads * them in as pages. This is normally called automatically at startup time, * when the first variable's value is referenced. See also * reload_implicit_pages(). @@ -46,9 +46,9 @@ get_search_path() { } /** - * Returns the number of patterns, like "*.prc", that are compiled in that + * Returns the number of patterns, like `*.prc`, that are compiled in that * will be searched for as default config filenames. Normally there is only - * one pattern, and it is "*.prc", but others may be specified with the + * one pattern, and it is `*.prc`, but others may be specified with the * PRC_FILENAME variable in Config.pp. */ INLINE size_t ConfigPageManager:: @@ -67,7 +67,7 @@ get_prc_pattern(size_t n) const { } /** - * Returns the number of patterns, like "*.pre", that are compiled in that + * Returns the number of patterns, like `*.pre`, that are compiled in that * will be searched for as special config files that are understood to be * encrypted. */ @@ -87,7 +87,7 @@ get_prc_encrypted_pattern(size_t n) const { } /** - * Returns the number of patterns, like "*.exe", that are compiled in that + * Returns the number of patterns, like `*.exe`, that are compiled in that * will be searched for as special config files that are to be executed as a * program, and their output taken to be input. This is normally empty. */ diff --git a/dtool/src/prc/configVariableManager.cxx b/dtool/src/prc/configVariableManager.cxx index 774dc19f6b..86375764e4 100644 --- a/dtool/src/prc/configVariableManager.cxx +++ b/dtool/src/prc/configVariableManager.cxx @@ -82,7 +82,7 @@ make_variable(const string &name) { * Defines a variable "template" to match against dynamically-defined * variables that may or may not be created in the future. * - * The template consists of a glob pattern, e.g. "notify-level-*", which will + * The template consists of a glob pattern, e.g. `notify-level-*`, which will * be tested against any config variable passed to a future call to * make_variable(). If the pattern matches, the returned ConfigVariableCore * is copied to define the new variable, instead of creating a default, empty @@ -92,7 +92,7 @@ make_variable(const string &name) { * all have similar properties, and all may not be created at the same time. * It is especially useful to avoid cluttering up the list of available * variables with user-declared variables that have not been defined yet by - * the application (e.g. "egg-object-type-*"). + * the application (e.g. `egg-object-type-*`). * * This method basically pre-defines all variables that match the specified * glob pattern. diff --git a/panda/src/audio/audioManager.h b/panda/src/audio/audioManager.h index 62d9a5d090..713661ca69 100644 --- a/panda/src/audio/audioManager.h +++ b/panda/src/audio/audioManager.h @@ -106,13 +106,11 @@ PUBLISHED: virtual void set_volume(PN_stdfloat volume) = 0; virtual PN_stdfloat get_volume() const = 0; -/* - * Turn the manager on or off. If you play a sound while the manager is - * inactive, it won't start. If you deactivate the manager while sounds are - * playing, they'll stop. If you activate the manager while looping sounds - * are playing (those that have a loop_count of zero), they will start playing - * from the beginning of their loop. inits to true. - */ + // Turn the manager on or off. If you play a sound while the manager is + // inactive, it won't start. If you deactivate the manager while sounds are + // playing, they'll stop. If you activate the manager while looping sounds + // are playing (those that have a loop_count of zero), they will start + // playing from the beginning of their loop. Defaults to true. virtual void set_active(bool flag) = 0; virtual bool get_active() const = 0; diff --git a/panda/src/audio/audioSound.cxx b/panda/src/audio/audioSound.cxx index 19cc27f030..8cce08bf7f 100644 --- a/panda/src/audio/audioSound.cxx +++ b/panda/src/audio/audioSound.cxx @@ -71,8 +71,8 @@ get_3d_max_distance() const { */ PN_stdfloat AudioSound:: get_speaker_mix(int speaker) { - // intentionally blank - return 0.0; + // intentionally blank + return 0.0; } /** @@ -80,7 +80,7 @@ get_speaker_mix(int speaker) { */ void AudioSound:: set_speaker_mix(PN_stdfloat frontleft, PN_stdfloat frontright, PN_stdfloat center, PN_stdfloat sub, PN_stdfloat backleft, PN_stdfloat backright, PN_stdfloat sideleft, PN_stdfloat sideright) { - // intentionally blank + // intentionally blank } /** diff --git a/panda/src/audio/audioSound.h b/panda/src/audio/audioSound.h index 486b0504f3..b5500f1b05 100644 --- a/panda/src/audio/audioSound.h +++ b/panda/src/audio/audioSound.h @@ -110,8 +110,8 @@ PUBLISHED: virtual void set_3d_max_distance(PN_stdfloat dist); virtual PN_stdfloat get_3d_max_distance() const; - // *_speaker_mix and *_speaker_level(s) serve the same purpose. - // *_speaker_mix is for use with FMOD. *_speaker_level(s) is for use with + // speaker_mix and speaker_level(s) serve the same purpose. + // speaker_mix is for use with FMOD. speaker_level(s) is for use with // Miles. Both interfaces exist because of a significant difference in the // two APIs. Hopefully the difference can be reconciled into a single // interface at some point. diff --git a/panda/src/downloader/httpClient.cxx b/panda/src/downloader/httpClient.cxx index 1f80bf61fd..c451f13084 100644 --- a/panda/src/downloader/httpClient.cxx +++ b/panda/src/downloader/httpClient.cxx @@ -663,7 +663,7 @@ get_proxies_for_url(const URLSpec &url) const { * Specifies the username:password string corresponding to a particular server * and/or realm, when demanded by the server. Either or both of the server or * realm may be empty; if so, they match anything. Also, the server may be - * set to the special string "*proxy", which will match any proxy server. + * set to the special string `"*proxy"`, which will match any proxy server. * * If the username is set to the empty string, this clears the password for * the particular server/realm pair. diff --git a/panda/src/linmath/lmatrix4_src.I b/panda/src/linmath/lmatrix4_src.I index fe8ba22bb7..99d930bd0b 100644 --- a/panda/src/linmath/lmatrix4_src.I +++ b/panda/src/linmath/lmatrix4_src.I @@ -1349,7 +1349,7 @@ invert_in_place() { } /** - * Computes (*this) += other * weight. + * Computes `(*this) += other * weight`. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: accumulate(const FLOATNAME(LMatrix4) &other, FLOATTYPE weight) { From d997be50ff42006279c37d6376db5eb16746db23 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 9 Sep 2020 18:05:35 +0200 Subject: [PATCH 12/23] glgsg: fix state tracking bug passing view parameters to shader These parameters are already taken care of by set_state_and_transform(). Also comment out a few lines of code that would prevent the latter from being called for transform changes, but which never triggered anyway. --- panda/src/glstuff/glGraphicsStateGuardian_src.cxx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index dd29bda619..9083c31acc 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -3992,12 +3992,6 @@ prepare_lens() { } #endif -#ifndef OPENGLES_1 - if (_current_shader_context) { - _current_shader_context->issue_parameters(Shader::SSD_transform); - } -#endif - return true; } @@ -11205,9 +11199,10 @@ set_state_and_transform(const RenderState *target, do_issue_transform(); } - if (target == _state_rs && (_state_mask | _inv_state_mask).is_all_on()) { - return; - } + //XXX the _inv_state_mask system does not appear to be used at the moment. + //if (target == _state_rs && (_state_mask | _inv_state_mask).is_all_on()) { + // return; + //} _target_rs = target; #ifndef OPENGLES_1 From 54238e97307bb03a6e6aea2bcb9a1f3eb3b184da Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 11 Sep 2020 13:14:54 +0200 Subject: [PATCH 13/23] direct: Add more links to manual pages in module docstrings See panda3d/panda3d-docs#53 [skip ci] --- direct/src/actor/Actor.py | 6 +++++- direct/src/actor/__init__.py | 3 +++ direct/src/distributed/__init__.py | 3 +++ direct/src/filter/CommonFilters.py | 3 ++- direct/src/filter/FilterManager.py | 2 ++ direct/src/filter/__init__.py | 3 +++ direct/src/showbase/__init__.py | 3 +++ direct/src/stdpy/__init__.py | 3 ++- direct/src/tkpanels/Inspector.py | 22 ++++++++++++++-------- 9 files changed, 37 insertions(+), 11 deletions(-) diff --git a/direct/src/actor/Actor.py b/direct/src/actor/Actor.py index 6ebf01341c..1d3fd2b0c4 100644 --- a/direct/src/actor/Actor.py +++ b/direct/src/actor/Actor.py @@ -1,4 +1,8 @@ -"""Actor module: contains the Actor class""" +"""Actor module: contains the Actor class. + +See the :ref:`models-and-actors` page in the Programming Guide to learn +more about loading models and animated actors. +""" __all__ = ['Actor'] diff --git a/direct/src/actor/__init__.py b/direct/src/actor/__init__.py index 8a080475bb..14d116777f 100644 --- a/direct/src/actor/__init__.py +++ b/direct/src/actor/__init__.py @@ -4,4 +4,7 @@ distributed variant thereof. Actor is a high-level interface around the lower-level :class:`panda3d.core.Character` implementation. It loads and controls an animated character and manages the animations playing on it. + +See the :ref:`models-and-actors` page in the Programming Guide to learn +more about loading models and animated actors. """ diff --git a/direct/src/distributed/__init__.py b/direct/src/distributed/__init__.py index cf5b4bc502..e20792afad 100644 --- a/direct/src/distributed/__init__.py +++ b/direct/src/distributed/__init__.py @@ -2,4 +2,7 @@ This package contains an implementation of the Distributed Networking API, a high-level networking system that automatically propagates changes made on distributed objects to interested clients. + +See the :ref:`distributed-networking` section of the Programming Guide to +learn more about the distributed networking system. """ diff --git a/direct/src/filter/CommonFilters.py b/direct/src/filter/CommonFilters.py index 18e62afc22..26601ced2e 100644 --- a/direct/src/filter/CommonFilters.py +++ b/direct/src/filter/CommonFilters.py @@ -1,7 +1,8 @@ """ Class CommonFilters implements certain common image -postprocessing filters. +postprocessing filters. See the :ref:`common-image-filters` page for +more information about how to use these filters. It is not ideal that these filters are all included in a single monolithic module. Unfortunately, when you want to apply two filters diff --git a/direct/src/filter/FilterManager.py b/direct/src/filter/FilterManager.py index 88b151ec89..fd3cda3921 100644 --- a/direct/src/filter/FilterManager.py +++ b/direct/src/filter/FilterManager.py @@ -3,6 +3,8 @@ The FilterManager is a convenience class that helps with the creation of render-to-texture buffers for image postprocessing applications. +See :ref:`generalized-image-filters` for information on how to use this class. + Still need to implement: * Make sure sort-order of buffers is correct. diff --git a/direct/src/filter/__init__.py b/direct/src/filter/__init__.py index 4acb30b438..52644c9e19 100644 --- a/direct/src/filter/__init__.py +++ b/direct/src/filter/__init__.py @@ -8,4 +8,7 @@ texture values as desired. The :class:`.CommonFilters` class contains various filters that are provided out of the box, whereas the :class:`.FilterManager` class is a lower-level class that allows you to set up your own filters. + +See the :ref:`render-to-texture-and-image-postprocessing` section of the +Programming Guide to learn more about image postprocessing in Panda3D. """ diff --git a/direct/src/showbase/__init__.py b/direct/src/showbase/__init__.py index e69de29bb2..0222b80817 100644 --- a/direct/src/showbase/__init__.py +++ b/direct/src/showbase/__init__.py @@ -0,0 +1,3 @@ +""" This package contains `.ShowBase`, an application framework responsible +for opening a graphical display, setting up input devices and creating +the scene graph. """ diff --git a/direct/src/stdpy/__init__.py b/direct/src/stdpy/__init__.py index 9e4739449c..d6c3be8322 100644 --- a/direct/src/stdpy/__init__.py +++ b/direct/src/stdpy/__init__.py @@ -1,5 +1,6 @@ """ This package contains various modules that provide a drop-in substitute for some of the built-in Python modules. These substitutes make better -use of Panda3D's virtual file system and threading system. +use of Panda3D's :ref:`Virtual File System ` and +:ref:`threading` system. """ diff --git a/direct/src/tkpanels/Inspector.py b/direct/src/tkpanels/Inspector.py index 4480332699..ddbbe30dc1 100644 --- a/direct/src/tkpanels/Inspector.py +++ b/direct/src/tkpanels/Inspector.py @@ -1,8 +1,15 @@ """Inspectors allow you to visually browse through the members of -various python objects. To open an inspector, import this module, and -execute inspector.inspect(anObject) I start IDLE with this command -line: idle.py -c "from inspector import inspect" -so that I can just type: inspect(anObject) any time.""" +various Python objects. To open an inspector, import this module, and +execute ``inspector.inspect(anObject)``. + +I start IDLE with this command line:: + + idle.py -c "from inspector import inspect" + +so that I can just type: ``inspect(anObject)`` any time. + +See :ref:`inspection-utilities` for more information. +""" __all__ = ['inspect', 'inspectorFor', 'Inspector', 'ModuleInspector', 'ClassInspector', 'InstanceInspector', 'FunctionInspector', 'InstanceMethodInspector', 'CodeInspector', 'ComplexInspector', 'DictionaryInspector', 'SequenceInspector', 'SliceInspector', 'InspectorWindow'] @@ -13,6 +20,9 @@ import Pmw ### public API def inspect(anObject): + """Opens up a window for visually inspecting the details of a given Python + object. See :ref:`inspection-utilities`. + """ inspector = inspectorFor(anObject) inspectorWindow = InspectorWindow(inspector) inspectorWindow.open() @@ -437,7 +447,3 @@ class InspectorWindow: label = item, command = lambda p = part, f = func: f(p)) return popupMenu - - - - From a94914fd861c697e2e969f5c9a075a96bc56d607 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 14:59:53 +0200 Subject: [PATCH 14/23] deploy-stub: forward compat with Python 4.0 --- pandatool/src/deploy-stub/deploy-stub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandatool/src/deploy-stub/deploy-stub.c b/pandatool/src/deploy-stub/deploy-stub.c index d986d4638a..b19ce4b25a 100644 --- a/pandatool/src/deploy-stub/deploy-stub.c +++ b/pandatool/src/deploy-stub/deploy-stub.c @@ -25,7 +25,7 @@ #if PY_MAJOR_VERSION >= 3 # include -# if PY_MINOR_VERSION < 5 +# if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 5 # define Py_DecodeLocale _Py_char2wchar # endif #endif @@ -550,7 +550,7 @@ int Py_FrozenMain(int argc, char **argv) error: if (argv_copy2) { for (i = 0; i < argc; i++) { -#if PY_MINOR_VERSION >= 4 +#if PY_MAJOR_VERSION > 3 || PY_MINOR_VERSION >= 4 PyMem_RawFree(argv_copy2[i]); #else PyMem_Free(argv_copy2[i]); From e443acd7a01490919512abd6aede61c62ea572bc Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 15:03:56 +0200 Subject: [PATCH 15/23] deploy-stub: Enable line_buffering on Windows when writing to log file Fixes #947 --- pandatool/src/deploy-stub/deploy-stub.c | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/pandatool/src/deploy-stub/deploy-stub.c b/pandatool/src/deploy-stub/deploy-stub.c index b19ce4b25a..25f426f5cd 100644 --- a/pandatool/src/deploy-stub/deploy-stub.c +++ b/pandatool/src/deploy-stub/deploy-stub.c @@ -28,6 +28,8 @@ # if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 5 # define Py_DecodeLocale _Py_char2wchar # endif + +# include "structmember.h" #endif /* Leave room for future expansion. We only read pointer 0, but there are @@ -343,6 +345,51 @@ static int setup_logging(const char *path, int append) { #endif } +/** + * Sets the line_buffering property on a TextIOWrapper object. + */ +#if PY_MAJOR_VERSION >= 3 +static int enable_line_buffering(PyObject *file) { +#if PY_VERSION_HEX >= 0x03070000 + /* Python 3.7 has a useful reconfigure() method. */ + PyObject *kwargs = _PyDict_NewPresized(1); + PyDict_SetItemString(kwargs, "line_buffering", Py_True); + PyObject *args = PyTuple_New(0); + + PyObject *method = PyObject_GetAttrString(file, "reconfigure"); + if (method != NULL) { + PyObject *result = PyObject_Call(method, args, kwargs); + Py_DECREF(method); + if (result != NULL) { + Py_DECREF(result); + } else { + PyErr_Clear(); + return 0; + } + } + Py_DECREF(kwargs); + Py_DECREF(args); +#else + /* Older versions just don't expose a way to reconfigure(), but it's still + safe to override the property; we just have to use a hack to do it, + because it's officially marked "readonly". */ + + PyTypeObject *type = Py_TYPE(file); + PyMemberDef *member = type->tp_members; + + while (member != NULL && member->name != NULL) { + if (strcmp(member->name, "line_buffering") == 0) { + *((char *)file + member->offset) = 1; + return 1; + } + ++member; + } + fflush(stdout); +#endif + return 1; +} +#endif + /* Main program */ #ifdef WIN_UNICODE @@ -483,6 +530,24 @@ int Py_FrozenMain(int argc, char **argv) } #endif +#if defined(MS_WINDOWS) && PY_VERSION_HEX >= 0x03040000 + /* Ensure that line buffering is enabled on the output streams. */ + if (!unbuffered) { + /* Python 3.7 has a useful reconfigure() method. */ + PyObject *sys_stream; + sys_stream = PySys_GetObject("__stdout__"); + if (sys_stream && !enable_line_buffering(sys_stream)) { + fprintf(stderr, "Failed to enable line buffering on sys.stdout\n"); + fflush(stderr); + } + sys_stream = PySys_GetObject("__stderr__"); + if (sys_stream && !enable_line_buffering(sys_stream)) { + fprintf(stderr, "Failed to enable line buffering on sys.stderr\n"); + fflush(stderr); + } + } +#endif + if (Py_VerboseFlag) fprintf(stderr, "Python %s\n%s\n", Py_GetVersion(), Py_GetCopyright()); From ce4690b869ca92751046856643d7d7d08be00612 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 15:10:03 +0200 Subject: [PATCH 16/23] deploy-stub: disable PYTHONINSPECT mechanism in +opt builds --- pandatool/src/deploy-stub/deploy-stub.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pandatool/src/deploy-stub/deploy-stub.c b/pandatool/src/deploy-stub/deploy-stub.c index 25f426f5cd..1668b63c0d 100644 --- a/pandatool/src/deploy-stub/deploy-stub.c +++ b/pandatool/src/deploy-stub/deploy-stub.c @@ -400,8 +400,10 @@ int Py_FrozenMain(int argc, char **argv) { char *p; int n, sts = 1; - int inspect = 0; int unbuffered = 0; +#ifndef NDEBUG + int inspect = 0; +#endif #if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE) int i; @@ -433,8 +435,10 @@ int Py_FrozenMain(int argc, char **argv) Py_NoSiteFlag = 0; Py_NoUserSiteDirectory = 1; +#ifndef NDEBUG if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') inspect = 1; +#endif if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') unbuffered = 1; @@ -603,8 +607,10 @@ int Py_FrozenMain(int argc, char **argv) else sts = 0; +#ifndef NDEBUG if (inspect && isatty((int)fileno(stdin))) sts = PyRun_AnyFile(stdin, "") != 0; +#endif #ifdef MS_WINDOWS PyWinFreeze_ExeTerm(); From a968caf1d207023b2820cf4c31ae3e7324ffb218 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 15:38:50 +0200 Subject: [PATCH 17/23] windisplay: Fix parented window receiving WS_POPUP style Fixes #915 --- panda/src/windisplay/winGraphicsWindow.cxx | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index c2e39d592e..372cfafede 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -973,17 +973,25 @@ make_style(const WindowProperties &properties) { // Additionally, the window class attribute should not include the // CS_PARENTDC style. - DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + DWORD window_style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS; if (properties.get_fullscreen()) { - window_style |= WS_SYSMENU; - } else if (!properties.get_undecorated()) { - window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); - - if (!properties.get_fixed_size()) { - window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX); + window_style |= WS_POPUP | WS_SYSMENU; + } else { + if (_parent_window_handle) { + window_style |= WS_CHILD; } else { - window_style |= WS_BORDER; + window_style |= WS_POPUP; + } + + if (!properties.get_undecorated()) { + window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); + + if (!properties.get_fixed_size()) { + window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX); + } else { + window_style |= WS_BORDER; + } } } return window_style; From 306c0fce0f747fe1de4d082312c2829b88bb21db Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Mon, 16 Mar 2020 18:27:15 -0700 Subject: [PATCH 18/23] build_apps: Disable the pip version check when downloading wheels If the user is not using the latest version of pip, they will likely be spammed by pip enough as is. There is not much need to remind them about this for each built platform. --- direct/src/dist/commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index cc281fb4e3..6564592a1a 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -425,12 +425,13 @@ class build_apps(setuptools.Command): os.remove(os.path.join(whldir, whl)) pip_args = [ + '--disable-pip-version-check', 'download', '-d', whldir, '-r', self.requirements_path, '--only-binary', ':all:', '--platform', platform, - '--abi', abi_tag + '--abi', abi_tag, ] if self.use_optimized_wheels: From 54ffc534fb32eb69aa53b8bfc016441f23198e7d Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 22:49:46 +0200 Subject: [PATCH 19/23] makepanda: Fix various issues building with Python 3.10 --- makepanda/makepackage.py | 9 ++++++--- makepanda/makepandacore.py | 32 ++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index b79a4430d7..8e1f9bb2fa 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -225,10 +225,13 @@ def MakeInstallerNSIS(version, file, title, installdir, runtime=False, compresso # Are we shipping a version of Python? if os.path.isfile(os.path.join(outputdir, "python", "python.exe")): py_dlls = glob.glob(os.path.join(outputdir, "python", "python[0-9][0-9].dll")) \ - + glob.glob(os.path.join(outputdir, "python", "python[0-9][0-9]_d.dll")) + + glob.glob(os.path.join(outputdir, "python", "python[0-9][0-9]_d.dll")) \ + + glob.glob(os.path.join(outputdir, "python", "python[0-9][0-9][0-9].dll")) \ + + glob.glob(os.path.join(outputdir, "python", "python[0-9][0-9][0-9]_d.dll")) assert py_dlls py_dll = os.path.basename(py_dlls[0]) - pyver = py_dll[6] + "." + py_dll[7] + py_dllver = py_dll.strip(".DHLNOPTY_dhlnopty") + pyver = py_dllver[0] + '.' + py_dllver[1:] if GetTargetArch() != 'x64': pyver += '-32' @@ -864,7 +867,7 @@ def MakeInstallerFreeBSD(version, runtime=False, python_versions=[], **kwargs): oscmd("rm -f %s/tmp/python_dep" % outputdir) if "PYTHONVERSION" in SDK: - pyver_nodot = SDK["PYTHONVERSION"][6:9:2] + pyver_nodot = SDK["PYTHONVERSION"][6:].replace('.', '') else: pyver_nodot = "%d%d" % (sys.version_info[:2]) diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index d26bbeed9d..307115bcd0 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -2169,9 +2169,11 @@ def SdkLocatePython(prefer_thirdparty_python=False): # Determine which version it is by checking which dll is in the directory. if (GetOptimize() <= 2): - py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]_d.dll") + py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]_d.dll") + \ + glob.glob(SDK["PYTHON"] + "/python[0-9][0-9][0-9]_d.dll") else: - py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9].dll") + py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9].dll") + \ + glob.glob(SDK["PYTHON"] + "/python[0-9][0-9][0-9].dll") if len(py_dlls) == 0: exit("Could not find the Python dll in %s." % (SDK["PYTHON"])) @@ -2179,24 +2181,29 @@ def SdkLocatePython(prefer_thirdparty_python=False): exit("Found multiple Python dlls in %s." % (SDK["PYTHON"])) py_dll = os.path.basename(py_dlls[0]) - ver = py_dll[6] + "." + py_dll[7] + py_dllver = py_dll.strip(".DHLNOPTY_dhlnopty") + ver = py_dllver[0] + '.' + py_dllver[1:] SDK["PYTHONVERSION"] = "python" + ver os.environ["PYTHONHOME"] = SDK["PYTHON"] - if sys.version[:3] != ver: - Warn("running makepanda with Python %s, but building Panda3D with Python %s." % (sys.version[:3], ver)) + running_ver = '%d.%d' % sys.version_info[:2] + if ver != running_ver: + Warn("running makepanda with Python %s, but building Panda3D with Python %s." % (running_ver, ver)) elif CrossCompiling() or (prefer_thirdparty_python and os.path.isdir(os.path.join(GetThirdpartyDir(), "python"))): tp_python = os.path.join(GetThirdpartyDir(), "python") if GetTarget() == 'darwin': - py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].dylib") + py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].dylib") + \ + glob.glob(tp_python + "/lib/libpython[0-9].[0-9][0-9].dylib") else: - py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].so") + py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].so") + \ + glob.glob(tp_python + "/lib/libpython[0-9].[0-9][0-9].so") if len(py_libs) == 0: - py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].a") + py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].a") + \ + glob.glob(tp_python + "/lib/libpython[0-9].[0-9][0-9].a") if len(py_libs) == 0: exit("Could not find the Python library in %s." % (tp_python)) @@ -2204,7 +2211,8 @@ def SdkLocatePython(prefer_thirdparty_python=False): exit("Found multiple Python libraries in %s." % (tp_python)) py_lib = os.path.basename(py_libs[0]) - SDK["PYTHONVERSION"] = "python" + py_lib[9] + "." + py_lib[11] + py_libver = py_lib.strip('.abdhilnopsty') + SDK["PYTHONVERSION"] = "python" + py_libver SDK["PYTHONEXEC"] = tp_python + "/bin/" + SDK["PYTHONVERSION"] SDK["PYTHON"] = tp_python + "/include/" + SDK["PYTHONVERSION"] @@ -2250,9 +2258,9 @@ def SdkLocatePython(prefer_thirdparty_python=False): exit("Host Python version (%s) must be the same as target Python version (%s)!" % (host_version, SDK["PYTHONVERSION"])) if GetVerbose(): - print("Using Python %s build located at %s" % (SDK["PYTHONVERSION"][6:9], SDK["PYTHON"])) + print("Using Python %s build located at %s" % (SDK["PYTHONVERSION"][6:], SDK["PYTHON"])) else: - print("Using Python %s" % (SDK["PYTHONVERSION"][6:9])) + print("Using Python %s" % (SDK["PYTHONVERSION"][6:])) def SdkLocateVisualStudio(version=(10,0)): if (GetHost() != "windows"): return @@ -3578,7 +3586,7 @@ def GetCurrentPythonVersionInfo(): from distutils.sysconfig import get_python_lib return { - "version": SDK["PYTHONVERSION"][6:9], + "version": SDK["PYTHONVERSION"][6:], "soabi": GetPythonABI(), "ext_suffix": GetExtensionSuffix(), "executable": sys.executable, From dabab90415e5786b2712c16764072a364ef2d5c2 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 22:50:03 +0200 Subject: [PATCH 20/23] interrogate: Fix compilation error of bindings with Python 3.9+ --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 2a90a4b1db..bf0ff5d333 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -6545,7 +6545,9 @@ write_make_seq(ostream &out, Object *obj, const std::string &ClassName, "\n"; if ((elem_getter->_args_type & AT_varargs) == AT_varargs) { + out << "#if defined(Py_TRACE_REFS) || PY_VERSION_HEX < 0x03090000\n"; out << " _Py_ForgetReference((PyObject *)&args);\n"; + out << "#endif\n"; } out << From 240259480832481456f28fd58466409ff335ed95 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 22:50:29 +0200 Subject: [PATCH 21/23] interrogatedb: Fix faulty version comparison in Python 3.10 --- dtool/src/interrogatedb/py_panda.cxx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index 5d17d8851f..11c86ae251 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -10,6 +10,9 @@ #ifdef HAVE_PYTHON +#define _STRINGIFY_VERSION(a, b) (#a "." #b) +#define STRINGIFY_VERSION(a, b) _STRINGIFY_VERSION(a, b) + using std::string; /** @@ -531,6 +534,8 @@ Dtool_TypeMap *Dtool_GetGlobalTypeMap() { } } +#define PY_MAJOR_VERSION_STR #PY_MAJOR_VERSION "." #PY_MINOR_VERSION + #if PY_MAJOR_VERSION >= 3 PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def) { #else @@ -538,15 +543,18 @@ PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulen #endif // Check the version so we can print a helpful error if it doesn't match. string version = Py_GetVersion(); + size_t version_len = version.find('.', 2); + if (version_len != string::npos) { + version.resize(version_len); + } - if (version[0] != '0' + PY_MAJOR_VERSION || - version[2] != '0' + PY_MINOR_VERSION) { + if (version != STRINGIFY_VERSION(PY_MAJOR_VERSION, PY_MINOR_VERSION)) { // Raise a helpful error message. We can safely do this because the // signature and behavior for PyErr_SetString has remained consistent. std::ostringstream errs; errs << "this module was compiled for Python " << PY_MAJOR_VERSION << "." << PY_MINOR_VERSION << ", which is " - << "incompatible with Python " << version.substr(0, 3); + << "incompatible with Python " << version; string error = errs.str(); PyErr_SetString(PyExc_ImportError, error.c_str()); return nullptr; From 2b3a1d9d736013aa358376f1cf897938eef603e0 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 22:53:37 +0200 Subject: [PATCH 22/23] prc: StreamReader should hold GIL for PyBytes_FromStringAndSize This is due to python/cpython#21074, which causes a segfault in the latest Python master when creating a bytes object of size 0. readlines() has been reimplemented to use a C++ vector in order to prevent constantly re-locking and unlocking the GIL for every line. --- dtool/src/prc/streamReader.h | 6 +-- dtool/src/prc/streamReader_ext.cxx | 71 +++++++++++++++++++++++++----- dtool/src/prc/streamReader_ext.h | 6 +-- 3 files changed, 67 insertions(+), 16 deletions(-) diff --git a/dtool/src/prc/streamReader.h b/dtool/src/prc/streamReader.h index a317f0a783..dc4748799b 100644 --- a/dtool/src/prc/streamReader.h +++ b/dtool/src/prc/streamReader.h @@ -66,10 +66,10 @@ PUBLISHED: BLOCKING void skip_bytes(size_t size); BLOCKING size_t extract_bytes(unsigned char *into, size_t size); - EXTENSION(BLOCKING PyObject *extract_bytes(size_t size)); + EXTENSION(PyObject *extract_bytes(size_t size)); - EXTENSION(BLOCKING PyObject *readline()); - EXTENSION(BLOCKING PyObject *readlines()); + EXTENSION(PyObject *readline()); + EXTENSION(PyObject *readlines()); public: BLOCKING vector_uchar extract_bytes(size_t size); diff --git a/dtool/src/prc/streamReader_ext.cxx b/dtool/src/prc/streamReader_ext.cxx index 9fc12dc51f..a64b568b95 100644 --- a/dtool/src/prc/streamReader_ext.cxx +++ b/dtool/src/prc/streamReader_ext.cxx @@ -15,6 +15,8 @@ #ifdef HAVE_PYTHON +#include "vector_string.h" + /** * Extracts the indicated number of bytes in the stream and returns them as a * string (or bytes, in Python 3). Returns empty string at end-of-file. @@ -23,13 +25,25 @@ PyObject *Extension:: extract_bytes(size_t size) { std::istream *in = _this->get_istream(); if (in->eof() || in->fail() || size == 0) { + // Note that this is only safe to call with size 0 while the GIL is held. return PyBytes_FromStringAndSize(nullptr, 0); } PyObject *bytes = PyBytes_FromStringAndSize(nullptr, size); - in->read(PyBytes_AS_STRING(bytes), size); + char *buffer = (char *)PyBytes_AS_STRING(bytes); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyThreadState *_save; + Py_UNBLOCK_THREADS +#endif // HAVE_THREADS && !SIMPLE_THREADS + + in->read(buffer, size); size_t read_bytes = in->gcount(); +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + Py_BLOCK_THREADS +#endif // HAVE_THREADS && !SIMPLE_THREADS + if (read_bytes == size || _PyBytes_Resize(&bytes, read_bytes) == 0) { return bytes; } else { @@ -47,6 +61,11 @@ extract_bytes(size_t size) { */ PyObject *Extension:: readline() { +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyThreadState *_save; + Py_UNBLOCK_THREADS +#endif // HAVE_THREADS && !SIMPLE_THREADS + std::istream *in = _this->get_istream(); std::string line; @@ -60,6 +79,10 @@ readline() { ch = in->get(); } +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + Py_BLOCK_THREADS +#endif // HAVE_THREADS && !SIMPLE_THREADS + #if PY_MAJOR_VERSION >= 3 return PyBytes_FromStringAndSize(line.data(), line.size()); #else @@ -73,22 +96,50 @@ readline() { */ PyObject *Extension:: readlines() { - PyObject *lst = PyList_New(0); +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyThreadState *_save; + Py_UNBLOCK_THREADS +#endif // HAVE_THREADS && !SIMPLE_THREADS + + std::istream *in = _this->get_istream(); + vector_string lines; + + while (true) { + std::string line; + int ch = in->get(); + while (ch != EOF && !in->fail()) { + line += ch; + if (ch == '\n' || in->eof()) { + // Here's the newline character. + break; + } + ch = in->get(); + } + + if (line.empty()) { + break; + } + + lines.push_back(std::move(line)); + } + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + Py_BLOCK_THREADS +#endif // HAVE_THREADS && !SIMPLE_THREADS + + PyObject *lst = PyList_New(lines.size()); if (lst == nullptr) { return nullptr; } - PyObject *py_line = readline(); - + Py_ssize_t i = 0; + for (const std::string &line : lines) { #if PY_MAJOR_VERSION >= 3 - while (PyBytes_GET_SIZE(py_line) > 0) { + PyObject *py_line = PyBytes_FromStringAndSize(line.data(), line.size()); #else - while (PyString_GET_SIZE(py_line) > 0) { + PyObject *py_line = PyString_FromStringAndSize(line.data(), line.size()); #endif - PyList_Append(lst, py_line); - Py_DECREF(py_line); - - py_line = readline(); + PyList_SET_ITEM(lst, i++, py_line); } return lst; diff --git a/dtool/src/prc/streamReader_ext.h b/dtool/src/prc/streamReader_ext.h index fe74694f8b..a04cdf8fdd 100644 --- a/dtool/src/prc/streamReader_ext.h +++ b/dtool/src/prc/streamReader_ext.h @@ -29,9 +29,9 @@ template<> class Extension : public ExtensionBase { public: - BLOCKING PyObject *extract_bytes(size_t size); - BLOCKING PyObject *readline(); - BLOCKING PyObject *readlines(); + PyObject *extract_bytes(size_t size); + PyObject *readline(); + PyObject *readlines(); }; #endif // HAVE_PYTHON From 0c2f8fec3c9bb67d0127f400acce256aae58091a Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 12 Sep 2020 22:57:59 +0200 Subject: [PATCH 23/23] palettizer: fix missing case for F_srgb and F_srgb_alpha --- pandatool/src/palettizer/textureProperties.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandatool/src/palettizer/textureProperties.cxx b/pandatool/src/palettizer/textureProperties.cxx index 573dd784b3..30d102f0a0 100644 --- a/pandatool/src/palettizer/textureProperties.cxx +++ b/pandatool/src/palettizer/textureProperties.cxx @@ -244,6 +244,7 @@ fully_define() { case EggTexture::F_rgba8: case EggTexture::F_rgba4: case EggTexture::F_rgba5: + case EggTexture::F_srgb_alpha: _num_channels = 4; break; @@ -253,6 +254,7 @@ fully_define() { case EggTexture::F_rgb8: case EggTexture::F_rgb5: case EggTexture::F_rgb332: + case EggTexture::F_srgb: _num_channels = 3; break;