GLSLShader.cpp 31.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-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>
Sylvain Thery's avatar
Sylvain Thery committed
31
#include <algorithm>
32
#include "Utils/cgognStream.h"
Pierre Kraemer's avatar
Pierre Kraemer committed
33

Sylvain Thery's avatar
Sylvain Thery committed
34
#include "glm/gtc/matrix_inverse.hpp"
Sylvain Thery's avatar
Sylvain Thery committed
35

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

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

42 43 44
#ifdef USE_OGL_CORE_PROFILE
unsigned int GLSLShader::CURRENT_OGL_VERSION = 3;
#else
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
45
unsigned int GLSLShader::CURRENT_OGL_VERSION = 2;
46 47 48 49 50
#endif

unsigned int GLSLShader::MAJOR_OGL_CORE = 3;
unsigned int GLSLShader::MINOR_OGL_CORE = 3;

Sylvain Thery's avatar
Sylvain Thery committed
51 52 53

std::string GLSLShader::DEFINES_GL2=\
"#version 110\n"
54
"#define PRECISION float pipo_PRECISION\n"
Sylvain Thery's avatar
Sylvain Thery committed
55 56 57
"#define ATTRIBUTE attribute\n"
"#define VARYING_VERT varying\n"
"#define VARYING_FRAG varying\n"
58
"#define FRAG_OUT_DEF float pipo_FRAGDEF\n"
59
"#define FRAG_OUT gl_FragColor\n"
60
"#define INVARIANT_POS float pipo_INVARIANT\n";
Sylvain Thery's avatar
Sylvain Thery committed
61

Pierre Kraemer's avatar
Pierre Kraemer committed
62

Sylvain Thery's avatar
Sylvain Thery committed
63
std::string GLSLShader::DEFINES_GL3=\
64
"#version 150\n"
65
"#define PRECISION precision highp float\n"
Sylvain Thery's avatar
Sylvain Thery committed
66
"#define ATTRIBUTE in\n"
sylvain thery's avatar
sylvain thery committed
67 68
"#define VARYING_VERT out\n"
"#define VARYING_FRAG in\n"
69 70
"#define FRAG_OUT_DEF out vec4 outFragColor\n"
"#define FRAG_OUT outFragColor\n"
71
"#define INVARIANT_POS invariant gl_Position\n";
Sylvain Thery's avatar
Sylvain Thery committed
72

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
73 74

std::string* GLSLShader::DEFINES_GL = NULL;
75 76 77

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

78
std::set< std::pair<void*, GLSLShader*> >* GLSLShader::m_registeredShaders = NULL;
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
79

80 81 82
//glm::mat4* GLSLShader::s_current_matrices=NULL;
Utils::GL_Matrices* GLSLShader::s_current_matrices=NULL;

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
83
GLSLShader::GLSLShader() :
84
	m_vao(0),
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
85 86 87
	m_vertex_shader_source(NULL),
	m_fragment_shader_source(NULL),
	m_geom_shader_source(NULL)
Pierre Kraemer's avatar
Pierre Kraemer committed
88
{
89 90 91 92 93 94 95 96 97
	*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
98
	if (DEFINES_GL == NULL)
99
		DEFINES_GL = &DEFINES_GL2;
Sylvain Thery's avatar
Sylvain Thery committed
100 101

	m_nbMaxVertices = 16;
102 103 104

	if (m_registeredShaders==NULL)
		m_registeredShaders = new std::set< std::pair<void*, GLSLShader*> >;
Pierre Kraemer's avatar
Pierre Kraemer committed
105 106
}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
107
void GLSLShader::registerShader(void* ptr, GLSLShader* shader)
108
{
109
	m_registeredShaders->insert(std::pair<void*,GLSLShader*>(ptr, shader));
110 111
}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
112
void GLSLShader::unregisterShader(void* ptr, GLSLShader* shader)
113
{
114
	m_registeredShaders->erase(std::pair<void*,GLSLShader*>(ptr, shader));
115 116 117 118
}

