Supermodel/Src/Graphics/New3D/Model.h
Ian Curtis 40c8259130 Rewrite the whole project for GL4+. I figured if we removed the limitation of a legacy rendering API we could improve things a bit. With GL4+ we can do unsigned integer math in the shaders. This allows us to upload a direct copy of the real3d texture sheet, and texture directly from this memory given the x/y pos and type. This massively simplifies the binding and invalidation code. Also the crazy corner cases will work because it essentially works the same way as the original hardware.
The standard triangle render requires gl 4.1 core, so should work on mac. The quad renderer runs on 4.5 core. The legacy renderer should still work, and when enabled a regular opengl context will be created, which allows functions marked depreciated in the core profiles to still work. This will only work in windows/linux I think. Apple doesn't support this.

A GL 4.1 GPU is now the min required spec. Sorry if you have an OLDER gpu. GL 4.1 is over 12 years old now.

This is a big update so I apologise in advance if I accidently broke something :]
2022-11-07 21:33:01 +00:00

263 lines
6.4 KiB
C++

#ifndef _MODEL_H_
#define _MODEL_H_
#include <vector>
#include <unordered_map>
#include <memory>
#include <cstring>
#include "Types.h"
#include "Mat4.h"
namespace New3D {
struct ClipVertex
{
float pos[4];
};
struct ClipPoly
{
ClipVertex list[12]; // what's the max number we can hit for a triangle + 4 planes?
int count = 0;
};
struct Vertex // half vertex
{
float pos[4];
float normal[3];
float texcoords[2];
float fixedShade;
static bool Equal(const Vertex& p1, const Vertex& p2)
{
return (p1.pos[0] == p2.pos[0] &&
p1.pos[1] == p2.pos[1] &&
p1.pos[2] == p2.pos[2]);
}
static void Average(const Vertex& p1, const Vertex& p2, Vertex& p3)
{
p3.pos[3] = 1.0f; //always 1
p3.fixedShade = (p1.fixedShade + p2.fixedShade) * 0.5f;
for (int i = 0; i < 3; i++) { p3.pos[i] = (p1.pos[i] + p2.pos[i]) * 0.5f; }
for (int i = 0; i < 3; i++) { p3.normal[i] = (p1.normal[i] + p2.normal[i]) * 0.5f; }
for (int i = 0; i < 2; i++) { p3.texcoords[i] = (p1.texcoords[i] + p2.texcoords[i]) * 0.5f; }
}
};
struct R3DPoly
{
Vertex v[4]; // just easier to have them as an array
float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself
UINT8 faceColour[4]; // per face colour
int number = 4;
};
struct FVertex : Vertex // full vertex including face attributes
{
float faceNormal[3];
UINT8 faceColour[4];
FVertex& operator=(const Vertex& vertex)
{
memcpy(this, &vertex, sizeof(Vertex));
return *this;
}
FVertex() {}
FVertex(const R3DPoly& r3dPoly, int index)
{
for (int i = 0; i < 4; i++) { faceColour[i] = r3dPoly.faceColour[i]; }
for (int i = 0; i < 3; i++) { faceNormal[i] = r3dPoly.faceNormal[i]; }
*this = r3dPoly.v[index];
}
FVertex(const R3DPoly& r3dPoly, int index1, int index2) // average of 2 points
{
Vertex::Average(r3dPoly.v[index1], r3dPoly.v[index2], *this);
// copy face attributes
for (int i = 0; i < 4; i++) { faceColour[i] = r3dPoly.faceColour[i]; }
for (int i = 0; i < 3; i++) { faceNormal[i] = r3dPoly.faceNormal[i]; }
}
static void Average(const FVertex& p1, const FVertex& p2, FVertex& p3)
{
Vertex::Average(p1, p2, p3);
for (int i = 0; i < 4; i++) { p3.faceColour[i] = p1.faceColour[i]; }
for (int i = 0; i < 3; i++) { p3.faceNormal[i] = p1.faceNormal[i]; }
}
};
enum class Layer { colour, trans1, trans2, trans12 /*both 1&2*/, all, none };
struct Mesh
{
//helper funcs
bool Render(Layer layer)
{
switch (layer)
{
case Layer::colour:
if (polyAlpha) {
return false;
}
break;
case Layer::trans1:
if ((!textureAlpha && !polyAlpha) || transLSelect) {
return false;
}
break;
case Layer::trans2:
if ((!textureAlpha && !polyAlpha) || !transLSelect) {
return false;
}
break;
default: // not using these types
return false;
}
return true;
}
enum TexWrapMode : int { repeat = 0, repeatClamp, mirror, mirrorClamp };
// texture
int format, x, y, width, height = 0;
TexWrapMode wrapModeU;
TexWrapMode wrapModeV;
bool inverted = false;
// microtexture
bool microTexture = false;
int microTextureID = 0;
float microTextureScale = 0;
// attributes
bool textured = false;
bool polyAlpha = false; // specified in the rgba colour
bool textureAlpha = false; // use alpha in texture
bool alphaTest = false; // discard fragment based on alpha (ogl does this with fixed function)
bool layered = false; // stencil poly
bool highPriority = false; // rendered over the top
bool transLSelect = false; // actually the transparency layer, false = layer 0, true = layer 1
bool translatorMap = false; // colours are multiplied by 16
// lighting
bool fixedShading = false;
bool lighting = false;
bool specular = false;
float shininess = 0;
float specularValue = 0;
// fog
float fogIntensity = 1.0f;
// opengl resources
int vboOffset = 0; // this will be calculated later
int vertexCount = 0; // /3 for triangles /4 for quads
};
struct SortingMesh : public Mesh // This struct temporarily holds the model data, before it gets copied to the main buffer
{
std::vector<FVertex> verts;
};
struct Model
{
std::shared_ptr<std::vector<Mesh>> meshes; // this reason why this is a shared ptr to an array, is that multiple models might use the same meshes
//which memory are we in
bool dynamic = true;
// texture offsets for model
int textureOffsetX = 0;
int textureOffsetY = 0;
int page = 0;
//matrices
float modelMat[16];
//model scale step 1.5+
float scale = 1.0f;
};
struct Viewport
{
int vpX; // these are the original hardware values
int vpY;
int vpWidth;
int vpHeight;
float angle_left;
float angle_right;
float angle_top;
float angle_bottom;
Mat4 projectionMatrix; // projection matrix, we will calc this later when we have scene near/far vals
float lightingParams[6]; // lighting parameters (see RenderViewport() and vertex shader)
bool sunClamp; // unknown how this is set
bool intensityClamp; // unknown how this is set
float spotEllipse[4]; // spotlight ellipse (see RenderViewport())
float spotRange[2]; // Z range
float spotColor[3]; // color
float fogParams[7]; // fog parameters (...)
float scrollFog; // a transparency value that determines if fog is blended over the bottom 2D layer
int losPosX, losPosY; // line of sight position
int x, y; // viewport coordinates (scaled and in OpenGL format)
int width, height; // viewport dimensions (scaled for display surface size)
int priority; // priority
int select; // viewport select?
int number; // viewport number
float spotFogColor[3]; // spotlight color on fog
float scrollAtt;
int hardwareStep; // not really a viewport param but will do here
};
enum class Clip { INSIDE, OUTSIDE, INTERCEPT, NOT_SET };
class NodeAttributes
{
public:
NodeAttributes();
bool Push();
bool Pop();
bool StackLimit();
void Reset();
int currentTexOffsetX;
int currentTexOffsetY;
int currentPage;
Clip currentClipStatus;
float currentModelScale;
private:
struct NodeAttribs
{
int texOffsetX;
int texOffsetY;
int page;
Clip clip;
float modelScale;
};
std::vector<NodeAttribs> m_vecAttribs;
};
struct Node
{
Viewport viewport;
std::vector<Model> models;
};
} // New3D
#endif