MD2/MD3 support rewritten + optimizations [by SSNTails]

Backported from Roly Poly Putt, this is my code for a common model format. I also included two loaders, for both MD2 and MD3. This abstracts the rendering code away from the idiosyncrasies of a particular model format, making it a lot easier to add support for others (I also have a non-animated MS3D loader that I may contribute in the future).This also includes some optimization -- it should now be possible to push a lot more polygons in the renderer itself.

Current progress (12/19):
## No interpolation (comment out `#define USE_MODEL_NEXTFRAME`)
Sonic is MD3, Crawlas are MD2
![PassionateLongIlladopsis](/uploads/7ca7366d6e9a04a6a11b6b5d10233a4d/PassionateLongIlladopsis.mp4)
## With interpolation, MD2
Tris everywhere!
Textures are incorrectly mapped on Sonic; don't know why.
Non-broken models are straight frames; e.g., the rings are not interpolated.
![FakeBoringKawala](/uploads/08cf89482143fa2543959566246c2fa4/FakeBoringKawala.mp4)
## With interpolation, MD3:
Sigsegv upon attempting to animate
Not sure what the black color is from. Either a mismapped texture, or I screwed up color blending when I removed Kart's fancy skin color handling from `HWR_DrawMD2`.
![UglyDeliciousGonolek](/uploads/35fd633422b0c0084eb89c8a6b286880/UglyDeliciousGonolek.mp4)

