GLSLShader.cpp 29.4 KB
Newer Older
Pierre Kraemer's avatar
Pierre Kraemer committed
1 2 3
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps  *
* version 0.1                                                                  *
4
* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg           *
Pierre Kraemer's avatar
Pierre Kraemer committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
*                                                                              *
* This library is free software; you can redistribute it and/or modify it      *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your     *
* option) any later version.                                                   *
*                                                                              *
* This library 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 Lesser General Public License  *
* for more details.                                                            *
*                                                                              *
* You should have received a copy of the GNU Lesser General Public License     *
* along with this library; if not, write to the Free Software Foundation,      *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.           *
*                                                                              *
20
* Web site: http://cgogn.unistra.fr/                                           *
Pierre Kraemer's avatar
Pierre Kraemer committed
21 22 23
* Contact information: cgogn@unistra.fr                                        *
*                                                                              *
*******************************************************************************/
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
24

Pierre Kraemer's avatar
Pierre Kraemer committed
25 26 27 28 29
#define EXPORTING 1

#include "Utils/GLSLShader.h"
#include <iostream>
#include <fstream>
30
#include <vector>
31
#include "Utils/cgognStream.h"
Pierre Kraemer's avatar
Pierre Kraemer committed
32

Sylvain Thery's avatar
Sylvain Thery committed
33 34
#include "glm/gtx/inverse_transpose.hpp"

Pierre Kraemer's avatar
Pierre Kraemer committed
35 36 37 38 39
namespace CGoGN
{

namespace Utils
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
40 41

unsigned int GLSLShader::CURRENT_OGL_VERSION = 2;
Sylvain Thery's avatar
Sylvain Thery committed
42 43 44

std::string GLSLShader::DEFINES_GL2=\
"#version 110\n"
45
"#define PRECISON float pipo_PRECISION\n"
Sylvain Thery's avatar
Sylvain Thery committed
46 47 48
"#define ATTRIBUTE attribute\n"
"#define VARYING_VERT varying\n"
"#define VARYING_FRAG varying\n"
49 50
"#define FRAG_OUT_DEF float pipo_FRAGDEF\n"
"#define INVARIANT_POS float pipo_INVARIANT\n";
Sylvain Thery's avatar
Sylvain Thery committed
51

Pierre Kraemer's avatar
Pierre Kraemer committed
52

Sylvain Thery's avatar
Sylvain Thery committed
53
std::string GLSLShader::DEFINES_GL3=\
54
"#version 150\n"
55
"#define PRECISON precision highp float\n"
Sylvain Thery's avatar
Sylvain Thery committed
56 57 58 59
"#define ATTRIBUTE in\n"
"#define VARYING_VERT smooth out\n"
"#define VARYING_FRAG smooth in\n"
"#define FRAG_OUT_DEF out vec4 gl_FragColor\n"
60
"#define INVARIANT_POS invariant gl_Position\n";
Sylvain Thery's avatar
Sylvain Thery committed
61

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
62 63

std::string* GLSLShader::DEFINES_GL = NULL;
64 65 66

std::vector<std::string> GLSLShader::m_pathes;

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
67 68 69
std::set< std::pair<void*, GLSLShader*> > GLSLShader::m_registeredShaders;


70 71 72
//glm::mat4* GLSLShader::s_current_matrices=NULL;
Utils::GL_Matrices* GLSLShader::s_current_matrices=NULL;

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
73 74 75 76
GLSLShader::GLSLShader() :
	m_vertex_shader_source(NULL),
	m_fragment_shader_source(NULL),
	m_geom_shader_source(NULL)
Pierre Kraemer's avatar
Pierre Kraemer committed
77
{
78 79 80 81 82 83 84 85 86
	*m_vertex_shader_object = 0;
	*m_fragment_shader_object = 0;
	*m_geom_shader_object = 0;
	*m_program_object = 0;
	*m_uniMat_Proj = -1;
	*m_uniMat_Model = -1;
	*m_uniMat_ModelProj = -1;
	*m_uniMat_Normal = -1;

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
87
	if (DEFINES_GL == NULL)
88
		DEFINES_GL = &DEFINES_GL2;
Sylvain Thery's avatar
Sylvain Thery committed
89 90

	m_nbMaxVertices = 16;
Pierre Kraemer's avatar
Pierre Kraemer committed
91 92
}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
93
void GLSLShader::registerShader(void* ptr, GLSLShader* shader)
94
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
95
	m_registeredShaders.insert(std::pair<void*,GLSLShader*>(ptr, shader));
96 97
}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
98
void GLSLShader::unregisterShader(void* ptr, GLSLShader* shader)
99
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
100
	m_registeredShaders.erase(std::pair<void*,GLSLShader*>(ptr, shader));
