/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Jean Le Feuvre 2000-2005
 *					All rights reserved
 *
 *  This file is part of GPAC / 3D rendering plugin
 *
 *  GPAC 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, or (at your option)
 *  any later version.
 *   
 *  GPAC 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 GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */


#ifndef M4MESH_H_
#define M4MESH_H_

#include <gpac/m4_scenegraph_vrml.h>
#include <gpac/m4_raster2d.h>

typedef struct
{
	/*position*/
	SFVec3f pos;	
	/*normal*/
	SFVec3f normal;	
	/*color if used by mesh object*/
	SFColorRGBA color;
	/*texture coordinates*/
	SFVec2f texcoords;
} M4Vertex;

/*mesh type used*/
enum
{
	/*default: triangles described by indices (nb triangles = nb indices / 3) */
	MESH_TRIANGLES = 0,
	/*point set: indices is meaningless*/
	MESH_POINTSET,
	/*line set: lines described by indices (nb lines = nb indices / 2) */
	MESH_LINESET,
};

/*mesh flags*/
enum
{
	/*vertex.color is used*/
	MESH_HAS_COLOR = 1, 
	/*mesh is 2D: normal should be ignored and a global normal set to 0 0 1*/
	MESH_IS_2D = 1<<1, 
	/*mesh has no texture coords - disable texturing*/
	MESH_NO_TEXTURE = 1<<2, 
	/*mesh faces are clockwise*/
	MESH_IS_CW = 1<<3, 
	/*mesh is solid (back face culling + 2 side lighting)*/
	MESH_IS_SOLID = 1<<4, 
	/*mesh has smoothed normals*/
	MESH_IS_SMOOTHED = 1<<5, 
	/*vertex.color is used with alpha channel*/
	MESH_HAS_ALPHA = 1<<6, 
};

/*mesh object used by all 2D/3D primitives. */
typedef struct
{
	/*vertex list*/
	u32 v_count, v_alloc;
	M4Vertex *vertices;
	/*triangle indexes*/
	u32 i_count, i_alloc;
	u32 *indices;

	/*one of the above type*/
	u32 mesh_type;

	/*one of the above flags*/
	u32 flags;

	/*bounds info: bounding box and bounding sphere radius*/
	M4BBox bounds;

	/*aabb tree of the mesh if any*/
	struct __AABBNode *aabb_root;
	u32 *aabb_indices;
	u32 aabb_nb_index;
	/*max tree depth, 0 is unlimited*/
	u32 max_depth;
	/*min triangles at node to split. 0 is full split (one triangle per leaf)*/
	u32 min_tri_limit;
	/*one of the above type*/
	u32 split_type;
	u32 depth, nb_nodes;
} M4Mesh;

M4Mesh *new_mesh();
void mesh_free(M4Mesh *mesh);
/*reset mesh*/
void mesh_reset(M4Mesh *mesh);
/*recompute mesh bounds*/
void mesh_update_bounds(M4Mesh *mesh);
/*adds new vertex*/
void mesh_set_vertex_vx(M4Mesh *mesh, M4Vertex *vx);
/*adds new vertex (exported for tesselator only)*/
void mesh_set_vertex(M4Mesh *mesh, Fixed x, Fixed y, Fixed z, Fixed nx, Fixed ny, Fixed nz, Fixed u, Fixed v);
/*adds an index (exported for tesselator only)*/
void mesh_set_index(M4Mesh *mesh, u32 idx);
/*adds an point & associated color, normal set to NULL*/
void mesh_set_point(M4Mesh *mesh, Fixed x, Fixed y, Fixed z, SFColorRGBA col);
/*adds an index (exported for tesselator only)*/
void mesh_set_triangle(M4Mesh *mesh, u32 id1, u32 id2, u32 id3);
/*make dest mesh the clone of orig*/
void mesh_clone(M4Mesh *dest, M4Mesh *orig);
/*recompute all normals*/
void mesh_recompute_normals(M4Mesh *mesh);
/*generate texture coordinate - ONLY LOCAL MODES SUPPORTED FOR NOW*/
void mesh_generate_tex_coords(M4Mesh *mesh, SFNode *__texCoords);

/*inserts a box (lines only) of size 1.0 1.0 1.0*/
void mesh_new_unit_bbox(M4Mesh *mesh);

