With this PR we refactor a `premultiplied alpha` user string set by `characterpreview.cpp` into a more flexible mechanism allowing us to assign any state to GUI textures. We can consider these changes more future proof than the previous approach.
This PR aims to spark the retirement of a questionable pattern I have found all over our code base. I will illustrate how this pattern encourages code duplication, lacks type safety, requires documentation and can be prone to bugs.
```
std::map<std::string, Object> mMap; // Stored in all lowercase for a case-insensitive lookup
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.emplace(lowerKey, object);
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.find(lowerKey);
mMap.find(key); // Not found. Oops!
```
An alternative approach produces no such issues.
```
std::unordered_map<std::string, Object, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mMap;
mMap.emplace(key, object);
mMap.find(key);
```
Of course, such an alternative will work for a `map` as well, but an `unordered_map` is generally preferable over a `map` with these changes because we have moved `lowerCase` into the comparison operator.
In this PR I have refactored `Animation::mNodeMap` accordingly. I have reviewed and adapted all direct and indirect usage of `Animation::mNodeMap` to ensure we do not change behaviour with this PR.
To construct serializer from given entities:
* Data source/destination - any value that has to be serialized/deserialized,
usually already existing type.
* Format - functional object to define high level serialization logic to
define specific format and data schema. Like order of fields, allocation.
* Visitor - functional object to define low level serialization logic to
operator on given data part.
* BinaryWriter - copies given value into provided buffer.
* BinaryReader - copies value into given destination from provided buffer.
* SizeAccumulator - calculates required buffer size for given data.
This PR fixes a crash caused by the improperly ensured lifetime of RigGeometry::mSourceGeometry. mSourceGeometry was not adequate to ensure mSourceGeometry would outlive mGeometry because we extend mGeometrys lifetime beyond this lifetime by passing mGeometry to the draw traversal instead of this.
In addition,
We add important comments.
We detect and prevent generally unsafe operations in high level code.
We add a sprinkling of const to help clarify intentions.
Currently, we use an `UnrefQueue` which supposedly aims to transfer destruction costs to another thread. The implications of this unusual pattern can not be well understood because some allocators might free resources more efficiently if they are freed by the same thread that allocated them. In addition, `UnrefQueue` complicates the validation of thread safety in our engine. Lastly, our current usage of `UnrefQueue` triggers `ref()`, `unref()` atomic operations as objects are passed into the queue. These operations could be more expensive than the actual destruction.
With this PR we thus remove `UnrefQueue`. We can expect these changes to have a minor impact at most because we free most resources elsewhere in `ResourceSystem::updateCache`.
It can fail due to float arithmetic precision with error:
Expected equality of these values:
getAsString(lua, "moveAndScale")
Which is: "TransformM{ move(6, 22, 18) scale(0.5, 1, 0.5) rotation(angle=8.53284e-17, axis=(1, 0, 0)) }"
"TransformM{ move(6, 22, 18) scale(0.5, 1, 0.5) }"
A component to load ESM content files with limited support for record types and
selection which of them to load. Supported record types are:
ACTI, CELL, CONT, DOOR, GMST, LAND, STAT.
==16218== Conditional jump or move depends on uninitialised value(s)
==16218== at 0xCDBC27: MWPhysics::Object::commitPositionChange() (object.cpp:68)
==16218== by 0xCE5B64: MWPhysics::PhysicsTaskScheduler::updatePtrAabb(std::shared_ptr<MWPhysics::PtrHolder> const&) (mtphysics.cpp:446)
==16218== by 0xCE5CC3: operator() (mtphysics.cpp:432)
==16218== by 0xCE5CC3: for_each<std::_Rb_tree_const_iterator<std::shared_ptr<MWPhysics::PtrHolder> >, MWPhysics::PhysicsTaskScheduler::updateAabbs()::<lambda(const std::shared_ptr<MWPhysics::PtrHolder>&)> > (stl_algo.h:3820)
==16218== by 0xCE5CC3: MWPhysics::PhysicsTaskScheduler::updateAabbs() (mtphysics.cpp:431)
==16218== by 0xCE5E35: MWPhysics::PhysicsTaskScheduler::afterPreStep() (mtphysics.cpp:586)
==16218== by 0xCE6238: operator() (mtphysics.cpp:533)
==16218== by 0xCE6238: wait<MWPhysics::PhysicsTaskScheduler::doSimulation()::<lambda()> > (barrier.hpp:33)
==16218== by 0xCE6238: MWPhysics::PhysicsTaskScheduler::doSimulation() (mtphysics.cpp:533)
==16218== by 0xCE6377: MWPhysics::PhysicsTaskScheduler::worker() (mtphysics.cpp:464)
==16218== by 0x74523C3: execute_native_thread_routine (thread.cc:82)
==16218== by 0x76FF258: start_thread (in /usr/lib/libpthread-2.33.so)
==16218== by 0x78155E2: clone (in /usr/lib/libc-2.33.so)
==16218==
==16218== Conditional jump or move depends on uninitialised value(s)
==16218== at 0xCDBC30: MWPhysics::Object::commitPositionChange() (object.cpp:73)
==16218== by 0xCE5B64: MWPhysics::PhysicsTaskScheduler::updatePtrAabb(std::shared_ptr<MWPhysics::PtrHolder> const&) (mtphysics.cpp:446)
==16218== by 0xCE5CC3: operator() (mtphysics.cpp:432)
==16218== by 0xCE5CC3: for_each<std::_Rb_tree_const_iterator<std::shared_ptr<MWPhysics::PtrHolder> >, MWPhysics::PhysicsTaskScheduler::updateAabbs()::<lambda(const std::shared_ptr<MWPhysics::PtrHolder>&)> > (stl_algo.h:3820)
==16218== by 0xCE5CC3: MWPhysics::PhysicsTaskScheduler::updateAabbs() (mtphysics.cpp:431)
==16218== by 0xCE5E35: MWPhysics::PhysicsTaskScheduler::afterPreStep() (mtphysics.cpp:586)
==16218== by 0xCE6238: operator() (mtphysics.cpp:533)
==16218== by 0xCE6238: wait<MWPhysics::PhysicsTaskScheduler::doSimulation()::<lambda()> > (barrier.hpp:33)
==16218== by 0xCE6238: MWPhysics::PhysicsTaskScheduler::doSimulation() (mtphysics.cpp:533)
==16218== by 0xCE6377: MWPhysics::PhysicsTaskScheduler::worker() (mtphysics.cpp:464)
==16218== by 0x74523C3: execute_native_thread_routine (thread.cc:82)
==16218== by 0x76FF258: start_thread (in /usr/lib/libpthread-2.33.so)
==16218== by 0x78155E2: clone (in /usr/lib/libc-2.33.so)
==16218==
We currently build a large map of a BSAFile's contents unused by Open MW. We already map archive contents in VFS. With this PR we remove the map from BSAFile and reimplement its only current use in BSATool.
To reduce amount of computations on the caller side and restrict possible
values.
* verts can't be non-int because it's a number of things.
* worldsize is initially defined as int by ESM::Land::REAL_SIZE.
* Put function to calculate heightfied shift into components to be able to
reuse by other binaries.
We just can no longer use the former ptr.getTypeName() as a fallback, but I do not suppose it matters. This value was an implementation defined string that usually contained a garbled mess.
Probably we should additionally refactor Lua types completely now that we have Ptr::getType(). I will leave this up to MWLua developers.
Currently, we use a peculiar mapping of ESM classes by their std::type_info::name. This mapping is an undefined behaviour because std::type_info::name is strictly implementation defined. It could return a non-unique value on some platforms. With this PR we use the unsigned int sRecordId of the ESM class as a more efficient lookup type that does not build on undefined behaviour. We can expect marginally faster save-game loading with these changes as well.
Currently, we always traverse the scene graph an additional time with a ComputeLightSpaceBounds visitor during shadow casting. ComputeLightSpaceBounds is only useful when the shadow casting mask allows us to shrink the bounds of the rendered scene, so we guard its traversal with a check against getCastsShadowTraversalMask. In practice, this guard never works because we build the traversal mask inclusively.
With this PR we limit the getCastsShadowTraversalMask check to relevant masks. This new check allows us to skip a superfluous ComputeLightSpaceBounds traversal with most settings.
We now use PositionAttitudeTransform for unmerged nodes because I have been informed PositionAttitudeTransform's scene graph performance is measurably faster than MatrixTransform's. We still need to use MatrixTransform for merged nodes because the Optimizer has limited support for non-MatrixTransform nodes. These MatrixTransforms will be removed in the merging process anyway.
This is the value used by vanilla Morrowind engine. At this angle player
character starts sliding down the slope.
This fixes navigation and movement issue in Mournhold, Godsreach.
For some reason we have commented std::move keywords in keywordsearch.hpp while they are quite beneficial. openmw_test_suite for keywordsearch.hpp takes 30% less time with these changes.
As we discovered in #3148, `Transform` nodes and their low level equivalence `pushModelViewMatrix` are somewhat costly involving a `Matrix::invert` operation per frame.
With this PR we avoid one `Transform` node for sun flashes and avoid another `pushModelViewMatrix` call in case the sun is fully visible.
With this PR we test out osg's shader define system for a somewhat harmless feature. As we can see, our code becomes more concise and efficient in this case. Most importantly, we no longer create unneeded vertex shader objects.
* uses a bitfield in refdata.hpp
With this simple change we pack boolean values to reduce the memory requirements of game objects.
* refdata.hpp [ci skip]
* refdata.cpp
* avoids creating empty statesets on drawables
Currently, we attempt to skip creating state on drawable nodes when this state matches the default state. This attempt is incomplete because we still create an avoidable empty stateset in the default case.
* renderingmanager.cpp
* nifloader.cpp
* nifloader.cpp
* shadervisitor.cpp
* avoids creating empty statesets on drawables
Currently, we attempt to skip creating state on drawable nodes when this state matches the default state. This attempt is incomplete because we still create an avoidable empty stateset in the default case.
* renderingmanager.cpp
* nifloader.cpp
Use faster aabbTest but without destance filter. To avoid dependency on a
specific constant and correctly handle situations when there is a big
difference between actors sizes.
Recastnavigation uses path cost and heuristic based on distance to find
shortest path by A* algorithm. Using raw speed values makes cost much lower
value than heuristic (1000 times less at maximum). Heuristic is defined as
distance from node to target * 0.999 that means area cost should never be less
than 0.999 or 1 for simplicity.
Use max speed to make lowest possible cost factor equal to 1.
Simple Physics API modification for Lua
See merge request OpenMW/openmw!1216
(cherry picked from commit d88494c90b501d0832ae0330a0ca81d8b8e5aa50)
02dd055a Save hitObject in castSphere() just like in castRay()
0793d0bf Allow to override collision mask and group for castSphere() as for castRay()