clippingShader.cpp 36.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps  *
* version 0.1                                                                  *
* Copyright (C) 2009-2011, IGG Team, LSIIT, University of Strasbourg           *
*                                                                              *
* 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.           *
*                                                                              *
* Web site: http://cgogn.u-strasbg.fr/                                         *
* Contact information: cgogn@unistra.fr                                        *
*                                                                              *
*******************************************************************************/

#include "Utils/clippingShader.h"

namespace CGoGN
{

namespace Utils
{

33

34 35
/***********************************************
 *
36
 * 		Constructor / Destructor
37 38 39
 *
 ***********************************************/

40

41 42 43 44 45 46 47 48 49
ClippingShader::ClippingShader():
		// Initialize clipping shapes variables
		m_unif_clipPlanesEquations (0),
		m_unif_clipSpheresCentersAndRadiuses (0),

		// Initialize default global clipping variables
		m_hasClippingCodeBeenInserted (false),
		m_clipColorAttenuationFactor (1.0),
		m_unif_clipColorAttenuationFactor (0),
50
		m_colorAttenuationMode (COLOR_ATTENUATION_MODE_LINEAR),
51
		m_clipMode (CLIPPING_MODE_AND)
52
{
53

54 55
}

56

57 58 59 60 61
/***********************************************
 *
 * 		Plane Clipping
 *
 ***********************************************/
62

63

64
int ClippingShader::addClipPlane()
65
{
66 67 68
	// Check if the clipping code has been inserted into shader
	if (errorRaiseClippingCodeNotInserted(!m_hasClippingCodeBeenInserted, "ClippingShader::addClipPlane"))
		return -1;
69

70 71
	// Shader name string
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;
72

73 74
	// Use a shader mutator
	ShaderMutator SM(shaderName, getVertexShaderSrc(), getFragmentShaderSrc());
75

76 77
	// Previous planes count
	int previousPlanesCount = getClipPlanesCount();
78

79 80 81 82 83 84
	// Modify the clip planes count constant in both shader
	if (errorRaiseShaderMutatorFailure(
			   (!SM.changeIntConstantValue(ShaderMutator::VERTEX_SHADER, "CLIP_PLANES_COUNT", previousPlanesCount + 1))
			|| (!SM.changeIntConstantValue(ShaderMutator::FRAGMENT_SHADER, "CLIP_PLANES_COUNT", previousPlanesCount + 1)),
			"ClippingShader::addClipPlane"))
		return -1;
85

86 87 88
	// Reload both shaders
	reloadVertexShaderFromMemory(SM.getModifiedVertexShaderSrc().c_str());
	reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());
89

90 91
	// Get new plane id
	unsigned int newPlaneId = getFreeClipPlaneId();
92

93 94
	// Resize planes arrays to the right size
	m_clipPlanes.resize((size_t)(previousPlanesCount + 1));
95 96
	if (newPlaneId >= m_clipPlanesIds.size())
		m_clipPlanesIds.resize((size_t)(newPlaneId + 1));
97
	m_clipPlanesEquations.resize(4*(size_t)(previousPlanesCount + 1), 0.0);
98

99 100 101
	// Set new plane id
	m_clipPlanesIds[newPlaneId].used = true;
	m_clipPlanesIds[newPlaneId].index = previousPlanesCount;
102

103
	// Set default parameters values for the new plane
104
	Geom::Vec3f defaultNormal (0.0, 0.0, 1.0);
105
	Geom::Vec3f defaultOrigin (0.0, 0.0, 0.0);
106
	setClipPlaneParamsAll(newPlaneId, defaultNormal, defaultOrigin);
107

108 109
	// Recompile shaders (automatically calls updateClippingUniforms)
	recompile();
110

111 112 113 114 115 116 117 118
	return newPlaneId;
}

void ClippingShader::deleteClipPlane(unsigned int id)
{
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipPlanesIds.size()), "ClippingShader::deleteClipPlane"))
		return;
119
	if (errorRaiseWrongId(!m_clipPlanesIds[id].used, "ClippingShader::deleteClipPlane"))
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 146 147
		return;

	// Check if the clipping code has been inserted into shader
	if (errorRaiseClippingCodeNotInserted(!m_hasClippingCodeBeenInserted, "ClippingShader::deleteClipPlane"))
		return;

	// Shader name string
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

	// Use a shader mutator
	ShaderMutator SM(shaderName, getVertexShaderSrc(), getFragmentShaderSrc());

	// Previous planes count
	int previousPlanesCount = getClipPlanesCount();

	// Modify the clip planes count constant in both shader
	if (errorRaiseShaderMutatorFailure(
			   (!SM.changeIntConstantValue(ShaderMutator::VERTEX_SHADER, "CLIP_PLANES_COUNT", previousPlanesCount - 1))
			|| (!SM.changeIntConstantValue(ShaderMutator::FRAGMENT_SHADER, "CLIP_PLANES_COUNT", previousPlanesCount - 1)),
			"ClippingShader::deleteClipPlane"))
		return;

	// Reload both shaders
	reloadVertexShaderFromMemory(SM.getModifiedVertexShaderSrc().c_str());
	reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());

	// Rearrange planes arrays
	m_clipPlanes.erase(m_clipPlanes.begin() + m_clipPlanesIds[id].index);
148
	for (size_t i = 0; i < m_clipPlanesIds.size(); i++)
149 150 151
	{
		if (m_clipPlanesIds[i].index > m_clipPlanesIds[id].index)
			m_clipPlanesIds[i].index -= 1;
152
	}