std::string GLSLShader::defines_Geom(const std::string& primitivesIn, const std::string& primitivesOut, int maxVert)
{
119
	if (CURRENT_OGL_VERSION >= 3)
120 121 122 123 124 125 126 127 128 129 130 131 132 133
	{
		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");
sylvain thery's avatar
sylvain thery committed
134 135
		str.append("#define VARYING_IN in\n");
		str.append("#define VARYING_OUT out\n");
136
		str.append("#define POSITION_IN(X) gl_in[X].gl_Position\n");
137
		str.append("#define NBVERTS_IN gl_in.length()\n");
138 139 140 141
		return str;
	}
	else
	{
Sylvain Thery's avatar
Sylvain Thery committed
142 143
		std::string str("#version 110\n");
		str.append("#extension GL_EXT_geometry_shader4 : enable\n");
kvanhoey's avatar
kvanhoey committed
144
		str.append("#define PRECISION float pipo_PRECISION\n");
145 146 147 148
		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");
149
		str.append("#define NBVERTS_IN gl_VerticesIn\n");
150 151 152 153
		return str;
	}
}

Pierre Kraemer's avatar
Pierre Kraemer committed
154 155
bool GLSLShader::areGeometryShadersSupported()
{
156
	if (!glewGetExtension("GL_ARB_geometry_shader4"))
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
157
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
158 159 160 161 162 163
	return true;
}


bool GLSLShader::areVBOSupported()
{
164
	if (!glewGetExtension("GL_vertex_buffer_object"))
Pierre Kraemer's avatar
Pierre Kraemer committed
165 166 167 168
		return false;
	return true;
}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
169
char* GLSLShader::loadSourceFile(const std::string& filename)
Pierre Kraemer's avatar
Pierre Kraemer committed
170 171 172 173 174 175 176 177 178 179
{
	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() )
	{
180
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - unable to open the file " << filename << "." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
		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 )
	{
201
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - " << io_exception.what() << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
202 203 204 205 206 207 208 209 210 211 212 213
		file.close();
		return NULL;
	}

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

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

216 217
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
218
	m_vertex_shader_source = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
219

220
	m_vertex_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
221

222
	if( !m_vertex_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
223
	{
224
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
225 226 227
		return false;
	}

228 229
	flag = loadVertexShaderSourceString( m_vertex_shader_source );
//	delete [] vertex_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
230 231 232 233

	return flag;
}

234
bool GLSLShader::loadFragmentShader(const std::string& filename )
Pierre Kraemer's avatar
Pierre Kraemer committed
235 236
{
	bool	flag;
237
//	char	*fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
238

239 240
	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;
241
	m_fragment_shader_source = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
242

243
	m_fragment_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
244

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

251 252
	flag = loadFragmentShaderSourceString( m_fragment_shader_source );
//	delete [] fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
253 254 255 256 257 258 259

	return flag;
}

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

262 263
	if (m_geom_shader_source)
		delete [] m_geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
264

265
	m_geom_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
266

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

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

	return flag;
}

Sylvain Thery's avatar
Sylvain Thery committed
279
bool GLSLShader::logError(GLuint handle, const std::string& nameSrc, const char *src)
Pierre Kraemer's avatar
Pierre Kraemer committed
280
{
Sylvain Thery's avatar
Sylvain Thery committed
281
	char *info_log;
282
	info_log = getInfoLogShader( handle );
Sylvain Thery's avatar
Sylvain Thery committed
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	if (info_log!=NULL)
	{
		CGoGNerr << "============================================================================" << CGoGNendl;
		CGoGNerr << "Error in " << nameSrc << CGoGNendl;
		CGoGNerr << "----------------------------------------------------------------------------" << CGoGNendl;
		char line[256];
		int ln=1;
		std::stringstream ss(src);
		do
		{
			ss.getline(line,256);
			std::cout << ln++ << ": "<< line<< std::endl;
		}while (!ss.eof());
		CGoGNerr << "----------------------------------------------------------------------------" << CGoGNendl;
		CGoGNerr << info_log;
		CGoGNerr << "============================================================================" << CGoGNendl;
		delete [] info_log;
		return false;
	}
	return true;
}
Pierre Kraemer's avatar
Pierre Kraemer committed
304

