
#ifndef __tmeshview_h__
#define __tmeshview_h__


#ifndef __XGLVIEW_H__
#include <XOpenGLView.h>
#endif

#ifndef PandaWave_XPTRSET
#include <XPtrSet.h>
#endif

#ifndef PandaWave_XDYNARRAY
#include <XDynArray.h>
#endif

#ifndef __vec3_h__
#include "vec3.h"
#endif

#ifndef __tags_h__
#include "tags.h"
#endif

#ifndef __mesh_h__
#include "mesh.h"
#endif

#ifndef __markers_h__
#include "markers.h"
#endif

#include <string.h>

#if defined(macintosh) && !defined(APIENTRY)
#define APIENTRY
#endif



enum
{
	_cell_physical_height = 0,
	_cell_media_height = 4,
	_cell_render_height = 5,
	MAXIMUM_CELL_HEIGHTS = sizeof(mesh_cell) / sizeof(short_world_distance),
	
	_cell_height_none = -1,
	_cell_render_physical_max = -2
};

class TMeshView: public XGOpenGLView
{
	friend class TMeshForm;
	
	public:
							TMeshView( XGView *parent, XGArgStream &s );
		virtual				~TMeshView();
		
		enum {
			kClassID = 'mesh'
		};
		
		virtual void		DoDrawView( XRect );
		virtual bool		DoMouseDown( XPoint pt, short a );
		virtual void		DoMouseMove( XPoint pt, short a );
		virtual void		DoMouseUp(XPoint,short);
		
//		DECLAREDISPATCH
//		long				DoKeyEvent(long, void *);
		
		void				SetMarkerWorldAxis( bool world );
		void				SetShowMeshPolys( bool show );
		void				SetShowTerrainType( bool show );
		void				SetGridVisibility( int which_heights, bool shown );
		void				SetGridViewMode( int menuMode );
		void				SetMarkerViewMode( int menuMode );
		void				SetClickableMeshHeight( int which_height );
		void				ClearMeshHeightChangeMask() { memset( meshHeightMask, 0, sizeof(meshHeightMask) ); }
		void				SetMeshHeightChangeMask( int which_height, bool modifiable );
		
		bool				GetMarkerWorldAxis() { return this->markerWorldAxis; }
		bool				GetShowMeshPolys() { return this->showMeshPolys; }
		bool				GetShowTerrainType() { return this->showTerrainType; }
		bool				GetGridVisibility( int which_height ) { return this->meshHeightShown[which_height]; }
		int					GetMarkerViewMode() { return this->markerViewMode; }
		int					GetClickableMeshHeight() { return this->targetHeightKind; }
		bool				GetMeshHeightMask( int which_height ) { return this->meshHeightMask[which_height]; }
		
		void				ResetAllTextures();
		void				ResetTexture( tag id );
		void				ResetMarkers();
		void				ResetMesh( TMeshForm *form );
		void				ResetAllSkelmodels();
		void				ResetSkelmodel( tag id );
		
		void				UpdateStatusBar();
		
		void				ClearSelection();
		
	private:
		static unsigned char terrain_type_colors[16][4];
		
		static long MarkerInfoProc( class XGDialog *dlog, void *data, long msg, long arg, void * /*parg*/ );
		
		bool markerWorldAxis;
		bool showMeshPolys;
		bool showTerrainType;
		int markerViewMode;
		
		float softBrushRadius;
		float softBrushRoundness;
		float softBrushSoftness;
		float get_soft_brush_level( float distance );
		
		XGPtrSet<struct mesh_cell> cellSelect;
		XGPtrSet<struct marker_data> markerSelect;
		
		XGPtrSet<struct mesh_cell> baseCellSelect;
		XGPtrSet<struct marker_data> baseMarkerSelect;
		
		XGSDynArray<world_location3d> marker_drag_start;
		XGSDynArray<mesh_cell> cell_drag_start;
		XGSDynArray<float> soft_brush_level;
		mesh_cell smooth_target_heights;
		
