GLSLShader.cpp 32.8 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

Sylvain Thery's avatar
Sylvain Thery committed
25
#define CGoGN_UTILS_DLL_EXPORT 1
Pierre Kraemer's avatar
Pierre Kraemer committed
26 27 28 29

#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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
//#ifdef CGOGN_USE_OGL_CORE_PROFILE
//unsigned int GLSLShader::CURRENT_OGL_VERSION = 3;
//unsigned int GLSLShader::MAJOR_OGL_CORE = 3;
//unsigned int GLSLShader::MINOR_OGL_CORE = 3;
//#else
//unsigned int GLSLShader::CURRENT_OGL_VERSION = 2;
//unsigned int GLSLShader::MAJOR_OGL_CORE = 2;
//unsigned int GLSLShader::MINOR_OGL_CORE = 1;
//#endif



//std::string GLSLShader::DEFINES_GL2=\
//"#version 110\n"
//"#define PRECISION float pipo_PRECISION\n"
//"#define ATTRIBUTE attribute\n"
//"#define VARYING_VERT varying\n"
//"#define VARYING_FRAG varying\n"
//"#define FRAG_OUT_DEF float pipo_FRAGDEF\n"
//"#define FRAG_OUT gl_FragColor\n"
//"#define INVARIANT_POS float pipo_INVARIANT\n"
//"#define TEXTURE2D texture2D\n";


//std::string GLSLShader::DEFINES_GL3=\
//"#version 150\n"
//"#define PRECISION precision highp float\n"
//"#define ATTRIBUTE in\n"
//"#define VARYING_VERT out\n"
//"#define VARYING_FRAG in\n"
//"#define FRAG_OUT_DEF out vec4 outFragColor\n"
//"#define FRAG_OUT outFragColor\n"
//"#define INVARIANT_POS invariant gl_Position\n"
//"#define TEXTURE2D texture\n";


//std::string* GLSLShader::DEFINES_GL = NULL;
79 80 81

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

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

84 85 86
//glm::mat4* GLSLShader::s_current_matrices=NULL;
Utils::GL_Matrices* GLSLShader::s_current_matrices=NULL;

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

102 103
//	if (DEFINES_GL == NULL)
//		setCurrentOGLVersion(MAJOR_OGL_CORE,MINOR_OGL_CORE);
Sylvain Thery's avatar
Sylvain Thery committed
104 105

	m_nbMaxVertices = 16;
106 107 108

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

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
111
void GLSLShader::registerShader(void* ptr, GLSLShader* shader)
112
{
113
	m_registeredShaders->insert(std::pair<void*,GLSLShader*>(ptr, shader));
114 115
}

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

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
std::string GLSLShader::defines_gl()
{
#ifdef CGOGN_USE_OGL_CORE_PROFILE
	return std::string("#version 330\n\
#define PRECISION precision highp float\n\
#define ATTRIBUTE in\n\
#define VARYING_VERT out\n\
#define VARYING_FRAG in\n\
#define FRAG_OUT_DEF out vec4 outFragColor\n\
#define FRAG_OUT outFragColor\n\
#define INVARIANT_POS invariant gl_Position\n\
#define TEXTURE2D texture\n");
#else
	return std::string("#version 110\n \
#define PRECISION float pipo_PRECISION\n\
#define ATTRIBUTE attribute\n\
#define VARYING_VERT varying\n\
#define VARYING_FRAG varying\n\
#define FRAG_OUT_DEF float pipo_FRAGDEF\n\
#define FRAG_OUT gl_FragColor\n\
#define INVARIANT_POS float pipo_INVARIANT\n\
#define TEXTURE2D texture2D\n");
#endif
}

