Firstly your choices aren't just inheritance hierarchies or ECS. Most software is built around composition! It's actually a core rule of OOP to prefer composition over inheritance when possible - so a hierarchy would probably be wrong here under traditional OOP too...
The part of ECS where you can query whether a component type is present in a particular entity is formally known as the Service locator pattern. IMHO, this pattern fulfils your description of:
5 hours ago, lGuy said:
coming up with strange ways resolve certain problems concerning checking which resources some models have
i.e. With an ECS style solution you'll have lots of "if a normal buffer component is present then do...", which I feel will be a complicated mess.
So:
6 hours ago, lGuy said:
some models need a texture and texture coordinate data to go with it, others just need some color data (vec3). Some have a normals buffer whereas others just get their normals calculated on the fly (geometry shader). Some have an index buffer (rendered with glDrawElements) whereas others don't and get rendered using glDrawArrays etc...
I solve this in my engine by having the shader file be the master decision maker -- The shader has a list of all the vertex attributes that it expects as inputs.
I then also add some meta data to my shaders for how the vertex data should be arranged in memory -- e.g. A single buffer with position, normal, UV interleaved, or three buffers with one attribute each. Also whether the attributes should be floating point, 16bit signed ints, 8bit fractions, etc...
My model importer can then look at the shader file that's been specified for a particular mesh and import the required attributes and store them in the appropriate structure (one buffer vs multiple, type conversions, etc). The importer can then also generate a structure that tells the runtime how to bind this data to the pipeline - VAO args for GL or an Input Layout in D3D. The importer can also generate a draw structure per mesh, specifying which "draw" function should be used by the runtime (indexed vs non-indexed) and the parameters (primitive type, number of primitives, buffer offsets, etc).
At runtime I don't have a hierarchy of model types, nor dynamic composition and service location... Just buffer descriptions, draw item descriptions, VAO descriptions, binding command descriptions, pipeline state command descriptions.