Supermodel/Src/Graphics/New3D/Model.h
gm-matthew 483dbdda2e Add LOD switching and blending out culling nodes
We're not blending between LODs yet as we're not sure of the best way to implement it
Also implementing control bits for disable culling and enable model scale (needed for ECA and Harley)
2023-11-02 14:16:07 +00:00

272 lines
6.7 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, float nodeAlpha)
{
bool nAlpha = nodeAlpha < 1.0f;
switch (layer)
{
case Layer::colour:
if (polyAlpha || nAlpha) {
return false;
}
break;
case Layer::trans1:
if ((!textureAlpha && !polyAlpha && !nAlpha) || transLSelect) {
return false;
}
break;
case Layer::trans2:
if ((!textureAlpha && !polyAlpha && !nAlpha) || !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;
//node transparency
float alpha = 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;
float currentModelAlpha;
bool currentDisableCulling;
private:
struct NodeAttribs
{
int texOffsetX;
int texOffsetY;
int page;
Clip clip;
float modelScale;
float modelAlpha; // from culling node
bool disableCulling;
};
std::vector<NodeAttribs> m_vecAttribs;
};
struct Node
{
Viewport viewport;
std::vector<Model> models;
};
} // New3D
#endif