146 147
std::string GLSLShader::defines_Geom(const std::string& primitivesIn, const std::string& primitivesOut, int maxVert)
{
148
	if (CURRENT_OGL_VERSION >= 3)
149
	{
150
		std::string str("#version 330\n");
151 152 153 154 155 156 157 158 159 160 161 162
		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
163 164
		str.append("#define VARYING_IN in\n");
		str.append("#define VARYING_OUT out\n");
165
		str.append("#define POSITION_IN(X) gl_in[X].gl_Position\n");
166
		str.append("#define NBVERTS_IN gl_in.length()\n");
167 168 169 170
		return str;
	}
	else
	{
Sylvain Thery's avatar
Sylvain Thery committed
171 172
		std::string str("#version 110\n");
		str.append("#extension GL_EXT_geometry_shader4 : enable\n");
kvanhoey's avatar
kvanhoey committed
173
		str.append("#define PRECISION float pipo_PRECISION\n");
174 175 176 177
		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");
178
		str.append("#define NBVERTS_IN gl_VerticesIn\n");
179 180 181 182
		return str;
	}
}

Pierre Kraemer's avatar
Pierre Kraemer committed
183 184
bool GLSLShader::areGeometryShadersSupported()
{
185
	if (!glewGetExtension("GL_ARB_geometry_shader4"))
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
186
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
187 188 189 190 191 192
	return true;
}


bool GLSLShader::areVBOSupported()
{
193
	if (!glewGetExtension("GL_vertex_buffer_object"))
Pierre Kraemer's avatar
Pierre Kraemer committed
194 195 196 197
		return false;
	return true;
}

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
198
char* GLSLShader::loadSourceFile(const std::string& filename)
Pierre Kraemer's avatar
Pierre Kraemer committed
199 200 201 202 203 204 205 206 207 208
{
	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() )
	{
209
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - unable to open the file " << filename << "." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
210 211 212 213 214 215 216 217
		return NULL;
	}

	/*** reading file ***/
	try
	{
		/* get file size */
		file.seekg( 0, std::ios::end );
218
		file_size = int(file.tellg());
Pierre Kraemer's avatar
Pierre Kraemer committed
219 220 221 222 223 224 225 226 227 228 229
		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 )
	{
230
		CGoGNerr << "ERROR - GLSLShader::loadSourceFile() - " << io_exception.what() << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
231 232 233 234 235 236 237 238 239 240 241 242
		file.close();
		return NULL;
	}

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

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

245 246
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
247
	m_vertex_shader_source = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
248

249
	m_vertex_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
250

251
	if( !m_vertex_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
252
	{
253
		CGoGNerr << "ERROR - GLSLShader::loadVertexShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
254 255 256
		return false;
	}

257 258
	flag = loadVertexShaderSourceString( m_vertex_shader_source );
//	delete [] vertex_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
259 260 261 262

	return flag;
}

