GLSLShader.cpp 26.7 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-2011, 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.u-strasbg.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 77 78 79 80 81 82 83 84
GLSLShader::GLSLShader() :
	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),
	m_vertex_shader_source(NULL),
	m_fragment_shader_source(NULL),
	m_geom_shader_source(NULL)
Pierre Kraemer's avatar
Pierre Kraemer committed
85
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
86
	if (DEFINES_GL == NULL)
Sylvain Thery's avatar
Sylvain Thery committed
87
		DEFINES_GL = &DEFINES_GL3;
Pierre Kraemer's avatar
Pierre Kraemer committed
88 89
}

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

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

std::string GLSLShader::defines_Geom(const std::string& primitivesIn, const std::string& primitivesOut, int maxVert)
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
102
	if (CURRENT_OGL_VERSION == 3)
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
	{
		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");
120
		str.append("#define NBVERTS_IN gl_in.length()\n");
121 122 123 124 125 126 127 128 129 130
		return str;
	}
	else
	{
		std::string str("#extension GL_EXT_geometry_shader4 : enable\n");
		str.append("#define PRECISION\n");
		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");
131
		str.append("#define NBVERTS_IN gl_VerticesIn\n");
132 133 134 135
		return str;
	}
}

Pierre Kraemer's avatar
Pierre Kraemer committed
136 137
bool GLSLShader::areGeometryShadersSupported()
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
138 139
	if (!glewGetExtension("GL_EXT_geometry_shader4"))
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
	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
160
char* GLSLShader::loadSourceFile(const std::string& filename)
Pierre Kraemer's avatar
Pierre Kraemer committed
161 162 163 164 165 166 167 168 169 170
{
	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() )
	{
171
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - unable to open the file " << filename << "." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
		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 )
	{
192
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - " << io_exception.what() << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
193 194 195 196 197 198 199 200 201 202 203 204
		file.close();
		return NULL;
	}

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

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

207 208
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
209

210
	m_vertex_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
211

212
	if( !m_vertex_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
213
	{
214
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
215 216 217 218
		return false;
	}


219 220
	flag = loadVertexShaderSourceString( m_vertex_shader_source );
//	delete [] vertex_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
221 222 223 224

	return flag;
}

