/*
  Copyright (C) 2010-2011  Charles Pence <charles@charlespence.net>
  Copyright (C) 1996-1997  Id Software, Inc.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __MODEL__
#define __MODEL__

#include "modelgen.h"
#include "spritegn.h"

/*

d*_t structures are on-disk representations
m*_t structures are in-memory

*/

// entity effects

#define    EF_BRIGHTFIELD            1
#define    EF_MUZZLEFLASH             2
#define    EF_BRIGHTLIGHT             4
#define    EF_DIMLIGHT             8


/*
==============================================================================

BRUSH MODELS

==============================================================================
*/


//
// in memory representation
//
typedef struct
{
    vec3_t        position;
} mvertex_t;

#define    SIDE_FRONT    0
#define    SIDE_BACK    1
#define    SIDE_ON        2


// plane_t structure
typedef struct mplane_s
{
    vec3_t    normal;
    float    dist;
    byte    type;            // for texture axis selection and fast side tests
    byte    signbits;        // signx + signy<<1 + signz<<1
    byte    pad[2];
} mplane_t;

typedef struct texture_s
{
    char name[16];
    unsigned width, height;

    int gl_texturenum;

    struct msurface_s *texturechain;

    qboolean sky;
    GLuint sky_solid, sky_alpha;

    // total tenths in sequence ( 0 = no)
    int    anim_total;
    // time for this frame min <=time< max
    int anim_min, anim_max;
    // in the animation sequence
    struct texture_s *anim_next;
    // bmodels in frmae 1 use these
    struct texture_s *alternate_anims;
} texture_t;


#define    SURF_PLANEBACK            2
#define    SURF_DRAWSKY            4
#define SURF_DRAWSPRITE            8
#define SURF_DRAWTURB            0x10
#define SURF_NOLIGHTMAPS        0x20
#define SURF_DRAWBACKGROUND        0x40
#define SURF_UNDERWATER            0x80

typedef struct
{
    unsigned short    v[2];
    unsigned int    cachededgeoffset;
} medge_t;

typedef struct
{
    float        vecs[2][4];
    float        mipadjust;
    texture_t    *texture;
    int            flags;
} mtexinfo_t;

#define    VERTEXSIZE    7

typedef struct glpoly_s
{
    struct    glpoly_s    *next;
    int        numverts;
    int        flags;            // for SURF_UNDERWATER
    float    verts[4][VERTEXSIZE];    // variable sized (xyz s1t1 s2t2)
} glpoly_t;

typedef struct msurface_s
{
    int            visframe;        // should be drawn when node is crossed

    mplane_t    *plane;
    int            flags;

    int            firstedge;    // look up in model->surfedges[], negative numbers
    int            numedges;    // are backwards edges

    short        texturemins[2];
    short        extents[2];

    int            light_s, light_t;    // gl lightmap coordinates

    glpoly_t    *polys;                // multiple if warped
    struct    msurface_s    *texturechain;

    mtexinfo_t    *texinfo;

// lighting info
    int            dlightframe;
    int            dlightbits;

    int            lightmaptexturenum;
    byte        styles[MAXLIGHTMAPS];
    int            cached_light[MAXLIGHTMAPS];    // values currently used in lightmap
    qboolean    cached_dlight;                // true if dynamic light in cache
    byte        *samples;        // [numstyles*surfsize]
} msurface_t;

typedef struct mnode_s
{
// common with leaf
    int            contents;        // 0, to differentiate from leafs
    int            visframe;        // node needs to be traversed if current

    float        minmaxs[6];        // for bounding box culling

    struct mnode_s    *parent;

// node specific
    mplane_t    *plane;
    struct mnode_s    *children[2];

    unsigned short        firstsurface;
    unsigned short        numsurfaces;
} mnode_t;



typedef struct mleaf_s
{
// common with node
    int            contents;        // wil be a negative contents number
    int            visframe;        // node needs to be traversed if current

    float        minmaxs[6];        // for bounding box culling

    struct mnode_s    *parent;

// leaf specific
    byte        *compressed_vis;
    efrag_t        *efrags;

    msurface_t    **firstmarksurface;
    int            nummarksurfaces;
    int            key;            // BSP sequence number for leaf's contents
    byte        ambient_sound_level[NUM_AMBIENTS];
} mleaf_t;

typedef struct
{
    dclipnode_t    *clipnodes;
    mplane_t    *planes;
    int            firstclipnode;
    int            lastclipnode;
    vec3_t        clip_mins;
    vec3_t        clip_maxs;
} hull_t;

/*
==============================================================================

SPRITE MODELS

==============================================================================
*/


// FIXME: shorten these?
typedef struct mspriteframe_s
{
    int        width;
    int        height;
    float    up, down, left, right;
    int        gl_texturenum;
} mspriteframe_t;