263
bool GLSLShader::loadFragmentShader(const std::string& filename )
Pierre Kraemer's avatar
Pierre Kraemer committed
264 265
{
	bool	flag;
266
//	char	*fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
267

268 269
	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;
270
	m_fragment_shader_source = NULL;
Pierre Kraemer's avatar
Pierre Kraemer committed
271

272
	m_fragment_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
273

274
	if( !m_fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
275
	{
276
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
277 278 279
		return false;
	}

280 281
	flag = loadFragmentShaderSourceString( m_fragment_shader_source );
//	delete [] fragment_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
282 283 284 285 286 287 288

	return flag;
}

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

291 292
	if (m_geom_shader_source)
		delete [] m_geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
293

294
	m_geom_shader_source = loadSourceFile( filename );
Pierre Kraemer's avatar
Pierre Kraemer committed
295

296
	if( !m_geom_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
297
	{
298
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - error occured while loading source file." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
299 300 301
		return false;
	}

302 303
	flag = loadGeometryShaderSourceString( m_geom_shader_source );
//	delete [] geom_shader_source;
Pierre Kraemer's avatar
Pierre Kraemer committed
304 305 306 307

	return flag;
}

Sylvain Thery's avatar
Sylvain Thery committed
308
bool GLSLShader::logError(GLuint handle, const std::string& nameSrc, const char *src)
Pierre Kraemer's avatar
Pierre Kraemer committed
309
{
Sylvain Thery's avatar
Sylvain Thery committed
310
	char *info_log;
311
	info_log = getInfoLogShader( handle );
Sylvain Thery's avatar
Sylvain Thery committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
	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
333

Sylvain Thery's avatar
Sylvain Thery committed
334 335
bool GLSLShader::loadVertexShaderSourceString( const char *vertex_shader_source )
{
336
	if (*m_vertex_shader_object!=0)
Sylvain Thery's avatar
Sylvain Thery committed
337
	{
338 339
		glDeleteShader(*m_vertex_shader_object);
		*m_vertex_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
340
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
341 342

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

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

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

356
		glDeleteShader(*m_vertex_shader_object );
357
		*m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
358 359 360 361

		return false;
	}

362
	glShaderSource( *m_vertex_shader_object, 1, (const char**)&vertex_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
363 364

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

Sylvain Thery's avatar
Sylvain Thery committed
367
	if (!logError(*m_vertex_shader_object, m_nameVS, vertex_shader_source))
Pierre Kraemer's avatar
Pierre Kraemer committed
368
	{
369
		glDeleteShader( *m_vertex_shader_object );
370
		*m_vertex_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
371 372 373 374 375 376 377
		return false;
	}

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

378
bool GLSLShader::loadFragmentShaderSourceString( const char *fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
379
{
380
	if (*m_fragment_shader_object!=0)
Sylvain Thery's avatar
Sylvain Thery committed
381
	{
382 383
		glDeleteShader(*m_fragment_shader_object);
		*m_fragment_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
384
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
385 386

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

389
	if( !*m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
390
	{
391
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
392 393 394 395
		return false;
	}

	/*** load source file ***/
396
	if( !fragment_shader_source )
Pierre Kraemer's avatar
Pierre Kraemer committed
397
	{
398
		CGoGNerr << "ERROR - GLSLShader::loadFragmentShader() - source string is empty." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
399

400
		glDeleteShader( *m_fragment_shader_object );
401
		*m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
402 403 404 405

		return false;
	}

406
	glShaderSource( *m_fragment_shader_object, 1, (const char**)&fragment_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
407 408

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

Sylvain Thery's avatar
Sylvain Thery committed
411
	if (!logError(*m_fragment_shader_object, m_nameFS, fragment_shader_source))
Pierre Kraemer's avatar
Pierre Kraemer committed
412
	{
413
		glDeleteShader( *m_fragment_shader_object );
414
		*m_fragment_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
415 416 417 418 419 420 421 422 423
		return false;
	}

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

bool GLSLShader::loadGeometryShaderSourceString( const char *geom_shader_source )
{
424
	if (*m_geom_shader_object!=0)
Sylvain Thery's avatar
Sylvain Thery committed
425
	{
426 427
		glDeleteShader(*m_geom_shader_object);
		*m_geom_shader_object=0;
Sylvain Thery's avatar
Sylvain Thery committed
428
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
429
	/*** create shader object ***/
Sylvain Thery's avatar
Sylvain Thery committed
430
	*m_geom_shader_object = glCreateShader(GL_GEOMETRY_SHADER);
Pierre Kraemer's avatar
Pierre Kraemer committed
431

432
	if( !*m_geom_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
433
	{
434
		CGoGNerr << "ERROR - GLSLShader::loadGeometryShader() - unable to create shader object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
435 436 437 438 439 440
		return false;
	}

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

443
		glDeleteShader( *m_geom_shader_object );
444
		*m_geom_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
445 446 447 448

		return false;
	}

449
	glShaderSource( *m_geom_shader_object, 1, (const char**)&geom_shader_source, NULL );
Pierre Kraemer's avatar
Pierre Kraemer committed
450 451

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

Sylvain Thery's avatar
Sylvain Thery committed
454
	if (!logError(*m_geom_shader_object, m_nameGS, geom_shader_source))
Pierre Kraemer's avatar
Pierre Kraemer committed
455
	{
456
		glDeleteShader( *m_geom_shader_object );
457
		*m_geom_shader_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
458 459 460 461 462 463 464
		return false;
	}

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

465
char* GLSLShader::getInfoLog( GLuint obj )
Pierre Kraemer's avatar
Pierre Kraemer committed
466
{
467 468 469
	char* info_log;
	int info_log_length;
	int length;
Pierre Kraemer's avatar
Pierre Kraemer committed
470

471
	glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &info_log_length);
Sylvain Thery's avatar
Sylvain Thery committed
472 473 474

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

	info_log = new char [info_log_length];
477
	glGetProgramInfoLog( obj, info_log_length, &length, info_log );
Pierre Kraemer's avatar
Pierre Kraemer committed
478 479 480 481

	return info_log;
}

482 483
char* GLSLShader::getInfoLogShader( GLuint obj )
{
484 485 486
	char* info_log;
	int	info_log_length;
	int	length;
487 488 489 490 491 492 493 494 495 496 497 498

    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
499
bool GLSLShader::create(GLint inputGeometryPrimitive,GLint outputGeometryPrimitive, int nb_max_vertices)
Pierre Kraemer's avatar
Pierre Kraemer committed
500
{
501 502
	int	status;
	char* info_log;
Pierre Kraemer's avatar
Pierre Kraemer committed
503

504
	if (nb_max_vertices != -1)
Sylvain Thery's avatar
Sylvain Thery committed
505 506
		m_nbMaxVertices = nb_max_vertices;

507 508
	m_geom_inputPrimitives = inputGeometryPrimitive;
	m_geom_outputPrimitives = outputGeometryPrimitive;
Pierre Kraemer's avatar
Pierre Kraemer committed
509 510

	/*** check if shaders are loaded ***/
511
	if( !*m_vertex_shader_object || !*m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
512
	{
513
		CGoGNerr << "ERROR - GLSLShader::create() - shaders are not defined." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
514 515 516 517
		return false;
	}

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

520
	if( !*m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
521
	{
522
		CGoGNerr << "ERROR - GLSLShader::create() - unable to create program object." << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
523 524 525 526
		return false;
	}

	/*** attach shaders to program object ***/
527 528
	glAttachShader( *m_program_object, *m_vertex_shader_object );
	glAttachShader( *m_program_object, *m_fragment_shader_object );
529
	if (*m_geom_shader_object)
Pierre Kraemer's avatar
Pierre Kraemer committed
530
	{
531
		glAttachShader( *m_program_object, *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
532

533 534 535 536 537 538
		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
539 540 541
	}

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

544
	glGetProgramiv( *m_program_object, GL_LINK_STATUS, &status );
Pierre Kraemer's avatar
Pierre Kraemer committed
545 546
	if( !status )
	{
547
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
548
		info_log = getInfoLog( *m_program_object );
549
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
550 551
		delete [] info_log;

552 553
		glDetachShader( *m_program_object, *m_vertex_shader_object );
		glDetachShader( *m_program_object, *m_fragment_shader_object );
554
		if (*m_geom_shader_object)
555 556
			glDetachShader( *m_program_object, *m_geom_shader_object );
		glDeleteShader( *m_program_object );
557
		*m_program_object = 0;
Pierre Kraemer's avatar
Pierre Kraemer committed
558 559 560 561

		return false;
	}

562 563 564 565
	*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");
566

Pierre Kraemer's avatar
Pierre Kraemer committed
567 568 569
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
570 571 572
bool GLSLShader::changeNbMaxVertices(int nb_max_vertices)
{
	m_nbMaxVertices = nb_max_vertices;
573
	if ((*m_geom_shader_object) && (CURRENT_OGL_VERSION == 2))
Sylvain Thery's avatar
Sylvain Thery committed
574
	{
575
		glProgramParameteriEXT(*m_program_object, GL_GEOMETRY_VERTICES_OUT_EXT, m_nbMaxVertices);
Sylvain Thery's avatar
Sylvain Thery committed
576 577 578 579 580 581
		// need to relink
		return true;
	}
	return false;
}

582 583 584 585 586 587
bool GLSLShader::link()
{
	int		status;
	char	*info_log;

	/*** link program object ***/
588
	glLinkProgram( *m_program_object );
589

590
	glGetProgramiv( *m_program_object, GL_OBJECT_LINK_STATUS_ARB, &status );
591 592
	if( !status )
	{
593
		CGoGNerr << "ERROR - GLSLShader::create() - error occured while linking shader program." << CGoGNendl;
594
		info_log = getInfoLog( *m_program_object );
595
		CGoGNerr << "  LINK " << info_log << CGoGNendl;
596 597
		delete [] info_log;

598 599
		glDetachShader( *m_program_object, *m_vertex_shader_object );
		glDetachShader( *m_program_object, *m_fragment_shader_object );
600
		if (*m_geom_shader_object)
601 602
			glDetachShader( *m_program_object, *m_geom_shader_object );
		glDeleteShader( *m_program_object );
603
		*m_program_object = 0;
604 605 606 607 608 609

		return false;
	}
	return true;
}

610
bool GLSLShader::bind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
611
{
612
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
613
	{
614
		glUseProgram( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
615 616
		return true;
	}
617 618
	else
		return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
619 620
}

621
void GLSLShader::unbind() const
Pierre Kraemer's avatar
Pierre Kraemer committed
622
{
623
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
624
	{
625
		glUseProgram( 0 );
Pierre Kraemer's avatar
Pierre Kraemer committed
626 627 628 629 630
	}
}

bool GLSLShader::isBinded()
{
631 632 633 634 635 636
	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
637 638 639 640
}

GLSLShader::~GLSLShader()
{
641
	if( *m_program_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
642 643 644
	{
		unbind();

645
		if( *m_vertex_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
646
		{
647 648
			glDetachShader( *m_program_object, *m_vertex_shader_object );
			glDeleteShader( *m_vertex_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
649
		}
650
		if( *m_fragment_shader_object )
Pierre Kraemer's avatar
Pierre Kraemer committed
651
		{
652 653
			glDetachShader( *m_program_object, *m_fragment_shader_object );
			glDeleteShader( *m_fragment_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
654
		}
655
		if (*m_geom_shader_object)
Pierre Kraemer's avatar
Pierre Kraemer committed
656
		{
657 658
			glDetachShader( *m_program_object, *m_geom_shader_object );
			glDeleteShader( *m_geom_shader_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
659 660
		}

661
		glDeleteShader( *m_program_object );
Pierre Kraemer's avatar
Pierre Kraemer committed
662
	}
663

664 665 666 667 668 669 670
	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;

671
//	m_registeredShaders->erase(this);
Pierre Kraemer's avatar
Pierre Kraemer committed
672 673 674 675
}

std::string GLSLShader::findFile(const std::string filename)
{
Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
676
	// cherche d'abord dans le repertoire courant
Pierre Kraemer's avatar
Pierre Kraemer committed
677 678 679 680 681 682 683 684 685
	std::ifstream file;
	file.open(filename.c_str(),std::ios::in );
	if (!file.fail())
	{
		file.close();
		return filename;
	}
	file.close();

686 687 688 689 690 691 692 693 694 695 696 697 698 699
	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
700
	// LA MACRO SHADERPATH contient le chemin du repertoire qui contient les fichiers textes
Pierre Kraemer's avatar
Pierre Kraemer committed
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
	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()
{
717
#ifndef CGOGN_GLEW_MX
Pierre Kraemer's avatar
Pierre Kraemer committed
718 719 720
	GLenum error = glewInit();

	if (error != GLEW_OK)
721
		CGoGNerr << "Error: " << glewGetErrorString(error) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
722
	else
723
		CGoGNout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
724 725

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

728 729 730
	if  ((CURRENT_OGL_VERSION == 2) && (!glewIsSupported("GL_VERSION_2_0")))
	{
		CGoGNerr << " GL 2.0 not supported" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
731 732
		return false;
	}
733 734 735 736 737 738 739

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

740 741 742
#endif
	return true;

Pierre Kraemer's avatar
Pierre Kraemer committed
743 744 745 746
}

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

Pierre Kraemer's avatar
Pierre Kraemer committed
750 751 752 753
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;
	
	std::string pss = findFile(ps);
754
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
755 756

	if(!create()) {
757
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
758 759
		return false;
	}
760
	CGoGNout << "Shaders loaded (" << vs << "," << ps << ")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
761 762 763
	return true; 
}

Sylvain Thery's avatar
Sylvain Thery committed
764
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
765
{
Sylvain Thery's avatar
Sylvain Thery committed
766 767 768 769
	m_nameVS = vs;
	m_nameFS = ps;
	m_nameGS = gs;

Pierre Kraemer's avatar
Pierre Kraemer committed
770 771 772 773
	std::string vss = findFile(vs);
	if(!loadVertexShader(vss)) return false;

	std::string pss = findFile(ps);
774
	if(!loadFragmentShader(pss)) return false;
Pierre Kraemer's avatar
Pierre Kraemer committed
775 776 777 778 779 780

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

	if (!geomShaderLoaded)
	{
781
		CGoGNerr << "Error while loading geometry shader" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
782 783
	}

Sylvain Thery's avatar
Sylvain Thery committed
784
	if(!create(inputGeometryPrimitive,outputGeometryPrimitive,nb_max_vertices))
Pierre Kraemer's avatar
Pierre Kraemer committed
785
	{
786
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
787 788 789
		return false;
	}

790
	CGoGNout << "Shaders loaded (" << vs << "," << ps << "," << gs <<")" << CGoGNendl;
Pierre Kraemer's avatar
Pierre Kraemer committed
791 792 793
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
794 795
bool GLSLShader::loadShadersFromMemory(const char* vs, const char* fs)
{
796 797
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
798
	m_vertex_shader_source = NULL;
799

800
	size_t sz = strlen(vs);
801
	m_vertex_shader_source = new char[sz+1];
802 803 804
	memcpy(m_vertex_shader_source, vs,sz+1);
	

805 806 807 808 809 810

	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;

	sz = strlen(fs);
	m_fragment_shader_source = new char[sz+1];
811
	memcpy(m_fragment_shader_source, fs,sz+1);
812

813 814
	if(!loadVertexShaderSourceString(vs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
815

816 817
	if(!loadFragmentShaderSourceString(fs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
818 819 820

	if(!create())
	{
821
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
822 823 824 825 826
		return false;
	}
	return true;
}

Sylvain Thery's avatar
Sylvain Thery committed
827
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
828
{
829 830
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
831
	m_vertex_shader_source = NULL;
832

833
	size_t sz = strlen(vs);
834
	m_vertex_shader_source = new char[sz+1];
835
	memcpy(m_vertex_shader_source,vs,sz+1);
836 837 838 839 840 841

	if (m_fragment_shader_source)
		delete [] m_fragment_shader_source;

	sz = strlen(fs);
	m_fragment_shader_source = new char[sz+1];
842
	memcpy(m_fragment_shader_source,fs,sz+1);
843 844 845 846 847 848

	if (m_geom_shader_source)
		delete [] m_geom_shader_source;

	sz = strlen(gs);
	m_geom_shader_source = new char[sz+1];
849
	memcpy(m_geom_shader_source,gs,sz+1);
850

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
851 852
	if(!loadVertexShaderSourceString(vs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
853

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
854 855
	if(!loadFragmentShaderSourceString(fs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
856

Pierre Kraemer's avatar
merge..  
Pierre Kraemer committed
857 858
	if(!loadGeometryShaderSourceString(gs))
		return false;
Sylvain Thery's avatar
Sylvain Thery committed
859

860
	if(!create(inputGeometryPrimitive, outputGeometryPrimitive, nb_max_vertices))
Sylvain Thery's avatar
Sylvain Thery committed
861
	{
862
		CGoGNout << "Unable to create the shaders !" << CGoGNendl;
Sylvain Thery's avatar
Sylvain Thery committed
863 864 865 866 867 868
		return false;
	}

	return true;
}

869 870 871 872
bool GLSLShader::reloadVertexShaderFromMemory(const char* vs)
{
	if (m_vertex_shader_source)
		delete [] m_vertex_shader_source;
873
	m_vertex_shader_source = NULL;
874

875
	size_t sz = strlen(vs);
876
	m_vertex_shader_source = new char[sz+1];
877
	memcpy(m_vertex_shader_source,vs,sz+1);
878 879 880 881 882 883 884 885 886

	return true;
}

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

887
	unsigned int sz = uint32(strlen(fs));
888
	m_fragment_shader_source = new char[sz+1];
889
	memcpy(m_fragment_shader_source,fs,sz+1);
890 891 892 893 894 895 896 897 898

	return true;
}

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

899
	unsigned int sz = uint32(strlen(gs));
900
	m_geom_shader_source = new char[sz+1];
901
	memcpy(m_geom_shader_source,gs,sz+1);
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916

	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))
	{
917
		CGoGNerr << "Unable to create the shaders !" << CGoGNendl;
918 919 920
		return false;
	}

921 922 923
	*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
924
	*m_uniMat_Normal	= glGetUniformLocation(*m_program_object,"NormalMatrix");
925 926 927

	restoreUniformsAttribs();

928 929
	updateClippingUniforms();

930 931 932
	return true;
}

933 934
bool GLSLShader::validateProgram()
{
935
	if(!*m_program_object)
936 937
		return false;

938
	glValidateProgram(*m_program_object);
939
	GLint Result = GL_FALSE;
940
	glGetProgramiv(*m_program_object, GL_VALIDATE_STATUS, &Result);
941 942 943

	if(Result == GL_FALSE)
	{
944
		CGoGNout << "Validate program:" << CGoGNendl;
945
		int InfoLogLength;
946
		glGetProgramiv(*m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
947
		std::vector<char> Buffer(InfoLogLength);
948
		glGetProgramInfoLog(*m_program_object, InfoLogLength, NULL, &Buffer[0]);
949
		CGoGNout <<  &(Buffer[0]) << CGoGNendl;
950 951 952 953 954 955 956 957 958
		return false;
	}

	return true;
}

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

	int InfoLogLength;
962
	glGetProgramiv(*m_program_object, GL_INFO_LOG_LENGTH, &InfoLogLength);
963
	std::vector<char> Buffer(std::max(InfoLogLength, int(1)));
964
	glGetProgramInfoLog(*m_program_object, InfoLogLength, NULL, &Buffer[0]);
965
	CGoGNout << &Buffer[0] << CGoGNendl;
966 967 968 969 970 971 972 973

	return Result == GL_TRUE;
}

bool GLSLShader::checkShader(int shaderType)
{
	GLint Result = GL_FALSE;
	int InfoLogLength;
974
	GLuint id;
975 976 977 978

	switch(shaderType)
	{
	case VERTEX_SHADER:
979
		id = *m_vertex_shader_object;
980 981
		break;
	case FRAGMENT_SHADER:
982
		id = *m_fragment_shader_object;
983 984
		break;
	case GEOMETRY_SHADER:
985
		id = *m_geom_shader_object;
986 987
		break;
	default:
988
		CGoGNerr << "Error unkown shader type" << CGoGNendl;
989 990 991 992 993 994 995 996
		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]);
997
	CGoGNout << &Buffer[0] << CGoGNendl;
998 999 1000 1001

	return Result == GL_TRUE;
}

Sylvain Thery's avatar
Sylvain Thery committed
1002
void GLSLShader::bindAttrib(unsigned int att, const char* name) const
1003
{
1004
	glBindAttribLocation(*m_program_object, att, name);
1005 1006
}

1007 1008 1009 1010 1011
void GLSLShader::addPathFileSeach(const std::string& path)
{
	m_pathes.push_back(path);
}

1012
unsigned int GLSLShader::bindVA_VBO(const std::string& name, VBO* vbo)
Sylvain Thery's avatar
Sylvain Thery committed
1013
{
1014
	GLint idVA = glGetAttribLocation(*(this->m_program_object), name.c_str());
Sylvain Thery's avatar
Sylvain Thery committed
1015 1016 1017
	//valid ?
	if (idVA < 0)
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
1018
		CGoGNerr << "GLSLShader: Attribute " << name << " does not exist in shader" << CGoGNendl;