shaderMutator.cpp 23.5 KB
Newer Older
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           *
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/                                           *
21
22
23
24
25
* Contact information: cgogn@unistra.fr                                        *
*                                                                              *
*******************************************************************************/

#include "Utils/shaderMutator.h"
26
#include <regex>
27
28
29
30
31
32
33

namespace CGoGN
{

namespace Utils
{

34

35
36
37
38
39
40
/***********************************************
 *
 * 		Public Section
 *
 ***********************************************/

41

42
43
44
45
46
47
48
49
50
51
52
ShaderMutator::ShaderMutator(const std:: string& shaderName, const std::string& vertShaderSrc, const std::string& fragShaderSrc, const std::string& geomShaderSrc)
{
	// Store the shader name
	m_shaderName = shaderName;

	// Store the shader source codes
	m_vShaderMutation = vertShaderSrc;
	m_fShaderMutation = fragShaderSrc;
	m_gShaderMutation = geomShaderSrc;
}

53
bool ShaderMutator::containsVariableDeclaration(shaderSrcType srcType, const std::string& variableName)
54
{
55
	bool result = false;
56

57
58
59
60
61
	switch (srcType)
	{
		case VERTEX_SHADER :
			result = srcContainsVariableDeclaration(variableName, m_vShaderMutation);
			break;
62

63
64
65
		case FRAGMENT_SHADER :
			result = srcContainsVariableDeclaration(variableName, m_fShaderMutation);
			break;
66

67
68
69
		case GEOMETRY_SHADER :
			result = srcContainsVariableDeclaration(variableName, m_gShaderMutation);
			break;
70
71
	}

72
	return result;
73
74
}

Maire Nicolas's avatar
Maire Nicolas committed
75
bool ShaderMutator::setMinShadingLanguageVersion(shaderSrcType srcType, int version)
76
{
Maire Nicolas's avatar
Maire Nicolas committed
77
78
	bool result = false;

79
	switch (srcType)
80
	{
81
		case VERTEX_SHADER :
Maire Nicolas's avatar
Maire Nicolas committed
82
			result = srcSetMinShadingLanguageVersion(version, m_vShaderMutation);
83
			break;
84

85
		case FRAGMENT_SHADER :
Maire Nicolas's avatar
Maire Nicolas committed
86
			result = srcSetMinShadingLanguageVersion(version, m_fShaderMutation);
87
			break;
88

89
		case GEOMETRY_SHADER :
Maire Nicolas's avatar
Maire Nicolas committed
90
			result = srcSetMinShadingLanguageVersion(version, m_gShaderMutation);
91
			break;
92
	}
Maire Nicolas's avatar
Maire Nicolas committed
93
94

	return result;
95
96
}

Maire Nicolas's avatar
Maire Nicolas committed
97
bool ShaderMutator::changeIntConstantValue(shaderSrcType srcType, const std::string& constantName, int newVal)
98
{
99
	switch (srcType)
100
	{
101
		case VERTEX_SHADER :
102
			if (!srcChangeIntConstantValue(newVal, constantName, m_vShaderMutation))
103
104
105
106
107
108
109
110
111
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::changeIntConstantValue : "
				<< "Unable to change int constant value in vertex shader of "
				<< m_shaderName
				<< ". Constant declaration not found"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
112
				return false;
113
114
115
116
			}
			break;

		case FRAGMENT_SHADER :
117
			if (!srcChangeIntConstantValue(newVal, constantName, m_fShaderMutation))
118
119
120
121
122
123
124
125
126
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::changeIntConstantValue : "
				<< "Unable to change int constant value in fragment shader of "
				<< m_shaderName
				<< ". Constant declaration not found"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
127
				return false;
128
129
130
131
			}
			break;

		case GEOMETRY_SHADER :
132
			if (!srcChangeIntConstantValue(newVal, constantName, m_gShaderMutation))
133
134
135
136
137
138
139
140
141
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::changeIntConstantValue : "
				<< "Unable to change int constant value in geometry shader of "
				<< m_shaderName
				<< ". Constant declaration not found"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
142
				return false;
143
144
			}
			break;
145
	}
Maire Nicolas's avatar
Maire Nicolas committed
146
147

	return true;
