diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index efa3a861c7..a25c387697 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -213,6 +213,7 @@ class build_apps(setuptools.Command): 'dciman32.dll', 'comdlg32.dll', 'comctl32.dll', 'ole32.dll', 'oleaut32.dll', 'gdiplus.dll', 'winmm.dll', 'iphlpapi.dll', 'msvcrt.dll', 'kernelbase.dll', 'msimg32.dll', 'msacm32.dll', + 'setupapi.dll', 'version.dll', # manylinux1/linux 'libdl.so.*', 'libstdc++.so.*', 'libm.so.*', 'libgcc_s.so.*', @@ -230,6 +231,12 @@ class build_apps(setuptools.Command): '/usr/lib/libedit.*.dylib', '/System/Library/**', ] + + if sys.version_info >= (3, 5): + # Python 3.5+ requires at least Windows Vista to run anyway, so we + # shouldn't warn about DLLs that are shipped with Vista. + self.exclude_dependencies += ['bcrypt.dll'] + self.package_data_dirs = {} # We keep track of the zip files we've opened. @@ -1350,17 +1357,22 @@ class bdist_apps(setuptools.Command): nsi.write('Section "" SecCore\n') nsi.write(' SetOutPath "$INSTDIR"\n') curdir = "" + nsi_dir = p3d.Filename.fromOsSpecific(build_cmd.build_base) + build_root_dir = p3d.Filename.fromOsSpecific(build_dir) for root, dirs, files in os.walk(build_dir): for name in files: basefile = p3d.Filename.fromOsSpecific(os.path.join(root, name)) file = p3d.Filename(basefile) file.makeAbsolute() - file.makeRelativeTo(build_dir) - outdir = file.getDirname().replace('/', '\\') + file.makeRelativeTo(nsi_dir) + outdir = p3d.Filename(basefile) + outdir.makeAbsolute() + outdir.makeRelativeTo(build_root_dir) + outdir = outdir.getDirname().replace('/', '\\') if curdir != outdir: nsi.write(' SetOutPath "$INSTDIR\\%s"\n' % outdir) curdir = outdir - nsi.write(' File "%s"\n' % (basefile.toOsSpecific())) + nsi.write(' File "%s"\n' % (file.toOsSpecific())) nsi.write(' SetOutPath "$INSTDIR"\n') nsi.write(' WriteUninstaller "$INSTDIR\\Uninstall.exe"\n') nsi.write(' ; Start menu items\n') diff --git a/direct/src/gui/DirectGuiGlobals.py b/direct/src/gui/DirectGuiGlobals.py index dce1d38b18..78bf1040e3 100644 --- a/direct/src/gui/DirectGuiGlobals.py +++ b/direct/src/gui/DirectGuiGlobals.py @@ -128,6 +128,8 @@ def getDefaultFont(): return defaultFont def setDefaultFont(newFont): + """Changes the default font for DirectGUI items. To change the default + font across the board, see :meth:`.TextNode.setDefaultFont`. """ global defaultFont defaultFont = newFont @@ -161,3 +163,17 @@ def getDefaultPanel(): def setDefaultPanel(newPanel): global panel panel = newPanel + +get_default_rollover_sound = getDefaultRolloverSound +set_default_rollover_sound = setDefaultRolloverSound +get_default_click_sound = getDefaultClickSound +set_default_click_sound = setDefaultClickSound +get_default_font = getDefaultFont +set_default_font = setDefaultFont +get_default_dialog_geom = getDefaultDialogGeom +get_default_dialog_relief = getDefaultDialogRelief +set_default_dialog_geom = setDefaultDialogGeom +get_default_draw_order = getDefaultDrawOrder +set_default_draw_order = setDefaultDrawOrder +get_default_panel = getDefaultPanel +set_default_panel = setDefaultPanel diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 8e417f5340..c4657a4894 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,3 +1,73 @@ +------------------------ RELEASE 1.10.7 ----------------------- + +This is primarily a bugfix release, but includes a few new features as well. + +Rendering +* Add High Dynamic Range filter with ACES tone mapping to CommonFilters +* Add sRGB filter to CommonFilters (to be used as fallback to framebuffer-srgb) +* Fix (shadow) buffer no longer working after host buffer is destroyed (#890) +* Fix rare bug with shader parameters not being set right across render passes +* Fog density passed to shader now defaults to 0 when no fog is applied +* Don't check sampler/light type mismatch for non-shadow-casting lights (#942) +* Shader generator now makes use of Material alpha values if present (#912) +* Support sRGB textures and framebuffers in OpenGL ES 2 renderer + +Asset Loading +* Egg files can now be loaded with sRGB texture formats automatically +* Fix maya2egg regression not creating animations properly (#1004) +* Fix FMOD issue reading sounds from read-write-opened multifiles (#1002) + +Stability +* Fix faulty collision detection when sphere is under polygon (#907) +* Fix PStats misreporting an exploding number of RenderState/TransformState +* Fix memory leak when removing a task that is awaiting a non-Panda future +* Optimize RenderState cache for case where texture is replaced repeatedly +* PNMImage add_sub_image() / mult_sub_image() now properly adds offset (#903) +* Fix some ServerRepository issues in Python 3 +* Fix has_tags() still returning true after clearing all Python tags (#936) +* Fix crash in BitArray.has_any_of() +* Fix errors in PythonUtil.detectLeaks() and PythonUtil.report() +* Fix runtime error during ControlManager deletion (#884) +* Some error messages in nativenet are changed to debug messages +* Fix TexMemWatcher crash when graphics memory reaches 1 GB (#975) +* Fix a Triangulator crash dealing with certain invalid polygons (#985) +* Fix in MultiplexStreamBuf::Output::write_string() (#902) +* Fix a buffer overrun on FreeBSD when extracting very long command-line args + +Input and Windowing +* M_confined mouse mode on Windows now confines mouse to client rectangle +* Fix incorrect handling of shift modifier on macOS (#959) +* Fix erroneous dpad_*-up events when emulating a dpad on Linux (#973) +* Fix tab handling in DirectEntry with certain versions of Windows CRT (#994) +* Fix parented window receiving WS_POPUP style on Windows (#915) + +Deployment +* macOS app bundle now performs chdir into Resources folder upon launch +* No longer defaults to FMOD audio on macOS unless FMOD is explicitly bundled +* Improvements to Config.prc handling (strip comments, sort files, etc.) +* Line buffering is now used on Windows when writing to log files (#947) +* stdout/stderr output streams are now flushed on exit (#946) +* Build paths are now properly stripped from compiled Python code (#991) +* Update to support a change in location of numpy/Pillow libraries (#914) +* Fix libffi-7.dll not being included in official wheels +* PYTHONINSPECT mechanism is no longer enabled when building with optimizations +* A few unnecessary warning messages are squelched + +API +* Add pickle support to Datagram class +* Unexpose a crashing CollisionPolygon constructor and method (#908) +* FilterManager has new parameter to control framebuffer clamping +* Add snake_case aliases for functions in DirectGuiGlobals +* Global delete operator is now safe to call with a null pointer +* Improvements to API reference documentation + +Build +* Fix issues building with development versions Python 3.9 and 3.10 +* Fix an ABI incompatibility issue with MouseWatcher in NDEBUG builds +* Fix incorrect NaN/inf detection in double-precision release builds (#987) +* interrogate C++ parser supports arbitrary constant expressions in bitfields +* interrogate C++ parser supports sizeof with constant expression + ------------------------ RELEASE 1.10.6 ----------------------- This is a recommended bugfix release that adds additional stability fixes. diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 588085cdda..29e3bd8ce9 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1111,8 +1111,12 @@ def CompileCxx(obj,src,opts): cmd += "/DWINVER=0x600 " cmd += "/Fo" + obj + " /nologo /c" - if GetTargetArch() != 'x64' and (not PkgSkip("SSE2") or 'SSE2' in opts): - cmd += " /arch:SSE2" + if GetTargetArch() == 'x86': + # x86 (32 bit) MSVC 2015+ defaults to /arch:SSE2 + if not PkgSkip("SSE2") or 'SSE2' in opts: # x86 with SSE2 + cmd += " /arch:SSE2" # let's still be explicit and pass in /arch:SSE2 + else: # x86 without SSE2 + cmd += " /arch:IA32" for x in ipath: cmd += " /I" + x for (opt,dir) in INCDIRECTORIES: if (opt=="ALWAYS") or (opt in opts): cmd += " /I" + BracketNameWithQuotes(dir) diff --git a/panda/src/egg2pg/config_egg2pg.cxx b/panda/src/egg2pg/config_egg2pg.cxx index e32aa19914..0b42a6f450 100644 --- a/panda/src/egg2pg/config_egg2pg.cxx +++ b/panda/src/egg2pg/config_egg2pg.cxx @@ -194,6 +194,13 @@ ConfigVariableBool egg_implicit_alpha_binary "will automatically be downgraded to alpha type \"binary\" instead of " "whatever appears in the egg file.")); +ConfigVariableBool egg_force_srgb_textures +("egg-force-srgb-textures", false, + PRC_DESC("If this is true, Panda3D will automatically assign the F_srgb or " + "F_srgb_alpha format to all textures loaded from egg files, unless " + "their envtype is set to a non-color map. Keep in mind that the " + "model-cache must be cleared after changing this setting.")); + ConfigureFn(config_egg2pg) { init_libegg2pg(); } diff --git a/panda/src/egg2pg/config_egg2pg.h b/panda/src/egg2pg/config_egg2pg.h index e9e0e202d6..f833772676 100644 --- a/panda/src/egg2pg/config_egg2pg.h +++ b/panda/src/egg2pg/config_egg2pg.h @@ -54,6 +54,7 @@ extern EXPCL_PANDA_EGG2PG ConfigVariableBool egg_preload_simple_textures; extern EXPCL_PANDA_EGG2PG ConfigVariableDouble egg_vertex_membership_quantize; extern EXPCL_PANDA_EGG2PG ConfigVariableInt egg_vertex_max_num_joints; extern EXPCL_PANDA_EGG2PG ConfigVariableBool egg_implicit_alpha_binary; +extern EXPCL_PANDA_EGG2PG ConfigVariableBool egg_force_srgb_textures; extern EXPCL_PANDA_EGG2PG void init_libegg2pg(); diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 170cc6f7ae..d456dd5b16 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -1188,6 +1188,30 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { tex->set_default_sampler(sampler); + bool force_srgb = false; + if (egg_force_srgb_textures) { + switch (egg_tex->get_env_type()) { + case EggTexture::ET_unspecified: + case EggTexture::ET_modulate: + case EggTexture::ET_decal: + case EggTexture::ET_blend: + case EggTexture::ET_replace: + case EggTexture::ET_add: + case EggTexture::ET_blend_color_scale: + case EggTexture::ET_modulate_glow: + case EggTexture::ET_modulate_gloss: + force_srgb = true; + if (egg2pg_cat.is_debug()) { + egg2pg_cat.debug() + << "Enabling sRGB format on texture " << egg_tex->get_name() << "\n"; + } + break; + + default: + break; + } + } + if (tex->get_num_components() == 1) { switch (egg_tex->get_format()) { case EggTexture::F_red: @@ -1203,44 +1227,52 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { tex->set_format(Texture::F_alpha); break; case EggTexture::F_luminance: - tex->set_format(Texture::F_luminance); - break; - - case EggTexture::F_unspecified: + tex->set_format(force_srgb ? Texture::F_sluminance : Texture::F_luminance); break; default: egg2pg_cat.warning() << "Ignoring inappropriate format " << egg_tex->get_format() << " for 1-component texture " << egg_tex->get_name() << "\n"; + + case EggTexture::F_unspecified: + if (force_srgb) { + tex->set_format(Texture::F_sluminance); + } + break; } } else if (tex->get_num_components() == 2) { switch (egg_tex->get_format()) { case EggTexture::F_luminance_alpha: - tex->set_format(Texture::F_luminance_alpha); + tex->set_format(force_srgb ? Texture::F_sluminance_alpha : Texture::F_luminance_alpha); break; case EggTexture::F_luminance_alphamask: - tex->set_format(Texture::F_luminance_alphamask); - break; - - case EggTexture::F_unspecified: + tex->set_format(force_srgb ? Texture::F_sluminance_alpha : Texture::F_luminance_alphamask); break; default: egg2pg_cat.warning() << "Ignoring inappropriate format " << egg_tex->get_format() << " for 2-component texture " << egg_tex->get_name() << "\n"; + + case EggTexture::F_unspecified: + if (force_srgb) { + tex->set_format(Texture::F_sluminance_alpha); + } + break; } } else if (tex->get_num_components() == 3) { switch (egg_tex->get_format()) { case EggTexture::F_rgb: - tex->set_format(Texture::F_rgb); + tex->set_format(force_srgb ? Texture::F_srgb : Texture::F_rgb); break; case EggTexture::F_rgb12: - if (tex->get_component_width() >= 2) { + if (force_srgb) { + tex->set_format(Texture::F_srgb); + } else if (tex->get_component_width() >= 2) { // Only do this if the component width supports it. tex->set_format(Texture::F_rgb12); } else { @@ -1253,40 +1285,45 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { case EggTexture::F_rgba8: // We'll quietly accept RGBA8 for a 3-component texture, since flt2egg // generates these for 3-component as well as for 4-component textures. - tex->set_format(Texture::F_rgb8); + tex->set_format(force_srgb ? Texture::F_srgb : Texture::F_rgb8); break; case EggTexture::F_rgb5: - tex->set_format(Texture::F_rgb5); + tex->set_format(force_srgb ? Texture::F_srgb : Texture::F_rgb5); break; case EggTexture::F_rgb332: - tex->set_format(Texture::F_rgb332); + tex->set_format(force_srgb ? Texture::F_srgb : 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; - default: egg2pg_cat.warning() << "Ignoring inappropriate format " << egg_tex->get_format() << " for 3-component texture " << egg_tex->get_name() << "\n"; + + case EggTexture::F_unspecified: + if (force_srgb) { + tex->set_format(Texture::F_srgb); + } + break; } } else if (tex->get_num_components() == 4) { switch (egg_tex->get_format()) { case EggTexture::F_rgba: - tex->set_format(Texture::F_rgba); + tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba); break; case EggTexture::F_rgbm: - tex->set_format(Texture::F_rgbm); + tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgbm); break; case EggTexture::F_rgba12: - if (tex->get_component_width() >= 2) { + if (force_srgb) { + tex->set_format(Texture::F_srgb_alpha); + } else if (tex->get_component_width() >= 2) { // Only do this if the component width supports it. - tex->set_format(Texture::F_rgba12); + tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba12); } else { egg2pg_cat.warning() << "Ignoring inappropriate format " << egg_tex->get_format() @@ -1294,28 +1331,38 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) { } break; case EggTexture::F_rgba8: - tex->set_format(Texture::F_rgba8); + tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba8); break; case EggTexture::F_rgba4: - tex->set_format(Texture::F_rgba4); + tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba4); break; case EggTexture::F_rgba5: - tex->set_format(Texture::F_rgba5); + tex->set_format(force_srgb ? Texture::F_srgb_alpha : Texture::F_rgba5); break; case EggTexture::F_srgb_alpha: tex->set_format(Texture::F_srgb_alpha); break; - case EggTexture::F_unspecified: - break; - default: egg2pg_cat.warning() << "Ignoring inappropriate format " << egg_tex->get_format() << " for 4-component texture " << egg_tex->get_name() << "\n"; + + case EggTexture::F_unspecified: + if (force_srgb) { + tex->set_format(Texture::F_srgb_alpha); + } + break; } } + if (force_srgb && tex->get_format() != Texture::F_alpha && + !Texture::is_srgb(tex->get_format())) { + egg2pg_cat.warning() + << "Unable to enable sRGB format on texture " << egg_tex->get_name() + << " with specified format " << egg_tex->get_format() << "\n"; + } + switch (egg_tex->get_quality_level()) { case EggTexture::QL_unspecified: case EggTexture::QL_default: diff --git a/tests/prc/test_stream_reader.py b/tests/prc/test_stream_reader.py index bea5db5614..7dcec0a5a1 100644 --- a/tests/prc/test_stream_reader.py +++ b/tests/prc/test_stream_reader.py @@ -157,6 +157,42 @@ def test_streamreader_readline(): assert reader.readline() == b'\x00\x00' +def test_streamreader_readlines(): + # Empty stream + stream = StringStream(b'') + reader = StreamReader(stream, False) + assert reader.readlines() == [] + + # Single line without newline + stream = StringStream(b'A') + reader = StreamReader(stream, False) + assert reader.readlines() == [b'A'] + assert reader.readlines() == [] + + # Single newline + stream = StringStream(b'\n') + reader = StreamReader(stream, False) + assert reader.readlines() == [b'\n'] + assert reader.readlines() == [] + + # Line with text followed by empty line + stream = StringStream(b'A\n\n') + reader = StreamReader(stream, False) + assert reader.readlines() == [b'A\n', b'\n'] + assert reader.readlines() == [] + + # Multiple lines + stream = StringStream(b'A\nB\nC') + reader = StreamReader(stream, False) + assert reader.readlines() == [b'A\n', b'B\n', b'C'] + assert reader.readlines() == [] + + # Preserve null byte + stream = StringStream(b'\x00\x00') + reader = StreamReader(stream, False) + assert reader.readlines() == [b'\x00\x00'] + + def test_streamreader_extract_bytes(): # Empty bytes stream = StringStream(b'')