153 154 155 156 157 158 159
	m_clipPlanesIds[id].used = false;
	m_clipPlanesEquations.erase(
			m_clipPlanesEquations.begin() + 4*m_clipPlanesIds[id].index,
			m_clipPlanesEquations.begin() + 4*m_clipPlanesIds[id].index + 4);

	// Recompile shaders (automatically calls updateClippingUniforms)
	recompile();
160 161
}

162 163 164 165 166
int ClippingShader::getClipPlanesCount()
{
	return (int)m_clipPlanes.size();
}

167
void ClippingShader::setClipPlaneParamsAll(unsigned int id, Geom::Vec3f normal, Geom::Vec3f origin)
168
{
169 170 171
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipPlanesIds.size()), "ClippingShader::setClipPlaneParamsAll"))
		return;
172
	if (errorRaiseWrongId(!m_clipPlanesIds[id].used, "ClippingShader::setClipPlaneParamsAll"))
173 174 175 176
		return;

	// Get the corresponding plane index
	int planeIndex = m_clipPlanesIds[id].index;
177

178
	// Normalize
179 180
	Geom::Vec3f normalNormalized = normal;
	normalNormalized.normalize();
181

182 183 184 185
	// Check if it is worth updating values !
	if ((normalNormalized == m_clipPlanes[planeIndex].normal)
			&& (origin == m_clipPlanes[planeIndex].origin))
		return;
186

187 188 189
	// Copy the given clipping plane parameters
	m_clipPlanes[planeIndex].normal = normalNormalized;
	m_clipPlanes[planeIndex].origin = origin;
190

191 192 193 194 195
	// Update the plane arrays
	updateClipPlaneUniformsArray(id);

	// Send again the whole planes equations array to shader
	sendClipPlanesEquationsUniform();
196 197
}

198
void ClippingShader::setClipPlaneParamsNormal(unsigned int id, Geom::Vec3f normal)
199
{
200 201 202
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipPlanesIds.size()), "ClippingShader::setClipPlaneParamsFirstVec"))
		return;
203
	if (errorRaiseWrongId(!m_clipPlanesIds[id].used, "ClippingShader::setClipPlaneParamsFirstVec"))
204 205 206 207
		return;

	// Get the corresponding plane index
	int planeIndex = m_clipPlanesIds[id].index;
208

209
	// Normalize
210 211
	Geom::Vec3f normalNormalized = normal;
	normalNormalized.normalize();
212

213 214 215
	// Check if it is worth updating values !
	if (normalNormalized == m_clipPlanes[planeIndex].normal)
		return;
216

217 218
	// Copy the given clipping plane parameter
	m_clipPlanes[planeIndex].normal = normalNormalized;
219

220 221 222 223 224
	// Update the plane arrays
	updateClipPlaneUniformsArray(id);

	// Send again the whole planes equations array to shader
	sendClipPlanesEquationsUniform();
225 226
}

227
void ClippingShader::setClipPlaneParamsOrigin(unsigned int id, Geom::Vec3f origin)
228
{
229 230 231
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipPlanesIds.size()), "ClippingShader::setClipPlaneParamsOrigin"))
		return;
232
	if (errorRaiseWrongId(!m_clipPlanesIds[id].used, "ClippingShader::setClipPlaneParamsOrigin"))
233 234 235 236
		return;

	// Get the corresponding plane index
	int planeIndex = m_clipPlanesIds[id].index;
237

238 239 240
	// Check if it is worth updating values !
	if (origin == m_clipPlanes[planeIndex].origin)
		return;
241

242 243
	// Copy the given clipping plane parameter
	m_clipPlanes[planeIndex].origin = origin;
244

245 246 247 248 249
	// Update the plane arrays
	updateClipPlaneUniformsArray(id);

	// Send again the whole planes equations array to shader
	sendClipPlanesEquationsUniform();
250 251
}

252
Geom::Vec3f ClippingShader::getClipPlaneParamsNormal(unsigned int id)
253
{
254 255 256
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipPlanesIds.size()), "ClippingShader::getClipPlaneParamsFirstVec"))
		return Geom::Vec3f(0.0, 0.0, 0.0);
257
	if (errorRaiseWrongId(!m_clipPlanesIds[id].used, "ClippingShader::getClipPlaneParamsFirstVec"))
258 259 260 261
		return Geom::Vec3f(0.0, 0.0, 0.0);

	// Get the corresponding plane index
	int planeIndex = m_clipPlanesIds[id].index;
262 263

	// Return the parameter
264
	return m_clipPlanes[planeIndex].normal;
265 266
}

267
Geom::Vec3f ClippingShader::getClipPlaneParamsOrigin(unsigned int id)
268
{
269 270 271
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipPlanesIds.size()), "ClippingShader::getClipPlaneParamsOrigin"))
		return Geom::Vec3f(0.0, 0.0, 0.0);
272
	if (errorRaiseWrongId(!m_clipPlanesIds[id].used, "ClippingShader::getClipPlaneParamsOrigin"))
273 274 275 276
		return Geom::Vec3f(0.0, 0.0, 0.0);

	// Get the corresponding plane index
	int planeIndex = m_clipPlanesIds[id].index;
277 278 279 280 281

	// Return the parameter
	return m_clipPlanes[planeIndex].origin;
}

282
unsigned int ClippingShader::getFreeClipPlaneId()
283
{
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
	unsigned int freeId = 0;

	// Free id = either out of current ids vector size or no more used
	while (freeId < m_clipPlanesIds.size())
	{
		if (!m_clipPlanesIds[freeId].used)
			return freeId;
		else
			freeId++;
	}

	return freeId;
}

void ClippingShader::updateClipPlaneUniformsArray(unsigned int id)
{
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipPlanesIds.size()), "ClippingShader::updateClipPlaneUniformsArray"))
		return;
