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