I realized those are too annoying when writing a glTF exporter which
contains a lot of switches over enums. And as further shown by the diff,
those were only inflicting additional pain in *all* switch statements,
nothing else, no other added value. And everywhere else the helpers are
the designated way to deal with those, so there's no point in having an
explicit enum value denoting start of a "custom range".
It wasn't even any convenient to have it in the enum, as the extra
effort needed for casting actually made it *exactly* the same length as
if I'd just use a separately-defined constant.
Until now, these were only transitively tested in concrete plugin
implementations, meaning that if the base implementation would have an
error (such as accessing a null optional), it would only get discovered
when building a plugin, worst case a plugin in a completely different
repo.
Consistently with changes done to Utility::Path, this enforces proper
error handling on user side. Originally I didn't want to do this and
instead wanted to have a special Array instance devoted for an error
state, but that still would allow the error state be errorneously
treated as a successful but empty array.
Again not publicly documented because I don't like the naming and I
don't have the full behavior and interactions figured out yet -- i.e.,
an array of VertexFormats would be printed with Debug::packed as a long
string of characters without any whitespace. Not good, thus this
feature probably needs to be split in two, with this being named
"compact" or something else.
It limits the support for CMake 3.12+, but it's much less verbose and I
don't expect people to use ancient CMake versions with IDEs like Xcode
or VS anyway, so this should be fine.
Except for file callbacks, for these I have another change planned for
zero-copy import and it would be unwise to break stuff twice, providing
two sets of backwards compatibility wrappers. The image / scene
converter plugins went through a similar change earlier already and the
shader converters were made sane since the very beginning. OTOH audio
importers and text stuff are scheduled for merging with Trade or a
larger rework anyway, so I didn't see any point in updating those.
It's mostly a trivial change, except that returned String instances are
now also checked for non-default deleters same as Arrays because yes,
wow such flexibility compared to STL strings. Same was done for
ShaderTools::AbstractConverter already anyway, so nothing unheard-of
either.
The importer plugin interface version is bumped as this likely breaks
ABI in a nasty way that would lead to crashes.
For file opening there's no longer an unatomic pair of exists() +
read(), but since Path::read() now returns an Optional, it means we can
reliably distinguish between empty files and failures.
While at it, also added TODOs for removal of the StringStl.h header
that's needed in various places for compatibility with APIs still using
STL strings.
It's dangerous, as in case of failure it will attempt to print them as
strings. Plus now with latest de-std-string-ification of TestSuite it
causes the compilation to fail due to an ambigupus overload.
This should eventually be catched and disallowed directly by the Tester
class.
With really huge materials it's kinda useless to not know which layer
the error happened in -- and usually it's exactly because the layer
indices were specified wrong.
It was a clever harmless trick. Well, it was way more harmless than it
was clever, but even then it caused UBSan to complain. And that's Not A
Good Thing for various reasons, so let's just comply.
The main bad effect of this change is a *slightly* larger list of
exported symbols but until we actually get rid of the major bloats like
<iostream>, <string> and the like, this is not going to have any
measurable impact.
This mirrors what's done already for implementation-specific vertex
formats, thus:
* Ability to construct the classes without tripping up when trying to
check for type size in various asserts
* Providing a zero-size type-erased access in indices() and
mutableIndices()
* Disallowing typed and convenience access
Also not something the classic GPU vertex pipeline can handle, but
useful for other scenarios. Subsequently a support for array indices
will be added, allowing to directly represent for example OBJ files,
where each attribute has its own index buffer.
This is not something the classic GPU vertex pipeline can handle
(except maybe Vulkan, which can handle zero strides for instanced
attributes?), but useful for other scenarios. This means existing code
needs to be aware of and handle the new corner case.
No functional change, just splitting them to two separate headers and
two separate tests. These will eventually become public SceneTools
APIs... once I figure out better naming.
Mostly just to avoid the return types changing to incompatible types in
the future, breaking existing code. The internals are currently not
fully ready to operate with 64-bit object IDs, especially the AsArray()
APIs -- those I will have to solve in the future somehow. Returning
64-bit values in the pairs would add four byte padding after basically
each value, which is way too wasteful for the common case.
The Into() APIs could eventually get 64-bit overloads though.
Not really important right now as the SceneData from these are used only
in internal deprecated APIs, but at least it might speed up the
children2D() / children3D() queries. Mainly done so I don't forget to do
this later when these APIs are published in the SceneTools library.
What's not done is the rather complex logic in the single-function
conversion utility, where a field could retain the implicit/ordered
flags in *some* scenarios. There's too many corner cases so better be
conservative and don't preserve anything rather than mark something as
ordered while it's no longer the case. The corner cases are hopefully
all checled for (and XFAIL'd) in the test.
Currently used by the per-object access APIs to make the lookup
constant- or logarithmic-time instead of linear, available for use by
external data consumers as well.
Now it's a field and its corresponding object mapping, instead of
field and "objects":
- Goes better with the concept that there's not really any materialized
"object" anywhere, just fields mapped to them.
- No more weird singular/plural difference between field() and
objects(), it's field() and mapping() now.
- The objectCount() that actually wasn't really object count is now a
mappingBound(), an upper bound for object IDs contained in the object
mapping views. Which is quite self-explanatory without having to
mention every time that the range may be sparse.
This got originally added as some sort of a kludge to make it easy to go
to the parent transformation, assuming Parent and Transformation share
the same object mapping:
parentTransformation = transformations[parents[i]]
But after some ACTUAL REAL WORLD use, I realized that there's often a
set of objects that have a Parent defined, and then another, completely
disjoint, set of objects that have a transformation (for example certain
nodes having no transformation at all because it's an identity). And so
this parent indirection is not only useless, but in fact an additional
complication. Let's say we make a map of the transformations, where
transformationMap[i] is a transformation for object i:
transformationMap = {}
for j in range(len(transformations)):
transformationMap[transformationObject[j]] = transformation[j]
Then, with *no* assumptions about shared object mapping, the indirection
would cause parent transformation retrieval to look like this:
parentTransformation = transformationMap[parentObjects[parents[i]]
While *without* the indirection, it'd be just
parentTransformation = transformationMap[parents[i]]
Because that way one can query a field with *AsArray() and iterate
through it in a single expression. This also resolves the pending issue
where it was more than annoying to fetch object mapping for TRS fields
when only a subset of the fields is available.
This has to be solved on a more systematic level, perhaps even by
switching all types to be 64-bit. In the following commit all *AsArray()
and *Int() functions will output the object IDs as well, meaning this
would need to be handled in each and every API, which is a huge
maintenance burden.
As it's very unlikely that there actually will *ever* be >4G objects,
one possible option would be to introduce some "object ID hash" field
that would provide (contiguous?) remapping of the object ID to 32-bit
values, and the Into() and AsArray() accessors would return this
remapping instead of the original. But then again it'd cause issues with
for example animation references that would still reference the original
64-bit value.