		vec3	point_to_vector( XPoint pt );
		void	cell_to_pos( int *out_x, int *out_y, const struct mesh_cell *cell );
		float	get_mesh_height( float x, float y, int which_height );
		float	line_intersects_cell( vec3 origin, vec3 direction, int cell_x, int cell_y, float slop, int which_height );
		bool	line_intersects_mesh( vec3 origin, vec3 direction, int *out_vertex_x, int *out_vertex_y, vec3 *out_point, bool pick_vertices, bool transparent_mesh, int which_height );
		bool	line_intersects_marker( vec3 v_origin, vec3 mouse_vec, int *out_marker, int *out_axis, vec3 *out_point );
		void	get_affected_markers( XGPtrSet<struct marker_data> &out_markers, const XGPtrSet<struct mesh_cell> &cells );
		void	adjust_markers_over_changed_cells( const XGPtrSet<struct marker_data> &markers );
		
		TMeshForm *form;
		
		int		subsection_width, subsection_height;
		int		mesh_width, mesh_height;
		
		int		get_txst( tag id );
		int 	BindTexture( tag id, int stack, int index, int layer, int use );
		int 	bound_texture_number;

		struct cached_marker_data {
			float mat[3][3];
			float endpoints[3][2][3];
		};
		XGSDynArray<cached_marker_data> marker_cache;
		void MarkerChanged( int index );
		
		struct cached_texture_data {
			short index;
			short use;
			short layer;
			unsigned gl_texture_number;
		};
		typedef XGSDynArray<cached_texture_data> stack_cache;
		struct cached_txst_info {
			tag id;
			tag_entry *entry;
		};
		typedef XGDynArray<stack_cache> cached_txst_data;
		XGSDynArray<cached_txst_info> txst_cache_info;
		XGDynArray<cached_txst_data> txst_caches;
		
		struct cached_skelmodel_data {
			tag id;
			tag texture;
			int permutation;
			int vertex_count;
			int index_count;
			float bounds[3][2];
			float *vertices;
			float *normals;
			float *uv;
			unsigned short *indices;
		};
		XGSDynArray<cached_skelmodel_data> skelcache;
		cached_skelmodel_data *get_skelmodel( tag id, int permutation );
		
		int drag_mode;
		enum {
			drag_mode_none = 0,
			drag_mode_mesh_vertices,
			drag_mode_marker_axis,
			drag_mode_marker_xy,
			drag_mode_marker_rotate,
			drag_mode_band_add,
			drag_mode_band_remove,
			drag_mode_water_set,
			drag_mode_water_clear,
			drag_mode_terrain_paint,
			drag_mode_pull_grid,
			drag_mode_smooth_grid
		};
		vec3 drag_rotate_plane_normal;
		float drag_rotate_plane_constant;
		vec3 drag_anchor_point;
		vec3 drag_axis;
		XPoint drag_screen_start;
		XPoint drag_screen_end;
		mesh_cell *dragged_cell;
		marker_data *dragged_marker;
		int dragged_handle;
		
		int last_drag_delta;
		
		int targetHeightKind;
		bool meshHeightMask[MAXIMUM_CELL_HEIGHTS];
		bool moveMarkersWithMesh;
		bool meshHeightShown[MAXIMUM_CELL_HEIGHTS];
		
		short_world_distance targetMediaHeight;
		void paint_line( vec3 start, vec3 end, void (TMeshView::*paint_func)( int cell_x, int cell_y, int triangle ) );
		void clear_water( int cell_x, int cell_y, int triangle );
		void set_water( int cell_x, int cell_y, int triangle );
		void set_terrain( int cell_x, int cell_y, int triangle );
		
		void flood_fill_terrain( int cell_x, int cell_y, int triangle, int source_type, int dest_type );
		void flood_fill_water( int cell_x, int cell_y, bool src_wet, int dest_wet );
		
		int get_terrain_vert_index( int base_x, int base_y, int vx, int vy, int terrain_type, vec3 *mesh_verts, unsigned *mesh_colors, word mesh_mask[17][17], short mesh_index[16][17][17], int *vcount );
		
		bool extensions_done;
		bool gl_has_multitexture;
		int gl_has_extension( const char* str);
		void gl_setup_imp_extensions( void );
		void (APIENTRY *q_glActiveTextureARB) (GLenum);
		void (APIENTRY *q_glClientActiveTextureARB) (GLenum);
		void (APIENTRY *q_glMultiTexCoord2fARB) (GLenum, GLfloat, GLfloat);
		void (APIENTRY *q_glDrawRangeElementsEXT) (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
		void (APIENTRY *q_glLockArraysEXT) (GLint, GLsizei);
		void (APIENTRY *q_glUnlockArraysEXT) (void);
};


#endif