303
	if (errorRaiseWrongId(!m_clipPlanesIds[id].used, "ClippingShader::updateClipPlaneUniformsArray"))
304 305 306 307
		return;

	// Get the corresponding plane index
	int planeIndex = m_clipPlanesIds[id].index;
308

309
	// Update the planes equations array
310 311 312 313
	float d = -(m_clipPlanes[planeIndex].normal * m_clipPlanes[planeIndex].origin);
	m_clipPlanesEquations[4*planeIndex + 0] = m_clipPlanes[planeIndex].normal[0];
	m_clipPlanesEquations[4*planeIndex + 1] = m_clipPlanes[planeIndex].normal[1];
	m_clipPlanesEquations[4*planeIndex + 2] = m_clipPlanes[planeIndex].normal[2];
314 315 316 317
	m_clipPlanesEquations[4*planeIndex + 3] = d;

}

318

319 320 321 322 323 324 325
/***********************************************
 *
 * 		Sphere Clipping
 *
 ***********************************************/


326
int ClippingShader::addClipSphere()
327
{
328 329 330
	// Check if the clipping code has been inserted into shader
	if (errorRaiseClippingCodeNotInserted(!m_hasClippingCodeBeenInserted, "ClippingShader::addClipSphere"))
		return -1;
331

332 333
	// Shader name string
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;
334

335 336
	// Use a shader mutator
	ShaderMutator SM(shaderName, getVertexShaderSrc(), getFragmentShaderSrc());
337

338 339
	// Previous spheres count
	int previousSpheresCount = getClipSpheresCount();
340

341 342 343 344 345 346
	// Modify the clip spheres count constant in both shader
	if (errorRaiseShaderMutatorFailure(
			   (!SM.changeIntConstantValue(ShaderMutator::VERTEX_SHADER, "CLIP_SPHERES_COUNT", previousSpheresCount + 1))
			|| (!SM.changeIntConstantValue(ShaderMutator::FRAGMENT_SHADER, "CLIP_SPHERES_COUNT", previousSpheresCount + 1)),
			"ClippingShader::addClipSphere"))
		return -1;
347

348 349 350
	// Reload both shaders
	reloadVertexShaderFromMemory(SM.getModifiedVertexShaderSrc().c_str());
	reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());
351

352 353
	// Get new sphere id
	unsigned int newSphereId = getFreeClipSphereId();
354

355 356
	// Resize spheres arrays to the right size
	m_clipSpheres.resize((size_t)(previousSpheresCount + 1));
357 358
	if (newSphereId >= m_clipSpheresIds.size())
		m_clipSpheresIds.resize((size_t)(newSphereId + 1));
359
	m_clipSpheresCentersAndRadiuses.resize(4*(size_t)(previousSpheresCount + 1), 0.0);
360

361 362 363
	// Set new sphere id
	m_clipSpheresIds[newSphereId].used = true;
	m_clipSpheresIds[newSphereId].index = previousSpheresCount;
364

365 366 367 368
	// Set default parameters values for the new sphere
	Geom::Vec3f defaultCenter (0.0, 0.0, 0.0);
	float defaultRadius = 10.0;
	setClipSphereParamsAll(newSphereId, defaultCenter, defaultRadius);
369

370 371
	// Recompile shaders (automatically calls updateClippingUniforms)
	recompile();
372

373 374 375 376 377 378 379 380
	return newSphereId;
}

void ClippingShader::deleteClipSphere(unsigned int id)
{
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipSpheresIds.size()), "ClippingShader::deleteClipSphere"))
		return;
381
	if (errorRaiseWrongId(!m_clipSpheresIds[id].used, "ClippingShader::deleteClipSphere"))
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
		return;

	// Check if the clipping code has been inserted into shader
	if (errorRaiseClippingCodeNotInserted(!m_hasClippingCodeBeenInserted, "ClippingShader::deleteClipSphere"))
		return;

	// Shader name string
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

	// Use a shader mutator
	ShaderMutator SM(shaderName, getVertexShaderSrc(), getFragmentShaderSrc());

	// Previous spheres count
	int previousSpheresCount = getClipSpheresCount();

	// Modify the clip spheres count constant in both shader
	if (errorRaiseShaderMutatorFailure(
			   (!SM.changeIntConstantValue(ShaderMutator::VERTEX_SHADER, "CLIP_SPHERES_COUNT", previousSpheresCount - 1))
			|| (!SM.changeIntConstantValue(ShaderMutator::FRAGMENT_SHADER, "CLIP_SPHERES_COUNT", previousSpheresCount - 1)),
			"ClippingShader::deleteClipSphere"))
		return;

	// Reload both shaders
	reloadVertexShaderFromMemory(SM.getModifiedVertexShaderSrc().c_str());
	reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());

	// Rearrange spheres arrays
	m_clipSpheres.erase(m_clipSpheres.begin() + m_clipSpheresIds[id].index);
410
	for (size_t i = 0; i < m_clipSpheresIds.size(); i++)
411 412 413
	{
		if (m_clipSpheresIds[i].index > m_clipSpheresIds[id].index)
			m_clipSpheresIds[i].index -= 1;
414
	}
415 416 417 418 419 420 421
	m_clipSpheresIds[id].used = false;
	m_clipSpheresCentersAndRadiuses.erase(
			m_clipSpheresCentersAndRadiuses.begin() + 4*m_clipSpheresIds[id].index,
			m_clipSpheresCentersAndRadiuses.begin() + 4*m_clipSpheresIds[id].index + 4);

	// Recompile shaders (automatically calls updateClippingUniforms)
	recompile();
422 423 424 425 426 427 428
}

