Instead of each group storing a separate face/index array, we now store
one large face/index array and each group stores offsets inside it.
This makes it easier to parse .obj files when group information is
unimportant since one can just skip it - group information is often
inessential as it doesn't affect rendering behavior.
This makes parsing large files slightly faster (rungholt.obj parses in
~500ms instead of ~530ms after this change).
For use-cases that require parsing the .obj file and outputting another
file, resolving texture paths is inconvenient since the result depends
on the path that's passed to obj_fast_read. While this can be resolved
by recomputing the relative path in user code, it seems cleaner to keep
the map names as is when parsing .mtl.
Of course, if .obj file is required for rendering, the path
concatenation is still convenient. This change makes
fastObjTexture::name contain the original data, and fastObjTexture::path
contains the resolved path that can be used to actually load the texture
if necessary.
Negative indices refer to offsets of vertices (before multiplying by
stride), but array size of position/etc. is multiplied by stride.
Integer division isn't ideal for performance, however division by 3 is
lowered into integer multiplication on gcc/clang/msvc so this shouldn't
be a big concern.
In some .obj files, there's a stray 'g' followed by a newline at the
very end of the file. What happens right now is that *p++ skips past the
"terminating newline", and then proceeds to process out of bounds memory
which leads to a crash.
I'm not sure if 'g' can actually be empty per spec, so this change just
fixes the crash without resetting the group to "default" or anything
like that; 'v'/'f' shouldn't be empty but this would fix crashing when
parsing malicious/malformed .obj files as well.