typedef struct
{
    int                numframes;
    float            *intervals;
    mspriteframe_t    *frames[1];
} mspritegroup_t;

typedef struct
{
    spriteframetype_t    type;
    mspriteframe_t        *frameptr;
} mspriteframedesc_t;

typedef struct
{
    int                    type;
    int                    maxwidth;
    int                    maxheight;
    int                    numframes;
    float                beamlength;        // remove?
    void                *cachespot;        // remove?
    mspriteframedesc_t    frames[1];
} msprite_t;


/*
==============================================================================

ALIAS MODELS

Alias models are position independent, so the cache manager can move them.
==============================================================================
*/

typedef struct
{
    int                    firstpose;
    int                    numposes;
    float                interval;
    trivertx_t            bboxmin;
    trivertx_t            bboxmax;
    int                    frame;
    char                name[16];
} maliasframedesc_t;

typedef struct
{
    trivertx_t            bboxmin;
    trivertx_t            bboxmax;
    int                    frame;
} maliasgroupframedesc_t;

typedef struct
{
    int                        numframes;
    int                        intervals;
    maliasgroupframedesc_t    frames[1];
} maliasgroup_t;

typedef struct mtriangle_s {
    int                    facesfront;
    int                    vertindex[3];
} mtriangle_t;


#define    MAX_SKINS    32
typedef struct {
    int            ident;
    int            version;
    vec3_t        scale;
    vec3_t        scale_origin;
    float        boundingradius;
    vec3_t        eyeposition;
    int            numskins;
    int            skinwidth;
    int            skinheight;
    int            numverts;
    int            numtris;
    int            numframes;
    synctype_t    synctype;
    int            flags;
    float        size;

    int                    numposes;
    int                    poseverts;
    int                    posedata;    // numposes*poseverts trivert_t
    int                    commands;    // gl command list with embedded s/t
    int                    gl_texturenum[MAX_SKINS][4];
    int                    texels[MAX_SKINS];    // only for player skins
    int                 trans_texels[MAX_SKINS];
    maliasframedesc_t    frames[1];    // variable sized
} aliashdr_t;

#define    MAXALIASVERTS    1024
#define    MAXALIASFRAMES    256
#define    MAXALIASTRIS    2048
extern    aliashdr_t    *pheader;
extern    stvert_t    stverts[MAXALIASVERTS];
extern    mtriangle_t    triangles[MAXALIASTRIS];
extern    trivertx_t    *poseverts[MAXALIASFRAMES];

//===================================================================

//
// Whole model
//

typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;

#define    EF_ROCKET    1            // leave a trail
#define    EF_GRENADE    2            // leave a trail
#define    EF_GIB        4            // leave a trail
#define    EF_ROTATE    8            // rotate (bonus items)
#define    EF_TRACER    16            // green split trail
#define    EF_ZOMGIB    32            // small blood trail
#define    EF_TRACER2    64            // orange split trail + rotate
#define    EF_TRACER3    128            // purple trail

typedef struct model_s
{
    char        name[MAX_QPATH];
    qboolean    needload;        // bmodels and sprites don't cache normally

    modtype_t    type;
    int            numframes;
    synctype_t    synctype;

    int            flags;

//
// volume occupied by the model graphics
//
    vec3_t        mins, maxs;
    float        radius;

//
// solid volume for clipping
//
    qboolean    clipbox;
    vec3_t        clipmins, clipmaxs;

//
// brush model
//
    int            firstmodelsurface, nummodelsurfaces;

    int            numsubmodels;
    dmodel_t    *submodels;

    int            numplanes;
    mplane_t    *planes;

    int            numleafs;        // number of visible leafs, not counting 0
    mleaf_t        *leafs;

    int            numvertexes;
    mvertex_t    *vertexes;

    int            numedges;
    medge_t        *edges;

    int            numnodes;
    mnode_t        *nodes;

    int            numtexinfo;
    mtexinfo_t    *texinfo;

    int            numsurfaces;
    msurface_t    *surfaces;

    int            numsurfedges;
    int            *surfedges;

    int            numclipnodes;
    dclipnode_t    *clipnodes;

    int            nummarksurfaces;
    msurface_t    **marksurfaces;

    hull_t        hulls[MAX_MAP_HULLS];

    int            numtextures;
    texture_t    **textures;

    byte        *visdata;
    byte        *lightdata;
    char        *entities;

//
// additional model data
//
    cache_user_t    cache;        // only access through Mod_Extradata

} model_t;

//============================================================================

void    Mod_Init (void);
void    Mod_ClearAll (void);
model_t *Mod_ForName (char *name, qboolean crash);
void    *Mod_Extradata (model_t *mod);    // handles caching
void    Mod_TouchModel (char *name);

mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
byte    *Mod_LeafPVS (mleaf_t *leaf, model_t *model);

#endif    // __MODEL__