int ClippingShader::getClipSpheresCount()
{
	return (int)m_clipSpheres.size();
}

429
void ClippingShader::setClipSphereParamsAll(unsigned int id, Geom::Vec3f center, float radius)
430
{
431 432 433
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipSpheresIds.size()), "ClippingShader::setClipSphereParamsAll"))
		return;
434
	if (errorRaiseWrongId(!m_clipSpheresIds[id].used, "ClippingShader::setClipSphereParamsAll"))
435 436 437 438
		return;

	// Get the corresponding sphere index
	int sphereIndex = m_clipSpheresIds[id].index;
439

440 441 442 443
	// Check if it is worth updating values !
	if ((center == m_clipSpheres[sphereIndex].center)
			&& (radius == m_clipSpheres[sphereIndex].radius))
		return;
444

445 446 447
	// Copy the given clipping sphere parameters
	m_clipSpheres[sphereIndex].center = center;
	m_clipSpheres[sphereIndex].radius = radius;
448

449 450 451 452 453
	// Update the sphere array
	updateClipSphereUniformsArray(id);

	// Send again the whole spheres centers and radiuses array to shader
	sendClipSpheresCentersAndRadiusesUniform();
454 455
}

456
void ClippingShader::setClipSphereParamsCenter(unsigned int id, Geom::Vec3f center)
457
{
458 459 460
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipSpheresIds.size()), "ClippingShader::setClipSphereParamsCenter"))
		return;
461
	if (errorRaiseWrongId(!m_clipSpheresIds[id].used, "ClippingShader::setClipSphereParamsCenter"))
462 463 464 465
		return;

	// Get the corresponding sphere index
	int sphereIndex = m_clipSpheresIds[id].index;
466

467 468 469
	// Check if it is worth updating values !
	if (center == m_clipSpheres[sphereIndex].center)
		return;
470

471 472
	// Copy the given clipping sphere parameter
	m_clipSpheres[sphereIndex].center = center;
473

474 475 476 477 478
	// Update the sphere array
	updateClipSphereUniformsArray(id);

	// Send again the whole spheres centers and radiuses array to shader
	sendClipSpheresCentersAndRadiusesUniform();
479 480
}

481
void ClippingShader::setClipSphereParamsRadius(unsigned int id, float radius)
482
{
483 484 485
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipSpheresIds.size()), "ClippingShader::setClipSphereParamsRadius"))
		return;
486
	if (errorRaiseWrongId(!m_clipSpheresIds[id].used, "ClippingShader::setClipSphereParamsRadius"))
487 488 489 490
		return;

	// Get the corresponding sphere index
	int sphereIndex = m_clipSpheresIds[id].index;
491

492 493 494
	// Check if it is worth updating values !
	if (radius == m_clipSpheres[sphereIndex].radius)
		return;
495

496 497
	// Copy the given clipping sphere parameter
	m_clipSpheres[sphereIndex].radius = radius;
498

499 500 501 502 503
	// Update the sphere array
	updateClipSphereUniformsArray(id);

	// Send again the whole spheres centers and radiuses array to shader
	sendClipSpheresCentersAndRadiusesUniform();
504 505
}

506
Geom::Vec3f ClippingShader::getClipSphereParamsCenter(unsigned int id)
507
{
508 509 510
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipSpheresIds.size()), "ClippingShader::getClipSphereParamsCenter"))
		return Geom::Vec3f(0.0, 0.0, 0.0);
511
	if (errorRaiseWrongId(!m_clipSpheresIds[id].used, "ClippingShader::getClipSphereParamsCenter"))
512 513 514 515
		return Geom::Vec3f(0.0, 0.0, 0.0);

	// Get the corresponding sphere index
	int sphereIndex = m_clipSpheresIds[id].index;
516 517 518 519 520

	// Return the parameter
	return m_clipSpheres[sphereIndex].center;
}

521
float ClippingShader::getClipSphereParamsRadius(unsigned int id)
522
{
523 524 525
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipSpheresIds.size()), "ClippingShader::getClipSphereParamsRadius"))
		return 0.0;
526
	if (errorRaiseWrongId(!m_clipSpheresIds[id].used, "ClippingShader::getClipSphereParamsRadius"))
527 528 529 530
		return 0.0;

	// Get the corresponding sphere index
	int sphereIndex = m_clipSpheresIds[id].index;
531 532 533 534 535

	// Return the parameter
	return m_clipSpheres[sphereIndex].radius;
}

536
unsigned int ClippingShader::getFreeClipSphereId()
537
{
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
	unsigned int freeId = 0;

	// Free id = either out of current ids vector size or no more used
	while (freeId < m_clipSpheresIds.size())
	{
		if (!m_clipSpheresIds[freeId].used)
			return freeId;
		else
			freeId++;
	}

	return freeId;
}

void ClippingShader::updateClipSphereUniformsArray(unsigned int id)
{
	// Check if the given id is valid
	if (errorRaiseWrongId(id > (m_clipSpheresIds.size()), "ClippingShader::updateClipSphereUniformsArray"))
		return;
557
	if (errorRaiseWrongId(!m_clipSpheresIds[id].used, "ClippingShader::updateClipSphereUniformsArray"))
558 559 560 561
		return;

	// Get the corresponding sphere index
	int sphereIndex = m_clipSpheresIds[id].index;
562 563 564 565 566 567 568 569 570 571

	// Update the spheres centers and radiuses array
	m_clipSpheresCentersAndRadiuses[4*sphereIndex + 0] = m_clipSpheres[sphereIndex].center[0];
	m_clipSpheresCentersAndRadiuses[4*sphereIndex + 1] = m_clipSpheres[sphereIndex].center[1];
	m_clipSpheresCentersAndRadiuses[4*sphereIndex + 2] = m_clipSpheres[sphereIndex].center[2];
	m_clipSpheresCentersAndRadiuses[4*sphereIndex + 3] = m_clipSpheres[sphereIndex].radius;

}


