#ifdef HAVE_CONFIG_H
#include <conf_config.h>
#endif

#ifdef WIN32
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#endif

#include <GL/glew.h>

#include "video_GL_mogul.h"
#include "storage.h"
#include "config.h"
#include <string>
#include <iostream>
#include <list>




#include <GL/mogul.h>

#define LOG_INFO std::cout

#ifdef HAVE_CONFIG_H
#include <conf_config.h>
#endif

#ifdef Revision
#undef Revision
#endif
#define Revision "video_GL_mogul.cpp $Revision: 1.2 $"


std::string storage_name;
std::string storage_prefix;
typedef Storage<std::string, Storage<std::string, Video_Surface*>* > _Surface_Group_Map_;
typedef Storage<std::string, Storage<std::string, Video_Sprite*>* > _Sprite_Group_Map_;
typedef Storage<std::string, Storage<std::string, Video_Particles*>* > _Particles_Group_Map_;
typedef Storage<std::string, Video_Surface*> _Surface_Map_;
typedef Storage<std::string, Video_Sprite*> _Sprite_Map_;
typedef Storage<std::string, Video_Particles*> _Particles_Map_;
typedef std::vector<Video_Sprite*> _Sprites_Draw_List_;
typedef std::vector<Video_Particles*> _Particles_Draw_List_;

Video_Interface* _get_video_driver ( std::string * params, int params_num )
{
	if ( params_num < 2 )
		return 0;
	storage_name = params[ 0 ];
	storage_prefix = params[ 1 ];
	Config_Interface *intf = config_get_interface ( storage_name );
	if ( !intf ) return 0;
	return new OpenGL_Video;
}
template <typename A>
struct clean1
{
	void operator() (A object)
	{
		std::cerr<<"Deiniting object:"<<object.first<<std::endl;	
		delete object.second;
	}
};
template <typename A, typename B>
struct clean
{
	clean1<B> clean_1;
	void operator() (A object)
	{
		std::cerr<<"Deiniting object:"<<object.first<<std::endl;	
		object.second->for_each(clean_1);
		delete object.second;
	}
};

bool OpenGL_Video::_deinit()
{
	clean<std::pair<std::string, Storage<std::string, Video_Surface*>* >, std::pair<std::string, Video_Surface*> > cleaner_surf;
	_surfaces_.for_each(cleaner_surf);
	clean<std::pair<std::string, Storage<std::string, Video_Sprite*>* >, std::pair<std::string, Video_Sprite*> > cleaner_spr;
	_sprites_.for_each(cleaner_spr);
	clean<std::pair<std::string, Storage<std::string, Video_Particles*>* >, std::pair<std::string, Video_Particles*> > cleaner_par;
	_particles_.for_each(cleaner_par);
	mogulEnd();
	return true;
}