101 102 103 104
}

std::string GLSLShader::defines_Geom(const std::string& primitivesIn, const std::string& primitivesOut, int maxVert)
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
105
	if (CURRENT_OGL_VERSION == 3)
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
	{
		std::string str("#version 150\n");
		str.append("precision highp float;\n");
		str.append("layout (");
		str.append(primitivesIn);
		str.append(") in;\n");

		str.append("layout (");
		str.append(primitivesOut);
		str.append(", max_vertices = ");
		std::stringstream ss;
		ss << maxVert;
		str.append(ss.str());
		str.append(") out;\n");
		str.append("#define VARYING_IN in\n");
		str.append("#define VARYING_OUT smooth out\n");
		str.append("#define POSITION_IN(X) gl_in[X].gl_Position\n");
123
		str.append("#define NBVERTS_IN gl_in.length()\n");
124 125 126 127
		return str;
	}
	else
	{
Sylvain Thery's avatar
Sylvain Thery committed
128 129 130
		std::string str("#version 110\n");
		str.append("#extension GL_EXT_geometry_shader4 : enable\n");
		str.append("#define PRECISON float pipo_PRECISION\n");
131 132 133 134
		str.append("#define ATTRIBUTE attribute\n");
		str.append("#define VARYING_IN varying in\n");
		str.append("#define VARYING_OUT varying out\n");
		str.append("#define POSITION_IN(X) gl_PositionIn[X]\n");
135
		str.append("#define NBVERTS_IN gl_VerticesIn\n");
136 137 138 139
		return str;
	}
}

Pierre Kraemer's avatar
Pierre Kraemer committed
140 141
bool GLSLShader::areGeometryShadersSupported()
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
142 143
	if (!glewGetExtension("GL_EXT_geometry_shader4"))
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	return true;
}

bool GLSLShader::areShadersSupported()
{
	if ( ! glewGetExtension("GL_ARB_vertex_shader")) return false;
	if ( ! glewGetExtension("GL_ARB_fragment_shader")) return false;
	if ( ! glewGetExtension("GL_ARB_shader_objects")) return false;
	if ( ! glewGetExtension("GL_ARB_shading_language_100")) return false;

	return true;
}

bool GLSLShader::areVBOSupported()
{
	if (!glewGetExtension("GL_ARB_vertex_buffer_object"))
		return false;
	return true;
}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
164
char* GLSLShader::loadSourceFile(const std::string& filename)
Pierre Kraemer's avatar
Pierre Kraemer committed
165 166 167 168 169 170 171 172 173 174
{
	std::ifstream	file;
	int				file_size;
	char*			shader_source;

	/*** opening file ***/
	file.open( filename.c_str() , std::ios::in | std::ios::binary );

	if( !file.good() )
	{
175
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - unable to open the file " << filename << "." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
		return NULL;
	}

	/*** reading file ***/
	try
	{
		/* get file size */
		file.seekg( 0, std::ios::end );
		file_size = file.tellg();
		file.seekg( 0, std::ios::beg );

		/* allocate shader source table */
		shader_source = new char [ file_size+1 ];

		/* read source file */
		file.read( shader_source, file_size );
		shader_source[ file_size ] = '\0';
	}
	catch( std::exception& io_exception )
	{
196
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - " << io_exception.what() << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
197 198 199 200 201 202 203 204 205 206 207 208
		file.close();
		return NULL;
	}

	/*** termination ***/
	file.close();
	return shader_source;
}