572 573 574 575 576 577 578
/***********************************************
 *
 * 		Global Clipping Stuff
 *
 ***********************************************/


579 580
bool ClippingShader::insertClippingCode()
{
581
	// Check if the code has not already been inserted
582 583 584 585 586 587 588
	if (errorRaiseClippingCodeAlreadyInserted(m_hasClippingCodeBeenInserted, "ClippingShader::insertClippingCode"))
		return false;

	// Check if the vertex and fragment sources are not empty
	if (errorRaiseShaderSourceIsEmpty((getVertexShaderSrc() == NULL), "ClippingShader::insertClippingCode", ShaderMutator::VERTEX_SHADER))
		return false;
	if (errorRaiseShaderSourceIsEmpty((getFragmentShaderSrc() == NULL), "ClippingShader::insertClippingCode", ShaderMutator::FRAGMENT_SHADER))
589
		return false;
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629

	// Check if the shader does not use a geometry shader
	if (errorRaiseShaderUsesGeometryShader((getGeometryShaderSrc() != NULL), "ClippingShader::insertClippingCode"))
		return false;


	// Strings to insert in shader sources

	std::string VS_headInsertion =
	"\n"
	"#define CLIP_PLANES_COUNT 0\n"
	"#define CLIP_SPHERES_COUNT 0\n"
	"\n"
	"#define PLANE_CLIPPING_ENABLED (CLIP_PLANES_COUNT > 0)\n"
	"#define SPHERE_CLIPPING_ENABLED (CLIP_SPHERES_COUNT > 0)\n"
	"\n"
	"#define CLIPPING_ENABLED (PLANE_CLIPPING_ENABLED || SPHERE_CLIPPING_ENABLED)\n"
	"\n"
	"#if CLIPPING_ENABLED\n"
	"	VARYING_VERT vec3 clip_nonTransformedPos;\n"
	"#endif\n"
	"\n";

	std::string VS_mainEndInsertion =
	"\n"
	"	#if CLIPPING_ENABLED\n"
	"		// Pass the non transformed vertex position to the fragment shader for clipping\n"
	"		clip_nonTransformedPos = VertexPosition;\n"
	"	#endif\n";

	std::string FS_headInsertion =
	"\n"
	"#define CLIP_PLANES_COUNT 0\n"
	"#define CLIP_SPHERES_COUNT 0\n"
	"\n"
	"#define PLANE_CLIPPING_ENABLED (CLIP_PLANES_COUNT > 0)\n"
	"#define SPHERE_CLIPPING_ENABLED (CLIP_SPHERES_COUNT > 0)\n"
	"\n"
	"#define CLIPPING_ENABLED (PLANE_CLIPPING_ENABLED || SPHERE_CLIPPING_ENABLED)\n"
	"\n"
630 631 632 633 634 635 636
	"// In following clipping modes, pixels may be deleted :\n"
	"//  - OR : only after being matched with every object\n"
	"//  - AND : on the fly as soon as one object does not match\n"
	"#define CLIPPING_MODE_AND 0\n"
	"#define CLIPPING_MODE_OR 1\n"
	"#define CLIPPING_MODE 0\n"
	"\n"
637 638 639 640
	"#define CLIPPING_COLOR_ATTENUATION_MODE_LINEAR 0\n"
	"#define CLIPPING_COLOR_ATTENUATION_MODE_QUADRATIC 1\n"
	"#define CLIPPING_COLOR_ATTENUATION_MODE 0\n"
	"\n"
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
	"#if CLIPPING_ENABLED\n"
	"\n"
	"	#if PLANE_CLIPPING_ENABLED\n"
	"		uniform vec4 clip_clipPlanesEquations[CLIP_PLANES_COUNT];\n"
	"	#endif\n"
	"\n"
	"	#if SPHERE_CLIPPING_ENABLED\n"
	"		uniform vec4 clip_clipSpheresCentersAndRadiuses[CLIP_SPHERES_COUNT];\n"
	"	#endif\n"
	"\n"
	"	uniform float clip_clipColorAttenuationFactor;\n"
	"\n"
	"	VARYING_FRAG vec3 clip_nonTransformedPos;\n"
	"\n"
	"#endif\n"
	"\n"
	"#if CLIPPING_ENABLED\n"
658
	"\n"
659 660 661 662 663
	"	float clip_doClippingAndGetClippingDistance()\n"
	"	{\n"
	"		// Distance to the nearest clipping object\n"
	"		float minDistanceToClipping = -1.0;\n"
	"\n"
664 665 666 667 668 669
	"		// OR clipping mode needs a boolean to know if the pixel must be clipped or not\n"
	"		// By default set to true : one clipping object matched sets it to false\n"
	"		#if (CLIPPING_MODE == CLIPPING_MODE_OR)\n"
	"			bool discardPixel = true;\n"
	"		#endif\n"
	"\n"
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
	"		#if PLANE_CLIPPING_ENABLED\n"
	"\n"
	"			// Do clipping for each plane\n"
	"			for (int i = 0; i < CLIP_PLANES_COUNT; i++)\n"
	"			{\n"
	"				// Get the current plane equation\n"
	"				vec4 currClipPlane = clip_clipPlanesEquations[i];\n"
	"\n"
	"				// If the plane normal is zero, use a default normal vector (0.0, 0.0, 1.0)\n"
	"				float clipPlaneNormalLength = length(currClipPlane.xyz);\n"
	"				if (clipPlaneNormalLength == 0.0)\n"
	"				{\n"
	"					currClipPlane.z = 1.0;\n"
	"					clipPlaneNormalLength = 1.0;\n"
	"				}\n"
	"\n"
	"				// Signed distance between the point and the plane\n"
	"				float distanceToPlane = dot(clip_nonTransformedPos, currClipPlane.xyz);\n"
	"				distanceToPlane += currClipPlane.w;\n"
	"				distanceToPlane /= clipPlaneNormalLength;\n"
	"\n"
691 692 693
	"				// AND clipping mode discards at first unmatched clipping object\n"
	"				#if (CLIPPING_MODE == CLIPPING_MODE_AND)\n"
	"					if (distanceToPlane > 0.0)\n"
694
	"						discard;\n"
695 696 697 698 699
	"				#endif\n"
	"\n"
	"				// In OR clipping mode, one match = no pixel clipping\n"
	"				#if (CLIPPING_MODE == CLIPPING_MODE_OR)\n"
	"					if (distanceToPlane < 0.0)\n"
700
	"						discardPixel = false;\n"
701
	"				#endif\n"
702
	"\n"
703 704 705 706 707
	"				// Keep the distance to the nearest plane\n"
	"				if (minDistanceToClipping < 0.0)\n"
	"					minDistanceToClipping = abs(distanceToPlane);\n"
	"				else\n"
	"					minDistanceToClipping = min(minDistanceToClipping, abs(distanceToPlane));\n"
708 709 710 711 712
	"			}\n"
	"\n"
	"		#endif\n"
	"\n"
	"		#if SPHERE_CLIPPING_ENABLED\n"
713
	"\n"
714 715 716 717 718 719 720 721 722
	"			// Do clipping for each sphere\n"
	"			for (int i = 0; i < CLIP_SPHERES_COUNT; i++)\n"
	"			{\n"
	"				// Get the current sphere center and radius\n"
	"				vec3 currClipSphereCenter = clip_clipSpheresCentersAndRadiuses[i].xyz;\n"
	"				float currClipSphereRadius = clip_clipSpheresCentersAndRadiuses[i].w;\n"
	"\n"
	"				// Signed distance between the point and the sphere\n"
	"				float distanceToSphere = length(clip_nonTransformedPos - currClipSphereCenter);\n"
723 724 725 726
	"				distanceToSphere -= abs(currClipSphereRadius);\n"
	"\n"
	"				// If the sphere radius is negative, this inverses the clipping effect\n"
	"				distanceToSphere *= sign(currClipSphereRadius);\n"
727
	"\n"
728 729 730
	"				// AND clipping mode discards at first unmatched clipping object\n"
	"				#if (CLIPPING_MODE == CLIPPING_MODE_AND)\n"
	"					if (distanceToSphere > 0.0)\n"
731
	"						discard;\n"
732 733 734 735 736
	"				#endif\n"
	"\n"
	"				// In OR clipping mode, one match = no pixel clipping\n"
	"				#if (CLIPPING_MODE == CLIPPING_MODE_OR)\n"
	"					if (distanceToSphere < 0.0)\n"
737
	"						discardPixel = false;\n"
738
	"				#endif\n"
739
	"\n"
740 741 742 743 744
	"				// Keep the distance to the nearest sphere\n"
	"				if (minDistanceToClipping < 0.0)\n"
	"					minDistanceToClipping = abs(distanceToSphere);\n"
	"				else\n"
	"					minDistanceToClipping = min(minDistanceToClipping, abs(distanceToSphere));\n"
745 746 747 748
	"			}\n"
	"\n"
	"		#endif\n"
	"\n"
749 750 751 752 753 754
	"		// In OR clipping mode, the pixel may be deleted only after being matched with every object\n"
	"		#if (CLIPPING_MODE == CLIPPING_MODE_OR)\n"
	"			if (discardPixel)\n"
	"				discard;\n"
	"		#endif\n"
	"\n"
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
	"		return minDistanceToClipping;\n"
	"	}\n"
	"\n"
	"#endif\n"
	"\n";

	std::string FS_mainBeginInsertion =
	"\n"
	"	#if CLIPPING_ENABLED\n"
	"		// Apply clipping and get the clipping distance\n"
	"		float clip_minDistanceToClipping = clip_doClippingAndGetClippingDistance();\n"
	"	#endif\n";

	std::string FS_mainEndInsertion =
	"\n"
	"	#if CLIPPING_ENABLED\n"
771 772 773 774 775 776 777
	"		// Attenuate the final fragment color depending on its distance to clipping objects\n"
	"		float clip_colorAttenuation = clip_minDistanceToClipping * clip_clipColorAttenuationFactor;\n"
	"		#if (CLIPPING_COLOR_ATTENUATION_MODE == CLIPPING_COLOR_ATTENUATION_MODE_QUADRATIC)\n"
	"			clip_colorAttenuation *= clip_colorAttenuation;\n"
	"		#endif\n"
	"		gl_FragColor.rgb /= (1.0 + clip_colorAttenuation);\n"
	"	#endif;\n";
778 779 780 781 782 783 784 785 786 787 788 789

	// Shader name string
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

	// Use a shader mutator
	ShaderMutator SM(shaderName, getVertexShaderSrc(), getFragmentShaderSrc());

	// First check if the vertex shader contains the VertexPosition attribute
	if (errorRaiseVariableNotFoundInShader(!SM.containsVariableDeclaration(ShaderMutator::VERTEX_SHADER, "VertexPosition"), "ClippingShader::insertClippingCode", ShaderMutator::VERTEX_SHADER, "VertexPosition"))
		return false;

	// Modify vertex shader source code
790 791 792 793 794
	if (errorRaiseShaderMutatorFailure(
			   (!SM.insertCodeBeforeMainFunction(ShaderMutator::VERTEX_SHADER, VS_headInsertion))
			|| (!SM.insertCodeAtMainFunctionBeginning(ShaderMutator::VERTEX_SHADER, VS_mainEndInsertion)),
			"ClippingShader::insertClippingCode"))
		return false;
795 796

	// Modify fragment shader source code
797 798 799 800 801 802 803
	if (errorRaiseShaderMutatorFailure(
			   (!SM.setMinShadingLanguageVersion(ShaderMutator::FRAGMENT_SHADER, 120)) // Following code insertions need at least shading language 120 (GLSL arrays)
			|| (!SM.insertCodeBeforeMainFunction(ShaderMutator::FRAGMENT_SHADER, FS_headInsertion))
			|| (!SM.insertCodeAtMainFunctionBeginning(ShaderMutator::FRAGMENT_SHADER, FS_mainBeginInsertion))
			|| (!SM.insertCodeAtMainFunctionEnd(ShaderMutator::FRAGMENT_SHADER, FS_mainEndInsertion)),
			"ClippingShader::insertClippingCode"))
		return false;
804 805 806 807 808 809 810 811 812 813 814 815 816

	// Reload both shaders
	reloadVertexShaderFromMemory(SM.getModifiedVertexShaderSrc().c_str());
	reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());

	// Recompile shaders (automatically calls updateClippingUniforms)
	recompile();

	m_hasClippingCodeBeenInserted = true;

	return true;
}