bool OpenGL_Video::_init()
{
	Config_Interface *intf = config_get_interface ( storage_name );
	if ( !intf )
	{
		_error = "Can`t get config interface";
		return false;
	}


	_w_ = atoi ( intf->_get_value ( storage_prefix + "Width", "800" ).c_str() );
	_h_ = atoi ( intf->_get_value ( storage_prefix + "Height", "600" ).c_str() );
	_DoubleBuffer_ = ( intf->_get_value ( storage_prefix + "DoubleBuffer", "yes" ) == "yes" ) ? true : false;
	_FullScreen_ = ( intf->_get_value ( storage_prefix + "FullScreen", "yes" ) == "yes" ) ? true : false;
	_mouse_ = ( intf->_get_value ( storage_prefix + "HideMouse", "yes" ) == "yes" ) ? false : true;
	_caption_=intf->_get_value ( storage_prefix + "Caption", std::string ( "OpenGL video driver Version: " ) +VERSION );
	_base_h_=atoi ( intf->_get_value ( storage_prefix + "BaseHeight", "600" ).c_str() );
	_base_scale_=(float)_h_/(float)_base_h_;
	
	LOG_INFO << "_w_\t=" << _w_ << std::endl;
	LOG_INFO << "_h_\t=" << _h_ << std::endl;
	LOG_INFO << "_DoubleBuffer_\t=" << _DoubleBuffer_ << std::endl;
	LOG_INFO << "_FullScreen_\t=" << _FullScreen_ << std::endl;
	unsigned int flags=MOGUL_32_BIT_RGBA|MOGUL_TITLE|MOGUL_SIZE;

	flags|= ( _FullScreen_ ) ?MOGUL_FULL_SCREEN:0;
	flags|= ( _DoubleBuffer_ ) ?MOGUL_DOUBLE_BUFFER:MOGUL_SINGLE_BUFFER;
	flags|= ( _mouse_ ) ?0:MOGUL_HIDE_POINTER;
	mogulBegin ( flags, _caption_.c_str(), -_w_, -_h_ );
	GLenum err = glewInit();
	if (err != GLEW_OK)
	{
		LOG_INFO<<"Error init glew: "<< glewGetErrorString(err)<<std::endl;
		return false;
	}
	GLint texts;
	glGetIntegerv ( GL_MAX_TEXTURE_SIZE, &texts );
	LOG_INFO << "OpenGL info:" << std::endl <<
	"OpenGL version: " << glGetString ( GL_VERSION ) << std::endl <<
	"Vendor:: " << glGetString ( GL_VENDOR ) << std::endl <<
	"Supported Extesions: " << glGetString ( GL_EXTENSIONS ) << std::endl <<
//	"Shading Language Version: " << glGetString( GL_SHADING_LANGUAGE_VERSION ) << std::endl <<
	"Renderer info: " << glGetString ( GL_RENDERER ) << std::endl;
	LOG_INFO << "MaxTextureSize " << texts << std::endl;
	glGetIntegerv( GL_MAX_ELEMENTS_VERTICES, (GLint*)&_max_element_vertices_);
	glGetIntegerv( GL_MAX_ELEMENTS_INDICES, (GLint*)&_max_element_indeces_);
	glGetIntegerv( GL_POINT_SIZE_MAX_ARB, (GLint*)&_max_point_size_ );
	LOG_INFO << "MaxPointSize "<<_max_point_size_<<std::endl;
	LOG_INFO << "Max element vertices "<<_max_element_vertices_<<std::endl;
	LOG_INFO << "Max element indeces "<<_max_element_indeces_<<std::endl;
	LOG_INFO<<"\n\nChecking required extensions:"<<std::endl;
	bool state=true;
	LOG_INFO<<"GL_ARB_vertex_buffer_object:";
	if(!strstr((char*)glGetString ( GL_EXTENSIONS ), "GL_ARB_vertex_buffer_object"))
	{
		LOG_INFO<<"no"<<std::endl;
		state=false;
	}
	else LOG_INFO<<" yes"<<std::endl;
	LOG_INFO<<"GL_ARB_point_sprite:";
	if(!strstr((char*)glGetString ( GL_EXTENSIONS ), "GL_ARB_point_sprite"))
	{
		LOG_INFO<<"no"<<std::endl;
		return false;
	}
	else LOG_INFO<<" yes"<<std::endl;
	if(!state)
	{
		mogulEnd();
		return false;
	}
	/*bool arb_vbo=false;
	arb_vbo=isExtensionSupported ( "GL_ARB_vertex_buffer_object" );*/
	
	glEnable ( GL_TEXTURE_2D );
	glEnable( GL_POINT_SPRITE_ARB );
	_GL_State.gl_blend=false;
	glDisable( GL_BLEND);
	glShadeModel ( GL_SMOOTH );
	glHint ( GL_LINE_SMOOTH_HINT, GL_NICEST );
	//		glViewport ( 0, 0, _w_, _h_ );
	
	glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	glClearColor ( 0, 0, 0, 0 );
	glClear ( GL_COLOR_BUFFER_BIT );

	return true;
}
OpenGL_Video::~ OpenGL_Video( )
{
	mogulEnd();
}