bool GLSLShader::loadVertexShader(  const std::string& filename )
{
	bool	flag;
209
//	char	*vertex_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
210

211 212
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
213
	m_vertex_shader_source = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
214

215
	m_vertex_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
216

217
	if( !m_vertex_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
218
	{
219
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
220 221 222 223
		return false;
	}


224 225
	flag = loadVertexShaderSourceString( m_vertex_shader_source );
//	delete [] vertex_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
226 227 228 229

	return flag;
}

230
bool GLSLShader::loadFragmentShader(const std::string& filename )
Pierre Kraemer's avatar
Pierre Kraemer committed
231 232
{
	bool	flag;
233
//	char	*fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
234

235 236
	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;
237
	m_fragment_shader_source = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
238

239
	m_fragment_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
240

241
	if( !m_fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
242
	{
243
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
244 245 246
		return false;
	}

247 248
	flag = loadFragmentShaderSourceString( m_fragment_shader_source );
//	delete [] fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
249 250 251 252 253 254 255 256


	return flag;
}

bool GLSLShader::loadGeometryShader(const std::string& filename )
{
	bool	flag;
257
//	char	*geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
258

259 260
	if (m_geom_shader_source)
		delete [] m_geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
261

262
	m_geom_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
263

264
	if( !m_geom_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
265
	{
266
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
267 268 269
		return false;
	}

270 271
	flag = loadGeometryShaderSourceString( m_geom_shader_source );
//	delete [] geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
272 273 274 275 276 277 278 279 280

	return flag;
}

bool GLSLShader::loadVertexShaderSourceString( const char *vertex_shader_source )
{
	int		status;
	char	*info_log;

281
	if (*m_vertex_shader_object==0)
Sylvain Thery's avatar
Sylvain Thery committed
282
	{
283 284
		glDeleteShader(*m_vertex_shader_object);
		*m_vertex_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
285
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
286 287

	/*** create shader object ***/
288
	*m_vertex_shader_object = glCreateShader( GL_VERTEX_SHADER );
Pierre Kraemer's avatar
Pierre Kraemer committed
289

290
	if( !*m_vertex_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
291
	{
292
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
293 294 295 296 297 298
		return false;
	}

	/*** load source file ***/
	if( !vertex_shader_source )
	{
299
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - source string is empty." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
300

301 302
		glDeleteObjectARB(*m_vertex_shader_object );
		*m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
303 304 305 306

		return false;
	}

307
	glShaderSourceARB( *m_vertex_shader_object, 1, (const char**)&vertex_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
308 309

	/*** compile shader object ***/
310
	glCompileShaderARB( *m_vertex_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
311

312
	glGetObjectParameterivARB( *m_vertex_shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
313 314
	if( !status )
	{
315
		CGoGNerr << "ERROR - GLshader::loadVertexShader() - error occured while compiling shader " << m_nameVS<< CGoGNendl;
316
		info_log = getInfoLog( *m_vertex_shader_object );
317
				CGoGNerr << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
318 319
		delete [] info_log;

320 321
		glDeleteObjectARB( *m_vertex_shader_object );
		*m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
322 323 324 325 326 327 328 329

		return false;
	}

	/*** termination ***/
	return true;
}

330
bool GLSLShader::loadFragmentShaderSourceString( const char *fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
331 332 333 334
{
	int		status;
	char	*info_log;

335
	if (*m_fragment_shader_object==0)
Sylvain Thery's avatar
Sylvain Thery committed
336
	{
337 338
		glDeleteShader(*m_fragment_shader_object);
		*m_fragment_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
339
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
340 341

	/*** create shader object ***/
342
	*m_fragment_shader_object = glCreateShader( GL_FRAGMENT_SHADER );
Pierre Kraemer's avatar
Pierre Kraemer committed
343

344
	if( !*m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
345
	{
346
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
347 348 349 350
		return false;
	}

	/*** load source file ***/
351
	if( !fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
352
	{
353
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - source string is empty." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
354

355 356
		glDeleteObjectARB( *m_fragment_shader_object );
		*m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
357 358 359 360

		return false;
	}

361
	glShaderSourceARB( *m_fragment_shader_object, 1, (const char**)&fragment_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
362 363

	/*** compile shader object ***/
364
	glCompileShaderARB( *m_fragment_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
365

366
	glGetObjectParameterivARB( *m_fragment_shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
367 368
	if( !status )
	{
369
		CGoGNerr << "ERROR - GLshader::loadFragmentShader() - error occured while compiling shader " <<  m_nameFS << CGoGNendl;
370
		info_log = getInfoLog( *m_fragment_shader_object );
371
		CGoGNerr << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
372 373
		delete [] info_log;

374 375
		glDeleteObjectARB( *m_fragment_shader_object );
		*m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
376 377 378 379 380 381 382 383 384 385 386 387 388

		return false;
	}

	/*** termination ***/
	return true;
}

bool GLSLShader::loadGeometryShaderSourceString( const char *geom_shader_source )
{
	int		status;
	char	*info_log;

389
	if (*m_geom_shader_object==0)
Sylvain Thery's avatar
Sylvain Thery committed
390
	{
391 392
		glDeleteShader(*m_geom_shader_object);
		*m_geom_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
393
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
394
	/*** create shader object ***/
395
	*m_geom_shader_object = glCreateShader(GL_GEOMETRY_SHADER_EXT);
Pierre Kraemer's avatar
Pierre Kraemer committed
396

397
	if( !*m_geom_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
398
	{
399
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
400 401 402 403 404 405
		return false;
	}

	/*** load source file ***/
	if( !geom_shader_source )
	{
406
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - source string is empty." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
407

408 409
		glDeleteObjectARB( *m_geom_shader_object );
		*m_geom_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
410 411 412 413

		return false;
	}

414
	glShaderSourceARB( *m_geom_shader_object, 1, (const char**)&geom_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
415 416

	/*** compile shader object ***/
417
	glCompileShaderARB( *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
418

419
	glGetObjectParameterivARB( *m_geom_shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
420 421
	if( !status )
	{
422
		CGoGNerr << "ERROR - GLshader::loadGeometryShader() - error occured while compiling shader "<< m_nameGS << CGoGNendl;
423
		info_log = getInfoLog( *m_geom_shader_object );
424
		CGoGNerr << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
425 426
		delete [] info_log;

427 428
		glDeleteObjectARB( *m_geom_shader_object );
		*m_geom_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450

		return false;
	}

	/*** termination ***/
	return true;
}

char* GLSLShader::getInfoLog( GLhandleARB obj )
{
	char	*info_log;
	int		info_log_length;
	int		length;

	glGetObjectParameterivARB( obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length );

	info_log = new char [info_log_length];
	glGetInfoLogARB( obj, info_log_length, &length, info_log );

	return info_log;
}

Sylvain Thery's avatar
Sylvain Thery committed
451
bool GLSLShader::create(GLint inputGeometryPrimitive,GLint outputGeometryPrimitive, int nb_max_vertices)
Pierre Kraemer's avatar
Pierre Kraemer committed
452 453 454 455
{
	int		status;
	char	*info_log;

456
	if (nb_max_vertices != -1)
Sylvain Thery's avatar
Sylvain Thery committed
457 458
		m_nbMaxVertices = nb_max_vertices;

459 460
	m_geom_inputPrimitives = inputGeometryPrimitive;
	m_geom_outputPrimitives = outputGeometryPrimitive;
Pierre Kraemer's avatar
Pierre Kraemer committed
461 462

	/*** check if shaders are loaded ***/
463
	if( !*m_vertex_shader_object || !*m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
464
	{
465
		CGoGNerr << "ERROR - GLSLShader::create() - shaders are not defined." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
466 467 468 469
		return false;
	}

	/*** create program object ***/
470
	m_program_object = glCreateProgramObjectARB();
Pierre Kraemer's avatar
Pierre Kraemer committed
471

472
	if( !*m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
473
	{
474
		CGoGNerr << "ERROR - GLSLShader::create() - unable to create program object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
475 476 477 478
		return false;
	}

	/*** attach shaders to program object ***/
479 480 481
	glAttachObjectARB( *m_program_object, *m_vertex_shader_object );
	glAttachObjectARB( *m_program_object, *m_fragment_shader_object );
	if (*m_geom_shader_object)
Pierre Kraemer's avatar
Pierre Kraemer committed
482
	{
483
		glAttachObjectARB( *m_program_object, *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
484

485 486 487
		glProgramParameteriEXT(*m_program_object, GL_GEOMETRY_INPUT_TYPE_EXT, inputGeometryPrimitive);
		glProgramParameteriEXT(*m_program_object, GL_GEOMETRY_OUTPUT_TYPE_EXT, outputGeometryPrimitive);
		glProgramParameteriEXT(*m_program_object, GL_GEOMETRY_VERTICES_OUT_EXT, m_nbMaxVertices);
Pierre Kraemer's avatar
Pierre Kraemer committed
488 489 490
	}

	/*** link program object ***/
491
	glLinkProgramARB( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
492

493
	glGetObjectParameterivARB( *m_program_object, GL_OBJECT_LINK_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
494 495
	if( !status )
	{
496
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
497
		info_log = getInfoLog( *m_program_object );
498
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
499 500
		delete [] info_log;

501 502 503 504 505 506
		glDetachObjectARB( *m_program_object, *m_vertex_shader_object );
		glDetachObjectARB( *m_program_object, *m_fragment_shader_object );
		if (*m_geom_shader_object)
			glDetachObjectARB( *m_program_object, *m_geom_shader_object );
		glDeleteObjectARB( *m_program_object );
		*m_program_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
507 508 509 510

		return false;
	}

511 512 513 514
	*m_uniMat_Proj		= glGetUniformLocation(*m_program_object, "ProjectionMatrix");
	*m_uniMat_Model		= glGetUniformLocation(*m_program_object, "ModelViewMatrix");
	*m_uniMat_ModelProj	= glGetUniformLocation(*m_program_object, "ModelViewProjectionMatrix");
	*m_uniMat_Normal	= glGetUniformLocation(*m_program_object, "NormalMatrix");
515

Pierre Kraemer's avatar
Pierre Kraemer committed
516 517 518
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538


bool GLSLShader::changeNbMaxVertices(int nb_max_vertices)
{
	m_nbMaxVertices = nb_max_vertices;
	if (*m_geom_shader_object)
	{
		glProgramParameteriEXT(*m_program_object,GL_GEOMETRY_VERTICES_OUT_EXT,m_nbMaxVertices);
		// need to relink
		return true;
	}
	return false;
}







539 540 541 542 543 544
bool GLSLShader::link()
{
	int		status;
	char	*info_log;

	/*** link program object ***/
545
	glLinkProgramARB( *m_program_object );
546

547
	glGetObjectParameterivARB( *m_program_object, GL_OBJECT_LINK_STATUS_ARB, &status );
548 549
	if( !status )
	{
550
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
551
		info_log = getInfoLog( *m_program_object );
552
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
553 554
		delete [] info_log;

555 556 557 558 559 560
		glDetachObjectARB( *m_program_object, *m_vertex_shader_object );
		glDetachObjectARB( *m_program_object, *m_fragment_shader_object );
		if (*m_geom_shader_object)
			glDetachObjectARB( *m_program_object, *m_geom_shader_object );
		glDeleteObjectARB( *m_program_object );
		*m_program_object = 0;
561 562 563 564 565 566 567

		return false;
	}

	return true;
}

568
bool GLSLShader::bind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
569
{
570
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
571
	{
572
		glUseProgramObjectARB( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
573 574
		return true;
	}
575 576
	else
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
577 578
}

579
void GLSLShader::unbind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
580
{
581
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
582 583 584 585 586 587 588
	{
		glUseProgramObjectARB( 0 );
	}
}

bool GLSLShader::isBinded()
{
589
	return ( *m_program_object && *m_program_object == glGetHandleARB(GL_PROGRAM_OBJECT_ARB) );
Pierre Kraemer's avatar
Pierre Kraemer committed
590 591 592 593
}

GLSLShader::~GLSLShader()
{
594
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
595 596 597
	{
		unbind();

598
		if( *m_vertex_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
599
		{
600 601
			glDetachObjectARB( *m_program_object, *m_vertex_shader_object );
			glDeleteObjectARB( *m_vertex_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
602
		}
603
		if( *m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
604
		{
605 606
			glDetachObjectARB( *m_program_object, *m_fragment_shader_object );
			glDeleteObjectARB( *m_fragment_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
607
		}
608
		if (*m_geom_shader_object)
Pierre Kraemer's avatar
Pierre Kraemer committed
609
		{
610 611
			glDetachObjectARB( *m_program_object, *m_geom_shader_object );
			glDeleteObjectARB( *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
612 613
		}

614
		glDeleteObjectARB( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
615
	}
616

617 618 619 620 621 622 623
	if (m_vertex_shader_source != NULL)
		delete[] m_vertex_shader_source;
	if (m_fragment_shader_source != NULL)
		delete[] m_fragment_shader_source;
	if (m_geom_shader_source != NULL)
		delete[] m_geom_shader_source;

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
624
//	m_registeredShaders.erase(this);
Pierre Kraemer's avatar
Pierre Kraemer committed
625 626 627 628
}

std::string GLSLShader::findFile(const std::string filename)
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
629
	// cherche d'abord dans le repertoire courant
Pierre Kraemer's avatar
Pierre Kraemer committed
630 631 632 633 634 635 636 637 638
	std::ifstream file;
	file.open(filename.c_str(),std::ios::in );
	if (!file.fail())
	{
		file.close();
		return filename;
	}
	file.close();

639 640 641 642 643 644 645 646 647 648 649 650 651 652
	for (std::vector<std::string>::const_iterator ipath = m_pathes.begin(); ipath != m_pathes.end(); ++ipath)
	{
		std::string st(*ipath);
		st.append(filename);

		std::ifstream file2;
		file2.open(st.c_str(),std::ios::in);
		if (!file2.fail())
		{
			file2.close();
			return st;
		}
	}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
653
	// LA MACRO SHADERPATH contient le chemin du repertoire qui contient les fichiers textes
Pierre Kraemer's avatar
Pierre Kraemer committed
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
	std::string st(SHADERPATH);
	st.append(filename);

	std::ifstream file2; // on ne peut pas réutiliser file ????
	file2.open(st.c_str(),std::ios::in);
	if (!file2.fail())
	{
		file2.close();
		return st;
	}

	return filename;
}

bool GLSLShader::init()
{
670
#ifndef GLEW_MX
Pierre Kraemer's avatar
Pierre Kraemer committed
671 672 673
	GLenum error = glewInit();

	if (error != GLEW_OK)
674
		CGoGNerr << "Error: " << glewGetErrorString(error) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
675
	else
676
		CGoGNout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
677 678

	if (!areVBOSupported())
679
		CGoGNout << "VBO not supported !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
680 681

	if(!areShadersSupported()) {
682
		CGoGNout << "Shaders not supported !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
683 684
		return false;
	}
685 686 687
#endif
	return true;

Pierre Kraemer's avatar
Pierre Kraemer committed
688 689 690 691
}

bool GLSLShader::loadShaders(const std::string& vs, const std::string& ps)
{
Sylvain Thery's avatar
Sylvain Thery committed
692 693
	m_nameVS = vs;
	m_nameFS = ps;
694

Pierre Kraemer's avatar
Pierre Kraemer committed
695 696 697 698
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;
	
	std::string pss = findFile(ps);
699
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
700 701

	if(!create()) {
702
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
703 704
		return false;
	}
705
	CGoGNout << "Shaders loaded (" << vs << "," << ps << ")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
706 707 708
	return true; 
}

Sylvain Thery's avatar
Sylvain Thery committed
709
bool GLSLShader::loadShaders(const std::string& vs, const std::string& ps, const std::string& gs, GLint inputGeometryPrimitive,GLint outputGeometryPrimitive, int nb_max_vertices)
Pierre Kraemer's avatar
Pierre Kraemer committed
710
{
Sylvain Thery's avatar
Sylvain Thery committed
711 712 713 714
	m_nameVS = vs;
	m_nameFS = ps;
	m_nameGS = gs;

Pierre Kraemer's avatar
Pierre Kraemer committed
715 716 717 718
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;

	std::string pss = findFile(ps);
719
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
720 721 722 723 724 725

	std::string gss = findFile(gs);
	bool geomShaderLoaded = loadGeometryShader(gss);

	if (!geomShaderLoaded)
	{
726
		CGoGNerr << "Error while loading geometry shader" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
727 728
	}

Sylvain Thery's avatar
Sylvain Thery committed
729
	if(!create(inputGeometryPrimitive,outputGeometryPrimitive,nb_max_vertices))
Pierre Kraemer's avatar
Pierre Kraemer committed
730
	{
731
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
732 733 734
		return false;
	}

735
	CGoGNout << "Shaders loaded (" << vs << "," << ps << "," << gs <<")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
736 737 738
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
739 740
bool GLSLShader::loadShadersFromMemory(const char* vs, const char* fs)
{
741 742
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
743
	m_vertex_shader_source = NULL;
744 745 746

	unsigned int sz = strlen(vs);
	m_vertex_shader_source = new char[sz+1];
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
747
	strcpy(m_vertex_shader_source, vs);
748 749 750 751 752 753

	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;

	sz = strlen(fs);
	m_fragment_shader_source = new char[sz+1];
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
754
	strcpy(m_fragment_shader_source, fs);
755

756 757
	if(!loadVertexShaderSourceString(vs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
758

759 760
	if(!loadFragmentShaderSourceString(fs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
761 762 763

	if(!create())
	{
764
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
765 766 767 768 769
		return false;
	}
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
770
bool GLSLShader::loadShadersFromMemory(const char* vs, const char* fs, const char* gs, GLint inputGeometryPrimitive,GLint outputGeometryPrimitive, int nb_max_vertices)
Sylvain Thery's avatar
Sylvain Thery committed
771
{
772 773
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
774
	m_vertex_shader_source = NULL;
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793

	unsigned int sz = strlen(vs);
	m_vertex_shader_source = new char[sz+1];
	strcpy(m_vertex_shader_source,vs);

	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;

	sz = strlen(fs);
	m_fragment_shader_source = new char[sz+1];
	strcpy(m_fragment_shader_source,fs);

	if (m_geom_shader_source)
		delete [] m_geom_shader_source;

	sz = strlen(gs);
	m_geom_shader_source = new char[sz+1];
	strcpy(m_geom_shader_source,gs);

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
794 795
	if(!loadVertexShaderSourceString(vs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
796

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
797 798
	if(!loadFragmentShaderSourceString(fs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
799

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
800 801
	if(!loadGeometryShaderSourceString(gs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
802

803
	if(!create(inputGeometryPrimitive, outputGeometryPrimitive, nb_max_vertices))
Sylvain Thery's avatar
Sylvain Thery committed
804
	{
805
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
806 807 808 809 810 811
		return false;
	}

	return true;
}

812 813 814 815
bool GLSLShader::reloadVertexShaderFromMemory(const char* vs)
{
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
816
	m_vertex_shader_source = NULL;
817 818 819

	unsigned int sz = strlen(vs);
	m_vertex_shader_source = new char[sz+1];
820

821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
	strcpy(m_vertex_shader_source,vs);

	return true;
}

bool GLSLShader::reloadFragmentShaderFromMemory(const char* fs)
{
	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;

	unsigned int sz = strlen(fs);
	m_fragment_shader_source = new char[sz+1];
	strcpy(m_fragment_shader_source,fs);

	return true;
}

bool GLSLShader::reloadGeometryShaderFromMemory(const char* gs)
{
	if (m_geom_shader_source)
		delete [] m_geom_shader_source;

	unsigned int sz = strlen(gs);
	m_geom_shader_source = new char[sz+1];
	strcpy(m_geom_shader_source,gs);

	return true;
}

bool GLSLShader::recompile()
{
	if (m_vertex_shader_source)
		if(!loadVertexShaderSourceString(m_vertex_shader_source)) return false;
	if (m_fragment_shader_source)
		if(!loadFragmentShaderSourceString(m_fragment_shader_source)) return false;
	if (m_geom_shader_source)
		if(!loadGeometryShaderSourceString(m_geom_shader_source)) return false;

	if(!create(m_geom_inputPrimitives,m_geom_outputPrimitives))
	{
861
		CGoGNerr << "Unable to create the shaders !" << CGoGNendl;
862 863 864
		return false;
	}

865 866 867
	*m_uniMat_Proj		= glGetUniformLocation(*m_program_object,"ProjectionMatrix");
	*m_uniMat_Model		= glGetUniformLocation(*m_program_object,"ModelViewMatrix");
	*m_uniMat_ModelProj	= glGetUniformLocation(*m_program_object,"ModelViewProjectionMatrix");
Sylvain Thery's avatar
Sylvain Thery committed
868
	*m_uniMat_Normal	= glGetUniformLocation(*m_program_object,"NormalMatrix");
869 870 871

	restoreUniformsAttribs();

872 873
	updateClippingUniforms();

874 875 876
	return true;
}

877 878
bool GLSLShader::validateProgram()
{
879
	if(!*m_program_object)
880 881
		return false;

882
	glValidateProgram(*m_program_object);
883
	GLint Result = GL_FALSE;
884
	glGetProgramiv(*m_program_object, GL_VALIDATE_STATUS, &Result);
885 886 887

	if(Result == GL_FALSE)
	{
888
		CGoGNout << "Validate program:" << CGoGNendl;
889
		int InfoLogLength;
890
		glGetProgramiv(*m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
891
		std::vector<char> Buffer(InfoLogLength);
892
		glGetProgramInfoLog(*m_program_object, InfoLogLength, NULL, &Buffer[0]);
893
		CGoGNout <<  &(Buffer[0]) << CGoGNendl;
894 895 896 897 898 899 900 901 902
		return false;
	}

	return true;
}

bool GLSLShader::checkProgram()
{
	GLint Result = GL_FALSE;
903
	glGetProgramiv(*m_program_object, GL_LINK_STATUS, &Result);
904 905

	int InfoLogLength;
906
	glGetProgramiv(*m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
907
	std::vector<char> Buffer(std::max(InfoLogLength, int(1)));
908
	glGetProgramInfoLog(*m_program_object, InfoLogLength, NULL, &Buffer[0]);
909
	CGoGNout << &Buffer[0] << CGoGNendl;
910 911 912 913 914 915 916 917 918 919 920 921 922

	return Result == GL_TRUE;
}

bool GLSLShader::checkShader(int shaderType)
{
	GLint Result = GL_FALSE;
	int InfoLogLength;
	GLhandleARB id;

	switch(shaderType)
	{
	case VERTEX_SHADER:
923
		id = *m_vertex_shader_object;
924 925
		break;
	case FRAGMENT_SHADER:
926
		id = *m_fragment_shader_object;
927 928
		break;
	case GEOMETRY_SHADER:
929
		id = *m_geom_shader_object;
930 931
		break;
	default:
932
		CGoGNerr << "Error unkown shader type" << CGoGNendl;
933 934 935 936 937 938 939 940
		return false;
		break;
	}

	glGetShaderiv(id, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(id, GL_INFO_LOG_LENGTH, &InfoLogLength);
	std::vector<char> Buffer(InfoLogLength);
	glGetShaderInfoLog(id, InfoLogLength, NULL, &Buffer[0]);
941
	CGoGNout << &Buffer[0] << CGoGNendl;
942 943 944 945

	return Result == GL_TRUE;
}

Sylvain Thery's avatar
Sylvain Thery committed
946
void GLSLShader::bindAttrib(unsigned int att, const char* name) const
947
{
948
	glBindAttribLocation(*m_program_object, att, name);
949 950
}

951 952 953 954 955
void GLSLShader::addPathFileSeach(const std::string& path)
{
	m_pathes.push_back(path);
}

956
unsigned int GLSLShader::bindVA_VBO(const std::string& name, VBO* vbo)
Sylvain Thery's avatar
Sylvain Thery committed
957
{
958
	GLint idVA = glGetAttribLocation(*(this->m_program_object), name.c_str());
Sylvain Thery's avatar
Sylvain Thery committed
959 960 961
	//valid ?
	if (idVA < 0)
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
962
		CGoGNerr << "GLSLShader: Attribute " << name << " does not exist in shader" << CGoGNendl;
963
		return idVA;
Sylvain Thery's avatar
Sylvain Thery committed
964 965 966 967 968 969
	}
	// search if name already exist
	for (std::vector<VAStr>::iterator it = m_va_vbo_binding.begin(); it != m_va_vbo_binding.end(); ++it)
	{
		if (it->va_id == idVA)
		{
970 971
			it->vbo_ptr = vbo;
			return (it - m_va_vbo_binding.begin());
Sylvain Thery's avatar
Sylvain Thery committed
972 973 974 975 976
		}
	}
	// new one:
	VAStr temp;
	temp.va_id = idVA;
977
	temp.vbo_ptr = vbo;
Sylvain Thery's avatar
Sylvain Thery committed
978
	m_va_vbo_binding.push_back(temp);
979 980 981 982 983 984
	return (m_va_vbo_binding.size() -1);
}

void GLSLShader::changeVA_VBO(unsigned int id, VBO* vbo)
{
	m_va_vbo_binding[id].vbo_ptr = vbo;
Sylvain Thery's avatar
Sylvain Thery committed
985 986 987 988
}

void GLSLShader::unbindVA(const std::string& name)
{
989
	GLint idVA = glGetAttribLocation(*(this->m_program_object), name.c_str());
Sylvain Thery's avatar
Sylvain Thery committed
990 991 992
	//valid ?
	if (idVA < 0)
	{
993
		CGoGNerr << "GLSLShader: Attribute " << name << " does not exist in shader, not unbinded" << CGoGNendl;