1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3 
4 This file is part of Aquaria.
5 
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21 #include "AfterEffect.h"
22 //#include "math.h"
23 
24 #include <assert.h>
25 
Effect()26 Effect::Effect()
27 {
28 	done = false;
29 	rate = 1;
30 }
31 
AfterEffectManager(int xDivs,int yDivs)32 AfterEffectManager::AfterEffectManager(int xDivs, int yDivs)
33 {
34 	active = false;
35 	numEffects = 0;
36 	bRenderGridPoints = true;
37 	shaderPipeline.resize(10, 0);
38 
39 	screenWidth = core->getWindowWidth();
40 	screenHeight = core->getWindowHeight();
41 
42 	this->xDivs = 0;
43 	this->yDivs = 0;
44 
45 	drawGrid = 0;
46 
47 	this->xDivs = xDivs;
48 	this->yDivs = yDivs;
49 
50 	reloadDevice();
51 
52 	if (xDivs != 0 && yDivs != 0)
53 	{
54 		drawGrid = new Vector * [xDivs];
55 		for (int i = 0; i < xDivs; i++)
56 		{
57 			drawGrid[i] = new Vector [yDivs];
58 		}
59 	}
60 
61 	loadShaders();
62 }
63 
loadShaders()64 void AfterEffectManager::loadShaders()
65 {
66 	deleteShaders();
67 
68 	// ...Load shaders here...
69 }
70 
~AfterEffectManager()71 AfterEffectManager::~AfterEffectManager()
72 {
73 	if (drawGrid)
74 	{
75 		int i;
76 		for (i = 0; i < xDivs; i++)
77 		{
78 			delete[] drawGrid[i];
79 		}
80 		delete[] drawGrid;
81 	}
82 	deleteEffects();
83 	deleteShaders();
84 }
85 
deleteEffects()86 void AfterEffectManager::deleteEffects()
87 {
88 	for (int i = 0; i < effects.size(); i++)
89 	{
90 		if (effects[i])
91 		{
92 			delete effects[i];
93 		}
94 	}
95 	effects.clear();
96 	numEffects=0;
97 	while (!openSpots.empty())
98 		openSpots.pop();
99 }
100 
deleteShaders()101 void AfterEffectManager::deleteShaders()
102 {
103 	for(size_t i = 0; i < shaderPipeline.size(); ++i)
104 		shaderPipeline[i] = 0;
105 
106 	for(size_t i = 0; i < loadedShaders.size(); ++i)
107 	{
108 		if(loadedShaders[i])
109 		{
110 			delete loadedShaders[i];
111 			loadedShaders[i] = 0;
112 		}
113 	}
114 }
115 
unloadShaders()116 void AfterEffectManager::unloadShaders()
117 {
118 	for(size_t i = 0; i < loadedShaders.size(); ++i)
119 		if(loadedShaders[i])
120 			loadedShaders[i]->unload();
121 }
122 
clear()123 void AfterEffectManager::clear()
124 {
125 	deleteEffects();
126 	resetGrid();
127 }
128 
update(float dt)129 void AfterEffectManager::update(float dt)
130 {
131 	if (core->particlesPaused) return;
132 
133 	resetGrid();
134 
135 	if (core->frameBuffer.isInited())
136 		active = true;
137 	else
138 		active = false;
139 
140 	for (int i = 0; i < effects.size(); i++)
141 	{
142 		Effect *e = effects[i];
143 		if (e)
144 		{
145 			active = true;
146 			e->update(dt, drawGrid, xDivs, yDivs);
147 			if (e->done)
148 			{
149 				numEffects--;
150 				destroyEffect(i);
151 			}
152 		}
153 	}
154 }
155 
156 
resetGrid()157 void AfterEffectManager::resetGrid()
158 {
159 	for (int i = 0; i < xDivs; i++)
160 	{
161 		for (int j = 0; j < yDivs; j++)
162 		{
163 			drawGrid[i][j].x = i/(float)(xDivs-1);
164 			drawGrid[i][j].y = j/(float)(yDivs-1);
165 		}
166 	}
167 }
168 
destroyEffect(int id)169 void AfterEffectManager::destroyEffect(int id)
170 {
171 	delete effects[id];
172 	effects[id] = 0;
173 	openSpots.push(id);
174 }
175 
render()176 void AfterEffectManager::render()
177 {
178 	assert(core->frameBuffer.isInited());
179 
180 #ifdef BBGE_BUILD_OPENGL
181 	glPushMatrix();
182 
183 	glDisable (GL_ALPHA_TEST);
184 	glDisable(GL_BLEND);
185 
186 	core->frameBuffer.endCapture();
187 	glTranslatef(core->cameraPos.x, core->cameraPos.y, 0);
188 	glScalef(core->invGlobalScale, core->invGlobalScale,0);
189 
190 	glColor4f(1,1,1,1);
191 	renderGrid();
192 	//renderGridPoints();
193 	glPopMatrix();
194 #endif
195 }
196 
renderGrid()197 void AfterEffectManager::renderGrid()
198 {
199 #ifdef BBGE_BUILD_OPENGL
200 
201 	int firstShader = -1;
202 	int lastShader = -1;
203 	Shader *activeShader = 0;
204 	for (size_t i = 0; i < shaderPipeline.size(); ++i)
205 	{
206 		if(shaderPipeline[i] && shaderPipeline[i]->isLoaded())
207 		{
208 			if(firstShader < 0)
209 			{
210 				firstShader = i;
211 				activeShader = shaderPipeline[i];
212 			}
213 			lastShader = i;
214 		}
215 	}
216 
217 	screenWidth = core->getWindowWidth();
218 	screenHeight = core->getWindowHeight();
219 
220 	float percentX, percentY;
221 	percentX = (float)screenWidth/(float)textureWidth;
222 	percentY = (float)screenHeight/(float)textureHeight;
223 
224 	int vw = core->getVirtualWidth();
225 	int vh = core->getVirtualHeight();
226 	int offx = -core->getVirtualOffX();
227 	int offy = -core->getVirtualOffY();
228 
229 	core->frameBuffer.bindTexture();
230 
231 	if(activeShader)
232 	{
233 		activeShader->bind();
234 		activeShader->setInt("tex", 0);
235 
236 		if(firstShader != lastShader)
237 			backupBuffer.startCapture();
238 	}
239 
240 	//float div = xDivs;
241 	for (int i = 0; i < (xDivs-1); i++)
242 	{
243 		for (int j = 0; j < (yDivs-1); j++)
244 		{
245 			glBegin(GL_QUADS);
246 				//glColor3f(i/div, i/div, i/div);
247 				glTexCoord2f(i/(float)(xDivs-1)*percentX,  1*percentY-(j)/(float)(yDivs-1)*percentY);
248 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,i/(float)(xDivs-1)*percentX,  1*percentY-(j)/(float)(yDivs-1)*percentY);
249 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,0,0);
250 				glVertex2f(offx + vw*drawGrid[i][j].x,		offy + vh*drawGrid[i][j].y);
251 				glTexCoord2f(i/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
252 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,i/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
253 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,0,(float)(screenHeight/(yDivs-1))/16);
254 				glVertex2f(offx + vw*drawGrid[i][j+1].x,		offy + vh*drawGrid[i][j+1].y);
255 				glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
256 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,(i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
257 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,(float)(screenWidth/(xDivs-1))/16,(float)(screenHeight/(yDivs-1))/16);
258 				glVertex2f(offx + vw*drawGrid[i+1][j+1].x,	offy + vh*drawGrid[i+1][j+1].y);
259 				glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
260 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,(i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
261 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,(float)(screenWidth/(xDivs-1))/16,0);
262 				glVertex2f(offx + vw*drawGrid[i+1][j].x,		offy + vh*drawGrid[i+1][j].y);
263 			glEnd();
264 		}
265 	}
266 
267 	if (activeShader)
268 		activeShader->unbind();
269 
270 	float width2 = float(vw)/2;
271 	float height2 = float(vh)/2;
272 
273 
274 	if(firstShader != lastShader)
275 	{
276 		// From here on: secondary shader passes.
277 		// We just outputted to the backup buffer...
278 		FrameBuffer *fbIn = &core->frameBuffer;
279 		FrameBuffer *fbOut = &backupBuffer;
280 
281 
282 		for(int i = firstShader + 1; i <= lastShader; ++i)
283 		{
284 			activeShader = shaderPipeline[i];
285 			if(!(activeShader && activeShader->isLoaded()))
286 				continue;
287 
288 			// Swap and exchange framebuffers. The old output buffer serves as texture input for the other one
289 			fbOut->endCapture();
290 			std::swap(fbIn, fbOut);
291 			fbIn->bindTexture();
292 
293 			// If this is the last pass, do not render to a frame buffer again
294 			if(i != lastShader)
295 				fbOut->startCapture();
296 
297 			activeShader->bind();
298 			activeShader->setInt("tex", 0);
299 
300 			// note that offx, offy are negative here!
301 			glBegin(GL_QUADS);
302 				glTexCoord2d(0.0f, 0.0f);
303 				glVertex3f(offx, vh+offy,  0.0f);
304 				glTexCoord2d(percentX, 0.0f);
305 				glVertex3f( vw+offx, vh+offy,  0.0f);
306 				glTexCoord2d(percentX, percentY);
307 				glVertex3f( vw+offx,  offy,  0.0f);
308 				glTexCoord2d(0.0f, percentY);
309 				glVertex3f(offx,  offy,  0.0f);
310 			glEnd();
311 
312 			activeShader->unbind();
313 		}
314 	}
315 
316 
317 	// uncomment to render grid points
318 	/*
319 	glBindTexture(GL_TEXTURE_2D, 0);
320 	glPointSize(2);
321 	glColor4f(1, 0, 0, 0.5);
322 	for (int i = 0; i < (xDivs-1); i++)
323 	{
324 		for (int j = 0; j < (yDivs-1); j++)
325 		{
326 			glBegin(GL_POINTS);
327 				//glColor3f(i/div, i/div, i/div);
328 				glTexCoord2f(i/(float)(xDivs-1)*percentX,  1*percentY-(j)/(float)(yDivs-1)*percentY);
329 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,i/(float)(xDivs-1)*percentX,  1*percentY-(j)/(float)(yDivs-1)*percentY);
330 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,0,0);
331 				glVertex2f(800*drawGrid[i][j].x,		600*drawGrid[i][j].y);
332 				glTexCoord2f(i/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
333 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,i/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
334 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,0,(float)(screenHeight/(yDivs-1))/16);
335 				glVertex2f(800*drawGrid[i][j+1].x,		600*drawGrid[i][j+1].y);
336 				glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
337 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,(i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
338 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,(float)(screenWidth/(xDivs-1))/16,(float)(screenHeight/(yDivs-1))/16);
339 				glVertex2f(800*drawGrid[i+1][j+1].x,	600*drawGrid[i+1][j+1].y);
340 				glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
341 					//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,(i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
342 					//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,(float)(screenWidth/(xDivs-1))/16,0);
343 				glVertex2f(800*drawGrid[i+1][j].x,		600*drawGrid[i+1][j].y);
344 			glEnd();
345 		}
346 	}
347 	*/
348 
349 	//glDisable(GL_TEXTURE_2D);
350 	RenderObject::lastTextureApplied = 0;
351 	glBindTexture(GL_TEXTURE_2D, 0);
352 
353 	//bwShader.unbind();
354 	//glActiveTextureARB(GL_TEXTURE0_ARB);
355 	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
356 	//if (bRenderGridPoints)
357 	//	renderGridPoints();
358 #endif
359 }
360 
renderGridPoints()361 void AfterEffectManager::renderGridPoints()
362 {
363 #ifdef BBGE_BUILD_OPENGL
364 	glColor4f(0.0f,0.0f,0.0f,1.0f);
365 	for (int i = 0; i < (xDivs); i++)
366 	{
367 		for (int j = 0; j < (yDivs); j++)
368 		{
369 		glBegin(GL_QUADS);
370 			glVertex2f(screenWidth*drawGrid[i][j].x-3,	screenHeight*drawGrid[i][j].y-3);
371 			glVertex2f(screenWidth*drawGrid[i][j].x-3,	screenHeight*drawGrid[i][j].y+3);
372 			glVertex2f(screenWidth*drawGrid[i][j].x+3,	screenHeight*drawGrid[i][j].y+3);
373 			glVertex2f(screenWidth*drawGrid[i][j].x+3,	screenHeight*drawGrid[i][j].y-3);
374 		glEnd();
375 		}
376 	}
377 #endif
378 }
379 
unloadDevice()380 void AfterEffectManager::unloadDevice()
381 {
382 	backupBuffer.unloadDevice();
383 	unloadShaders();
384 }
385 
reloadDevice()386 void AfterEffectManager::reloadDevice()
387 {
388 	screenWidth = core->getWindowWidth();
389 	screenHeight = core->getWindowHeight();
390 
391 	if (core->frameBuffer.isInited())
392 	{
393 		textureWidth = core->frameBuffer.getWidth();
394 		textureHeight = core->frameBuffer.getHeight();
395 	}
396 	else
397 	{
398 		textureWidth = screenWidth;
399 		sizePowerOf2Texture(textureWidth);
400 		textureHeight = screenHeight;
401 		sizePowerOf2Texture(textureHeight);
402 	}
403 
404 	if(backupBuffer.isInited())
405 		backupBuffer.reloadDevice();
406 	else
407 		backupBuffer.init(-1, -1, true);
408 
409 	for (size_t i = 0; i < loadedShaders.size(); ++i)
410 	{
411 		if (Shader *sh = loadedShaders[i])
412 		{
413 			sh->reload();
414 			if (!sh->isLoaded())
415 			{
416 				debugLog("AfterEffect::reloadDevice(): Failed to reload shader");
417 				delete sh;
418 				loadedShaders[i] = 0;
419 				for(size_t j = 0; j < shaderPipeline.size(); ++j)
420 					if(sh == shaderPipeline[j])
421 						shaderPipeline[j] = 0;
422 			}
423 		}
424 	}
425 }
426 
addEffect(Effect * e)427 void AfterEffectManager::addEffect(Effect *e)
428 {
429 
430 	if (!openSpots.empty())
431 	{
432 		int i = openSpots.front();
433 		openSpots.pop();
434 		effects[i] = e;
435 	}
436 	else
437 	{
438 		effects.push_back(e);
439 	}
440 	numEffects++;
441 	//float lowest = 9999;
442 	Vector base(0,0,0);
443 	//Vector *newPos = &base;
444 	//Vector *v;
445 	e->position.x /= screenWidth;
446 	//e->position.x *= xDivs;
447 	e->position.y /= screenHeight;
448 	//e->position.y *= yDivs;
449 
450 	/*
451 	for (int x = 1; x < xDivs-1; x++)
452 	{
453 		for (int y = 1; y < yDivs-1; y++)
454 		{
455 			v = &drawGrid[x][y];
456 			float dist = (v->x - e->position.x)*(v->x - e->position.x)+(v->y - e->position.y)*(v->y - e->position.y);
457 			if (dist < lowest)
458 			{
459 				lowest = dist;
460 				newPos = &drawGrid[x][y];
461 			}
462 		}
463 	}
464 	e->position = Vector(newPos->x, newPos->y, newPos->z);
465 	*/
466 
467 }
468 
469 
update(float dt,Vector ** drawGrid,int xDivs,int yDivs)470 void ShockEffect::update(float dt, Vector ** drawGrid, int xDivs, int yDivs)
471 {
472 	dt *= timeMultiplier;
473 	Effect::update(dt, drawGrid, xDivs, yDivs);
474 	//GLdouble sx, sy,sz;
475 	/*
476 	gluProject(position.x,position.y,position.z,
477 		nCameraPointer->modelMatrix,nCameraPointer->projMatrix,nCameraPointer->viewport,
478 		&sx,&sy,&sz); // Find out where the light is on the screen.
479 	centerPoint.Set(sx/(float)nCameraPointer->viewport[2],1-sy/(float)nCameraPointer->viewport[3],sz);
480 
481   */
482 	centerPoint = position;
483 	centerPoint -= ((core->screenCenter-originalCenter)*core->globalScale.x)/core->width;
484 	//centerPoint = position/xDivs;
485 	//centerPoint = drawGrid[xDivs/2][yDivs/2];
486 	float xDist,yDist,tDist;
487 
488 
489 	amplitude-=dt*rate;
490 	currentDistance+=dt*frequency;
491 
492 
493 	//float distFromCamp =(core->cameraPos - position).getLength2D();//v3dDist(nCameraPointer->pos, position);
494 	//if (distFromCamp < 4)
495 	float	distFromCamp = 4;
496 
497 	float adjWaveLength = waveLength/distFromCamp;
498 	float adjAmplitude = amplitude/distFromCamp;
499 
500 	if (amplitude < 0)
501 		done=true;
502 
503 	for (int i = 1; i < (xDivs-1); i++)
504 	{
505 		for (int j = 1; j < (yDivs-1); j++)
506 		{
507 			/*
508 			Vector p = getNearestPointOnLine(centerPoint, centerPoint + Vector(-200, -200), Vector(drawGrid[i][j].x*core->width, drawGrid[i][j].y*core->height));
509 
510 			p.x /= core->width;
511 			p.y /= core->height;
512 			*/
513 
514 			xDist = (centerPoint.x - drawGrid[i][j].x)/.75;
515 			yDist = centerPoint.y - drawGrid[i][j].y;
516 
517 			/*
518 			xDist = (p.x - drawGrid[i][j].x)/.75;
519 			yDist = p.y - drawGrid[i][j].y;
520 			*/
521 
522 			//xDist = 1;
523 			//yDist = 2;
524 			tDist = sqrtf(xDist*xDist+yDist*yDist);
525 
526 			//drawGrid[i][j].x += (rand()%100)/10000.0f;
527 			//drawGrid[i][j].y += (rand()%100)/10000.0f;
528 
529 
530 			if (tDist < currentDistance*adjWaveLength)
531 			{
532 				//drawGrid[i][j].x += rand()%50;
533 				//drawGrid[i][j].y += rand()%50;
534 				drawGrid[i][j].x += adjAmplitude*sinf(-tDist/adjWaveLength+currentDistance)*.75f;
535 				drawGrid[i][j].y += adjAmplitude*cosf(-tDist/adjWaveLength+currentDistance);
536 			}
537 		}
538 	}
539 }
540 
541 
RippleEffect()542 RippleEffect::RippleEffect() : Effect()
543 {
544 	time = 0;
545 }
546 
update(float dt,Vector ** drawGrid,int xDivs,int yDivs)547 void RippleEffect::update(float dt, Vector ** drawGrid, int xDivs, int yDivs)
548 {
549 	/*
550 	// whole screen roll
551 	time += dt;
552 	float amp = 0.01;
553 	for (int i = 0; i < (xDivs-1); i++)
554 	{
555 		for (int j = 0; j < (yDivs-1); j++)
556 		{
557 			float offset = +i/float(xDivs) +j/float(xDivs);
558 			//drawGrid[i][j].x += sinf(time+offset)*amp;
559 			drawGrid[i][j].y += cosf((time+offset)*2.5f)*amp;
560 		}
561 	}
562 	*/
563 	time += dt*0.5f;
564 	float amp = 0.002;
565 	for (int i = 0; i < (xDivs-1); i++)
566 	{
567 		for (int j = 0; j < (yDivs-1); j++)
568 		{
569 			float offset = i/float(xDivs) + (core->screenCenter.x/float(core->width)/2) +j/float(xDivs) + (core->screenCenter.y/float(core->height)/2);
570 			//drawGrid[i][j].x += sinf(time+offset)*amp;
571 			drawGrid[i][j].x += sinf((time+offset)*7.5f)*(amp*0.5f);
572 			drawGrid[i][j].y += cosf((time+offset)*7.5f)*amp;
573 		}
574 	}
575 }
576 
loadShaderFile(const char * vert,const char * frag)577 int AfterEffectManager::loadShaderFile(const char *vert, const char *frag)
578 {
579 	Shader *sh = new Shader();
580 	sh->load(vert, frag);
581 	if(!sh->isLoaded())
582 	{
583 		delete sh;
584 		return 0;
585 	}
586 	return _insertShader(sh);
587 }
588 
loadShaderSrc(const char * vert,const char * frag)589 int AfterEffectManager::loadShaderSrc(const char *vert, const char *frag)
590 {
591 	Shader *sh = new Shader();
592 	sh->loadSrc(vert, frag);
593 	if(!sh->isLoaded())
594 	{
595 		delete sh;
596 		return 0;
597 	}
598 	return _insertShader(sh);
599 }
600 
getShaderPtr(int handle)601 Shader *AfterEffectManager::getShaderPtr(int handle)
602 {
603 	size_t idx = handle - 1;
604 	return idx  < loadedShaders.size() ? loadedShaders[idx] : 0;
605 }
606 
setShaderPipelineSize(size_t size)607 void AfterEffectManager::setShaderPipelineSize(size_t size)
608 {
609 	shaderPipeline.resize(size, 0);
610 }
611 
setShaderPipelinePos(int handle,size_t pos)612 bool AfterEffectManager::setShaderPipelinePos(int handle, size_t pos)
613 {
614 	if(pos < shaderPipeline.size())
615 	{
616 		shaderPipeline[pos] = getShaderPtr(handle);
617 		return true;
618 	}
619 	return false;
620 }
621 
622 // returns handle (= index + 1)
_insertShader(Shader * sh)623 int AfterEffectManager::_insertShader(Shader *sh)
624 {
625 	for(size_t i = 0; i < loadedShaders.size(); ++i)
626 	{
627 		if(!loadedShaders[i])
628 		{
629 			loadedShaders[i] = sh;
630 			return i+1;
631 		}
632 	}
633 	loadedShaders.push_back(sh);
634 	return loadedShaders.size();
635 }
636 
deleteShader(int handle)637 void AfterEffectManager::deleteShader(int handle)
638 {
639 	Shader *sh = getShaderPtr(handle);
640 	if(!sh)
641 		return;
642 
643 	for(size_t i = 0; i < shaderPipeline.size(); ++i)
644 		if(shaderPipeline[i] == sh)
645 			shaderPipeline[i] = 0;
646 
647 	size_t idx = handle - 1;
648 	loadedShaders[idx] = 0;
649 	delete sh;
650 }
651 
652