#ifndef _MODEL_H_ #define _MODEL_H_ #include #include #include #include #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 bool noLosReturn = false; // line of sight test // 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 verts; }; struct Model { std::shared_ptr> 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 m_vecAttribs; }; struct Node { Viewport viewport; std::vector models; }; } // New3D #endif