/*insert base primitives - low res indicates less subdivision steps for circles (cone, cylinder, ellipse, sphere)*/
void mesh_new_rectangle(M4Mesh *mesh, SFVec2f size);
void mesh_new_ellipse(M4Mesh *mesh, Fixed a_dia, Fixed b_dia, Bool low_res);
void mesh_new_box(M4Mesh *mesh, SFVec3f size);
void mesh_new_cylinder(M4Mesh *mesh, Fixed height, Fixed radius, Bool bottom, Bool side, Bool top, Bool low_res);
void mesh_new_cone(M4Mesh *mesh, Fixed height, Fixed radius, Bool bottom, Bool side, Bool low_res);
void mesh_new_sphere(M4Mesh *mesh, Fixed radius, Bool low_res);
/*inserts ILS/ILS2D and IFS2D outline when not filled*/
void mesh_new_ils(M4Mesh *mesh, SFNode *__coord, MFInt32 *coordIndex, SFNode *__color, MFInt32 *colorIndex, Bool colorPerVertex, Bool do_close);
/*inserts IFS2D*/
void mesh_new_ifs2d(M4Mesh *mesh, SFNode *ifs2d);
/*inserts IFS*/
void mesh_new_ifs(M4Mesh *mesh, SFNode *ifs);
/*inserts PS/PS2D*/
void mesh_new_ps(M4Mesh *mesh, SFNode *__coord, SFNode *__color);
/*inserts ElevationGrid*/
void mesh_new_elevation_grid(M4Mesh *mesh, SFNode *eg);
/*inserts Extrusion*/
void mesh_new_extrusion(M4Mesh *mesh, SFNode *ext);
/*builds mesh from path, performing tesselation if desired*/
void mesh_from_path(M4Mesh *mesh, M4Path *path);
/*builds mesh for outline of the given path*/
void mesh_get_outline(M4Mesh *mesh, M4Path *path);
/*constructs an extrusion from given path - mesh is reseted, txcoords computed from path bounds
@thespine: spine line
@creaseAngle: creaseAngle for normal smoothing, 0 for no smoothing
begin_cap, end_cap: indicates whether start/end faces shall be added
@spine_ori: orientation at spine points
@spine_scale: scale at spine points
@tx_along_spine: if set, texture coords are generated so that the texture is mapped on the side, 
otherwise the same txcoords are used all along the extrusion spine
*/
void mesh_extrude_path(M4Mesh *mesh, M4Path *path, MFVec3f *thespine, Fixed creaseAngle, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine);
/*special extension of the above: APPENDS an extrusion from given path - mesh is NOT reseted, txcoords are computed based on min_cx, min_cy, width_cx, width_cy*/
void mesh_extrude_path_ext(M4Mesh *mesh, M4Path *path, MFVec3f *thespine, Fixed creaseAngle, Fixed min_cx, Fixed min_cy, Fixed width_cx, Fixed width_cy, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine);

/*returns 1 if intersection and set outPoint to closest intersection, 0 otherwise*/
Bool m4_mesh_intersect_ray(M4Mesh *mesh, M4Ray *r, SFVec3f *outPoint, SFVec3f *outNormal, SFVec2f *outTexCoords);
/*returns 1 if any face is less than min_dist from pos, with collision point on closest face (towards pos)*/
Bool m4_mesh_closest_face(M4Mesh *mesh, SFVec3f pos, Fixed min_dist, SFVec3f *outPoint);




/*AABB tree node (exported for bounds drawing)*/
typedef struct __AABBNode
{
	/*bbox*/
	SFVec3f min, max;
	/*sorted indices in mesh indices list*/
	u32 *indices;
	/*nb triangles*/
	u32 nb_idx;
	/*children nodes, NULL if leaf*/
	struct __AABBNode *pos, *neg;
} AABBNode;

/*tree construction modes*/
enum
{
	/*AABB tree is not used*/
	AABB_NONE, 
	/*longest box axis is used to divide an AABB node*/
	AABB_LONGEST, 
	/*keep tree well-balanced*/
	AABB_BALANCED,
	/*best axis is use: test largest, then middle, then smallest axis*/
	AABB_BEST_AXIS, 
	/*use variance to pick axis*/
	AABB_SPLATTER,
	/*fifty/fifty point split*/
	AABB_FIFTY,
};

void m4_mesh_build_aabbtree(M4Mesh *mesh);

#endif