817 818
void ClippingShader::setClipColorAttenuationFactor(float colorAttenuationFactor)
{
819 820 821
	// Check if it is worth updating values !
	if (colorAttenuationFactor == m_clipColorAttenuationFactor)
		return;
822

823 824 825 826 827
	// Copy the given value
	m_clipColorAttenuationFactor = colorAttenuationFactor;

	// Send again the uniform to shader
	sendClipColorAttenuationFactorUniform();
828 829 830 831 832 833 834
}

float ClippingShader::getClipColorAttenuationFactor()
{
	return m_clipColorAttenuationFactor;
}

835 836
void ClippingShader::setClipColorAttenuationMode(colorAttenuationMode colAttMode)
{
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
	// Check if it is worth updating values !
	if (colAttMode == m_colorAttenuationMode)
		return;

	// Check if the clipping code has been inserted into shader
	if (errorRaiseClippingCodeNotInserted(!m_hasClippingCodeBeenInserted, "ClippingShader::setClipColorAttenuationMode"))
		return;

	// Shader name string
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

	// Copy the given value
	m_colorAttenuationMode = colAttMode;

	// Use a shader mutator
	ShaderMutator SM(shaderName, getVertexShaderSrc(), getFragmentShaderSrc());

	// Change color attenuation mode constant
	int newConstantValue;
	switch (colAttMode)
857
	{
858 859 860 861 862 863 864 865 866 867 868
		case COLOR_ATTENUATION_MODE_LINEAR :
			newConstantValue = 0;
			break;

		case COLOR_ATTENUATION_MODE_QUADRATIC :
			newConstantValue = 1;
			break;

		default :
			newConstantValue = 0;
			break;
869
	}
870 871 872 873 874 875 876 877 878 879
	if (errorRaiseShaderMutatorFailure(
			(!SM.changeIntConstantValue(ShaderMutator::FRAGMENT_SHADER, "CLIPPING_COLOR_ATTENUATION_MODE", newConstantValue)),
			"ClippingShader::setClipColorAttenuationMode"))
		return;

	// Reload modified shader
	reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());

	// Recompile shaders (automatically calls updateClippingUniforms)
	recompile();
