#ifndef _RDMODEL3_H
#define _RDMODEL3_H

#include "types.h"
#include "globals.h"

#include "Primitives/rdVector.h"
#include "Raster/rdFace.h"
#include "Engine/rdMaterial.h"
#include "Primitives/rdMatrix.h"

#ifdef __cplusplus
extern "C" {
#endif

#define rdModel3_RegisterLoader_ADDR (0x00443DA0)
#define rdModel3_RegisterUnloader_ADDR (0x00443DB0)
#define rdModel3_ClearFrameCounters_ADDR (0x00443DC0)
#define rdModel3_NewEntry_ADDR (0x00443DD0)
#define rdModel3_Load_ADDR (0x00443E00)
#define rdModel3_LoadEntry_ADDR (0x00443E80)
#define rdModel3_LoadPostProcess_ADDR (0x00444B60)
#define rdModel3_Write_ADDR (0x00444B90)
#define rdModel3_Free_ADDR (0x004453C0)
#define rdModel3_FreeEntry_ADDR (0x004453F0)
#define rdModel3_FreeEntryGeometryOnly_ADDR (0x00445560)
#define rdModel3_Validate_ADDR (0x004456B0)
#define rdModel3_CalcRadii_ADDR (0x00445750)
#define rdModel3_BuildExpandedRadius_ADDR (0x00445810)
#define rdModel3_CalcFaceNormals_ADDR (0x00445970)
#define rdModel3_CalcVertexNormals_ADDR (0x00445AD0)
#define rdModel3_FindNamedNode_ADDR (0x00445D30)
#define rdModel3_GetMeshMatrix_ADDR (0x00445D80)
#define rdModel3_ReplaceMesh_ADDR (0x00445DD0)
#define rdModel3_Draw_ADDR (0x00445E10)
#define rdModel3_DrawHNode_ADDR (0x00446090)
#define rdModel3_DrawMesh_ADDR (0x00446110)
#define rdModel3_DrawFace_ADDR (0x00446580)

typedef struct rdThing rdThing;
typedef struct rdHierarchyNode rdHierarchyNode;
typedef struct rdMesh rdMesh;
typedef struct rdMeshinfo rdMeshinfo;

#ifndef JKM_TYPES
typedef struct rdHierarchyNode
{
    char name[32];
    uint32_t field_20;
    uint32_t field_24;
    uint32_t field_28;
    uint32_t field_2C;
    uint32_t field_30;
    uint32_t field_34;
    uint32_t field_38;
    uint32_t field_3C;
    uint32_t flags;
    uint32_t idx;
    int type;
    uint32_t meshIdx;
#ifdef JKM_BONES
    uint32_t numParents;
#endif
    rdHierarchyNode* parent;
    uint32_t numChildren;
    rdHierarchyNode* child;
    rdHierarchyNode* nextSibling;
    rdVector3 pivot;
    rdVector3 pos;
    rdVector3 rot;
    rdMatrix34 posRotMatrix;
} rdHierarchyNode;
#else
typedef struct rdHierarchyNode
{
    uint32_t flags;
    uint32_t idx;
    int type;
    uint32_t meshIdx;
    uint32_t numParents;
    rdHierarchyNode* parent;
    uint32_t numChildren;
    rdHierarchyNode* child;
    rdHierarchyNode* nextSibling;
    rdVector3 pivot;
    rdVector3 pos;
    rdVector3 rot;
    rdMatrix34 posRotMatrix;
} rdHierarchyNode;
#endif

typedef struct rdGeoset
{
    uint32_t numMeshes;
    rdMesh* aMeshes;    
} rdGeoset;

typedef struct rdModel3
{
    char filename[32];
    int id;
    rdGeoset aGeos[4];
    uint32_t numGeos;
    rdMaterial** aMaterials;
    uint32_t sizeMaterials;
    uint32_t geosetSelect;
    uint32_t numHNodes;
    rdHierarchyNode* aHierarchyNodes;
    flex_t radius;
    uint32_t field_60;
    flex_t field_64;
    uint32_t field_68;
    uint32_t field_6C;
    uint32_t field_70;
    uint32_t field_74;
    rdVector3 insertOffset;
} rdModel3;

#ifndef JKM_TYPES
typedef struct rdMesh
{
    char name[32];
    int mesh_num;
    int geometryMode;
    int lightingMode;
    int textureMode;
    rdVector3* aVertices;
    rdVector2* aTexVerticies;
    flex_t* vertices_i;
    flex_t* vertices_unk;
#ifdef JKM_LIGHTING
    flex_t* paRedIntensities;
    flex_t* paGreenIntensities;
    flex_t* paBlueIntensities;
#endif
    rdFace* faces;
    rdVector3* vertexNormals;
    int numVertices;
    int numUVs;
    int numFaces;
#ifdef JKM_LIGHTING
    flex_t extraLight;
#endif
    flex_t radius;
    int field_58;
    int field_5C;
    int field_60;
    flex_t field_64;
    int field_68;
    int field_6C;
#ifdef RDMODEL3_POOLED_FACE_INDICES
    int* paFaceIdxPool; // Added: pooled face vertex/UV indices
#endif
} rdMesh;
#else

typedef struct rdMesh
{
    //char name[32];
    int mesh_num;
    int geometryMode;
    int lightingMode;
    int textureMode;
    rdVector3* aVertices;
    rdVector2* aTexVerticies;
    flex_t* vertices_i;
    flex_t* vertices_unk;
    flex_t* paRedIntensities;
    flex_t* paGreenIntensities;
    flex_t* paBlueIntensities;
    int unk4;
    rdFace* faces;
    rdVector3* vertexNormals;
    int numVertices;
    int numUVs;
    int numFaces;
    flex_t extraLight;
    flex_t radius;
    int field_58;
    int field_5C;
    int field_60;
    flex_t field_64;
    int field_68;
    int field_6C;
#ifdef RDMODEL3_POOLED_FACE_INDICES
    int* paFaceIdxPool; // Added: pooled face vertex/UV indices
#endif
} rdMesh;
#endif

model3Loader_t rdModel3_RegisterLoader(model3Loader_t pfFunc);
model3Unloader_t rdModel3_RegisterUnloader(model3Unloader_t pfFunc);
void rdModel3_ClearFrameCounters();
int rdModel3_NewEntry(rdModel3 *pModel3);
rdModel3* rdModel3_Load(char *pName);
int rdModel3_LoadEntry(char *pFilename, rdModel3 *pModel3);
void rdModel3_LoadPostProcess(rdModel3 *pModel3);
int rdModel3_Write(char *pFilename, rdModel3 *pModel, char *pCratedName);
void rdModel3_Free(rdModel3 *pModel3);
void rdModel3_FreeEntry(rdModel3 *pModel3);
void rdModel3_FreeEntryGeometryOnly(rdModel3 *pModel3);
rdModel3* rdModel3_Validate(rdModel3 *pModel3);
MATH_FUNC void rdModel3_CalcRadii(rdModel3 *pModel3);
MATH_FUNC void rdModel3_BuildExpandedRadius(rdModel3 *pModel, rdHierarchyNode *pNode, const rdMatrix34 *orient);
MATH_FUNC void rdModel3_CalcFaceNormals(rdModel3 *pModel3);
MATH_FUNC void rdModel3_CalcVertexNormals(rdModel3 *pModel);
MATH_FUNC void rdModel3_CalcNumParents(rdModel3* pModel); // MOTS added
rdHierarchyNode* rdModel3_FindNamedNode(char *pName, rdModel3 *pModel3);
MATH_FUNC int rdModel3_GetMeshMatrix(rdThing *pThing, rdMatrix34 *orient, uint32_t nodeNum, rdMatrix34 *meshOrient);
MATH_FUNC int rdModel3_ReplaceMesh(rdModel3 *pModel, int geosetNum, int meshNum, rdMesh *pSrcMesh);
MATH_FUNC int rdModel3_Draw(rdThing *pThing, rdMatrix34 *pPlacement);
MATH_FUNC void rdModel3_DrawHNode(rdHierarchyNode *pNode);
MATH_FUNC void rdModel3_DrawMesh(rdMesh *pMesh, rdMatrix34 *orient);
MATH_FUNC FAST_FUNC int rdModel3_DrawFace(rdFace *pFace, int lightFlags);

// Added: Data preloading
void rdModel3_EnsureMaterialData(rdThing *pRdThing);

#ifdef __cplusplus
}
#endif

//static int (__cdecl *rdModel3_CalcVertexNormals)(rdModel3 *model) = (void*)rdModel3_CalcVertexNormals_ADDR;

#endif // _RDMODEL3_H