OpenGL_Video::OpenGL_Video( )
{
	_error = "";
}
void OpenGL_Video::_draw_sprites()
{
	_Sprites_Draw_List_::iterator it;
	Video_Sprite *spr, *cur_spr=0;
	OpenGL_Surface *surf;
	std::vector<std::pair<std::string, std::string> >::iterator sps_it;
	std::vector<Video_Sprite*>::iterator sps_p_it;
	int num=0;
	int blend_switch=0;
	int textures_count=0;
	int begins=0;
	for(it=_sprites_draw_list_.begin();it!=_sprites_draw_list_.end();++it)
	{	
		spr=*it;
		if(spr->_drawed_ || !spr->_need_draw_)continue;
		surf=dynamic_cast<OpenGL_Surface*>(_get_surface(spr->_surface_name_, spr->_surface_group_));
		if(!surf)continue;
		if(surf->_need_update_)surf->_update_();
		glBindTexture ( GL_TEXTURE_2D, surf->_tex_id_ );
		textures_count++;
		if(surf->_get_alpha_status()==Video_Surface::ALPHA_CHANNEL)
		{
			if(!_GL_State.gl_blend){glEnable(GL_BLEND); _GL_State.gl_blend=true;blend_switch++;}
		}
		else
		{
			if(_GL_State.gl_blend){glDisable(GL_BLEND); _GL_State.gl_blend=false;blend_switch++;}
		}
		glBegin ( GL_QUADS );
		begins++;
//		for(sps_it=surf->_sprites_.begin();sps_it!=surf->_sprites_.end();++sps_it)
		for(sps_p_it=surf->_sprites_p_.begin();sps_p_it!=surf->_sprites_p_.end();++sps_p_it)
		{
//			cur_spr=_get_sprite(sps_it->first, sps_it->second );
			cur_spr=*sps_p_it;
			if(!cur_spr)continue;
			if(cur_spr->_drawed_ || !cur_spr->_need_draw_)continue;
			double w, h, x,y,x1,y1;
			w=2.*(double)cur_spr->_w_/(double)_w_;
			h=2.*(double)cur_spr->_h_/(double)_h_;
			x=cur_spr->_x_-cur_spr->_base_x_;
			y=cur_spr->_y_-cur_spr->_base_y_;
			x1=x+w*(cur_spr->_scale_x_*_base_scale_);
			y1=y+h*(cur_spr->_scale_y_*_base_scale_);
			
			
			glColor4f ( 1.0,1.0,1.0,cur_spr->_Ablend_ );
//			glRotatef ( cur_spr->_rotation_[0],1,0,0 );
//			glRotatef ( cur_spr->_rotation_[1],0,1,0 );
//			glRotatef ( cur_spr->_rotation_[2],0,0,1 );
			
			glTexCoord2d ( 0, 0 );
			glVertex2f ( x, y );
			
			glTexCoord2d ( 0, 1 );
			glVertex2f ( x, y1 );
			
			glTexCoord2d ( 1, 1 );
			glVertex2f ( x1, y1 );
			
			glTexCoord2d ( 1, 0 );
			glVertex2f ( x1, y );
			
			cur_spr->_drawed_=true;
			cur_spr->_need_draw_=false;
			num++;
		}
		glEnd();
	}
	
	glPopMatrix();
//	std::cerr<<"Textures: "<<textures_count<<" Blend switch:"<<blend_switch<<" Sprites:"<<num<<" glBegin:"<<begins<<std::endl;

}
/*void OpenGL_Video::_draw_group()
{
	GLuint index;
	glGenBuffers ( 1,&index );
	glBindBuffer ( GL_ARRAY_BUFFER_ARB, index );
	float *buf;
	buf=new float[32000*8];
	
	int a;
	glEnableClientState ( GL_VERTEX_ARRAY );
	glEnableClientState ( GL_TEXTURE_COORD_ARRAY );

	buf[a*8]=x;
	buf[a*8+1]=y;
			
	buf[a*8+2]=x;
	buf[a*8+3]=y1;
			
	buf[a*8+4]=x1;
	buf[a*8+5]=y1;
			
	buf[a*8+6]=x1;
	buf[a*8+7]=y;
	
//		std::cerr<<"glBufferData"<<std::endl;
	glBufferData ( GL_ARRAY_BUFFER_ARB, 32000*8, (void*)buf, GL_STREAM_DRAW_ARB );
//		std::cerr<<"glBindBuffer"<<std::endl;
	glBindBuffer ( GL_ARRAY_BUFFER_ARB, index);
//		std::cerr<<"glVertexPointer"<<std::endl;
	glVertexPointer ( 2, GL_FLOAT, 0, 0 );
//		std::cerr<<"glDeletBuffers"<<std::endl;
	glDeleteBuffers ( 1, &index );
//		std::cerr<<"delete"<<std::endl;
	delete[] buf;
}*/
void OpenGL_Video::_draw_particles()
{
	glPushMatrix();
	glLoadIdentity();
	
	_Particles_Draw_List_::iterator it;
	OpenGL_Particles *par;
//	glPushClientState();
	glEnableClientState ( GL_VERTEX_ARRAY );
	glEnableClientState ( GL_COLOR_ARRAY );
	if(!_GL_State.gl_blend){glEnable(GL_BLEND); _GL_State.gl_blend=true;}
	for(it=_particles_draw_list_.begin();it!=_particles_draw_list_.end();++it)
	{
		par=dynamic_cast<OpenGL_Particles*>(*it);
		glPointSize( par->_size_ );
		if(par->_have_texture_)
		{
			OpenGL_Surface *surf;
			surf=dynamic_cast<OpenGL_Surface*>(_get_surface(par->_surface_name_, par->_surface_group_));
			if(surf->_need_update_)surf->_update_();
			glBindTexture ( GL_TEXTURE_2D, surf->_tex_id_ );
			glTexEnvf( GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE );
			glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 4.0f );
			glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 1.0f );
			glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, _max_point_size_ );

		}
		glBindBuffer(GL_ARRAY_BUFFER, par->_c_buf_id_);
		glBufferSubData(GL_ARRAY_BUFFER, 0, par->_count_*4*sizeof(GLfloat), par->_colors_);
		glColorPointer(4, GL_FLOAT, 0, 0);
		
		glBindBuffer(GL_ARRAY_BUFFER, par->_p_buf_id_);
		glBufferSubData(GL_ARRAY_BUFFER, 0, par->_count_*2*sizeof(GLfloat), par->_particles_);
		glVertexPointer(2, GL_FLOAT, 0, 0);
	
		glDrawArrays(GL_POINTS, 0, par->_count_);
	}
	glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE );
	glPopMatrix();
