1 
2 // fxman.cpp [pengine]
3 
4 // Copyright 2004-2006 Jasmine Langridge, jas@jareiko.net
5 // License: GPL version 2 (see included gpl.txt)
6 
7 
8 #include "pengine.h"
9 #include "physfs_utils.h"
10 
11 // @todo: what these two global things are?
12 fx_renderstate_s def_rs;
13 
14 int max_tex_units;
15 
16 
17 
PSSEffect(PApp & parentApp)18 PSSEffect::PSSEffect(PApp &parentApp) : PSubsystem(parentApp)
19 {
20   PUtil::outLog() << "Initialising effects subsystem" << std::endl;
21 
22   def_rs.depthtest = true;
23 
24   def_rs.lighting = true;
25   def_rs.lightmodeltwoside = false;
26 
27   def_rs.alphatest.func = GL_ALWAYS;
28   def_rs.alphatest.ref = 0.0; // not important for GL_ALWAYS anyway
29 
30   def_rs.cullface = CULLFACE_CW;
31 
32   def_rs.blendmode = BLEND_NONE;
33 
34   def_rs.texunit[0].texindex = -1;
35 
36   glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_tex_units);
37 }
38 
~PSSEffect()39 PSSEffect::~PSSEffect()
40 {
41   PUtil::outLog() << "Shutting down effects subsystem" << std::endl;
42 
43   fxlist.clear();
44 }
45 
46 
loadEffect(const std::string & name)47 PEffect *PSSEffect::loadEffect(const std::string &name)
48 {
49   PEffect *fx = fxlist.find(name);
50   if (!fx) {
51     try
52     {
53       fx = new PEffect (name);
54     }
55     catch (PException &e)
56     {
57       if (PUtil::isDebugLevel(DEBUGLEVEL_ENDUSER))
58         PUtil::outLog() << "Failed to load " << name << ": " << e.what () << std::endl;
59       return nullptr;
60     }
61     fx->setFirstValidTechnique();
62     fxlist.add(fx);
63   }
64   return fx;
65 }
66 
67 // ???
68 #define con_printf(...)
69 
70 
71 
72 
~PEffect()73 PEffect::~PEffect()
74 {
75   unload ();
76 }
77 
unload()78 void PEffect::unload()
79 {
80   tex.clear ();
81   tech.clear ();
82 }
83 
PEffect(const std::string & filename)84 PEffect::PEffect(const std::string &filename)
85 {
86    cur_tech = -1;
87 
88    /* Let's check each effect type will load (FX or OBJ's MTL) */
89    if(filename.find(".fx") != std::string::npos)
90    {
91       loadFX(filename);
92    }
93    else
94    {
95       loadMTL(filename);
96    }
97 }
98 
99 /*! Load an OBJ's MTL file as the effect definition.
100  * \note: It just create a default PEffect using the material first texture,
101  *        ignoring all material real things (unused by the renderer, btw) */
102 #define BUF_SIZE 1024
loadMTL(const std::string & filename)103 void PEffect::loadMTL(const std::string &filename)
104 {
105    char buff[BUF_SIZE];             /**< File buffer */
106    PHYSFS_file* pfile;          /**< The real .obj file */
107    std::string tok;             /**< Readed token from line */
108    std::string value;           /**< Readed value from line */
109    int numMaterials=0;          /**< Number of materials readed */
110 
111    if(PUtil::isDebugLevel(DEBUGLEVEL_TEST))
112    {
113       PUtil::outLog() << "Loading .mtl Material \"" << filename
114          << "\"" << std::endl;
115    }
116 
117    /* Unload previous loaded effect */
118    unload();
119 
120    /* Let's read from file */
121    pfile = PHYSFS_openRead(filename.c_str());
122    if(pfile == nullptr)
123    {
124       con_printf("Cannot find effect file \"%s\"\n",filename);
125       throw MakePException ("PhysFS: " + physfs_getErrorString());
126    }
127 
128    name = filename;
129 
130    /* Loop throught all file */
131    while(PUtil::fgets2(buff,BUF_SIZE,pfile))
132    {
133       if(PUtil::getToken(buff, tok, value))
134       {
135          if(numMaterials > 1)
136          {
137             /* FIXME: ignoring all further materials. */
138          }
139          else if(tok == "newmtl")
140          {
141             numMaterials++;
142             /* FIXME: ignoring material name, as it's already the filename. */
143          }
144          else if(tok == "map_Kd")
145          {
146             /* Define the FX single texture */
147             tex.push_back(fx_texture_s());
148             fx_texture_s *curtex = &tex.back();
149             /* Already as 2D texture. */
150             curtex->texobject = NULL;
151             curtex->name = value;
152             curtex->type = GL_TEXTURE_2D;
153             curtex->filename = PUtil::assemblePath(value, filename);
154 
155             /* Define the default Technique */
156             tech.push_back(fx_technique_s());
157             fx_technique_s *curtech = &tech.back();
158             curtech->name = "DefaultTechMTL";
159             /* And its default pass and render state */
160             curtech->pass.push_back(fx_pass_s());
161             fx_pass_s *curpass = &curtech->pass.back();
162             fx_renderstate_s *currs = &curpass->rs;
163             /* Uhm? Copyed from the loadFX bellow... Just set some defaults,
164              * and the the texture to the only one defined. */
165             *currs = def_rs;
166             currs->depthtest = true;
167             currs->cullface = CULLFACE_CW;
168             currs->texunit[0].texindex = 0;
169          }
170          else
171          {
172             /* Ignore everithing, as the FX will only use the texture. */
173          }
174       }
175    }
176 
177    /* Done! */
178    PHYSFS_close(pfile);
179 }
180 #undef BUF_SIZE
181 
loadFX(const std::string & filename)182 void PEffect::loadFX(const std::string &filename)
183 {
184 	if (PUtil::isDebugLevel(DEBUGLEVEL_TEST))
185 		PUtil::outLog() << "Loading fx shader \"" << filename << "\"" << std::endl;
186 
187 	// unload eventual previous loaded effect
188 	unload();
189 
190 	// open file
191 	PHYSFS_file *pfile = PHYSFS_openRead(filename.c_str());
192 	if (pfile == nullptr)
193 	{
194 		con_printf("Cannot find effect file \"%s\"\n",filename);
195 		throw MakePException ("PhysFS: " + physfs_getErrorString());
196 	}
197 
198 	// set the name
199 	name = filename;
200 
201 	// we'll create a string storing the whole file
202 	int leng = PHYSFS_fileLength(pfile);
203 	char *source = new char[leng+1];
204 	physfs_read(pfile, source, sizeof(char), leng);
205 	source[leng] = '\0';
206 
207 	// close file since we have everything in char *source
208 	PHYSFS_close(pfile);
209 
210 #define SKIPWHITESPACE \
211 { \
212 	while (*scan == ' ' || *scan == '\t' || *scan == '\n' || *scan == '\r') { \
213 		if (*scan == '\n') linec++; \
214 		scan++; \
215 	} \
216 }
217 
218 #define READTOKEN \
219 { \
220 	token = buff1; \
221 	if (*scan == '\"') { \
222 		scan++; \
223 		while ((*scan) && (*scan != '\"')) { \
224 			*(token++) = *(scan++); \
225 		} *token = '\0'; token = buff1; scan++; \
226 	} else { \
227 		while ((*scan >= 'a' && *scan <= 'z') || \
228 			(*scan >= 'A' && *scan <= 'Z') || \
229 			(*scan >= '0' && *scan <= '9') || \
230 			(*scan == '_')) { \
231 			*(token++) = *(scan++); \
232 		} *token = '\0'; token = buff1; \
233 	} \
234 }
235 
236 #define READNUMERICALTOKEN \
237 { \
238 	token = buff1; \
239 	while ((*scan >= '0' && *scan <= '9') || \
240 	(*scan == '-' || *scan == '.')) \
241 	{ \
242 		*(token++) = *(scan++); \
243 	} \
244 	*token = '\0'; \
245 	token = buff1; \
246 }
247 
248 #define FAILURE \
249 { \
250 	parseerror = true; \
251 	break; \
252 }
253 
254 	char buff1[512];
255 
256 	char *token;
257 
258 	// In case of failures, stores short descriptive string
259 	std::string detail("parse error");
260 
261 	int linec = 1;
262 	bool parseerror = false;
263 
264 	// this is the pointer to the char in source that's to be read next
265 	char* scan = source;
266 
267 	while (1)
268 	{
269 		SKIPWHITESPACE;
270 		if (!*scan)
271 			break;
272 
273 		READTOKEN;
274 		if (!*scan)
275 			FAILURE;
276 
277 		if (!strcmp(token, "texture"))
278 		{
279 			tex.push_back(fx_texture_s());
280 			fx_texture_s *curtex = &tex.back();
281 
282 			curtex->texobject = nullptr;
283 
284 			SKIPWHITESPACE;
285 			if (!*scan)
286 				FAILURE;
287 
288 			READTOKEN;
289 			if (!*scan)
290 				FAILURE;
291 
292 			curtex->name = token;
293 
294 			SKIPWHITESPACE;
295 			if (!*scan)
296 			{
297 				parseerror = true;
298 				break;
299 			}
300 			if (*scan != '{')
301 				FAILURE;
302 
303 			scan++;
304 
305 			while (1)
306 			{
307 				SKIPWHITESPACE;
308 				if (!*scan)
309 				FAILURE;
310 
311 				if (*scan == '}')
312 				{
313 					scan++;
314 					break;
315 				}
316 
317 				READTOKEN;
318 				if (!*scan)
319 					FAILURE;
320 
321 
322 				// type = [ TEX_2D | TEX_3D | TEX_CUBE ];
323 				if (!strcmp(token, "type"))
324 				{
325 					SKIPWHITESPACE;
326 					if (!*scan)
327 						FAILURE;
328 
329 					if (*scan != '=')
330 						FAILURE;
331 
332 					scan++;
333 					SKIPWHITESPACE;
334 					if (!*scan)
335 						FAILURE;
336 
337 					READTOKEN;
338 					if (!*scan)
339 						FAILURE;
340 
341 					if (!strcmp(token,"TEX_2D"))
342 						curtex->type = GL_TEXTURE_2D;
343 					else if (!strcmp(token,"TEX_3D"))
344 						curtex->type = GL_TEXTURE_3D;
345 					else if (!strcmp(token,"TEX_CUBE"))
346 						curtex->type = GL_TEXTURE_CUBE_MAP;
347 					else
348 					{
349 						parseerror = true;
350 						break;
351 					}
352 					SKIPWHITESPACE;
353 					if (!*scan)
354 						FAILURE;
355 
356 					if (*scan != ';')
357 						FAILURE;
358 
359 					scan++;
360 				}
361 				// src = "blah.png";
362 				else if (!strcmp(token, "src"))
363 				{
364 					SKIPWHITESPACE;
365 					if (!*scan)
366 						FAILURE;
367 
368 					if (*scan != '=')
369 						FAILURE;
370 
371 					scan++;
372 					SKIPWHITESPACE;
373 					if (!*scan)
374 						FAILURE;
375 
376 					READTOKEN;
377 					if (!*scan)
378 						FAILURE;
379 
380 					curtex->filename = PUtil::assemblePath(token, filename);
381 					SKIPWHITESPACE;
382 					if (!*scan)
383 						FAILURE;
384 
385 					if (*scan != ';')
386 						FAILURE;
387 
388 					scan++;
389 				}
390 				else
391 					FAILURE;
392 			}
393 		}
394 		else if (!strcmp(token, "technique"))
395 		{
396 			tech.push_back(fx_technique_s());
397 			fx_technique_s *curtech = &tech.back();
398 
399 			SKIPWHITESPACE;
400 			if (!*scan)
401 				FAILURE;
402 
403 
404 			READTOKEN;
405 			if (!*scan)
406 				FAILURE;
407 
408 			curtech->name = token;
409 
410 			SKIPWHITESPACE;
411 			if (!*scan)
412 				FAILURE;
413 
414 			if (*scan != '{')
415 				FAILURE;
416 
417 			scan++;
418 
419 			while (1)
420 			{
421 				SKIPWHITESPACE;
422 				if (!*scan)
423 					FAILURE;
424 
425 				if (*scan == '}')
426 					FAILURE;
427 
428 
429 				READTOKEN;
430 				if (!*scan)
431 					FAILURE;
432 
433 
434 				if (!strcmp(token, "pass"))
435 				{
436 					curtech->pass.push_back(fx_pass_s());
437 					fx_pass_s *curpass = &curtech->pass.back();
438 					fx_renderstate_s *currs = &curpass->rs;
439 					// set default render state for pass
440 					#if 0
441 					if (curtech->pass.size() > 1)
442 						*currs = curtech->pass[curtech->pass.size()-2].rs;
443 					else
444 						*currs = def_rs;
445 					#else
446 						*currs = def_rs;
447 					#endif
448 
449 					SKIPWHITESPACE;
450 					if (!*scan)
451 						FAILURE;
452 
453 					if (*scan != '{')
454 						FAILURE;
455 
456 					scan++;
457 
458 					while (1)
459 					{
460 						SKIPWHITESPACE;
461 						if (!*scan)
462 							FAILURE;
463 
464 						if (*scan == '}')
465 							FAILURE;
466 
467 
468 						READTOKEN;
469 						if (!*scan)
470 							FAILURE;
471 
472 
473 						// depthtest = [ true | false ];
474 						if (!strcmp(token, "depthtest"))
475 						{
476 							//con_printf("depthtest\n");
477 							SKIPWHITESPACE;
478 							if (!*scan)
479 								FAILURE;
480 
481 							if (*scan != '=')
482 								FAILURE;
483 
484 							scan++;
485 							SKIPWHITESPACE;
486 							if (!*scan)
487 								FAILURE;
488 
489 							READTOKEN;
490 							if (!*scan)
491 								FAILURE;
492 
493 							if (0);
494 							else if (!strcmp(token,"true"))
495 								currs->depthtest = true;
496 							else if (!strcmp(token,"false"))
497 								currs->depthtest = false;
498 							else
499 								FAILURE;
500 
501 							SKIPWHITESPACE;
502 							if (!*scan)
503 								FAILURE;
504 
505 							if (*scan != ';')
506 								FAILURE;
507 
508 							scan++;
509 						}
510 						// alphatest = { FUNC, value };
511 						else if (!strcmp(token, "alphatest"))
512 						{
513 							//con_printf("alphatest\n");
514 							SKIPWHITESPACE;
515 							if (!*scan)
516 								FAILURE;
517 
518 							if (*scan != '=')
519 								FAILURE;
520 
521 							scan++;
522 							SKIPWHITESPACE;
523 							if (!*scan)
524 								FAILURE
525 
526 							if (*scan != '{')
527 								FAILURE
528 
529 							scan++;
530 							SKIPWHITESPACE;
531 							if (!*scan)
532 								FAILURE
533 
534 							READTOKEN;
535 							if (!*scan)
536 								FAILURE
537 
538 							if (0);
539 							else if (!strcmp(token,"LESS"))
540 								currs->alphatest.func = GL_LESS;
541 							else if (!strcmp(token,"EQUAL"))
542 								currs->alphatest.func = GL_EQUAL;
543 							else if (!strcmp(token,"LEQUAL"))
544 								currs->alphatest.func = GL_LEQUAL;
545 							else if (!strcmp(token,"GREATER"))
546 								currs->alphatest.func = GL_GREATER;
547 							else if (!strcmp(token,"NOTEQUAL"))
548 								currs->alphatest.func = GL_NOTEQUAL;
549 							else if (!strcmp(token,"GEQUAL"))
550 								currs->alphatest.func = GL_GEQUAL;
551 							else if (!strcmp(token,"ALWAYS"))
552 								currs->alphatest.func = GL_ALWAYS;
553 							else
554 							{
555 								detail = "invalid alphatest func";
556 								FAILURE
557 							}
558 							SKIPWHITESPACE;
559 							if (!*scan)
560 								FAILURE;
561 
562 							if (*scan != ',')
563 								FAILURE;
564 
565 							scan++;
566 							SKIPWHITESPACE;
567 							if (!*scan)
568 								FAILURE;
569 
570 							READNUMERICALTOKEN;
571 							if (!*scan)
572 								FAILURE;
573 
574 							currs->alphatest.ref = atof(token);
575 							SKIPWHITESPACE;
576 							if (!*scan)
577 								FAILURE;
578 
579 							if (*scan != '}')
580 								FAILURE;
581 
582 							scan++;
583 							SKIPWHITESPACE;
584 							if (!*scan)
585 								FAILURE;
586 
587 							if (*scan != ';')
588 								FAILURE;
589 
590 							scan++;
591 						}
592 						// cullface
593 						else if (!strcmp(token, "cullface"))
594 						{
595 							//con_printf("cullface\n");
596 							SKIPWHITESPACE;
597 							if (!*scan)
598 								FAILURE;
599 
600 							if (*scan != '=')
601 								FAILURE;
602 
603 							scan++;
604 							SKIPWHITESPACE;
605 							if (!*scan)
606 								FAILURE;
607 
608 							READTOKEN;
609 							if (!*scan)
610 								FAILURE;
611 
612 							if (0);
613 							else if (!strcmp(token,"NONE"))
614 								currs->cullface = CULLFACE_NONE;
615 							else if (!strcmp(token,"CW"))
616 								currs->cullface = CULLFACE_CW;
617 							else if (!strcmp(token,"CCW"))
618 								currs->cullface = CULLFACE_CCW;
619 							else
620 							{
621 								detail = "invalid cullface mode";
622 								FAILURE
623 							}
624 							SKIPWHITESPACE;
625 							if (!*scan)
626 								FAILURE;
627 
628 							if (*scan != ';')
629 								FAILURE;
630 
631 							scan++;
632 						}
633 						// blendmode
634 						else if (!strcmp(token, "blendmode"))
635 						{
636 							SKIPWHITESPACE;
637 							if (!*scan)
638 								FAILURE;
639 
640 							if (*scan != '=')
641 								FAILURE;
642 
643 							scan++;
644 							SKIPWHITESPACE;
645 							if (!*scan)
646 								FAILURE;
647 
648 							READTOKEN;
649 							if (!*scan)
650 								FAILURE;
651 
652 							if (0);
653 							else if (!strcmp(token,"NONE"))
654 								currs->blendmode = BLEND_NONE;
655 							else if (!strcmp(token,"ADD"))
656 								currs->blendmode = BLEND_ADD;
657 							else if (!strcmp(token,"MULTIPLY"))
658 								currs->blendmode = BLEND_MULTIPLY;
659 							else if (!strcmp(token,"ALPHA"))
660 								currs->blendmode = BLEND_ALPHA;
661 							else if (!strcmp(token,"PREMULTALPHA"))
662 								currs->blendmode = BLEND_PREMULTALPHA;
663 							else
664 							{
665 								detail = "invalid blendmode mode";
666 								FAILURE
667 							}
668 							SKIPWHITESPACE;
669 							if (!*scan)
670 								FAILURE;
671 
672 							if (*scan != ';')
673 								FAILURE;
674 
675 							scan++;
676 						}
677 						// texunit0 = <texture>;
678 						else if (!strcmp(token, "texunit0"))
679 						{
680 							//con_printf("texunit0\n");
681 							SKIPWHITESPACE;
682 							if (!*scan)
683 								FAILURE;
684 
685 							if (*scan != '=')
686 								FAILURE;
687 
688 							scan++;
689 							SKIPWHITESPACE;
690 							if (!*scan)
691 								FAILURE;
692 
693 							READTOKEN;
694 							if (!*scan)
695 								FAILURE;
696 
697 							unsigned int iter;
698 							for (iter=0; iter<tex.size(); iter++)
699 							{
700 								if (!strcmp(token, tex[iter].name.c_str()))
701 									break;
702 							}
703 							if (iter == tex.size())
704 							{
705 								detail = std::string("texture name ") + token + " not found";
706 								parseerror = true;
707 								break;
708 							}
709 							currs->texunit[0].texindex = iter;
710 							SKIPWHITESPACE;
711 							if (!*scan)
712 								FAILURE;
713 
714 							if (*scan != ';')
715 								FAILURE;
716 
717 							scan++;
718 						}
719 						else if (!strcmp(token, "lighting"))
720 						{
721 							SKIPWHITESPACE;
722 							if (!*scan)
723 								FAILURE;
724 
725 							if (*scan != '=')
726 								FAILURE;
727 
728 							scan++;
729 							SKIPWHITESPACE;
730 							if (!*scan)
731 								FAILURE;
732 
733 							READTOKEN;
734 							if (!*scan)
735 								FAILURE;
736 
737 							if (0);
738 							else if (!strcmp(token,"true"))
739 								currs->lighting = true;
740 							else if (!strcmp(token,"false"))
741 								currs->lighting = false;
742 							else
743 								FAILURE;
744 
745 							SKIPWHITESPACE;
746 							if (!*scan)
747 								FAILURE;
748 
749 							if (*scan != ';')
750 								FAILURE;
751 
752 							scan++;
753 						}
754 						else if (!strcmp(token, "lightmodeltwoside"))
755 						{
756 							SKIPWHITESPACE;
757 							if (!*scan)
758 								FAILURE;
759 
760 							if (*scan != '=')
761 								FAILURE;
762 
763 							scan++;
764 							SKIPWHITESPACE;
765 							if (!*scan)
766 								FAILURE;
767 
768 							READTOKEN;
769 							if (!*scan)
770 								FAILURE;
771 
772 							if (0);
773 							else if (!strcmp(token,"true"))
774 								currs->lightmodeltwoside = true;
775 							else if (!strcmp(token,"false"))
776 								currs->lightmodeltwoside = false;
777 							else
778 								FAILURE;
779 
780 							SKIPWHITESPACE;
781 							if (!*scan)
782 								FAILURE;
783 
784 							if (*scan != ';')
785 								FAILURE;
786 
787 							scan++;
788 						}
789 						else
790 						{
791 							detail = "invalid render state";
792 							FAILURE
793 						}
794 					}
795 				}
796 				else
797 					FAILURE;
798 
799 				if (parseerror)
800 					break;
801 			}
802 		}
803 		else
804 			FAILURE;
805 
806 		if (parseerror)
807 			break;
808 	}
809 
810 	delete [] source;
811 
812 	if (parseerror)
813 	{
814 		con_printf("\"%s\": error at line %i : %s\n",name.c_str(),linec,detail);
815 		//*scan = '\0';
816 		//con_printf("[%s]\n",source);
817 		unload();
818 		throw MakePException (name + ": error at line " + PUtil::formatInt (linec) + " : " + detail);
819 	}
820 
821 	con_printf("Load complete\n");
822 }
823 
getNumTechniques()824 int PEffect::getNumTechniques()
825 {
826   return tech.size();
827 }
828 
validateTechnique(int technique)829 bool PEffect::validateTechnique(int technique)
830 {
831   // todo: determine real validity
832 
833   // even for fixed-function, this includes (eg) tex unit count
834 
835   if (technique >= 0 && technique < (int)tech.size()) {
836     tech[technique].validated = true;
837     return tech[technique].validated;
838   } else {
839     return false;
840   }
841 }
842 
getTechniqueName(int technique)843 const std::string &PEffect::getTechniqueName(int technique)
844 {
845   static std::string notfound = "[invalid technique index]";
846   if (technique >= 0 && technique < (int)tech.size()) {
847     return tech[technique].name;
848   } else {
849     return notfound;
850   }
851 }
852 
findTechnique(const std::string & techname,int * technique)853 bool PEffect::findTechnique(const std::string &techname, int *technique)
854 {
855   for (unsigned int i=0; i<tech.size(); i++) {
856     if (tech[i].name == techname) {
857       *technique = i;
858       return true;
859     }
860   }
861   return false;
862 }
863 
setCurrentTechnique(int technique)864 bool PEffect::setCurrentTechnique(int technique)
865 {
866   cur_tech = -1;
867   if (technique >= 0 && technique < (int)tech.size()) {
868     if (tech[technique].validated) {
869       cur_tech = technique;
870       return true;
871     } else {
872       con_printf("Effect::setCurrentTechnique(): technique not validated\n");
873       return false;
874     }
875   } else {
876     con_printf("Effect::setCurrentTechnique(): invalid technique index\n");
877     return false;
878   }
879 }
880 
getCurrentTechnique()881 int PEffect::getCurrentTechnique()
882 {
883   return cur_tech;
884 }
885 
setFirstValidTechnique()886 bool PEffect::setFirstValidTechnique()
887 {
888   for (int i=0; i<getNumTechniques(); i++) {
889     if (validateTechnique(i)) {
890       setCurrentTechnique(i);
891       return true;
892     }
893   }
894   return false;
895 }
896 
renderBegin(int * numPasses,PSSTexture & sstex)897 bool PEffect::renderBegin(int *numPasses, PSSTexture &sstex)
898 {
899   if (cur_tech == -1) return false;
900 
901   fx_technique_s *curtech = &tech[cur_tech];
902 
903   if (!curtech->textures_ready) {
904     for (unsigned int i=0; i<curtech->pass.size(); i++) {
905       int texindex = curtech->pass[i].rs.texunit[0].texindex;
906       if (texindex != -1 && !tex[texindex].texobject)
907         tex[texindex].texobject = sstex.loadTexture(tex[texindex].filename);
908     }
909     curtech->textures_ready = true;
910   }
911 
912   if (numPasses) *numPasses = curtech->pass.size();
913 
914   return true;
915 }
916 
917 // utility func to set GL state
migrateRenderState(fx_renderstate_s * rs_old,fx_renderstate_s * rs_new)918 void PEffect::migrateRenderState(fx_renderstate_s *rs_old, fx_renderstate_s *rs_new)
919 {
920   if (rs_old->depthtest != rs_new->depthtest) {
921     if (rs_new->depthtest)  glEnable(GL_DEPTH_TEST);
922     else                    glDisable(GL_DEPTH_TEST);
923   }
924 
925   if (rs_old->lighting != rs_new->lighting) {
926     if (rs_new->lighting)   glEnable(GL_LIGHTING);
927     else                    glDisable(GL_LIGHTING);
928   }
929 
930   if (rs_old->lightmodeltwoside != rs_new->lightmodeltwoside) {
931     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, rs_new->lightmodeltwoside ? GL_TRUE : GL_FALSE);
932   }
933 
934   if (rs_old->alphatest.func != rs_new->alphatest.func ||
935     (rs_new->alphatest.func != GL_ALWAYS &&
936       rs_old->alphatest.ref != rs_new->alphatest.ref)) {
937     if (rs_old->alphatest.func == GL_ALWAYS) {
938       // enabling alpha test
939       glEnable(GL_ALPHA_TEST);
940       glAlphaFunc(rs_new->alphatest.func, rs_new->alphatest.ref);
941     } else if (rs_new->alphatest.func == GL_ALWAYS) {
942       // disabling alpha test
943       glDisable(GL_ALPHA_TEST);
944     } else {
945       // changing alpha test
946       glAlphaFunc(rs_new->alphatest.func, rs_new->alphatest.ref);
947     }
948   }
949 
950   if (rs_old->cullface != rs_new->cullface) {
951     if (rs_old->cullface == CULLFACE_NONE) {
952       glEnable(GL_CULL_FACE);
953       glCullFace(rs_new->cullface == CULLFACE_CW ? GL_BACK : GL_FRONT);
954     } else if (rs_new->cullface == CULLFACE_NONE) {
955       glDisable(GL_CULL_FACE);
956     } else {
957       glCullFace(rs_new->cullface == CULLFACE_CW ? GL_BACK : GL_FRONT);
958     }
959   }
960 
961   if (rs_old->blendmode != rs_new->blendmode) {
962     switch (rs_new->blendmode) {
963     default:
964       glBlendFunc(GL_ONE,GL_ZERO);
965       break;
966     case BLEND_ADD:
967       glBlendFunc(GL_ONE,GL_ONE);
968       break;
969     case BLEND_MULTIPLY:
970       glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
971       break;
972     case BLEND_ALPHA:
973       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
974       break;
975     case BLEND_PREMULTALPHA:
976       glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
977       break;
978     }
979   }
980 
981   int texindex = rs_new->texunit[0].texindex;
982   if (texindex != -1 && tex[texindex].texobject)
983     tex[texindex].texobject->bind();
984   else
985     PTexture::unbind();
986 }
987 
renderPass(int pass)988 void PEffect::renderPass(int pass)
989 {
990   // assume pass is valid
991 
992   if (pass == 0)
993     migrateRenderState(&def_rs,
994             &tech[cur_tech].pass[0].rs);
995   else
996     migrateRenderState(&tech[cur_tech].pass[pass-1].rs,
997             &tech[cur_tech].pass[pass].rs);
998 }
999 
renderEnd()1000 void PEffect::renderEnd()
1001 {
1002   migrateRenderState(&tech[cur_tech].pass.back().rs,
1003           &def_rs);
1004 }
1005 
1006 
1007 
1008 
1009 
1010 
1011