/*
Copyright (C) 1997-2001 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 2
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#ifndef __GL_MODEL_H__
#define __GL_MODEL_H__

#include <alias/gl.h>

/*

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

*/

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

BRUSH MODELS

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

//
// in memory representation
//
// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct {
  vec3_t position;
} mvertex_t;

typedef struct {
  vec3_t mins, maxs;
  vec3_t origin; // for sounds or lights
  float radius;
  int headnode;
  int visleafs; // not including the solid leaf 0
  int firstface, numfaces;
} mmodel_t;

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

#define SURF_PLANEBACK 2
#define SURF_DRAWSKY 4
#define SURF_DRAWTURB 0x10
#define SURF_DRAWBACKGROUND 0x40
#define SURF_UNDERWATER 0x80

// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct {
  unsigned short v[2];
  unsigned int cachededgeoffset;
} medge_t;

typedef struct mtexinfo_s {
  float vecs[2][4];
  int flags;
  int numframes;
  struct mtexinfo_s *next; // animation chain
  uint16_t wal_width;
  uint16_t wal_height;
  image_t *albedo_image;
  image_t *normal_image;
} mtexinfo_t;

#define VERTEXSIZE 7

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

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

  cplane_t *plane;
  int flags;

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

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

  float texture_space_mat3[3][3];

  int light_s, light_t;   // gl lightmap coordinates
  int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps

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

  mtexinfo_t *texinfo;

  // lighting info
  int dlightframe;
  int dlightbits;

  int lightmaptexturenum;
  byte styles[MAXLIGHTMAPS];
  float cached_light[MAXLIGHTMAPS]; // values currently used in lightmap
  byte *samples;                    // [numstyles*surfsize]

  uint32_t elements_offset;
  uint32_t elements_count;
} msurface_t;

typedef struct mnode_s {
  // common with leaf
  int contents; // -1, 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
  cplane_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
  int cluster;
  int area;

  msurface_t **firstmarksurface;
  int nummarksurfaces;
} mleaf_t;

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

//
// Whole model
//

typedef enum { mod_load, mod_load_crash, mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t;

typedef struct model_s {
  char name[MAX_QPATH];

  int registration_sequence;

  modtype_t type;
  int numframes;

  int flags;

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

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

  //
  // brush model
  //
  int cmodel_index;
  int firstmodelsurface, nummodelsurfaces;
  int lightmap; // only for submodels

  int numsubmodels;
  mmodel_t *submodels;

  int numplanes;
  cplane_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;
  int firstnode;
  mnode_t *nodes;

  int numtexinfo;
  mtexinfo_t *texinfo;

  int numsurfaces;
  msurface_t *surfaces;

  int numsurfedges;
  int *surfedges;

  int nummarksurfaces;
  msurface_t **marksurfaces;

  dvis_t *vis;

  bool old_lightmap;

  int lightdatasize;
  byte *lightdata;

  // for alias models and skins
  image_t *skins[MAX_MD2SKINS];

  int extradatasize;
  void *extradata;

  struct alias_gl_Buffer element_buffer;   // triangles
  struct alias_gl_Buffer position_buffer;  // position float[3]
  struct alias_gl_Buffer attribute_buffer; // st unorm16[2] / 2, lightmap_st unorm16[2], quat snorm16[4]

  GLuint lightmap_rgb0;
  GLuint lightmap_r1;
  GLuint lightmap_g1;
  GLuint lightmap_b1;

  msurface_t *r_alpha_surfaces;
} model_t;

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

void Mod_Init(void);
void Mod_ClearAll(void);
model_t *Mod_ForName(int cmodel_index, char *name, bool crash);
mleaf_t *Mod_PointInLeaf(vec3_t p, model_t *model);
byte *Mod_ClusterPVS(int cluster, model_t *model);

void Mod_Modellist_f(void);

void Mod_FreeAll(void);
void Mod_Free(model_t *mod);

#endif