880 881 882 883 884 885 886
}

ClippingShader::colorAttenuationMode ClippingShader::getClipColorAttenuationMode()
{
	return m_colorAttenuationMode;
}

887 888
void ClippingShader::setClipMode(clippingMode clipMode)
{
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
	// Check if it is worth updating values !
	if (clipMode == m_clipMode)
		return;

	// Check if the clipping code has been inserted into shader
	if (errorRaiseClippingCodeNotInserted(!m_hasClippingCodeBeenInserted, "ClippingShader::setClipMode"))
		return;

	// Shader name string
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

	// Copy the given value
	m_clipMode = clipMode;

	// Use a shader mutator
	ShaderMutator SM(shaderName, getVertexShaderSrc(), getFragmentShaderSrc());

	// Change clipping mode constant
	int newConstantValue;
	switch (clipMode)
909
	{
910 911 912 913 914 915 916 917 918 919 920
		case CLIPPING_MODE_AND :
			newConstantValue = 0;
			break;

		case CLIPPING_MODE_OR :
			newConstantValue = 1;
			break;

		default :
			newConstantValue = 0;
			break;
921
	}
922 923 924 925 926 927 928 929 930 931
	if (errorRaiseShaderMutatorFailure(
			(!SM.changeIntConstantValue(ShaderMutator::FRAGMENT_SHADER, "CLIPPING_MODE", newConstantValue)),
			"ClippingShader::setClipMode"))
		return;

	// Reload modified shader
	reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());

	// Recompile shaders (automatically calls updateClippingUniforms)
	recompile();
932 933 934 935 936 937 938
}

ClippingShader::clippingMode ClippingShader::getClipMode()
{
	return m_clipMode;
}

939 940 941 942 943 944 945 946 947 948

/***********************************************
 *
 * 		Clipping Uniforms Handling
 *
 ***********************************************/


