diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 73cd444d0d..d86620e18f 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -2769,7 +2769,7 @@ def SetupVisualStudioEnviron(): elif not win_kit.endswith('\\'): win_kit += '\\' - for vnum in 10150, 10240, 10586, 14393, 15063, 16299, 17134, 17763, 18362: + for vnum in 10150, 10240, 10586, 14393, 15063, 16299, 17134, 17763, 18362, 19041: version = "10.0.{0}.0".format(vnum) if os.path.isfile(win_kit + "Include\\" + version + "\\ucrt\\assert.h"): print("Using Universal CRT %s" % (version)) diff --git a/panda/src/doc/eggSyntax.txt b/panda/src/doc/eggSyntax.txt index 4b57d91192..b81eb45c0e 100644 --- a/panda/src/doc/eggSyntax.txt +++ b/panda/src/doc/eggSyntax.txt @@ -3,7 +3,7 @@ THE PHILOSOPHY OF EGG FILES (vs. bam files) Egg files are used by Panda3D to describe many properties of a scene: simple geometry, including special effects and collision surfaces, characters including skeletons, morphs, and multiple-joint -assignments, and character animation tables. +assignments, and character animation tables. Egg files are designed to be the lingua franca of model manipulation for Panda tools. A number of utilities are provided that read and @@ -168,8 +168,9 @@ appear before they are referenced. The remaining formats are generic and specify only the semantic meaning of the channels. The size of the texels is determined by the width of the components in the image file. RGBA is the most - general; RGB is the same, but without any alpha channel. RGBM is - like RGBA, except that it requests only one bit of alpha, if the + general; RGB is the same, but without any alpha channel. + + RGBM is like RGBA, except that it requests only one bit of alpha, if the graphics card can provide that, to leave more room for the RGB components, which is especially important for older 16-bit graphics cards (the "M" stands for "mask", as in a cutout). @@ -211,7 +212,7 @@ appear before they are referenced. Although less often used, for 3-d textures wrapw may also be specified, and it behaves similarly to wrapu and wrapv. - There are other legal values in addtional to REPEAT and CLAMP. + There are other legal values in additional to REPEAT and CLAMP. The full list is: CLAMP @@ -278,7 +279,7 @@ appear before they are referenced. / (number of views). read-mipmaps { flag } - + If this flag is nonzero, then pre-generated mipmap levels will be loaded along with the texture. In this case, the filename should contain a sequence of one or more hash mark ("#") characters, @@ -413,7 +414,7 @@ appear before they are referenced. combine-alpha-operand2 { src-alpha } saved-result { flag } - + If flag is nonzero, then it indicates that this particular texture stage will be supplied as the "last_saved_result" source for any future texture stages. @@ -704,7 +705,7 @@ appear before they are referenced. [name] { u v [w] [tangent] [binormal] [morph-list] } This gives the texture coordinates of the vertex. This must be - specified if a texture is to be mapped onto this geometry. + specified if a texture is to be mapped onto this geometry. The texture coordinates are usually two-dimensional, with two component values (u v), but they may also be three-dimensional, @@ -739,7 +740,7 @@ appear before they are referenced. meaning to custom code or a custom shader. Like named UV's, there may be multiple Aux entries for a given vertex, each with a different name. - + name { vertices } @@ -758,18 +759,18 @@ appear before they are referenced. At the present time, the DynamicVertexPool is not implemented in Panda3D. - + GEOMETRY ENTRIES - name { - [attributes] - { - indices - { pool-name } - } + name { + [attributes] + { + indices + { pool-name } + } } A polygon consists of a sequence of vertices from a single vertex @@ -822,7 +823,7 @@ GEOMETRY ENTRIES used unless all vertices also have a normal. If no normal is defined, none will be supplied. The polygon normal, like the vertex normal, may be morphed by specifying a series of - entries. + entries. The polygon normal is used only for lighting and environment mapping calculations, and is not related to the implicit normal @@ -844,7 +845,7 @@ GEOMETRY ENTRIES disabled, and polygons are one-sided; specifying a nonzero value disables backface culling for this particular polygon and allows it to be viewed from either side. - + bin { bin-name } @@ -916,12 +917,12 @@ GEOMETRY ENTRIES or even within a texture. - name { - [attributes] - { - indices - { pool-name } - } + name { + [attributes] + { + indices + { pool-name } + } } A patch is similar to a polygon, but it is a special primitive that @@ -936,12 +937,12 @@ GEOMETRY ENTRIES specified for Patch. - name { - [attributes] - { - indices - { pool-name } - } + name { + [attributes] + { + indices + { pool-name } + } } A PointLight is a set of single points. One point is drawn for each @@ -964,12 +965,12 @@ GEOMETRY ENTRIES viewer normally. - name { - [attributes] - { - indices - { pool-name } - } + name { + [attributes] + { + indices + { pool-name } + } [component attributes] } @@ -985,11 +986,11 @@ GEOMETRY ENTRIES line segment, as in TriangleStrip, below. - name { - [attributes] - { - indices - { pool-name } + name { + [attributes] + { + indices + { pool-name } } [component attributes] } @@ -1013,7 +1014,7 @@ GEOMETRY ENTRIES It is possible for the individual triangles of a triangle strip to have a separate normal and/or color. If so, a entry should be given for each so-modified triangle: - + index { { r g b a [morph-list] } { x y z [morph-list] } @@ -1024,11 +1025,11 @@ GEOMETRY ENTRIES must always follow the vertex list. - name { - [attributes] - { - indices - { pool-name } + name { + [attributes] + { + indices + { pool-name } } [component attributes] } @@ -1057,7 +1058,7 @@ itself doesn't support them and will always create static curves and surfaces. External tools like egg-qtess, however, may respect them. { - [attributes] + [attributes] { order } { knot-list } @@ -1083,7 +1084,7 @@ surfaces. External tools like egg-qtess, however, may respect them. type { curve-type } - This defines the semanting meaning of this curve, either XYZ, HPR, + This defines the semantic meaning of this curve, either XYZ, HPR, or T. If the type is XYZ, the curve will automatically be transformed between Y-up and Z-up if necessary; otherwise, it will be left alone. @@ -1107,16 +1108,16 @@ surfaces. External tools like egg-qtess, however, may respect them. name { - [attributes] + [attributes] { u-order v-order } { u-knot-list } { v-knot-list } - { - indices - { pool-name } - } + { + indices + { pool-name } + } } A NURBS surface is an extension of a NURBS curve into two parametric @@ -1137,7 +1138,7 @@ surfaces. External tools like egg-qtess, however, may respect them. These define the number of subdivisions to make in the U and V directions to represent the surface. A uniform subdivision is always made, and trim curves are not respected (though they will - be drawn in if the trim curves themselves also have a subiv + be drawn in if the trim curves themselves also have a subdiv parameter). This is only intended as a cheesy visualization. @@ -1194,7 +1195,7 @@ surfaces. External tools like egg-qtess, however, may respect them. Although the egg syntax supports trim curves, there are at present no egg processing tools that respect them. For instance, egg-qtess - ignores trim curves and always tesselates the entire NURBS surface. + ignores trim curves and always tessellates the entire NURBS surface. MORPH DESCRIPTION ENTRIES @@ -1267,7 +1268,7 @@ GROUPING ENTRIES attributes of the group: GROUP BINARY ATTRIBUTES - + These attributes may be either on or off; they are off by default. They are turned on by specifying a non-zero "boolean-value". @@ -1310,6 +1311,15 @@ GROUPING ENTRIES vertices; joints and morphs appearing outside of a hierarchy identified with a flag are undefined. + { structured } + + This is an optional alternative for the flag. + By default, Panda will collapse all of the geometry in a group (with the { 1 } flag) + a single node. While this is optimal for conditions such as characters moving around + a scene, it may be suboptimal for larger or more complex characters. + This entry is typically generated by the egg-optchar program with the "-dart structured" flag. + { structured } implies { 1 }. + { boolean-value } This attribute indicates that the child nodes of this group @@ -1446,7 +1456,7 @@ GROUPING ENTRIES of the billboard, not at the origin of the scene. { - { + { in out [fade] { x y z } } } @@ -1483,7 +1493,7 @@ GROUPING ENTRIES Valid types so far are: Plane - + The geometry represents an infinite plane. The first polygon found in the group will define the plane. @@ -1550,7 +1560,7 @@ GROUPING ENTRIES most compatibility. keep - + Don't discard the visible geometry after using it to define a collision surface; create both an invisible collision surface and the visible geometry. @@ -1619,7 +1629,8 @@ GROUPING ENTRIES There may also be additional predefined egg object types not listed here; see the *.pp files that are installed into the etc - directory for a complete list. + directory for a complete list. Additionally, you can reference + the file located in $PANDA/src/doc/howto.MultiGenModelFlags { transform-definition } @@ -1683,9 +1694,9 @@ GROUPING ENTRIES current group, regardless of the group in which the geometry is actually defined. See the description, below. - { + { fps { float-value } - num-frames { integer-value } + num-frames { integer-value } } One or more AnimPreload entries may appear within the that @@ -1720,7 +1731,7 @@ GROUPING ENTRIES geometry in the scene graph. The syntax is: name { - { group-name } + { group-name } [ { group-name } ... ] } @@ -1746,8 +1757,8 @@ GROUPING ENTRIES and it may contain other joints. A tree of nodes only makes sense within a character - definition, which is created by applying the flag to a group. - See , above. + definition, which is created by applying the flag to a group. + See , above. The vertex assignment is crucial. This is how the geometry of a character is made to move with the joints. The character's geometry @@ -1790,7 +1801,7 @@ GROUPING ENTRIES bundles, or any one of the following ( entries are optional, and default as shown): - name { + name { fps { 24 } { values } } @@ -1844,7 +1855,7 @@ GROUPING ENTRIES an animation sequence. - name { + name { width { table-width } fps { 24 } { values } @@ -1913,6 +1924,10 @@ ANIMATION STRUCTURE animated model description. Without the flag, joints will be treated as ordinary groups, and morphs will be ignored. + It is important to note that utilizing { 1 } will collapse all of the + model's geometry into a single node. To omit this, use { structured } instead. + (See above.) + In the above, UPPERCASE NAMES represent an arbitrary name that you may choose. The name of the enclosing group, CHARACTER_NAME, is taken as the name of the animated model. It should generally match diff --git a/panda/src/doc/howto.MultiGenModelFlags b/panda/src/doc/howto.MultiGenModelFlags index ac67b7e93f..3989859803 100644 --- a/panda/src/doc/howto.MultiGenModelFlags +++ b/panda/src/doc/howto.MultiGenModelFlags @@ -3,7 +3,7 @@ This document describes the different kinds of model flags one can place in the comment field of MultiGen group beads. The general format for a model -flag is: +flag is: { {value} } The most up-to-date version of this document can be found in: @@ -30,7 +30,7 @@ The most up-to-date version of this document can be found in: { {camera-barrier} } Invisible collision surface for camera and colliders { {camera-barrier-sphere} } Invisible sphere collision surface for camera and colliders { {backstage} } Modeling reference object - { {1} } Decal the node below to me + { {1} } Decal the node below to me (like a window on a wall) { fps { # } } Set rate of animation for a pfSequence @@ -52,12 +52,12 @@ common flag/value pairs and describes what they are used for. which one places the flag (so names like red-hut are more useful than names like o34). - { {1} } + { {1} } - Used to show/hide, change the color, or change the collision properties + Used to show/hide, change the color, or change the collision properties of a chunk. - { {1} } + { {1} } Used to move, rotate, or scale a chunk of the model. Also can be used (like the flag) to show/hide, change the color, and change the @@ -91,7 +91,7 @@ common flag/value pairs and describes what they are used for. a door, for example, so the player can tell when the avatar has moved through the door. - BACKSTAGE objects are not translated over to the player. Modelers - should use this flag on reference objects that they include to help + should use this flag on reference objects that they include to help in the modeling task (such as scale references) IMPORTANT NOTE: @@ -108,7 +108,7 @@ common flag/value pairs and describes what they are used for. ********** PROPERTIES ********** -These are used to control properties of selected chunks. +These are used to control properties of selected chunks. { fps { frame-rate } } @@ -124,7 +124,7 @@ These are used to control properties of selected chunks. Multiple Flag/value pairs can be combined within an single field. For example: - { {1} + { {1} {barrier} } Generally, the flag can be combined with most other flags @@ -134,7 +134,7 @@ These are used to control properties of selected chunks. could also be written as: {{1}{barrier}} - + 3) Where to place the flags All model flags except flags are generally placed in the @@ -154,6 +154,6 @@ These are used to control properties of selected chunks. 4) Flags at different levels in the model Flags in lower level beads generally override flags in upper level - beads. + beads. 5) For more detailed information see $PANDA/src/doc/eggSyntax.txt. diff --git a/panda/src/egg2pg/characterMaker.cxx b/panda/src/egg2pg/characterMaker.cxx index f087ebf88e..0c8bb03650 100644 --- a/panda/src/egg2pg/characterMaker.cxx +++ b/panda/src/egg2pg/characterMaker.cxx @@ -36,10 +36,6 @@ using std::string; - - - - /** * */ @@ -589,16 +585,15 @@ determine_bin_home(EggBin *egg_bin) { // ahead and make an implicit node for the joint. if (egg_group->get_dcs_type() == EggGroup::DC_none) { -/* - * Unless the user specifically forbade exposing the joint by putting an - * explicit " { none }" entry in the joint. In this case, we return NULL - * to treat the geometry as dynamic (and animate it by animating its - * vertices), but display lists and vertex buffers will perform better if more - * geometry is rigid. There's a tradeoff, though, since the cull traverser - * will have to do more work with additional transforms in the scene graph, - * and this may also break up the geometry into more individual pieces, which - * is the biggest limiting factor on modern PC graphics cards. - */ + // Unless the user specifically forbade exposing the joint by putting an + // explicit " { none }" entry in the joint. In this case, we return + // nullptr to treat the geometry as dynamic (and animate it by animating + // its vertices), but display lists and vertex buffers will perform better + // if more geometry is rigid. There's a tradeoff, though, since the cull + // traverser will have to do more work with additional transforms in the + // scene graph, and this may also break up the geometry into more + // individual pieces, which is the biggest limiting factor on modern PC + // graphics cards. return nullptr; } diff --git a/panda/src/event/buttonEvent.I b/panda/src/event/buttonEvent.I index f082a4bee9..959f66dc47 100644 --- a/panda/src/event/buttonEvent.I +++ b/panda/src/event/buttonEvent.I @@ -149,3 +149,35 @@ update_mods(ModifierButtons &mods) const { return false; } } + +/** + * + */ +INLINE ButtonHandle ButtonEvent:: +get_button() const { + return _button; +} + +/** + * + */ +INLINE int ButtonEvent:: +get_keycode() const { + return _keycode; +} + +/** + * + */ +INLINE ButtonEvent::Type ButtonEvent:: +get_type() const { + return _type; +} + +/** + * + */ +INLINE double ButtonEvent:: +get_time() const { + return _time; +} diff --git a/panda/src/event/buttonEvent.h b/panda/src/event/buttonEvent.h index e839924c48..9da453a827 100644 --- a/panda/src/event/buttonEvent.h +++ b/panda/src/event/buttonEvent.h @@ -44,19 +44,20 @@ class DatagramIterator; * character set. */ class EXPCL_PANDA_EVENT ButtonEvent { -public: +PUBLISHED: enum Type { -/* - * T_down and T_up represent a button changing state correspondingly. - * T_resume_down is a special event that is only thrown when focus is returned - * to a window and a button is detected as being held down at that point; it - * indicates that the button should be considered down now (if it wasn't - * already), but it didn't just get pressed down at this moment, it was - * depressed some time ago. It's mainly used for correct tracking of modifier - * keys like shift and control, and can be ignored for other keys. - */ + // T_down is sent when a button was just pressed. T_down, + + // T_resume_down is a special event that is only thrown when focus is + // returned to a window and a button is detected as being held down at that + // point; it indicates that the button should be considered down now (if it + // wasn't already), but it didn't just get pressed down at this moment, it + // was depressed some time ago. It's mainly used for correct tracking of + // modifier keys like shift and control, and can be ignored for other keys. T_resume_down, + + // T_down is sent when a button is released. T_up, // T_repeat is sent for each a keyrepeat event generated by the system, @@ -84,6 +85,7 @@ public: T_raw_up, }; +public: INLINE ButtonEvent(); INLINE ButtonEvent(ButtonHandle button, Type type, double time = ClockObject::get_global_clock()->get_frame_time()); INLINE ButtonEvent(int keycode, double time = ClockObject::get_global_clock()->get_frame_time()); @@ -92,17 +94,30 @@ public: INLINE ButtonEvent(const ButtonEvent ©); INLINE void operator = (const ButtonEvent ©); +PUBLISHED: INLINE bool operator == (const ButtonEvent &other) const; INLINE bool operator != (const ButtonEvent &other) const; INLINE bool operator < (const ButtonEvent &other) const; +public: INLINE bool update_mods(ModifierButtons &mods) const; + INLINE ButtonHandle get_button() const; + INLINE int get_keycode() const; + INLINE Type get_type() const; + INLINE double get_time() const; + void output(std::ostream &out) const; void write_datagram(Datagram &dg) const; void read_datagram(DatagramIterator &scan); +PUBLISHED: + MAKE_PROPERTY(button, get_button); + MAKE_PROPERTY(keycode, get_keycode); + MAKE_PROPERTY(type, get_type); + MAKE_PROPERTY(time, get_time); + public: // _button will be filled in if type is T_down, T_resume_down, or T_up. ButtonHandle _button; diff --git a/panda/src/event/buttonEventList.h b/panda/src/event/buttonEventList.h index 0a7822fc63..a3cbcfb1e7 100644 --- a/panda/src/event/buttonEventList.h +++ b/panda/src/event/buttonEventList.h @@ -47,6 +47,8 @@ PUBLISHED: virtual void output(std::ostream &out) const; void write(std::ostream &out, int indent_level = 0) const; + MAKE_SEQ_PROPERTY(events, get_num_events, get_event); + private: typedef pvector Events; Events _events; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index d850364fe1..30541e4a0a 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -14190,7 +14190,8 @@ upload_simple_texture(CLP(TextureContext) *gtc) { #endif GLenum external_format = GL_BGRA; - const unsigned char *image_ptr = tex->get_simple_ram_image(); + CPTA_uchar image = tex->get_simple_ram_image(); + const unsigned char *image_ptr = image.p(); if (image_ptr == nullptr) { return false; } diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 38461838f6..60a137921b 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -2911,10 +2911,13 @@ update_shader_texture_bindings(ShaderContext *prev) { // Bindless texturing wasn't supported or didn't work, so let's just bind // the texture normally. + // Note that simple RAM images are always 2-D for now, so to avoid errors, + // we must load the real texture if this is not for a sampler2D. + bool force = (spec._desired_type != Texture::TT_2d_texture); #ifndef OPENGLES if (multi_bind) { // Multi-bind case. - if (!_glgsg->update_texture(gtc, false)) { + if (!_glgsg->update_texture(gtc, force)) { textures[i] = 0; } else { gtc->set_active(true); @@ -2934,7 +2937,7 @@ update_shader_texture_bindings(ShaderContext *prev) { { // Non-multibind case. _glgsg->set_active_texture_stage(i); - if (!_glgsg->update_texture(gtc, false)) { + if (!_glgsg->update_texture(gtc, force)) { continue; } _glgsg->apply_texture(gtc); diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index e5c4ce8809..bc6d218e38 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -10351,10 +10351,12 @@ make_this_from_bam(const FactoryParams ¶ms) { // object to read all of the attributes from the bam stream. Texture *dummy = this; AutoTextureScale auto_texture_scale = ATS_unspecified; + bool has_simple_ram_image = false; { CDWriter cdata_dummy(dummy->_cycler, true); dummy->do_fillin_body(cdata_dummy, scan, manager); auto_texture_scale = cdata_dummy->_auto_texture_scale; + has_simple_ram_image = !cdata_dummy->_simple_ram_image._image.empty(); } if (filename.empty()) { @@ -10387,6 +10389,61 @@ make_this_from_bam(const FactoryParams ¶ms) { case TT_1d_texture: case TT_2d_texture: case TT_1d_texture_array: + // If we don't want to preload textures, and we already have a simple + // RAM image (or don't need one), we don't need to load it from disk. + // We do check for it in the texture pool first, though, in case it has + // already been loaded. + if ((options.get_texture_flags() & LoaderOptions::TF_preload) == 0 && + (has_simple_ram_image || (options.get_texture_flags() & LoaderOptions::TF_preload_simple) == 0)) { + if (alpha_filename.empty()) { + me = TexturePool::get_texture(filename, primary_file_num_channels, + has_read_mipmaps); + } else { + me = TexturePool::get_texture(filename, alpha_filename, + primary_file_num_channels, + alpha_file_channel, + has_read_mipmaps); + } + if (me != nullptr && me->get_texture_type() == texture_type) { + // We can use this. + break; + } + + // We don't have a texture, but we didn't need to preload it, so we + // can just use this one. We just need to know where we can find it + // when we do need to reload it. + Filename fullpath = filename; + Filename alpha_fullpath = alpha_filename; + const DSearchPath &model_path = get_model_path(); + if (vfs->resolve_filename(fullpath, model_path) && + (alpha_fullpath.empty() || vfs->resolve_filename(alpha_fullpath, model_path))) { + me = dummy; + me->set_name(name); + + { + CDWriter cdata_me(me->_cycler, true); + cdata_me->_filename = filename; + cdata_me->_alpha_filename = alpha_filename; + cdata_me->_fullpath = fullpath; + cdata_me->_alpha_fullpath = alpha_fullpath; + cdata_me->_primary_file_num_channels = primary_file_num_channels; + cdata_me->_alpha_file_channel = alpha_file_channel; + cdata_me->_texture_type = texture_type; + cdata_me->_loaded_from_image = true; + cdata_me->_has_read_mipmaps = has_read_mipmaps; + } + + // To manage the reference count, explicitly ref it now, then unref + // it in the finalize callback. + me->ref(); + manager->register_finalize(me); + + // Do add it to the cache now, so that future uses of this same + // texture are unified. + TexturePool::add_texture(me); + return me; + } + } if (alpha_filename.empty()) { me = TexturePool::load_texture(filename, primary_file_num_channels, has_read_mipmaps, options); diff --git a/panda/src/gobj/texturePool.I b/panda/src/gobj/texturePool.I index 70836469fc..2cbb7da4b7 100644 --- a/panda/src/gobj/texturePool.I +++ b/panda/src/gobj/texturePool.I @@ -33,6 +33,29 @@ verify_texture(const Filename &filename) { return load_texture(filename) != nullptr; } +/** + * Returns the texture that has already been previously loaded, or NULL + * otherwise. + */ +INLINE Texture *TexturePool:: +get_texture(const Filename &filename, int primary_file_num_channels, + bool read_mipmaps) { + return get_global_ptr()->ns_get_texture(filename, primary_file_num_channels, + read_mipmaps); +} + +/** + * Returns the texture that has already been previously loaded, or NULL + * otherwise. + */ +INLINE Texture *TexturePool:: +get_texture(const Filename &filename, const Filename &alpha_filename, + int primary_file_num_channels, int alpha_file_channel, + bool read_mipmaps) { + return get_global_ptr()->ns_get_texture(filename, primary_file_num_channels, + read_mipmaps); +} + /** * Loads the given filename up into a texture, if it has not already been * loaded, and returns the new texture. If a texture with the same filename diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index b4ccbe11f6..755f937c67 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -273,6 +273,62 @@ ns_has_texture(const Filename &orig_filename) { return false; } +/** + * The nonstatic implementation of get_texture(). + */ +Texture *TexturePool:: +ns_get_texture(const Filename &orig_filename, int primary_file_num_channels, + bool read_mipmaps) { + LookupKey key; + key._primary_file_num_channels = primary_file_num_channels; + { + MutexHolder holder(_lock); + resolve_filename(key._fullpath, orig_filename, read_mipmaps, LoaderOptions()); + + Textures::const_iterator ti; + ti = _textures.find(key); + if (ti != _textures.end()) { + // This texture was previously loaded. + Texture *tex = (*ti).second; + nassertr(!tex->get_fullpath().empty(), tex); + return tex; + } + } + + return nullptr; +} + +/** + * The nonstatic implementation of get_texture(). + */ +Texture *TexturePool:: +ns_get_texture(const Filename &orig_filename, + const Filename &orig_alpha_filename, + int primary_file_num_channels, + int alpha_file_channel, + bool read_mipmaps) { + LookupKey key; + key._primary_file_num_channels = primary_file_num_channels; + key._alpha_file_channel = alpha_file_channel; + { + MutexHolder holder(_lock); + LoaderOptions options; + resolve_filename(key._fullpath, orig_filename, read_mipmaps, options); + resolve_filename(key._alpha_fullpath, orig_alpha_filename, read_mipmaps, options); + + Textures::const_iterator ti; + ti = _textures.find(key); + if (ti != _textures.end()) { + // This texture was previously loaded. + Texture *tex = (*ti).second; + nassertr(!tex->get_fullpath().empty(), tex); + return tex; + } + } + + return nullptr; +} + /** * The nonstatic implementation of load_texture(). */ diff --git a/panda/src/gobj/texturePool.h b/panda/src/gobj/texturePool.h index e89dd62a5d..997017ee2e 100644 --- a/panda/src/gobj/texturePool.h +++ b/panda/src/gobj/texturePool.h @@ -38,6 +38,14 @@ class EXPCL_PANDA_GOBJ TexturePool { PUBLISHED: INLINE static bool has_texture(const Filename &filename); INLINE static bool verify_texture(const Filename &filename); + INLINE static Texture *get_texture(const Filename &filename, + int primary_file_num_channels = 0, + bool read_mipmaps = false); + INLINE static Texture *get_texture(const Filename &filename, + const Filename &alpha_filename, + int primary_file_num_channels = 0, + int alpha_file_channel = 0, + bool read_mipmaps = false); BLOCKING INLINE static Texture *load_texture(const Filename &filename, int primary_file_num_channels = 0, bool read_mipmaps = false, @@ -109,6 +117,14 @@ private: TexturePool(); bool ns_has_texture(const Filename &orig_filename); + Texture *ns_get_texture(const Filename &filename, + int primary_file_num_channels = 0, + bool read_mipmaps = false); + Texture *ns_get_texture(const Filename &filename, + const Filename &alpha_filename, + int primary_file_num_channels = 0, + int alpha_file_channel = 0, + bool read_mipmaps = false); Texture *ns_load_texture(const Filename &orig_filename, int primary_file_num_channels, bool read_mipmaps, diff --git a/panda/src/gobj/textureReloadRequest.cxx b/panda/src/gobj/textureReloadRequest.cxx index b63acb6090..af6454c33a 100644 --- a/panda/src/gobj/textureReloadRequest.cxx +++ b/panda/src/gobj/textureReloadRequest.cxx @@ -22,28 +22,34 @@ TypeHandle TextureReloadRequest::_type_handle; AsyncTask::DoneStatus TextureReloadRequest:: do_task() { // Don't reload the texture if it doesn't need it. - if (_texture->was_image_modified(_pgo)) { - double delay = async_load_delay; - if (delay != 0.0) { - Thread::sleep(delay); - } + if (!_texture->was_image_modified(_pgo) && + (_allow_compressed ? _texture->has_ram_image() : _texture->has_uncompressed_ram_image())) { + return DS_done; + } - if (_texture->was_image_modified(_pgo)) { - if (_allow_compressed) { - _texture->get_ram_image(); - } else { - _texture->get_uncompressed_ram_image(); - } + double delay = async_load_delay; + if (delay != 0.0) { + Thread::sleep(delay); - // Now that we've loaded the texture, we should ensure it actually gets - // prepared--even if it's no longer visible in the frame--or it may - // become a kind of a leak (if the texture is never rendered again on - // this GSG, we'll just end up carrying the texture memory in RAM - // forever, instead of dumping it as soon as it gets prepared). - _pgo->enqueue_texture(_texture); + if (!_texture->was_image_modified(_pgo) && + (_allow_compressed ? _texture->has_ram_image() : _texture->has_uncompressed_ram_image())) { + return DS_done; } } + if (_allow_compressed) { + _texture->get_ram_image(); + } else { + _texture->get_uncompressed_ram_image(); + } + + // Now that we've loaded the texture, we should ensure it actually gets + // prepared--even if it's no longer visible in the frame--or it may become a + // kind of a leak (if the texture is never rendered again on this GSG, we'll + // just end up carrying the texture memory in RAM forever, instead of dumping + // it as soon as it gets prepared). + _pgo->enqueue_texture(_texture); + // Don't continue the task; we're done. return DS_done; } diff --git a/panda/src/linmath/lquaternion_src.cxx b/panda/src/linmath/lquaternion_src.cxx index cd48827eea..430b9971dc 100644 --- a/panda/src/linmath/lquaternion_src.cxx +++ b/panda/src/linmath/lquaternion_src.cxx @@ -106,7 +106,6 @@ set_hpr(const FLOATNAME(LVecBase3) &hpr, CoordinateSystem cs) { v = FLOATNAME(LVector3)::right(cs); a = deg_2_rad(hpr[1] * 0.5f); csincos(a, &s, &c); - s = csin(a); quat_p.set(c, v[0] * s, v[1] * s, v[2] * s); v = FLOATNAME(LVector3)::forward(cs); a = deg_2_rad(hpr[2] * 0.5f);