225
bool GLSLShader::loadFragmentShader(const std::string& filename )
Pierre Kraemer's avatar
Pierre Kraemer committed
226 227
{
	bool	flag;
228
//	char	*fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
229

230 231
	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
232

233
	m_fragment_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
234

235
	if( !m_fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
236
	{
237
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
238 239 240
		return false;
	}

241 242
	flag = loadFragmentShaderSourceString( m_fragment_shader_source );
//	delete [] fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
243 244 245 246 247 248 249 250


	return flag;
}

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

253 254
	if (m_geom_shader_source)
		delete [] m_geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
255

256
	m_geom_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
257

258
	if( !m_geom_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
259
	{
260
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
261 262 263
		return false;
	}

264 265
	flag = loadGeometryShaderSourceString( m_geom_shader_source );
//	delete [] geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
266 267 268 269 270 271 272 273 274

	return flag;
}

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

Sylvain Thery's avatar
Sylvain Thery committed
275 276 277 278 279
	if (m_vertex_shader_object==0)
	{
		glDeleteShader(m_vertex_shader_object);
		m_vertex_shader_object=0;
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
280 281

	/*** create shader object ***/
Sylvain Thery's avatar
Sylvain Thery committed
282
	m_vertex_shader_object = glCreateShader( GL_VERTEX_SHADER );
Pierre Kraemer's avatar
Pierre Kraemer committed
283

284
	if( !m_vertex_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
285
	{
286
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
287 288 289 290 291 292
		return false;
	}

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

295 296
		glDeleteObjectARB( m_vertex_shader_object );
		m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
297 298 299 300

		return false;
	}

301
	glShaderSourceARB( m_vertex_shader_object, 1, (const char**)&vertex_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
302 303

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

306
	glGetObjectParameterivARB( m_vertex_shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
307 308
	if( !status )
	{
309
		CGoGNerr << "ERROR - GLshader::loadVertexShader() - error occured while compiling shader " << m_nameVS<< CGoGNendl;
310
		info_log = getInfoLog( m_vertex_shader_object );
311
				CGoGNerr << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
312 313
		delete [] info_log;

314 315
		glDeleteObjectARB( m_vertex_shader_object );
		m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
316 317 318 319 320 321 322 323

		return false;
	}

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

324
bool GLSLShader::loadFragmentShaderSourceString( const char *fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
325 326 327 328
{
	int		status;
	char	*info_log;

Sylvain Thery's avatar
Sylvain Thery committed
329 330 331 332 333
	if (m_fragment_shader_object==0)
	{
		glDeleteShader(m_fragment_shader_object);
		m_fragment_shader_object=0;
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
334 335

	/*** create shader object ***/
Sylvain Thery's avatar
Sylvain Thery committed
336
	m_fragment_shader_object = glCreateShader( GL_FRAGMENT_SHADER );
Pierre Kraemer's avatar
Pierre Kraemer committed
337

338
	if( !m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
339
	{
340
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
341 342 343 344
		return false;
	}

	/*** load source file ***/
345
	if( !fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
346
	{
347
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - source string is empty." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
348

349 350
		glDeleteObjectARB( m_fragment_shader_object );
		m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
351 352 353 354

		return false;
	}

355
	glShaderSourceARB( m_fragment_shader_object, 1, (const char**)&fragment_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
356 357

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

360
	glGetObjectParameterivARB( m_fragment_shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
361 362
	if( !status )
	{
363
		CGoGNerr << "ERROR - GLshader::loadFragmentShader() - error occured while compiling shader " <<  m_nameFS << CGoGNendl;
364
		info_log = getInfoLog( m_fragment_shader_object );
365
		CGoGNerr << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
366 367
		delete [] info_log;

368 369
		glDeleteObjectARB( m_fragment_shader_object );
		m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
370 371 372 373 374 375 376 377 378 379 380 381 382

		return false;
	}

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

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

Sylvain Thery's avatar
Sylvain Thery committed
383 384 385 386 387
	if (m_geom_shader_object==0)
	{
		glDeleteShader(m_geom_shader_object);
		m_geom_shader_object=0;
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
388
	/*** create shader object ***/
389
	m_geom_shader_object = glCreateShader(GL_GEOMETRY_SHADER_EXT);
Pierre Kraemer's avatar
Pierre Kraemer committed
390

391
	if( !m_geom_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
392
	{
393
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
394 395 396 397 398 399
		return false;
	}

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

402 403
		glDeleteObjectARB( m_geom_shader_object );
		m_geom_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
404 405 406 407

		return false;
	}

408
	glShaderSourceARB( m_geom_shader_object, 1, (const char**)&geom_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
409 410

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

413
	glGetObjectParameterivARB( m_geom_shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
414 415
	if( !status )
	{
416
		CGoGNerr << "ERROR - GLshader::loadGeometryShader() - error occured while compiling shader "<< m_nameGS << CGoGNendl;
417
		info_log = getInfoLog( m_geom_shader_object );
418
		CGoGNerr << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
419 420
		delete [] info_log;

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

		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;
}

bool GLSLShader::create(GLint inputGeometryPrimitive,GLint outputGeometryPrimitive)
{
	int		status;
	char	*info_log;

450 451
	m_geom_inputPrimitives = inputGeometryPrimitive;
	m_geom_outputPrimitives = outputGeometryPrimitive;
Pierre Kraemer's avatar
Pierre Kraemer committed
452 453

	/*** check if shaders are loaded ***/
454
	if( !m_vertex_shader_object || !m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
455
	{
456
		CGoGNerr << "ERROR - GLSLShader::create() - shaders are not defined." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
457 458 459 460
		return false;
	}

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

463
	if( !m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
464
	{
465
		CGoGNerr << "ERROR - GLSLShader::create() - unable to create program object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
466 467 468 469
		return false;
	}

	/*** attach shaders to program object ***/
470 471 472
	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
473
	{
474
		glAttachObjectARB( m_program_object, m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
475

476 477
		glProgramParameteriEXT(m_program_object,GL_GEOMETRY_INPUT_TYPE_EXT,inputGeometryPrimitive);
		glProgramParameteriEXT(m_program_object,GL_GEOMETRY_OUTPUT_TYPE_EXT,outputGeometryPrimitive);
Pierre Kraemer's avatar
Pierre Kraemer committed
478 479
		int temp;
		glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT,&temp);
480
		glProgramParameteriEXT(m_program_object,GL_GEOMETRY_VERTICES_OUT_EXT,temp);
Pierre Kraemer's avatar
Pierre Kraemer committed
481 482 483
	}

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

486
	glGetObjectParameterivARB( m_program_object, GL_OBJECT_LINK_STATUS_ARB, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
487 488
	if( !status )
	{
489
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
490
		info_log = getInfoLog( m_program_object );
491
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
492 493
		delete [] info_log;

494 495 496 497 498 499
		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
500 501 502 503

		return false;
	}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
504 505 506 507
	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");
508

Pierre Kraemer's avatar
Pierre Kraemer committed
509 510 511
	return true;
}

512 513 514 515 516 517 518 519 520 521 522
bool GLSLShader::link()
{
	int		status;
	char	*info_log;

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

	glGetObjectParameterivARB( m_program_object, GL_OBJECT_LINK_STATUS_ARB, &status );
	if( !status )
	{
523
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
524
		info_log = getInfoLog( m_program_object );
525
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
		delete [] info_log;

		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;

		return false;
	}

	return true;
}

541
bool GLSLShader::bind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
542
{
543
	if( m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
544
	{
545
		glUseProgramObjectARB( m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
546 547
		return true;
	}
548 549
	else
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
550 551
}

552
void GLSLShader::unbind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
553
{
554
	if( m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
555 556 557 558 559 560 561
	{
		glUseProgramObjectARB( 0 );
	}
}

bool GLSLShader::isBinded()
{
562
	return ( m_program_object && m_program_object == glGetHandleARB(GL_PROGRAM_OBJECT_ARB) );
Pierre Kraemer's avatar
Pierre Kraemer committed
563 564 565 566
}

GLSLShader::~GLSLShader()
{
567
	if( m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
568 569 570
	{
		unbind();

571
		if( m_vertex_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
572
		{
573 574
			glDetachObjectARB( m_program_object, m_vertex_shader_object );
			glDeleteObjectARB( m_vertex_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
575
		}
576
		if( m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
577
		{
578 579
			glDetachObjectARB( m_program_object, m_fragment_shader_object );
			glDeleteObjectARB( m_fragment_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
580
		}
581
		if (m_geom_shader_object)
Pierre Kraemer's avatar
Pierre Kraemer committed
582
		{
583 584
			glDetachObjectARB( m_program_object, m_geom_shader_object );
			glDeleteObjectARB( m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
585 586
		}

587
		glDeleteObjectARB( m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
588
	}
589

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
590
//	m_registeredShaders.erase(this);
Pierre Kraemer's avatar
Pierre Kraemer committed
591 592 593 594
}

std::string GLSLShader::findFile(const std::string filename)
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
595
	// cherche d'abord dans le repertoire courant
Pierre Kraemer's avatar
Pierre Kraemer committed
596 597 598 599 600 601 602 603 604
	std::ifstream file;
	file.open(filename.c_str(),std::ios::in );
	if (!file.fail())
	{
		file.close();
		return filename;
	}
	file.close();

605 606 607 608 609 610 611 612 613 614 615 616 617 618
	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
619
	// LA MACRO SHADERPATH contient le chemin du repertoire qui contient les fichiers textes
Pierre Kraemer's avatar
Pierre Kraemer committed
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
	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()
{
	GLenum error = glewInit();

	if (error != GLEW_OK)
639
		CGoGNerr << "Error: " << glewGetErrorString(error) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
640
	else
641
		CGoGNout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
642 643

	if (!areVBOSupported())
644
		CGoGNout << "VBO not supported !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
645 646

	if(!areShadersSupported()) {
647
		CGoGNout << "Shaders not supported !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
648 649 650 651 652 653 654
		return false;
	}
	return true; 
}

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

Pierre Kraemer's avatar
Pierre Kraemer committed
658 659 660 661
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;
	
	std::string pss = findFile(ps);
662
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
663 664

	if(!create()) {
665
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
666 667
		return false;
	}
668
	CGoGNout << "Shaders loaded (" << vs << "," << ps << ")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
669 670 671 672 673
	return true; 
}

bool GLSLShader::loadShaders(const std::string& vs, const std::string& ps, const std::string& gs, GLint inputGeometryPrimitive,GLint outputGeometryPrimitive)
{
Sylvain Thery's avatar
Sylvain Thery committed
674 675 676 677
	m_nameVS = vs;
	m_nameFS = ps;
	m_nameGS = gs;

Pierre Kraemer's avatar
Pierre Kraemer committed
678 679 680 681
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;

	std::string pss = findFile(ps);
682
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
683 684 685 686 687 688

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

	if (!geomShaderLoaded)
	{
689
		CGoGNerr << "Error while loading geometry shader" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
690 691 692 693
	}

	if(!create(inputGeometryPrimitive,outputGeometryPrimitive))
	{
694
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
695 696 697
		return false;
	}

698
	CGoGNout << "Shaders loaded (" << vs << "," << ps << "," << gs <<")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
699 700 701
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
702 703
bool GLSLShader::loadShadersFromMemory(const char* vs, const char* fs)
{
704 705 706 707 708
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;

	unsigned int sz = strlen(vs);
	m_vertex_shader_source = new char[sz+1];
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
709
	strcpy(m_vertex_shader_source, vs);
710 711 712 713 714 715

	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
716
	strcpy(m_fragment_shader_source, fs);
717

Sylvain Thery's avatar
Sylvain Thery committed
718 719 720 721 722 723
	if(!loadVertexShaderSourceString(vs)) return false;

	if(!loadFragmentShaderSourceString(fs)) return false;

	if(!create())
	{
724
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
725 726 727 728 729 730 731
		return false;
	}
	return true;
}

bool GLSLShader::loadShadersFromMemory(const char* vs, const char* fs, const char* gs, GLint inputGeometryPrimitive,GLint outputGeometryPrimitive)
{
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;

	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
753 754
	if(!loadVertexShaderSourceString(vs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
755

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
756 757
	if(!loadFragmentShaderSourceString(fs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
758

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
759 760
	if(!loadGeometryShaderSourceString(gs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
761 762 763

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

	return true;
}

771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
bool GLSLShader::reloadVertexShaderFromMemory(const char* vs)
{
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;

	unsigned int sz = strlen(vs);
	m_vertex_shader_source = new char[sz+1];
	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))
	{
818
		CGoGNerr << "Unable to create the shaders !" << CGoGNendl;
819 820 821 822 823 824 825 826 827 828 829 830 831
		return false;
	}

	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");

	restoreUniformsAttribs();

	return true;
}

832 833 834 835 836 837 838 839 840 841 842
bool GLSLShader::validateProgram()
{
	if(!m_program_object)
		return false;

	glValidateProgram(m_program_object);
	GLint Result = GL_FALSE;
	glGetProgramiv(m_program_object, GL_VALIDATE_STATUS, &Result);

	if(Result == GL_FALSE)
	{
843
		CGoGNout << "Validate program:" << CGoGNendl;
844 845 846 847
		int InfoLogLength;
		glGetProgramiv(m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
		std::vector<char> Buffer(InfoLogLength);
		glGetProgramInfoLog(m_program_object, InfoLogLength, NULL, &Buffer[0]);
848
		CGoGNout <<  &(Buffer[0]) << CGoGNendl;
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
		return false;
	}

	return true;
}

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

	int InfoLogLength;
	glGetProgramiv(m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
	std::vector<char> Buffer(std::max(InfoLogLength, int(1)));
	glGetProgramInfoLog(m_program_object, InfoLogLength, NULL, &Buffer[0]);
864
	CGoGNout << &Buffer[0] << CGoGNendl;
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886

	return Result == GL_TRUE;
}

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

	switch(shaderType)
	{
	case VERTEX_SHADER:
		id = m_vertex_shader_object;
		break;
	case FRAGMENT_SHADER:
		id = m_fragment_shader_object;
		break;
	case GEOMETRY_SHADER:
		id = m_geom_shader_object;
		break;
	default:
887
		CGoGNerr << "Error unkown shader type"<< CGoGNendl;
888 889 890 891 892 893 894 895
		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]);
896
	CGoGNout << &Buffer[0] << CGoGNendl;
897 898 899 900

	return Result == GL_TRUE;
}

Sylvain Thery's avatar
Sylvain Thery committed
901
void GLSLShader::bindAttrib(unsigned int att, const char* name) const
902
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
903
	glBindAttribLocation(m_program_object, att, name);
904 905
}

906 907 908 909 910
void GLSLShader::addPathFileSeach(const std::string& path)
{
	m_pathes.push_back(path);
}

Sylvain Thery's avatar
Sylvain Thery committed
911

912
unsigned int GLSLShader::bindVA_VBO(const std::string& name, VBO* vbo)
Sylvain Thery's avatar
Sylvain Thery committed
913 914 915 916 917
{
	GLint idVA = glGetAttribLocation(this->m_program_object, name.c_str());
	//valid ?
	if (idVA < 0)
	{
918
		CGoGNerr << "GLSLShader: Attribute "<<name<< " does not exist in shader"<< CGoGNendl;
919
		return idVA;
Sylvain Thery's avatar
Sylvain Thery committed
920 921 922 923 924 925
	}
	// 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)
		{
926 927
			it->vbo_ptr = vbo;
			return (it - m_va_vbo_binding.begin());
Sylvain Thery's avatar
Sylvain Thery committed
928 929 930 931 932
		}
	}
	// new one:
	VAStr temp;
	temp.va_id = idVA;
933
	temp.vbo_ptr = vbo;
Sylvain Thery's avatar
Sylvain Thery committed
934
	m_va_vbo_binding.push_back(temp);
935 936 937
	return (m_va_vbo_binding.size() -1);
}

938 939 940



941 942 943
void GLSLShader::changeVA_VBO(unsigned int id, VBO* vbo)
{
	m_va_vbo_binding[id].vbo_ptr = vbo;
Sylvain Thery's avatar
Sylvain Thery committed
944 945
}

946 947


Sylvain Thery's avatar
Sylvain Thery committed
948 949 950 951 952 953
void GLSLShader::unbindVA(const std::string& name)
{
	GLint idVA = glGetAttribLocation(this->m_program_object, name.c_str());
	//valid ?
	if (idVA < 0)
	{
954
		CGoGNerr << "GLSLShader: Attribute "<<name<< " does not exist in shader, not unbinded"<< CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
955 956 957 958 959 960 961 962 963 964 965 966 967 968
		return;
	}
	// search if name already exist
	unsigned int nb = m_va_vbo_binding.size();
	for (unsigned int i =0; i<nb; ++i)
	{
		if (m_va_vbo_binding[i].va_id == idVA)
		{
			if (i != (nb-1))
				m_va_vbo_binding[i] = m_va_vbo_binding[nb-1];
			m_va_vbo_binding.pop_back();
			return;
		}
	}
969
	CGoGNerr << "GLSLShader: Attribute "<<name<< " not binded"<< CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
970 971
}

972 973 974



Sylvain Thery's avatar
Sylvain Thery committed
975 976
void GLSLShader::setCurrentOGLVersion(unsigned int version)
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
977
	CURRENT_OGL_VERSION = version;
Sylvain Thery's avatar
Sylvain Thery committed
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
	switch(version)
	{
	case 2:
		DEFINES_GL = &DEFINES_GL2;
		break;
	case 3:
		DEFINES_GL = &DEFINES_GL3;
		break;
	}
}

/**
 * update projection, modelview, ... matrices
 */
void GLSLShader::updateMatrices(const glm::mat4& projection, const glm::mat4& modelview)
{
	this->bind();
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
995
	glm::mat4 PMV = projection * modelview;
996
	glm::mat4 normalMatrix = glm::gtx::inverse_transpose::inverseTranspose(modelview);
Sylvain Thery's avatar
Sylvain Thery committed
997

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
998
	if (m_uniMat_Proj >= 0)
999
		glUniformMatrix4fv(m_uniMat_Proj,		1 , false, &projection[0][0]);
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
1000
	if (m_uniMat_Model >= 0)
1001
		glUniformMatrix4fv(m_uniMat_Model,		1 , false, &modelview[0][0]);
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
1002
	if (m_uniMat_ModelProj >= 0)
1003
		glUniformMatrix4fv(m_uniMat_ModelProj,	1 , false, &PMV[0][0]);
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
1004
	if (m_uniMat_Normal >= 0)
1005 1006 1007
		glUniformMatrix4fv(m_uniMat_Normal, 	1 , false, &normalMatrix[0][0]);
}

1008
void GLSLShader::enableVertexAttribs(unsigned int stride, unsigned int begin) const
1009 1010 1011 1012 1013 1014
{
	this->bind();
	for (std::vector<Utils::GLSLShader::VAStr>::const_iterator it= m_va_vbo_binding.begin(); it != m_va_vbo_binding.end(); ++it)
	{
		glBindBuffer(GL_ARRAY_BUFFER, it->vbo_ptr->id());
		glEnableVertexAttribArray(it->va_id);
1015
		glVertexAttribPointer(it->va_id, it->vbo_ptr->dataSize(), GL_FLOAT, false, stride, (const GLvoid*)begin);
1016 1017
	}
}
Sylvain Thery's avatar
Sylvain Thery committed
1018

1019 1020 1021
void GLSLShader::disableVertexAttribs() const
{
	for (std::vector<Utils::GLSLShader::VAStr>::const_iterator it= m_va_vbo_binding.begin(); it != m_va_vbo_binding.end(); ++it)
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
		glDisableVertexAttribArray(it->va_id);
	this->unbind();
}


void GLSLShader::updateCurrentMatrices()
{
	glm::mat4 model(currentModelView());
	model *= currentTransfo();

	for(std::set< std::pair<void*, GLSLShader*> >::iterator it = m_registeredShaders.begin();it != m_registeredShaders.end();++it)
			it->second->updateMatrices(currentProjection(), model);
Sylvain Thery's avatar
Sylvain Thery committed
1034
}
Pierre Kraemer's avatar
Pierre Kraemer committed
1035

1036 1037 1038



Pierre Kraemer's avatar
Pierre Kraemer committed
1039
} // namespace Utils
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
1040

Pierre Kraemer's avatar
Pierre Kraemer committed
1041
} // namespace CGoGN