//	glPopClientState();
}
void OpenGL_Video::_draw( )
{
	glMatrixMode ( GL_MODELVIEW );//сменим матрицу на всякий случай
	glPushMatrix();
	glLoadIdentity();
	
	int w,h, delta;
	mogulGetSize((int*)&w, (int*)&h);
	delta=_w_-w;
	_w_=w;
	_h_-=delta;
	mogulSetSize(_w_, _h_);
	
	_draw_sprites();
	_draw_particles();
	
	_sprites_draw_list_.clear();
	_particles_draw_list_.clear();
	glPopMatrix();
	mogulFlush();
	glClear ( GL_COLOR_BUFFER_BIT );
}

bool OpenGL_Video::_create_surface ( Video_Surface * surf, std::string name, std::string group_name, bool rewrite )
{
	/*		if ( group_name == "" ) group_name = _cur_group_;
			if ( !_surfaces_.exist( group_name ) )
			{
				_surfaces_.insert( group_name, new _Surface_Map_ );
			}
			else
			{
				_error = "Group already exist: " + group_name;
				return false;
			}

			_Surface_Map_ *smap = _surfaces_.get( group_name );
			if ( !smap )
			{
				_error = "Group not exist: " + group_name + " and creation was unsuccesfull";
				return false;
			}
			if ( smap->exist( name ) && !rewrite )
			{
				_error = "Surface already exist: " + name;
				return false;
			}

			smap->insert( name, surf );*/
	return false;
}

Video_Surface * OpenGL_Video::_get_surface ( std::string name , std::string group_name )
{
	if ( group_name == "" ) group_name = _cur_group_;
	if ( !_surfaces_.exist ( group_name ) )
	{
		_error = "Group not exist: " + group_name;
		return 0;
	}

	_Surface_Map_ *smap = _surfaces_.get ( group_name );
	if ( !smap )
	{
		_error = "Group not exist: " + group_name;
		return 0;
	}
	if ( !smap->exist ( name ) )
	{
		_error = "Surface not exist: " + name;
		return 0;
	}
	return smap->get ( name );
}
Video_Sprite * OpenGL_Video::_get_sprite ( std::string name , std::string group_name )
{
	if ( group_name == "" ) group_name = _cur_group_;
	if ( !_sprites_.exist ( group_name ) )
	{
		_error = "Group not exist: " + group_name;
		return 0;
	}

	_Sprite_Map_ *smap = _sprites_.get ( group_name );
	if ( !smap )
	{
		_error = "Group not exist: " + group_name;
		return 0;
	}
	if ( !smap->exist ( name ) )
	{
		_error = "Sprite not exist: " + name;
		return 0;
	}
	return smap->get ( name );
}

Video_Particles * OpenGL_Video::_get_particles ( std::string name , std::string group_name )
{
	if ( group_name == "" ) group_name = _cur_group_;
	if ( !_particles_.exist ( group_name ) )
	{
		_error = "Group not exist: " + group_name;
		return 0;
	}

	_Particles_Map_ *pmap = _particles_.get ( group_name );
	if ( !pmap )
	{
		_error = "Group not exist: " + group_name;
		return 0;
	}
	if ( !pmap->exist ( name ) )
	{
		_error = "Particles not exist: " + name;
		return 0;
	}
	return pmap->get ( name );
}

