The perf cost is just too great for these to be enabled always. The only
place where the assertions are kept always is in the batch APIs -- there
it's assumed the function is called on large enough data to offset this
overhead, plus since it's often dealing with large blocks of data the
memory safety is more important than various FP drifts which were the
usual case why other assertions were firing.
It compiles on GLES2 as well, but there it hits the massive PITA of
being unable to render to LUMINANXCE formats and GL_RED formats not
really being available everywhere.
I don't have the patience to fix that, and almost nobody needs to use
ES2 platforms nowadays, so this isn't really a priority.
So one can directly read it back on GLES without having to wrap the
texture in a framebuffer again.
This change also puts the framebuffer completeness check *before* the
clear() and bind() which makes it no longer emit a GL error. The error
is still silent though, which isn't nice. Gotta fix that eventually as
well.
This means I (and people making their own plugins) don't need to go and
update each and every plugin once the version in the interface string
gets bumped after a (silent) ABI break. Such as when new virtual
functions get added, as those often lead to strange crashes if the
plugins don't get rebuilt after.
The plugins will now use this macro, which means they'll
automatically embed an interface string that was present in the base
class header at build time. However, when the base class updates, the
previous string is still embedded in the plugin binary, which will then
fail to load -- this being automatic doesn't mean the original purpose
is lost. Subsequently rebuilding the plugins from source will make them
pick up the updated interface string again.
The article this API was originally based on assumes a scenario which
just *isn't* matching usual practices here, giving wrong results. Too
bad I didn't spend more time questioning the proof there and just
blindly assumed it's correct because everyone said so.
Won't be typing all that reasoning again in the commit message, see the
changelog entry and the comment in the test for details.
Taking Animation::TrackViewStorage wasn't really a good idea, as it
wasn't solving anything -- in order to create it, there needs to be a
TrackView of a concrete type first anyway, and even then it required a
lot of additional verbose typing.
The new constructors take basically what TrackView takes, plus there's
additionally a constructor that takes a typeless value view together
with explicitly specified value and result types, allowing a truly
type-erased usage. On the other hand, the templated variants directly
deduce the types without any additional typing, making the construction
similarly straightforward to e.g. SceneFieldData.
In case of the type-erased constructors, if the interpolator function
isn't supplied explicitly, an implicit one is picked based on the value
type, result type and interpolation. Not all combinations make sense of
course, so this is a new assertion point, however compared to the
previous way where the interpolator was picked from a *typed* TrackView,
this doesn't add any new restriction -- what asserted there, asserts now
as well, and additionally you can't have e.g. a Quaternion track with a
boolean result. I may also be eventually adding assertions to check that
the target name matches the result type -- so e.g. a rotation isn't
specified as an integer and such. Compared to newer APIs like MeshData,
MaterialData or SceneData the AnimationData API has a significant lack
of sanity asserts like this.
The `Type` was suggesting it'd be some C++ type, definitely not values
like Scaling3D or Translation2D, resulting in a significant "brain
autocompletion error" every time I was using that type.
Unfortunately on AnimationData the trackTargetType() couldn't similarly
get renamed to trackTarget() as there's already trackTarget() that
contains the node ID the target points to, so it's trackTargetName()
instead. Renaming trackTarget() to trackTargetId() wasn't an option as
that would be inconsistent with everything else (TextureTools::image(),
MaterialAttribute::BaseColorTexture, SceneField::Mesh are all IDs but
they don't have an `Id` suffix); renaming to AnimationTrackTargetName
would keep it insanely long and wouldn't make it consistent either
(MeshAttribute, SceneFIeld, MaterialAttribute are all referred to as
"names" yet they don't have a `Name` suffix).
So it has 32k values for custom targets, instead of just 127. This
makes it consistent with MeshAttribute, which also provides 32k values,
while SceneField has a whole 31-bit range to make it possible to store
arbitrary ECS identifiers as well.
Since this is an ABI break, I'm also shifting the values by 1 to have
zero used for an invalid value, consistently with SceneField,
MeshAttribute etc.
To perform conversion of an already-indexed TriangleStrip to Triangles,
for example, without having to perform an expensive deindexing using
duplicate() first.
To be consistent with what the generate*Indices() APIs expect -- it
doesn't make sense for this API to silently round down while the other
would fail for the same input. In particular, the primitiveCount() may
be used to calculate allocation size for an array to pass to
generate*IndicesInto(), and thus it should use the same rules.
The restriction didn't make sense. Disallowing 1 input vertex for lines
or 1/2 input vertices for triangles sure, but 0 vertices should work as
the expected behavior is obvious.
The GL::Renderer::setClearDepth() and setDepthRange() APIs now use the
non-clamping NV entrypoints if available. The float overloads do that
too, to avoid differences in behavior depending on whether these
functions are called with a float or a double type.
I need alpha to coverage for rendering line caps with MSAA, took it as
an opportunity to expose the other related features as well. Fun how I
survived 12+ years without needing those.
"Funny" how this is the only API where I can't use glCreateTextures().
Like, it would have been so easy to just stop teaching glGen*() and
all their quirks and "this ID exists but it's not an object until you
bind it somewhere actually" to people altogether, BUT NO! FFS.
THe remaining elements are zero-filled, consistently with the behavior
with zeroing out attributes that are missing in subsequent meshes. One
use case is concatenating a mesh with 4 JointIds / Weights into a mesh
that has 8 instead.
Right now, copying larger arrays to smaller arrays is still disallowed
to avoid data loss. That is inconsistent with behavior for attributes
(which are silently left out when not present in the first mesh), I'll
need to think about this more and solve the inconsistency somehow.
Either by allowing array slicing or by failing for unhandled attributes
as well, and the latter makes more sense from the perspective of
avoiding data loss.
Every time I think all std::initializer_list APIs already have an
ArrayView counterpart I discover a new one. (And yes, I did this for
Framebuffer, only to later realize that DefaultFramebuffer suffers from
the same.)
Counterparts to the sRGB-converting APIs, for when one doesn't want to
perform sRGB conversion. Or for "wrong sRGB" workflows. Named like this
and not just `fromRgbInt()` to make the calls at least a bit suspicious.
Exposes MaterialTools::phongToPbrMetallicRoughness() that got added some
time ago. Most of the code and tests is scaffolding needed for direct
material import and processing outside of the addImporterContents()
automagic, similar to what was already done for meshes and images.
In particular, adding more material conversion options such as
canonicalization or deduplication will be significantly easier now that
the basics are done and tested.
Because I got tired of having to manually postprocess ground truth files
for shader tests.
A bit strange / funny that the first ever version of my code manages to
produce smaller files than both stb_image and ImageMagick (with
-compress RunTimeLengthEncoded), for some reason both pick some strange
inefficient run combinations in various scenarios, such as "copy 2" +
"repeat 3" where I pick "repeat 5". And the difference is not
insignificant -- when testing with some shader test files, it resulted
in a ~17% smaller size!
The plugin follows the stricter variant of the spec by default (i.e.,
splitting runs across scanline boundaries) -- so that's *not* the
reason for the weird differences between my code and theirs -- but
provides an option to not do that for even smaller files. Which I'm
going to use for shader ground truth test files, because there every
byte counts. This option together with the above difference causes files
to be ~25% smaller, which is quite a lot.
Given that I made a breaking change by returning Containers::String
instead of a std::string, I can take it further and replace also
std::pair with Containers::Pair -- it won't bring any more pain to the
users, they have to change their code anyway.
Co-authored-by: Hugo Amiard <hugo.amiard@wonderlandengine.com>
Same as in the previous commit, most cases are inputs so a StringStl.h
compatibility include will do, the only breaking change is
GL::Shader::sources() which now returns a StringIterable instead of a
std::vector<std::string> (ew).
Awesome about this whole thing is that The Shader API now allows
creating a shader from sources coming either from string view literals
or Utility::Resource completely without having to allocate any strings
internally, because all those can be just non-owning references wrapped
with String::nullTerminatedGlobalView(). The only parts which aren't
references are the #line markers, but (especially on 64bit) those can
easily fit into the 22-byte (or 10-byte on 32bit) SSO storage.
Also, various Shader constructors and assignment operators had to be
deinlined in order to avoid having to include the String header, which
would be needed for Array destruction during a move.
Co-authored-by: Hugo Amiard <hugo.amiard@wonderlandengine.com>
Most of these are just inputs, so a compatibility StringStl.h include
will do, the only exception is the callback for which there needs to
stay a deprecated overload (which is internally delegated from the
StringView one).
Also explicitly testing with non-null-terminated strings -- the APIs
take an explicit size so it shouldn't be a problem, but it's always good
to have this verified independently. Drivers are crap, you know.
One consequence of no longer using an impossible-to-forward-declare
std::string is that I had to deinline the DebugGroup constructor because
it no longer worked with just a forward-declared StringView.