Sylvain Thery's avatar
Sylvain Thery committed
305 306
bool GLSLShader::loadVertexShaderSourceString( const char *vertex_shader_source )
{
307
	if (*m_vertex_shader_object!=0)
Sylvain Thery's avatar
Sylvain Thery committed
308
	{
309 310
		glDeleteShader(*m_vertex_shader_object);
		*m_vertex_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
311
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
312 313

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

316
	if( !*m_vertex_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
317
	{
318
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
319 320 321 322 323 324
		return false;
	}

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

327
		glDeleteShader(*m_vertex_shader_object );
328
		*m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
329 330 331 332

		return false;
	}

333
	glShaderSource( *m_vertex_shader_object, 1, (const char**)&vertex_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
334 335

	/*** compile shader object ***/
336
	glCompileShader( *m_vertex_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
337

Sylvain Thery's avatar
Sylvain Thery committed
338
	if (!logError(*m_vertex_shader_object, m_nameVS, vertex_shader_source))
Pierre Kraemer's avatar
Pierre Kraemer committed
339
	{
340
		glDeleteShader( *m_vertex_shader_object );
341
		*m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
342 343 344 345 346 347 348
		return false;
	}

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

349
bool GLSLShader::loadFragmentShaderSourceString( const char *fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
350
{
351
	if (*m_fragment_shader_object!=0)
Sylvain Thery's avatar
Sylvain Thery committed
352
	{
353 354
		glDeleteShader(*m_fragment_shader_object);
		*m_fragment_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
355
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
356 357

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

360
	if( !*m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
361
	{
362
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
363 364 365 366
		return false;
	}

	/*** load source file ***/
367
	if( !fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
368
	{
369
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - source string is empty." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
370

371
		glDeleteShader( *m_fragment_shader_object );
372
		*m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
373 374 375 376

		return false;
	}

377
	glShaderSource( *m_fragment_shader_object, 1, (const char**)&fragment_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
378 379

	/*** compile shader object ***/
380
	glCompileShader( *m_fragment_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
381

Sylvain Thery's avatar
Sylvain Thery committed
382
	if (!logError(*m_fragment_shader_object, m_nameFS, fragment_shader_source))
Pierre Kraemer's avatar
Pierre Kraemer committed
383
	{
384
		glDeleteShader( *m_fragment_shader_object );
385
		*m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
386 387 388 389 390 391 392 393 394
		return false;
	}

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

bool GLSLShader::loadGeometryShaderSourceString( const char *geom_shader_source )
{
395
	if (*m_geom_shader_object!=0)
Sylvain Thery's avatar
Sylvain Thery committed
396
	{
397 398
		glDeleteShader(*m_geom_shader_object);
		*m_geom_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
399
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
400
	/*** create shader object ***/
Sylvain Thery's avatar
Sylvain Thery committed
401
	*m_geom_shader_object = glCreateShader(GL_GEOMETRY_SHADER);
Pierre Kraemer's avatar
Pierre Kraemer committed
402

403
	if( !*m_geom_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
404
	{
405
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
406 407 408 409 410 411
		return false;
	}

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

414
		glDeleteShader( *m_geom_shader_object );
415
		*m_geom_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
416 417 418 419

		return false;
	}

420
	glShaderSource( *m_geom_shader_object, 1, (const char**)&geom_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
421 422

	/*** compile shader object ***/
423
	glCompileShader( *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
424

Sylvain Thery's avatar
Sylvain Thery committed
425
	if (!logError(*m_geom_shader_object, m_nameGS, geom_shader_source))
Pierre Kraemer's avatar
Pierre Kraemer committed
426
	{
427
		glDeleteShader( *m_geom_shader_object );
428
		*m_geom_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
429 430 431 432 433 434 435
		return false;
	}

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

436
char* GLSLShader::getInfoLog( GLuint obj )
Pierre Kraemer's avatar
Pierre Kraemer committed
437
{
438 439 440
	char* info_log;
	int info_log_length;
	int length;
Pierre Kraemer's avatar
Pierre Kraemer committed
441

442
	glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &info_log_length);
Sylvain Thery's avatar
Sylvain Thery committed
443 444 445

	if (info_log_length <= 1)
		return NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
446 447

	info_log = new char [info_log_length];
448
	glGetProgramInfoLog( obj, info_log_length, &length, info_log );
Pierre Kraemer's avatar
Pierre Kraemer committed
449 450 451 452

	return info_log;
}

453 454
char* GLSLShader::getInfoLogShader( GLuint obj )
{
455 456 457
	char* info_log;
	int	info_log_length;
	int	length;
458 459 460 461 462 463 464 465 466 467 468 469

    glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &info_log_length);

    if (info_log_length <= 1)
        return NULL;

    info_log = new char [info_log_length+1];
    glGetShaderInfoLog( obj, info_log_length, &length, info_log );
    info_log[info_log_length]=0;
    return info_log;
}

Sylvain Thery's avatar
Sylvain Thery committed
470
bool GLSLShader::create(GLint inputGeometryPrimitive,GLint outputGeometryPrimitive, int nb_max_vertices)
Pierre Kraemer's avatar
Pierre Kraemer committed
471
{
472 473
	int	status;
	char* info_log;
Pierre Kraemer's avatar
Pierre Kraemer committed
474

475
	if (nb_max_vertices != -1)
Sylvain Thery's avatar
Sylvain Thery committed
476 477
		m_nbMaxVertices = nb_max_vertices;

478 479
	m_geom_inputPrimitives = inputGeometryPrimitive;
	m_geom_outputPrimitives = outputGeometryPrimitive;
Pierre Kraemer's avatar
Pierre Kraemer committed
480 481

	/*** check if shaders are loaded ***/
482
	if( !*m_vertex_shader_object || !*m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
483
	{
484
		CGoGNerr << "ERROR - GLSLShader::create() - shaders are not defined." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
485 486 487 488
		return false;
	}

	/*** create program object ***/
489
	m_program_object = glCreateProgram();
Pierre Kraemer's avatar
Pierre Kraemer committed
490

491
	if( !*m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
492
	{
493
		CGoGNerr << "ERROR - GLSLShader::create() - unable to create program object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
494 495 496 497
		return false;
	}

	/*** attach shaders to program object ***/
498 499
	glAttachShader( *m_program_object, *m_vertex_shader_object );
	glAttachShader( *m_program_object, *m_fragment_shader_object );
500
	if (*m_geom_shader_object)
Pierre Kraemer's avatar
Pierre Kraemer committed
501
	{
502
		glAttachShader( *m_program_object, *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
503

504 505 506 507 508 509
		if (CURRENT_OGL_VERSION == 2)
		{
			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
510 511 512
	}

	/*** link program object ***/
513
	glLinkProgram( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
514

515
	glGetProgramiv( *m_program_object, GL_LINK_STATUS, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
516 517
	if( !status )
	{
518
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
519
		info_log = getInfoLog( *m_program_object );
520
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
521 522
		delete [] info_log;

523 524
		glDetachShader( *m_program_object, *m_vertex_shader_object );
		glDetachShader( *m_program_object, *m_fragment_shader_object );
525
		if (*m_geom_shader_object)
526 527
			glDetachShader( *m_program_object, *m_geom_shader_object );
		glDeleteShader( *m_program_object );
528
		*m_program_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
529 530 531 532

		return false;
	}

533 534 535 536
	*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");
537

Pierre Kraemer's avatar
Pierre Kraemer committed
538 539 540
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
541 542 543
bool GLSLShader::changeNbMaxVertices(int nb_max_vertices)
{
	m_nbMaxVertices = nb_max_vertices;
544
	if ((*m_geom_shader_object) && (CURRENT_OGL_VERSION == 2))
Sylvain Thery's avatar
Sylvain Thery committed
545
	{
546
		glProgramParameteriEXT(*m_program_object, GL_GEOMETRY_VERTICES_OUT_EXT, m_nbMaxVertices);
Sylvain Thery's avatar
Sylvain Thery committed
547 548 549 550 551 552
		// need to relink
		return true;
	}
	return false;
}

553 554 555 556 557 558
bool GLSLShader::link()
{
	int		status;
	char	*info_log;

	/*** link program object ***/
559
	glLinkProgram( *m_program_object );
560

561
	glGetProgramiv( *m_program_object, GL_OBJECT_LINK_STATUS_ARB, &status );
562 563
	if( !status )
	{
564
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
565
		info_log = getInfoLog( *m_program_object );
566
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
567 568
		delete [] info_log;

569 570
		glDetachShader( *m_program_object, *m_vertex_shader_object );
		glDetachShader( *m_program_object, *m_fragment_shader_object );
571
		if (*m_geom_shader_object)
572 573
			glDetachShader( *m_program_object, *m_geom_shader_object );
		glDeleteShader( *m_program_object );
574
		*m_program_object = 0;
575 576 577 578 579 580

		return false;
	}
	return true;
}

581
bool GLSLShader::bind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
582
{
583
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
584
	{
585
		glUseProgram( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
586 587
		return true;
	}
588 589
	else
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
590 591
}

592
void GLSLShader::unbind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
593
{
594
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
595
	{
596
		glUseProgram( 0 );
Pierre Kraemer's avatar
Pierre Kraemer committed
597 598 599 600 601
	}
}

bool GLSLShader::isBinded()
{
602 603 604 605 606 607
	if (*m_program_object == 0)
		return false;

	GLint po;
	glGetIntegerv(GL_CURRENT_PROGRAM,&po);
	return ( *m_program_object == po );
Pierre Kraemer's avatar
Pierre Kraemer committed
608 609 610 611
}

GLSLShader::~GLSLShader()
{
612
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
613 614 615
	{
		unbind();

616
		if( *m_vertex_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
617
		{
618 619
			glDetachShader( *m_program_object, *m_vertex_shader_object );
			glDeleteShader( *m_vertex_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
620
		}
621
		if( *m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
622
		{
623 624
			glDetachShader( *m_program_object, *m_fragment_shader_object );
			glDeleteShader( *m_fragment_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
625
		}
626
		if (*m_geom_shader_object)
Pierre Kraemer's avatar
Pierre Kraemer committed
627
		{
628 629
			glDetachShader( *m_program_object, *m_geom_shader_object );
			glDeleteShader( *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
630 631
		}

632
		glDeleteShader( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
633
	}
634

635 636 637 638 639 640 641
	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;

642
//	m_registeredShaders->erase(this);
Pierre Kraemer's avatar
Pierre Kraemer committed
643 644 645 646
}

std::string GLSLShader::findFile(const std::string filename)
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
647
	// cherche d'abord dans le repertoire courant
Pierre Kraemer's avatar
Pierre Kraemer committed
648 649 650 651 652 653 654 655 656
	std::ifstream file;
	file.open(filename.c_str(),std::ios::in );
	if (!file.fail())
	{
		file.close();
		return filename;
	}
	file.close();

657 658 659 660 661 662 663 664 665 666 667 668 669 670
	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
671
	// LA MACRO SHADERPATH contient le chemin du repertoire qui contient les fichiers textes
Pierre Kraemer's avatar
Pierre Kraemer committed
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
	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()
{
688
#ifndef GLEW_MX
Pierre Kraemer's avatar
Pierre Kraemer committed
689 690 691
	GLenum error = glewInit();

	if (error != GLEW_OK)
692
		CGoGNerr << "Error: " << glewGetErrorString(error) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
693
	else
694
		CGoGNout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
695 696

	if (!areVBOSupported())
697
		CGoGNerr << "VBO not supported !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
698

699 700 701
	if  ((CURRENT_OGL_VERSION == 2) && (!glewIsSupported("GL_VERSION_2_0")))
	{
		CGoGNerr << " GL 2.0 not supported" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
702 703
		return false;
	}
704 705 706 707 708 709 710

	if ((CURRENT_OGL_VERSION == 3) && (!glewIsSupported("GL_VERSION_3_3")))
	{
		CGoGNerr << " GL 3.3 not supported" << CGoGNendl;
		return false;
	}

711 712 713
#endif
	return true;

Pierre Kraemer's avatar
Pierre Kraemer committed
714 715 716 717
}

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

Pierre Kraemer's avatar
Pierre Kraemer committed
721 722 723 724
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;
	
	std::string pss = findFile(ps);
725
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
726 727

	if(!create()) {
728
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
729 730
		return false;
	}
731
	CGoGNout << "Shaders loaded (" << vs << "," << ps << ")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
732 733 734
	return true; 
}

Sylvain Thery's avatar
Sylvain Thery committed
735
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
736
{
Sylvain Thery's avatar
Sylvain Thery committed
737 738 739 740
	m_nameVS = vs;
	m_nameFS = ps;
	m_nameGS = gs;

Pierre Kraemer's avatar
Pierre Kraemer committed
741 742 743 744
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;

	std::string pss = findFile(ps);
745
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
746 747 748 749 750 751

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

	if (!geomShaderLoaded)
	{
752
		CGoGNerr << "Error while loading geometry shader" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
753 754
	}

Sylvain Thery's avatar
Sylvain Thery committed
755
	if(!create(inputGeometryPrimitive,outputGeometryPrimitive,nb_max_vertices))
Pierre Kraemer's avatar
Pierre Kraemer committed
756
	{
757
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
758 759 760
		return false;
	}

761
	CGoGNout << "Shaders loaded (" << vs << "," << ps << "," << gs <<")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
762 763 764
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
765 766
bool GLSLShader::loadShadersFromMemory(const char* vs, const char* fs)
{
767 768
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
769
	m_vertex_shader_source = NULL;
770 771 772

	unsigned int sz = strlen(vs);
	m_vertex_shader_source = new char[sz+1];
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
773
	strcpy(m_vertex_shader_source, vs);
774 775 776 777 778 779

	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
780
	strcpy(m_fragment_shader_source, fs);
781

782 783
	if(!loadVertexShaderSourceString(vs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
784

785 786
	if(!loadFragmentShaderSourceString(fs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
787 788 789

	if(!create())
	{
790
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
791 792 793 794 795
		return false;
	}
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
796
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
797
{
798 799
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
800
	m_vertex_shader_source = NULL;
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819

	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
820 821
	if(!loadVertexShaderSourceString(vs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
822

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
823 824
	if(!loadFragmentShaderSourceString(fs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
825

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
826 827
	if(!loadGeometryShaderSourceString(gs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
828

829
	if(!create(inputGeometryPrimitive, outputGeometryPrimitive, nb_max_vertices))
Sylvain Thery's avatar
Sylvain Thery committed
830
	{
831
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
832 833 834 835 836 837
		return false;
	}

	return true;
}

838 839 840 841
bool GLSLShader::reloadVertexShaderFromMemory(const char* vs)
{
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
842
	m_vertex_shader_source = NULL;
843 844 845

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

847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
	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))
	{
887
		CGoGNerr << "Unable to create the shaders !" << CGoGNendl;
888 889 890
		return false;
	}

891 892 893
	*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
894
	*m_uniMat_Normal	= glGetUniformLocation(*m_program_object,"NormalMatrix");
895 896 897

	restoreUniformsAttribs();

898 899
	updateClippingUniforms();

900 901 902
	return true;
}

903 904
bool GLSLShader::validateProgram()
{
905
	if(!*m_program_object)
906 907
		return false;

908
	glValidateProgram(*m_program_object);
909
	GLint Result = GL_FALSE;
910
	glGetProgramiv(*m_program_object, GL_VALIDATE_STATUS, &Result);
911 912 913

	if(Result == GL_FALSE)
	{
914
		CGoGNout << "Validate program:" << CGoGNendl;
915
		int InfoLogLength;
916
		glGetProgramiv(*m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
917
		std::vector<char> Buffer(InfoLogLength);
918
		glGetProgramInfoLog(*m_program_object, InfoLogLength, NULL, &Buffer[0]);
919
		CGoGNout <<  &(Buffer[0]) << CGoGNendl;
920 921 922 923 924 925 926 927 928
		return false;
	}

	return true;
}

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

	int InfoLogLength;
932
	glGetProgramiv(*m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
933
	std::vector<char> Buffer(std::max(InfoLogLength, int(1)));
934
	glGetProgramInfoLog(*m_program_object, InfoLogLength, NULL, &Buffer[0]);
935
	CGoGNout << &Buffer[0] << CGoGNendl;
936 937 938 939 940 941 942 943

	return Result == GL_TRUE;
}

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