std::string OpenGL_Video::_get_current_group( )
{
	return _cur_group_;
}

bool OpenGL_Video::_set_current_group ( std::string name )
{
	if ( _surfaces_.exist ( name ) ) {_cur_group_ = name; return true;}
	_error = "Group " + name + " not exist";
	return false;
}

bool OpenGL_Video::_create_surface ( double xs, double ys, std::string name, std::string group_name, bool rewrite )
{
	return _create_surface ( ( int ) ( xs * ( double ) _w_ ), ( int ) ( ys * ( double ) _h_ ), name, group_name, rewrite );
}

bool OpenGL_Video::_create_surface ( int xs, int ys, std::string name, std::string group_name, bool rewrite )
{
	if ( group_name == "" ) group_name = _cur_group_;
	OpenGL_Surface *s;
	s = new OpenGL_Surface ( );

	if ( !s->_create_ ( xs, ys ) )
	{
		_error = "Can`t crfeate surface";
		delete s;
		return false;
	}
	
	if ( !_surfaces_.exist ( group_name ) )
	{
		_surfaces_.insert ( group_name, new _Surface_Map_ );
	}

	_Surface_Map_ *smap = _surfaces_.get ( group_name );
	if ( !smap )
	{
		_error = "Group not exist: " + group_name + " and creation was unsuccesfull";
		delete s;
		return false;
	}
	if ( smap->exist ( name ) && !rewrite )
	{
		_error = "Surface already exist: " + name;
		return false;
	}
	if ( smap->exist ( name ) && rewrite )
	{
		_free_surface ( name, group_name );
	}
	smap->insert ( name, s );
	return true;
}

bool OpenGL_Video::_create_sprite ( std::string name, std::string group_name, std::string surf_name, std::string surf_group, bool rewrite )
{
	Video_Sprite *s;
 	s = new Video_Sprite( name, group_name, this);


	if ( !_sprites_.exist ( group_name ) )
	{
		_sprites_.insert ( group_name, new _Sprite_Map_ );
	}
	_Sprite_Map_ *smap = _sprites_.get ( group_name );
	if ( !smap )
	{
		_error = "Group not exist: " + group_name + " and creation was unsuccesfull";
		delete s;
		return false;
	}
	if ( smap->exist ( name ) && !rewrite )
	{
		_error = "Sprite already exist: " + name;
		return false;
	}
	if ( smap->exist ( name ) && rewrite )
	{
		delete smap->get(name);
		smap->remove(name);
//		_free_surface ( name, group_name );
	}
	s->_set_surface ( this, surf_name, surf_group );
	smap->insert ( name, s );
	return true;
}


bool OpenGL_Video::_add_sprite ( Video_Sprite *spr )
{
	if(!spr)
	{
		_error="Illegal sprite handler! 0x00000000";
		return false;
	}
	spr->_drawed_=false;
	spr->_need_draw_=true;
	_sprites_draw_list_.push_back(spr);
	return true;
}
bool OpenGL_Video::_add_sprite ( std::string sprite_name, std::string sprite_group )
{
	if ( sprite_group == "" ) sprite_group = _cur_group_;

	_Sprite_Map_ *mp;
	if ( !_sprites_.exist ( sprite_group ) )
	{
		_error = "No such group: " + sprite_group;
		return false;
	}
	mp = _sprites_.get ( sprite_group );
	if ( !mp->exist ( sprite_name ) )
	{
		_error = "No such surface: " + sprite_name;
		return false;
	}
	Video_Sprite *spr;
	spr=mp->get(sprite_name);
	spr->_drawed_=false;
	spr->_need_draw_=true;
	_sprites_draw_list_.push_back(spr);
	return true;
}

bool OpenGL_Video::_free_surface ( std::string name, std::string grp )
{
	_Surface_Map_ *mp;
	if ( !_surfaces_.exist ( grp ) )
	{
		_error = "No such group: " + grp;
		return false;
	}
	mp = _surfaces_.get ( grp );
	if ( !mp->exist ( name ) )
	{
		_error = "No such surface: " + name;
		return false;
	}
	delete mp->get ( name );
	mp->remove ( name );
	return true;
}

std::string OpenGL_Video::_get_driver_name( )
{
	std::string name = "OpenGL video driver Version: ";
	return name + VERSION;
}