it isn't really, it was initially made by Sryder to attempt to fix issues Kart had with the minimap. I just added on the "U"s at the end to make the compiler happy
(posted in wrong place earlier, don't mind me)

Something's wrong with the lerping (interpolation) in this general code block. Relevant facts:

All normal variables were changed from byte to char so that GCC recognizes it

glNormal3bv() takes GLbyte* as input, which is a signed char. Hence the (signed char*)normPtr cast, which may be ill-advised?

*normPtr++ = (char)..., in the code block immediately above, was originally a (short) cast. I thought this was a mistake, hence the change, but I'm not sure.

glNormal3bv() sigsegv's once in a while. I got it to stop sigsegving by using glNormal3sv() instead (short inputs instead of char inputs), but maybe there's a deeper fix that wouldn't require this change?

I stared at this code for a while and I don't understand how to fix it 🤔

The glitch could also be in model loading (see below comment), but I'm not qualified to say that for sure. The data appears to load fine.

Something's wrong with the lerping (interpolation) in this general code block. Relevant facts:
* All `normal` variables were changed from `byte` to `char` so that GCC recognizes it
* `glNormal3bv()` takes `GLbyte*` as input, which is a signed char. Hence the `(signed char*)normPtr` cast, which may be ill-advised?
* `*normPtr++ = (char)...`, in the code block immediately above, was originally a `(short)` cast. I thought this was a mistake, hence the change, but I'm not sure.
* `glNormal3bv()` sigsegv's once in a while. I got it to stop sigsegving by using `glNormal3sv()` instead (`short` inputs instead of `char` inputs), but maybe there's a deeper fix that wouldn't require this change?
I stared at this code for a while and I don't understand how to fix it :thinking:
The glitch could also be in model loading (see below comment), but I'm not qualified to say that for sure. The data appears to load fine.
@SSNTails

changed this line in [version 3 of the diff](https://git.magicalgirl.moe/STJr/SRB2/merge_requests/397/diffs?diff_id=1970&start_sha=59826860ab41bdb2d01f7ece21a4c9d5e4797f91#b5c1f6d8570b8f25f21c1b91798141e5519be496_2093_2077)

Since the models are currently large, I got it to match 2.1.20's model scale by changing this to

pglScalef(1 / 128.0f, 1 / 128.0f, 1 / 128.0f);

i.e., shrink the models in half.

IDK if there's a better advised solution?

Generally speaking, is it preferred to keep the model scale as-is currently in code, and ask the addon authors to adjust? Or is it reasonable to shrink the models in half in the code, for back compat? @SSNTails

Since the models are currently large, I got it to match 2.1.20's model scale by changing this to
`pglScalef(1 / 128.0f, 1 / 128.0f, 1 / 128.0f);`
i.e., shrink the models in half.
IDK if there's a better advised solution?
Generally speaking, is it preferred to keep the model scale as-is currently in code, and ask the addon authors to adjust? Or is it reasonable to shrink the models in half in the code, for back compat? @SSNTails

So here's the verdict -- the UV coordinates in MD2 are not compatible with glDrawElements like MD3 is. So they need to be loaded as full float. I'm going to make some other changes in the renderer to hopefully offset the performance impact. I still don't know what is going on with WAD-textured models, but I've reached out to Logan McCloud to help.

MD2 is intended to be draw in triangle strips and fans
not very compatible with a modern GL implementation, either
so the idea would be to full float expand it, and put it in a vertex buffer object
I'm sure there's a way to convert the UVs to 'tinyframes', but maybe that's a job for someone else.
You'd have to decompress the model, then recompress, reindexing the triangles and weeding out duplicate coordinates
I already have the decompression work done

So here's the verdict -- the UV coordinates in MD2 are not compatible with glDrawElements like MD3 is. So they need to be loaded as full float. I'm going to make some other changes in the renderer to hopefully offset the performance impact. I still don't know what is going on with WAD-textured models, but I've reached out to Logan McCloud to help.
MD2 is intended to be draw in triangle strips and fans
not very compatible with a modern GL implementation, either
so the idea would be to full float expand it, and put it in a vertex buffer object
I'm sure there's a way to convert the UVs to 'tinyframes', but maybe that's a job for someone else.
You'd have to decompress the model, then recompress, reindexing the triangles and weeding out duplicate coordinates
I already have the decompression work done

I’d be open to adding a texture scaler back in; right now I’m stripping GL down to the essentials to accommodate an ES 2.0 switchover.

Speaking of, is gr_Fog used at all other than ‘ooh I’m playing around in the console and that’s cool’? If not, the shaders can be simplified.

Possibly, but does the 3DS even use OpenGL?
I’d be open to adding a texture scaler back in; right now I’m stripping GL down to the essentials to accommodate an ES 2.0 switchover.
Speaking of, is gr_Fog used at all other than ‘ooh I’m playing around in the console and that’s cool’? If not, the shaders can be simplified.

I definitely know that the 3DS port isn't using the software renderer because the guy who was playing around with it discovered a memory issue in the GL code. Whether that was an adaptation to use a different 3DS-friendly library or straight-up GL I have no idea.

You would have to ask Sryder about the gr_fog. Good luck on the challenge!

I definitely know that the 3DS port isn't using the software renderer because the guy who was playing around with it discovered a memory issue in the GL code. Whether that was an adaptation to use a different 3DS-friendly library or straight-up GL I have no idea.
You would have to ask Sryder about the gr_fog. Good luck on the challenge!

gr_fog has a second option called lightplanes that makes the light dropoff on floors much stronger (which in practice looks absolutely ATROCIOUS by the way) to try and emulate software's lighting. (Last I recall the only major difference in code is just that it uses different math to calculate lighting on floor planes)

If it were me, I think I would only keep regular fog around. The light difference in lightplanes sticks out too much

gr_fog has a second option called lightplanes that makes the light dropoff on floors much stronger (which in practice looks absolutely ATROCIOUS by the way) to try and emulate software's lighting. (Last I recall the only major difference in code is just that it uses different math to calculate lighting on floor planes)
If it were me, I think I would only keep regular fog around. The light difference in lightplanes sticks out too much

@toaster Hmmm, ok. He's gotta be using some kind of GL translation layer, since the current GL code is VERY v1.1-ish and not compatible with anything you'd probably find on a low-power device like the 3DS.

@SinnamonLat Thanks for the extra info. I think what I will do is remove the console fog variables, and instead focus on applying fog where it is supposed to be, just like the software renderer (fog blocks, light distance, etc.)

@toaster Hmmm, ok. He's gotta be using some kind of GL translation layer, since the current GL code is VERY v1.1-ish and not compatible with anything you'd probably find on a low-power device like the 3DS.
@SinnamonLat Thanks for the extra info. I think what I will do is remove the console fog variables, and instead focus on applying fog where it is supposed to be, just like the software renderer (fog blocks, light distance, etc.)

There's no reason to ever disable fog anyway or leave options for different visual results, so both of those vars should be killed so that you can focus on applying what looks the closest to actual software

There's no reason to ever disable fog anyway or leave options for different visual results, so both of those vars should be killed so that you can focus on applying what looks the closest to actual software

From what I know, the 3DS port isn't using the actual OpenGL library, but it is using the hardware rendering code that we normally associate with the OpenGL renderer for Windows/Linux/Mac (?) builds.

From what I know, the 3DS port isn't using the actual OpenGL *library*, but it *is* using the hardware rendering code that we normally associate with the OpenGL renderer for Windows/Linux/Mac (?) builds.

The source of that bug is that creating VBOs leaves the buffer binded on for the rest of the frame.

There's currently a problem with shield MD2s. Where the entire view dies for three frames.
![](https://cdn.discordapp.com/attachments/360503773115973632/572928657706844171/2019-04-30_20-31-09.mp4.webm)
Which was fixed here
https://github.com/Jimita/SRB2/commit/2ff4a3c
The source of that bug is that creating VBOs leaves the buffer binded on for the rest of the frame.

I had a concern that, for unknown reasons, this code is unstable for SSNTails. But I'll probably follow Kart's lead and recommend this for merging.

I'll examine this in a couple weekends or so, if someone else doesn't do it first. I'm pretty tied up these days...

I had a concern that, for unknown reasons, this code is unstable for SSNTails. But I'll probably follow Kart's lead and recommend this for merging.
I'll examine this in a couple weekends or so, if someone else doesn't do it first. I'm pretty tied up these days...

From my tests in Kart I'm just about certain all of these changes are net-safe, but since models need to be setup differently now we decided to target next since some players compile from source. It wouldn't do for master to be incompatible with current assets.

I suppose since models are an optional feature here instead of enabled by default in GL, it would be okay to push these changes to master, but I'll leave that up to you.

From my tests in Kart I'm just about certain all of these changes are net-safe, but since models need to be setup differently now we decided to target `next` since some players compile from source. It wouldn't do for `master` to be incompatible with current assets.
I suppose since models are an optional feature here instead of enabled by default in GL, it would be okay to push these changes to `master`, but I'll leave that up to you.