148
149
}

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
bool ShaderMutator::changeFloatConstantValue(shaderSrcType srcType, const std::string& constantName, float newVal)
{
	switch (srcType)
	{
		case VERTEX_SHADER :
			if (!srcChangeFloatConstantValue(newVal, constantName, m_vShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::changeFloatConstantValue : "
				<< "Unable to change float constant value in vertex shader of "
				<< m_shaderName
				<< ". Constant declaration not found"
				<< CGoGNendl;

				return false;
			}
			break;

		case FRAGMENT_SHADER :
			if (!srcChangeFloatConstantValue(newVal, constantName, m_fShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::changeFloatConstantValue : "
				<< "Unable to change float constant value in fragment shader of "
				<< m_shaderName
				<< ". Constant declaration not found"
				<< CGoGNendl;

				return false;
			}
			break;

		case GEOMETRY_SHADER :
			if (!srcChangeFloatConstantValue(newVal, constantName, m_gShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::changeFloatConstantValue : "
				<< "Unable to change float constant value in geometry shader of "
				<< m_shaderName
				<< ". Constant declaration not found"
				<< CGoGNendl;

				return false;
			}
			break;
	}

	return true;
}

Maire Nicolas's avatar
Maire Nicolas committed
203
bool ShaderMutator::insertCodeBeforeMainFunction(shaderSrcType srcType, const std::string& insertedCode)
204
{
205
	switch (srcType)
206
	{
207
208
209
210
211
212
213
214
215
216
217
		case VERTEX_SHADER :
			if (!srcInsertCodeBeforeMainFunction(insertedCode, m_vShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeBeforeMainFunction : "
				<< "Unable to insert source code in vertex shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
218
				return false;
219
220
221
222
223
224
225
226
227
228
229
230
231
232
			}
			break;

		case FRAGMENT_SHADER :
			if (!srcInsertCodeBeforeMainFunction(insertedCode, m_fShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeBeforeMainFunction : "
				<< "Unable to insert source code in fragment shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
233
				return false;
234
235
236
237
238
239
240
241
242
243
244
245
246
247
			}
			break;

		case GEOMETRY_SHADER :
			if (!srcInsertCodeBeforeMainFunction(insertedCode, m_gShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeBeforeMainFunction : "
				<< "Unable to insert source code in geometry shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
248
				return false;
249
250
			}
			break;
251
	}
Maire Nicolas's avatar
Maire Nicolas committed
252
253

	return true;
254
255
}

Maire Nicolas's avatar
Maire Nicolas committed
256
bool ShaderMutator::insertCodeAtMainFunctionBeginning(shaderSrcType srcType, const std::string& insertedCode)
257
{
258
	switch (srcType)
259
	{
260
261
262
263
264
265
266
267
268
269
270
		case VERTEX_SHADER :
			if (!srcInsertCodeAtMainFunctionBeginning(insertedCode, m_vShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeAtMainFunctionBeginnning : "
				<< "Unable to insert source code in vertex shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
271
				return false;
272
273
274
275
276
277
278
279
280
281
282
283
284
285
			}
			break;

		case FRAGMENT_SHADER :
			if (!srcInsertCodeAtMainFunctionBeginning(insertedCode, m_fShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeAtMainFunctionBeginnning : "
				<< "Unable to insert source code in fragment shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
286
				return false;
287
288
289
290
291
292
293
294
295
296
297
298
299
300
			}
			break;

		case GEOMETRY_SHADER :
			if (!srcInsertCodeAtMainFunctionBeginning(insertedCode, m_gShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeAtMainFunctionBeginnning : "
				<< "Unable to insert source code in geometry shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
301
				return false;
302
303
			}
			break;
304
	}
Maire Nicolas's avatar
Maire Nicolas committed
305
306

	return true;
307
308
}

Maire Nicolas's avatar
Maire Nicolas committed
309
bool ShaderMutator::insertCodeAtMainFunctionEnd(shaderSrcType srcType, const std::string& insertedCode)
310
{
311
	switch (srcType)
312
	{
313
314
315
316
317
318
319
320
321
322
323
324
		case VERTEX_SHADER :
			if (!srcInsertCodeAtMainFunctionEnd(insertedCode, m_vShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeAtMainFunctionEnd : "
				<< "Unable to insert source code in vertex shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration "
				<< "and as many '{' as '}' in main"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
325
				return false;
326
327
			}
			break;
328

329
330
331
332
333
334
335
336
337
338
339
340
		case FRAGMENT_SHADER :
			if (!srcInsertCodeAtMainFunctionEnd(insertedCode, m_fShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeAtMainFunctionEnd : "
				<< "Unable to insert source code in fragment shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration "
				<< "and as many '{' as '}' in main"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
341
				return false;
342
343
			}
			break;
344

345
346
347
348
349
350
351
352
353
354
355
356
		case GEOMETRY_SHADER :
			if (!srcInsertCodeAtMainFunctionEnd(insertedCode, m_gShaderMutation))
			{
				CGoGNerr
				<< "ERROR - "
				<< "ShaderMutator::insertCodeAtMainFunctionEnd : "
				<< "Unable to insert source code in geometry shader of "
				<< m_shaderName
				<< ". You should check if the shader has a main function declaration "
				<< "and as many '{' as '}' in main"
				<< CGoGNendl;

Maire Nicolas's avatar
Maire Nicolas committed
357
				return false;
358
359
360
			}
			break;
	}
Maire Nicolas's avatar
Maire Nicolas committed
361
362

	return true;
363
}
364
365


366
367
368
369
370
/***********************************************
 *
 * 		Private Section
 *
 ***********************************************/
371
372


373
bool ShaderMutator::srcIsCommented(size_t pos, const std::string& src)
374
{
375
376
	// Verify that the given position is not out of the source
	if (pos >= src.length())
377
378
379
	{
		CGoGNerr
		<< "ERROR - "
380
		<< "ShaderMutator::srcIsCommented : "
381
382
383
384
385
		<< "Given position is out of range"
		<< CGoGNendl;
		return false;
	}
	
386
	// Look backward in the source to see if there is any comment symbol (// or /* */)
387
388
	
	// First look for one-line comments
389
	if (srcIsOneLineCommented(pos, src))
390
391
392
		return true;
	
	// Now look for multi-line comments 
393
	for (size_t i = pos; i > 0; i--)
394
	{	
395
		if (src[i] == '/')
396
397
		{
			// End of multi-line comment
398
			if (src[i-1] == '*')
399
400
			{
				// Verify that the end of multi-line comment is not one-line commented !
401
				if (!srcIsOneLineCommented(i, src))
402
403
404
					return false;
			}
		}
405
		else if (src[i] == '*')
406
407
		{
			// Beginning of multi-line comment
408
			if (src[i-1] == '/')
409
410
			{
				// Verify that the beginning of multi-line comment is not one-line commented !
411
				if (!srcIsOneLineCommented(i, src))
412
413
414
415
416
417
418
419
420
421
					return true;
			}
		}
	}
	
	// No one-line or multi-line comments were found
	return false;
	
}

422
bool ShaderMutator::srcIsOneLineCommented(size_t pos, const std::string& src)
423
{
424
425
	// Verify that the given position is not out of the source
	if (pos >= src.length())
426
427
428
	{
		CGoGNerr
		<< "ERROR - "
429
		<< "ShaderMutator::srcIsOneLineCommented : "
430
431
432
433
434
		<< "Given position is out of range"
		<< CGoGNendl;
		return false;
	}
	
435
	// Look backward in the source to see if there is any "//"
436
	for (size_t i = pos; i > 0; i--)
437
438
	{
		// As soon as a '\n' is found, any other "//" will not affect this line anymore
439
		if (src[i] == '\n')
440
			return false;
441
		// Else if a '/' is found, look if it is followed by another
442
443
		else if (src[i] == '/')
			if (src[i-1] == '/')
444
445
446
447
448
449
450
				return true;
	}
	
	// No one-line comments were found
	return false;
}

451
bool ShaderMutator::srcContainsVariableDeclaration(const std::string& variableName, std::string& src)
452
453
454
{
	// Regular expression for variable declaration
	// <',' OR white-space[1 or more times]> <variableName> <',' OR ';' OR white-space>
455
	std::regex var_re("(,|\\s+)" + variableName + "(,|;|\\s)");
456
457
	
	// Matches results
458
	std::match_results <std::string::iterator> matches;
459
460
461
462
	
	// Search for the first expression that matches and isn't commented
	std::string::iterator start = src.begin();
	std::string::iterator end = src.end();
463
	while (std::regex_search(start, end, matches, var_re, std::regex_constants::format_first_only))
464
465
466
467
468
	{
		// Start position of the match
		size_t startPosition = std::distance(src.begin(), matches[0].first);
		
		// Finish if the matched variable is the good one (i.e. not commented)
469
		if (!srcIsCommented(startPosition, src))
470
471
472
473
474
475
476
477
478
479
			return true;
		// Else continue to search for it after last match
		else
			start = matches[0].second;
	}
	
	// At this point no correct match was found
	return false;
}

480
bool ShaderMutator::srcSetMinShadingLanguageVersion(int version, std::string& modifiedSrc)
481
482
{
	// Regular expression for shading language version
483
	// <#version> <white-space>[1 or more times] <digit>[1 or more times]
484
	std::regex version_re("#version\\s+(\\d+)");
485
486

	// Matches results
487
	std::match_results <std::string::iterator> matches;
488
489
490
491
492
493
494
495
496
497

	// Build the version string
	std::string versionStr;
	std::stringstream ss;
	ss << version;
	versionStr = ss.str();

	// Search for the first expression that matches and isn't commented
	std::string::iterator start = modifiedSrc.begin();
	std::string::iterator end = modifiedSrc.end();
498
	while (std::regex_search(start, end, matches, version_re, std::regex_constants::format_first_only))
499
500
501
502
503
	{
		// Start position of the match
		size_t startPosition = std::distance(modifiedSrc.begin(), matches[0].first);

		// Change the version number if the matched "#version ..." is the good one (i.e. not commented)
504
		if (!srcIsCommented(startPosition, modifiedSrc))
505
		{
506
			// The submatch Match[1] should be the version number
507
508
509
510
511
			std::string oldVersion(matches[1].first, matches[1].second);
			int oldVersionValue = atoi(oldVersion.c_str());
			size_t oldVersionLength = oldVersion.length();
			size_t oldVersionPosition = std::distance(modifiedSrc.begin(), matches[1].first);

512
			// Replace the old version value only if it is lower than 'version'
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
			if (oldVersionValue < version)
			{
				modifiedSrc.replace(oldVersionPosition, oldVersionLength, versionStr);
				return true;
			}
			else
				return false;
		}
		// Else continue to search for it after last match
		else
		{
			start = matches[0].second;
		}
	}

	// At this point no correct match was found : insert directly the "#version ..." line
	std::string versionLineStr = "#version " + versionStr + "\n";
	modifiedSrc.insert(0, versionLineStr);

	return true;
}

535
bool ShaderMutator::srcChangeIntConstantValue(int newVal, const std::string& constantName, std::string& modifiedSrc)
536
537
{
	// Regular expression for constant expression
538
	// <#define> <white-space>[1 or more times] <constant name> <white-space>[1 or more times] <digit>[1 or more times]
539
	std::regex const_re("#define\\s+" + constantName + "\\s+(\\d+)");
540
541

	// Matches results
542
	std::match_results <std::string::iterator> matches;
543
544
545
546
547
548
549

	// Build the constant value string
	std::string newValStr;
	std::stringstream ss;
	ss << newVal;
	newValStr = ss.str();

550
551
552
	// Search for the first expression that matches and isn't commented
	std::string::iterator start = modifiedSrc.begin();
	std::string::iterator end = modifiedSrc.end();
553
	while (std::regex_search(start, end, matches, const_re, std::regex_constants::format_first_only))
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
	{
		// Start position of the match
		size_t startPosition = std::distance(modifiedSrc.begin(), matches[0].first);

		// Change the constant value if the matched "#define ..." is the good one (i.e. not commented)
		if (!srcIsCommented(startPosition, modifiedSrc))
		{
			// The submatch Match[1] should be the old constant value
			std::string oldValStr(matches[1].first, matches[1].second);
			size_t oldValLength = oldValStr.length();
			size_t oldValPosition = std::distance(modifiedSrc.begin(), matches[1].first);

			// Replace the old constant value
			modifiedSrc.replace(oldValPosition, oldValLength, newValStr);
			return true;
		}
		// Else continue to search for it after last match
		else
		{
			start = matches[0].second;
		}
	}

	// At this point no correct match was found
	return false;
}

bool ShaderMutator::srcChangeFloatConstantValue(float newVal, const std::string& constantName, std::string& modifiedSrc)
{
	// Regular expression for constant expression
	// <#define> <white-space>[1 or more times] <constant name> <white-space>[1 or more times]
	// <digit>[1 or more times] <.>[0 or 1 time] <digit>[0 or more times]
586
	std::regex const_re("#define\\s+" + constantName + "\\s+(\\d+\\.?\\d*)");
587
588

	// Matches results
589
	std::match_results <std::string::iterator> matches;
590
591
592
593
594
595
596

	// Build the constant value string
	std::string newValStr;
	std::stringstream ss;
	ss << newVal;
	newValStr = ss.str();

597
598
599
	// Search for the first expression that matches and isn't commented
	std::string::iterator start = modifiedSrc.begin();
	std::string::iterator end = modifiedSrc.end();
600
	while (std::regex_search(start, end, matches, const_re, std::regex_constants::format_first_only))
601
602
603
604
605
606
607
608
609
610
611
612
	{
		// Start position of the match
		size_t startPosition = std::distance(modifiedSrc.begin(), matches[0].first);

		// Change the constant value if the matched "#define ..." is the good one (i.e. not commented)
		if (!srcIsCommented(startPosition, modifiedSrc))
		{
			// The submatch Match[1] should be the old constant value
			std::string oldValStr(matches[1].first, matches[1].second);
			size_t oldValLength = oldValStr.length();
			size_t oldValPosition = std::distance(modifiedSrc.begin(), matches[1].first);

613
			// Replace the old constant value
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
			modifiedSrc.replace(oldValPosition, oldValLength, newValStr);
			return true;
		}
		// Else continue to search for it after last match
		else
		{
			start = matches[0].second;
		}
	}

	// At this point no correct match was found
	return false;
}

bool ShaderMutator::srcInsertCodeBeforeMainFunction(const std::string& insertedCode, std::string& modifiedSrc)
629
630
631
{
	// Regular expression for main function
	// <void> <white-space>[1 or more times] <main> <white-space>[0 or more times] <'('>
632
	std::regex main_re("(void)\\s+(main)\\s*\\(");
633
634
	
	// Matches results
635
	std::match_results <std::string::iterator> matches;
636
637
638
639
	
	// Search for the first expression that matches and isn't commented
	std::string::iterator start = modifiedSrc.begin();
	std::string::iterator end = modifiedSrc.end();
640
	while (std::regex_search(start, end, matches, main_re, std::regex_constants::format_first_only))
641
642
643
644
645
	{
		// Start position of the match
		size_t startPosition = std::distance(modifiedSrc.begin(), matches[0].first);
		
		// Insert and finish if the matched "main" is the good one (i.e. not commented)
646
		if (!srcIsCommented(startPosition, modifiedSrc))
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
		{
			modifiedSrc.insert(startPosition, insertedCode);
			return true;
		}
		// Else continue to search for it after last match
		else
		{
			start = matches[0].second;
		}
	}
	
	// At this point no correct match was found
	return false;
}

662
bool ShaderMutator::srcInsertCodeAtMainFunctionBeginning(const std::string& insertedCode, std::string& modifiedSrc)
663
664
665
666
667
{
	// Regular expression for main function
	// <void> <white-space>[1 or more times] <main> <white-space>[0 or more times]
	// <'('> <white-space>[0 or more times] <')'>
	// <white-space>[0 or more times] <'{'>
668
	std::regex main_re("(void)\\s+(main)\\s*\\(\\s*\\)\\s*\\{");
669
670
	
	// Matches results
671
	std::match_results <std::string::iterator> matches;
672
673
674
675
	
	// Search for the first expression that matches and isn't commented
	std::string::iterator start = modifiedSrc.begin();
	std::string::iterator end = modifiedSrc.end();
676
	while (std::regex_search(start, end, matches, main_re, std::regex_constants::format_first_only))
677
678
679
680
681
682
683
684
	{
		// Start position of the match
		size_t startPosition = std::distance(modifiedSrc.begin(), matches[0].first);
		
		// End position of the match
		size_t endPosition = std::distance(modifiedSrc.begin(), matches[0].second);
		
		// Insert and finish if the matched "main" is the good one (i.e. not commented)
685
		if (!srcIsCommented(startPosition, modifiedSrc))
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
		{
			modifiedSrc.insert(endPosition, insertedCode);
			return true;
		}
		// Else continue to search for it after last match
		else
		{
			start = matches[0].second;
		}
	}
	
	// At this point no correct match was found
	return false;
}

701
bool ShaderMutator::srcInsertCodeAtMainFunctionEnd(const std::string& insertedCode, std::string& modifiedSrc)
702
703
704
705
706
{
	// Regular expression for main function
	// <void> <white-space>[1 or more times] <main> <white-space>[0 or more times]
	// <'('> <white-space>[0 or more times] <')'>
	// <white-space>[0 or more times] <'{'>
707
	std::regex main_re("(void)\\s+(main)\\s*\\(\\s*\\)\\s*\\{");
708
709
	
	// Matches results
710
	std::match_results <std::string::iterator> matches;
711
712
713
714
	
	// Search for the first expression that matches and isn't commented
	std::string::iterator start = modifiedSrc.begin();
	std::string::iterator end = modifiedSrc.end();
715
	size_t mainFirstBracePos = 0;  // The aim is first to find this position
716
	while (std::regex_search(start, end, matches, main_re, std::regex_constants::format_first_only) && (mainFirstBracePos == 0))
717
718
719
720
721
722
723
724
	{
		// Start position of the match
		size_t startPosition = std::distance(modifiedSrc.begin(), matches[0].first);
		
		// End position of the match
		size_t endPosition = std::distance(modifiedSrc.begin(), matches[0].second);
		
		// Get the main first brace position if the matched "main" is the good one (i.e. not commented)
725
		if (!srcIsCommented(startPosition, modifiedSrc))
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
			mainFirstBracePos = endPosition;
		// Else continue to search for it after last match
		else
			start = matches[0].second;
	}
	
	// If mainFirstBracePos is still zero, no correct match was found
	if (mainFirstBracePos == 0)
		return false;
	
	// Else, it is now possible to count the opening and closing braces till the final closing brace of the main function is reached
	int bracesCounter = 1;  // =1 since the first opening brace is counted in, it will be =0 when the final closing brace is reached
	size_t closestBracePos = mainFirstBracePos;
	size_t closestOpeningBracePos;
	size_t closestClosingBracePos;
	while (bracesCounter != 0)
	{
		closestOpeningBracePos = modifiedSrc.find_first_of('{', closestBracePos + 1);
		// If this brace appears to be commented, try to get the next one
745
		while ((closestOpeningBracePos != std::string::npos) && srcIsCommented(closestOpeningBracePos, modifiedSrc))
746
747
748
749
			closestOpeningBracePos = modifiedSrc.find_first_of('{', closestOpeningBracePos + 1);
		
		closestClosingBracePos = modifiedSrc.find_first_of('}', closestBracePos + 1);
		// If this brace appears to be commented, try to get the next one
750
		while ((closestClosingBracePos != std::string::npos) && srcIsCommented(closestClosingBracePos, modifiedSrc))
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
			closestClosingBracePos = modifiedSrc.find_first_of('}', closestClosingBracePos + 1);

		// Happens if there is not enough "}" for the corresponding "{"
		if (closestClosingBracePos == std::string::npos)
			return false;

		// Refresh the closest brace position, and increment or decrement the counter
		if (closestClosingBracePos < closestOpeningBracePos)
		{
			closestBracePos = closestClosingBracePos;
			bracesCounter -= 1;
		}
		else
		{
			closestBracePos = closestOpeningBracePos;
			bracesCounter += 1;
		}
	}

	// We should now have the final '}' of the main function
	size_t mainLastBracePos = closestBracePos;
	
	// Insert the source there
	modifiedSrc.insert(mainLastBracePos, insertedCode);
Thery Sylvain's avatar
Thery Sylvain committed
775
776
777
778
779

	size_t posPb = modifiedSrc.find_last_of(';');
	if (modifiedSrc.substr(posPb-6,7) == "#endif;")
		modifiedSrc[posPb] = '\n';

780
781
782
783
784
785
	return true;
}

} // namespace Utils

} // namespace CGoGN