const Video_Features & OpenGL_Video::_get_features( )
{
	OpenGL_Video_Features _features;
	return _features;
}
void OpenGL_Video::show_mouse ( bool state )
{
	/// @todo Make show_mouse work
}
void OpenGL_Video::_get_mouse_position ( int *x, int *y )
{
	mogulGetPointerPosition ( x, y );
	*x-=_w_/2;
	*y-=_w_/2;
	return;
}
void OpenGL_Video::_get_mouse_position ( double *x, double *y )
{
	int xi, yi;
	mogulGetPointerPosition ( &xi, &yi );
	xi-=_w_/2;
	yi-=_h_/2;

	*x= ( double ) xi/ ( ( double ) _w_/2. );
	*y= ( double ) yi/ ( ( double ) _h_/2. );

	return;
}
EVENT_TYPE OpenGL_Video::_get_event()
{
	int event;
	event=mogulEventNow();
	switch ( event )
	{
		case MOGUL_EXIT:
			return EXIT;
		case MOGUL_MOUSE_EVENT|1:
			return MOUSE_LCLICK;
			break;
		default: return NO_EVENT;
	}
}
bool OpenGL_Video::check_surface_point ( double x_pos, double y_pos, double x_point, double y_point, std::string sprite_name, std::string group_name )
{
	double w,h;
	int wi, hi;
	Video_Sprite *spr;
	spr=_get_sprite ( sprite_name , group_name );
	if(!spr)return false;
	wi=spr->_w_;
	hi=spr->_h_;
	w= ( double ) wi/ ( ( double ) _w_/2. );
	h= ( double ) hi/ ( ( double ) _h_/2. );

	float xs,xe,ys,ye;
	xs=x_pos-spr->_base_x_;
	xe=xs+w;
	ys=y_pos-spr->_base_y_;
	ye=ys+h;

	if ( x_point>=xs && x_point<=xe && y_point>=ys && y_point<=ye )
	{
		std::cerr<<"Hit OK"<<std::endl;
		return true;
	}

	return false;
}

bool OpenGL_Video::_add_particles(std::string name, std::string group)
{
	if ( group == "" ) group = _cur_group_;

	_Particles_Map_ *mp;
	if ( !_particles_.exist ( group ) )
	{
		_error = "No such particles group: " + group;
		return false;
	}
	mp = _particles_.get ( group );
	if ( !mp->exist ( name ) )
	{
		_error = "No such particles: " + name;
		return false;
	}
	Video_Particles *particle;
	particle=mp->get(name);
	_particles_draw_list_.push_back(particle);
	return true;
}

bool OpenGL_Video::_create_particles(std::string name, std::string group_name, std::string surf_name, std::string surf_group, int count, bool rewrite)
{
	OpenGL_Particles *p;
	p = new OpenGL_Particles();


	if ( !_particles_.exist ( group_name ) )
	{
		_particles_.insert ( group_name, new _Particles_Map_ );
	}
	_Particles_Map_ *pmap = _particles_.get ( group_name );
	if ( !pmap )
	{
		_error = "Group not exist: " + group_name + " and creation was unsuccesfull";
		delete p;
		return false;
	}
	if ( pmap->exist ( name ) && !rewrite )
	{
		_error = "Particles already exist: " + name;
		delete p;
		return false;
	}
	if ( pmap->exist ( name ) && rewrite )
	{
		delete pmap->get(name);
		pmap->remove(name);
	}
	p->_have_texture_=(surf_name=="")?false:true;
	//Создадим буфер для частиц
	p->_particles_=new GLfloat[2*count];//6
	p->_colors_=new GLfloat[4*count];//6
	glGenBuffers ( 1,(GLuint*)&p->_p_buf_id_ );
	glGenBuffers ( 1,(GLuint*)&p->_c_buf_id_ );
	glBindBuffer(GL_ARRAY_BUFFER, p->_p_buf_id_);
	glBufferData(GL_ARRAY_BUFFER, count*sizeof(GLfloat)*2, 0, GL_STREAM_DRAW);//Создаем объект
	glBindBuffer(GL_ARRAY_BUFFER, p->_c_buf_id_);
	glBufferData(GL_ARRAY_BUFFER, count*sizeof(GLfloat)*4, 0, GL_STREAM_DRAW);//Создаем объект
	if(p->_have_texture_)
	{
		p->_surface_name_=surf_name;
		p->_surface_group_=surf_group;
	}
	p->_count_=count;
	pmap->insert ( name, p );
	return true;
}