void ClippingShader::updateClippingUniforms()
{
949 950 951 952 953 954 955 956 957 958
	// Plane clipping uniforms
	if (getClipPlanesCount() > 0)
	{
		// Get uniform location
		m_unif_clipPlanesEquations = glGetUniformLocation(program_handler(), "clip_clipPlanesEquations");
		errorRaiseUniformNotFoundInShader((m_unif_clipPlanesEquations == -1), "ClippingShader::updateClippingUniforms", "clip_clipPlanesEquations");

		// Send again uniform value
		sendClipPlanesEquationsUniform();
	}
959

960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
	// Sphere clipping uniforms
	if (getClipSpheresCount() > 0)
	{
		// Get uniform location
		m_unif_clipSpheresCentersAndRadiuses = glGetUniformLocation(program_handler(), "clip_clipSpheresCentersAndRadiuses");
		errorRaiseUniformNotFoundInShader((m_unif_clipSpheresCentersAndRadiuses == -1), "ClippingShader::updateClippingUniforms", "clip_clipSpheresCentersAndRadiuses");

		// Send again uniform value
		sendClipSpheresCentersAndRadiusesUniform();
	}

	// Global clipping uniforms
	if ((getClipPlanesCount() > 0) || (getClipSpheresCount() > 0))
	{
		// Get uniform location
		m_unif_clipColorAttenuationFactor = glGetUniformLocation(program_handler(), "clip_clipColorAttenuationFactor");
		errorRaiseUniformNotFoundInShader((m_unif_clipColorAttenuationFactor == -1), "ClippingShader::updateClippingUniforms", "clip_clipColorAttenuationFactor");
977

978 979 980
		// Send again uniform value
		sendClipColorAttenuationFactorUniform();
	}
981 982 983 984 985 986 987 988
}

void ClippingShader::sendClipPlanesEquationsUniform()
{
	bind();
	glUniform4fv(m_unif_clipPlanesEquations, getClipPlanesCount(), &m_clipPlanesEquations.front());
}

989 990 991 992 993 994
void ClippingShader::sendClipSpheresCentersAndRadiusesUniform()
{
	bind();
	glUniform4fv(m_unif_clipSpheresCentersAndRadiuses, getClipSpheresCount(), &m_clipSpheresCentersAndRadiuses.front());
}

995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
void ClippingShader::sendClipColorAttenuationFactorUniform()
{
	bind();
	glUniform1f(m_unif_clipColorAttenuationFactor, m_clipColorAttenuationFactor);
}


/***********************************************
 *
 * 		Error Raising
 *
 ***********************************************/


1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
bool ClippingShader::errorRaiseShaderMutatorFailure(bool condition, const std::string& location)
{
	if (condition)
	{
		CGoGNerr
		<< "ERROR - "
		<< location
		<< " - Shader Mutator failure"
		<< CGoGNendl;
	}

	return condition;
}

1023
bool ClippingShader::errorRaiseShaderSourceIsEmpty(bool condition, const std::string& location, ShaderMutator::shaderSrcType shaderType)
1024 1025 1026
{
	if (condition)
	{
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
		std::string shaderName;
		switch (shaderType)
		{
			case ShaderMutator::VERTEX_SHADER :
				shaderName = m_nameVS;
				break;

			case ShaderMutator::FRAGMENT_SHADER :
				shaderName = m_nameFS;
				break;

			case ShaderMutator::GEOMETRY_SHADER :
				shaderName = m_nameGS;
				break;

			default :
				shaderName = m_nameVS;
				break;
		}
1046 1047 1048 1049 1050

		CGoGNerr
		<< "ERROR - "
		<< location
		<< " - Could not process shader "
1051
		<< shaderName
1052
		<< " source code : shader source is empty"
1053 1054 1055
		<< CGoGNendl;
	}

1056 1057 1058 1059 1060 1061
	return condition;
}

bool ClippingShader::errorRaiseShaderUsesGeometryShader(bool condition, const std::string& location)
{
	if (condition)
1062
	{
1063 1064
		std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

1065 1066
		CGoGNerr
		<< "ERROR - "
1067 1068
		<< location
		<< " - Could not process shader "
1069
		<< shaderName
1070
		<< " source code : unable to add clipping to a shader which uses a geometry shader"
1071 1072 1073
		<< CGoGNendl;
	}

1074
	return condition;
1075 1076
}

1077
bool ClippingShader::errorRaiseVariableNotFoundInShader(bool condition, const std::string& location, ShaderMutator::shaderSrcType shaderType, const std::string& varName)
1078
{
1079 1080 1081
	if (condition)
	{
		std::string shaderName;
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
		switch (shaderType)
		{
			case ShaderMutator::VERTEX_SHADER :
				shaderName = m_nameVS;
				break;

			case ShaderMutator::FRAGMENT_SHADER :
				shaderName = m_nameFS;
				break;

			case ShaderMutator::GEOMETRY_SHADER :
				shaderName = m_nameGS;
				break;

			default :
				shaderName = m_nameVS;
				break;
		}
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112

		CGoGNerr
		<< "ERROR - "
		<< location
		<< " - Could not process shader "
		<< shaderName
		<< " source code : "
		<< varName
		<< " not found"
		<< CGoGNendl;
	}

	return condition;
1113
}
1114
bool ClippingShader::errorRaiseWrongId(bool condition, const std::string& location)
1115 1116 1117 1118 1119 1120
{
	if (condition)
	{
		CGoGNerr
		<< "ERROR - "
		<< location
1121
		<< " - Given ID is not valid"
1122 1123
		<< CGoGNendl;
	}
1124

1125 1126 1127 1128
	return condition;
}

bool ClippingShader::errorRaiseUniformNotFoundInShader(bool condition, const std::string& location, const std::string& uniformName)
Maire Nicolas's avatar