00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00040 #include <string>
00041
00042 #include "omicron/internal.h"
00043 #include "omicron/render.h"
00044 #include "omicron/texture.h"
00045 #include "omicron/file.h"
00046 #include "omicron/list.h"
00047
00048
00049 static ushort waveform_from_string
00050 (
00051 const char *t
00052 )
00053 {
00054 AssertReturnValue1(t, 0);
00055
00056 if (!strcmpi(t, "sine"))
00057 return WF_SINE;
00058
00059 if (!strcmpi(t, "rect"))
00060 return WF_RECT;
00061
00062 if (!strcmpi(t, "sine2d"))
00063 return WF_SINE2D;
00064
00065 if (!strcmpi(t, "rect2d"))
00066 return WF_RECT2D;
00067
00068 if (!strcmpi(t, "none"))
00069 return WF_NONE;
00070
00071 _log_printf(MSG_ERROR, "ERROR: invalid token \"%s\"", t);
00072
00073 return WF_NONE;
00074 }
00075
00076 static ushort texfilter_from_string
00077 (
00078 const char *t
00079 )
00080 {
00081 if (!strcmpi(t, "linear"))
00082 return TF_LINEAR;
00083
00084 if (!strcmpi(t, "nearest_mipmap_nearest"))
00085 return TF_NEAREST_MIPMAP_NEAREST;
00086
00087 if (!strcmpi(t, "nearest_mipmap_linear"))
00088 return TF_NEAREST_MIPMAP_LINEAR;
00089
00090 if (!strcmpi(t, "linear_mipmap_nearest"))
00091 return TF_LINEAR_MIPMAP_NEAREST;
00092
00093 if (!strcmpi(t, "linear_mipmap_linear"))
00094 return TF_LINEAR_MIPMAP_LINEAR;
00095
00096 return TF_NEAREST;
00097 }
00098
00099 static ushort texwrap_from_string
00100 (
00101 const char *t
00102 )
00103 {
00104 AssertReturnValue1(t, 0);
00105
00106 if (!strcmpi(t, "clamp"))
00107 return TW_CLAMP;
00108
00109 return TW_REPEAT;
00110 }
00111
00112 static ushort texbtype_from_string
00113 (
00114 const char *t
00115 )
00116 {
00117 AssertReturnValue1(t, 0);
00118
00119
00120 if (!strcmpi(t, "add"))
00121 return BT_ADD;
00122 if (!strcmpi(t, "blend"))
00123 return BT_BLEND;
00124 if (!strcmpi(t, "modulate"))
00125 return BT_MODULATE;
00126 if (!strcmpi(t, "alphatest"))
00127 return BT_ALPHATEST;
00128 if (!strcmpi(t, "modulate2x"))
00129 return BT_MODULATE2X;
00130
00131 return BT_OPAQUE;
00132 }
00133
00134
00135
00136
00137 void shader_initstage
00138 (
00139 shader_t *shad,
00140 ushort n
00141 )
00142 {
00143 AssertReturn1(shad);
00144
00145 shad->passes[n].scalex = 1;
00146 shad->passes[n].scaley = 1;
00147 shad->passes[n].soffsetx =
00148 shad->passes[n].soffsety =
00149 shad->passes[n].offsetx =
00150 shad->passes[n].offsety = 0;
00151 shad->passes[n].magfilter = TF_LINEAR_MIPMAP_LINEAR;
00152 shad->passes[n].minfilter = TF_LINEAR_MIPMAP_LINEAR;
00153 shad->passes[n].texwrapu =
00154 shad->passes[n].texwrapv = TW_REPEAT;
00155
00156 shad->passes[n].rotation =
00157 shad->passes[n].angle =
00158 shad->passes[n].scrollx =
00159 shad->passes[n].scrolly = 0.0f;
00160 shad->passes[n].shiny = 0;
00161
00162 shad->passes[n].matrix = false;
00163 shad->passes[n].fog = true;
00164
00165 shad->passes[n].colorwave.type = 0;
00166 shad->passes[n].colorwave.bias = 1;
00167
00168 shad->passes[n].color1 =
00169 shad->passes[n].color2 = COLOR_WHITE;
00170
00171 shad->passes[n].color = false;
00172
00173 shad->passes[n].scalewavex.type = 0;
00174 shad->passes[n].scalewavex.bias = 1;
00175 shad->passes[n].scalewavey.type = 0;
00176 shad->passes[n].scalewavey.bias = 1;
00177
00178 shad->passes[n].lightmap = 0;
00179 shad->passes[n].lighting = 0;
00180 shad->passes[n].blendtype = BT_OPAQUE;
00181 shad->passes[n].twosided = 0;
00182 shad->passes[n].nodepth = 0;
00183 shad->passes[n].ignorediffuse = false;
00184 }
00185
00186
00187
00188
00189 float shader_get_waveform_frac
00190 (
00191 const shader_waveform_t *wf
00192 )
00193 {
00194 AssertReturnValue1(wf, 0);
00195
00196 if (wf->type == WF_NONE)
00197 return 0;
00198
00199 if (wf->freq == 0)
00200 return wf->bias;
00201
00202 float invfreq = 1/wf->freq;
00203 float t = gv.time + wf->phase;
00204
00205 switch(wf->type)
00206 {
00207 case WF_RECT:
00208 if (fmod(t, invfreq) < invfreq/2)
00209 return wf->bias-wf->amplitude;
00210 else
00211 return wf->bias+wf->amplitude;
00212
00213 case WF_SINE:
00214 return (float)(wf->amplitude*sin(t*PI2*wf->freq)+wf->bias);
00215
00216
00217
00218
00219 }
00220
00221 return 0;
00222 }
00223
00224
00225
00226
00227
00228 shader_t *shader_create_simple
00229 (
00230 ushort blendtype,
00231 sshort texture
00232 )
00233 {
00234 shader_t *shad = new shader_t;
00235
00236 shader_init(shad, blendtype, texture);
00237 gv.shaders->add_first(shad);
00238
00239 return shad;
00240 }
00241
00242
00243
00244
00245
00246 void shader_init
00247 (
00248 shader_t *shad,
00249 ushort blendtype,
00250 sshort texture
00251 )
00252 {
00253 AssertReturn1(shad);
00254
00255 memset(shad, 0, sizeof(shader_t));
00256 shad->passcount = 1;
00257
00258 shader_initstage(shad, 0);
00259 shad->dynamic = 0;
00260 shad->passes[0].blendtype = blendtype;
00261 shad->passes[0].texture = texture;
00262 sprintf(shad->name, "unnamed");
00263 }
00264
00265
00266
00267
00268 shader_t *shader_create
00269 (
00270 )
00271 {
00272 shader_t *shad = new shader_t;
00273 gv.shaders->add_first(shad);
00274 return shad;
00275 }
00276
00277
00278
00279
00280 shader_t *shader_find
00281 (
00282 const char *name
00283 )
00284 {
00285 AssertReturnValue1(name, NULL);
00286
00287 shader_t *shad = (shader_t*)gv.shaders->get_first();
00288
00289 while(shad)
00290 {
00291 if (!strcmpi(name, shad->name))
00292 return shad;
00293
00294 shad = (shader_t*)gv.shaders->get_next();
00295 }
00296
00297 return NULL;
00298 }
00299
00300
00301
00302
00303
00304 shader_t *shader_load
00305 (
00306 const char *fname
00307 )
00308 {
00309 AssertReturnValue1(fname, NULL);
00310
00311 shader_t *shad = NULL;
00312 file_t *f;
00313 std::string fname2;
00314
00315 shad = shader_find(fname);
00316
00317 if (shad)
00318 return shad;
00319
00320 fname2 = fname;
00321 fname2 += ".shader";
00322
00323 f = gv.fileman->load(fname2.c_str(), false);
00324
00325 if (!f)
00326 {
00327 sshort t = gv.texman->load(fname);
00328
00329 if (t != TEXTURE_NOTFOUND)
00330 {
00331 shad = shader_create_simple(BT_OPAQUE, t);
00332 sprintf(shad->name, "%s", fname);
00333 }
00334 else
00335 {
00336 shad = shader_find("noshader");
00337 }
00338 return shad;
00339 }
00340
00341 ushort currentpass = 0;
00342 char tmp[256] = "";
00343 ulong linenum = 0;
00344
00345 std::string cmd = "";
00346 std::string params = "";
00347 std::string line = "";
00348
00349 slong comment = 0;
00350
00351 shad = shader_create();
00352
00353 if (!shad)
00354 {
00355 gv.fileman->close(f);
00356 return NULL;
00357 }
00358
00359 sprintf(shad->name, "%s", fname);
00360 shad->passcount = 0;
00361 shad->dynamic = 0;
00362
00363 while(!gv.fileman->eof(f))
00364 {
00365 int i;
00366
00367 linenum++;
00368 gv.fileman->gets(tmp, 256, f);
00369
00370 line = tmp;
00371
00372 comment = line.find('#');
00373 if (comment != -1)
00374 line[comment] = 0;
00375
00376 for (i=line.length(); i>=0; --i)
00377 if (strchr(" \n\r\t", line.at(i)))
00378 line.erase(i);
00379
00380
00381 if (!line.length())
00382 continue;
00383
00384 if (line.find_first_of(" \n\t")==line.length())
00385 {
00386 cmd = line;
00387 params = "";
00388 }
00389 else
00390 {
00391 slong p = line.find_first_of(" \n\t");
00392 cmd = line.substr(0, p);
00393 params = line.substr(p+1, line.length()-p-1);
00394 }
00395
00396
00397 if (!cmd.compare("newpass"))
00398 {
00399 if (currentpass>=7)
00400 {
00401 _log_printf(MSG_ERROR, "ERROR: while parsing shader \"%s\" line %u: "
00402 "all passes already used. newstage invalid",
00403 fname, linenum);
00404 break;
00405 }
00406
00407 shader_initstage(shad, currentpass=++(shad->passcount)-1);
00408
00409
00410 continue;
00411 }
00412
00413
00414 if (!cmd.compare("blendtype"))
00415 {
00416 shad->passes[currentpass].blendtype = texbtype_from_string(params.c_str());
00417 continue;
00418 }
00419
00420 if (!cmd.compare("texture"))
00421 {
00422 shad->passes[currentpass].texture = gv.texman->load(params.c_str());
00423 continue;
00424 }
00425
00426
00427 if (!cmd.compare("texturenocomp"))
00428 {
00429 shad->passes[currentpass].texture = gv.texman->load(params.c_str(), true);
00430 continue;
00431 }
00432
00433
00434 if (!cmd.compare("twosided"))
00435 {
00436 shad->passes[currentpass].twosided = 1;
00437 continue;
00438 }
00439
00440 if (!cmd.compare("nodepth"))
00441 {
00442 shad->passes[currentpass].nodepth = 1;
00443 continue;
00444 }
00445
00446
00447 if (!cmd.compare("lightmapped"))
00448 {
00449 shad->passes[currentpass].lightmap = !!atoi(params.c_str());
00450 continue;
00451 }
00452
00453
00454 if (!cmd.compare("fog"))
00455 {
00456 shad->passes[currentpass].fog = !!atoi(params.c_str());
00457 continue;
00458 }
00459
00460
00461 if (!cmd.compare("ignorediffuse"))
00462 {
00463 shad->passes[currentpass].ignorediffuse = !!atoi(params.c_str());
00464 continue;
00465 }
00466
00467
00468 if (!cmd.compare("shiny"))
00469 {
00470 shad->passes[currentpass].shiny = !!atoi(params.c_str());
00471 continue;
00472 }
00473
00474
00475 if (!cmd.compare("lighting"))
00476 {
00477 shad->passes[currentpass].lighting = !!atoi(params.c_str());
00478 continue;
00479 }
00480
00481
00482
00483 if (!cmd.compare("rotation"))
00484 {
00485 shad->passes[currentpass].rotation = (float)atof(params.c_str());
00486 shad->dynamic = 1;
00487 shad->passes[currentpass].matrix = true;
00488 continue;
00489 }
00490
00491
00492 if (!cmd.compare("angle"))
00493 {
00494 shad->passes[currentpass].angle = (float)atof(params.c_str());
00495 shad->passes[currentpass].matrix = true;
00496 continue;
00497 }
00498
00499
00500 if (!cmd.compare("scale"))
00501 {
00502 sscanf(params.c_str(), "%f %f",
00503 &shad->passes[currentpass].scalex,
00504 &shad->passes[currentpass].scaley );
00505
00506 shad->passes[currentpass].matrix = true;
00507 continue;
00508 }
00509
00510
00511 if (!cmd.compare("scroll"))
00512 {
00513 sscanf(params.c_str(), "%f %f",
00514 &shad->passes[currentpass].scrollx,
00515 &shad->passes[currentpass].scrolly );
00516 shad->dynamic = 1;
00517 shad->passes[currentpass].matrix = true;
00518 continue;
00519 }
00520
00521
00522 if (!cmd.compare("offset"))
00523 {
00524 sscanf(params.c_str(), "%f %f",
00525 &shad->passes[currentpass].offsetx,
00526 &shad->passes[currentpass].offsety );
00527 shad->dynamic = 1;
00528 shad->passes[currentpass].matrix = true;
00529 continue;
00530 }
00531
00532
00533 if (!cmd.compare("scaleoffset"))
00534 {
00535 sscanf(params.c_str(), "%f %f",
00536 &shad->passes[currentpass].soffsetx,
00537 &shad->passes[currentpass].soffsety );
00538 shad->dynamic = 1;
00539 shad->passes[currentpass].matrix = true;
00540 continue;
00541 }
00542
00543
00544 if (!cmd.compare("filter"))
00545 {
00546 char filter1[256];
00547 char filter2[256];
00548
00549 sscanf(params.c_str(), "%s %s", filter1, filter2 );
00550
00551 shad->passes[currentpass].minfilter = texfilter_from_string(filter1);
00552 shad->passes[currentpass].magfilter = texfilter_from_string(filter2);
00553 continue;
00554 }
00555
00556
00557 if (!cmd.compare("wrap"))
00558 {
00559 char wrap1[256];
00560 char wrap2[256];
00561
00562 sscanf(params.c_str(), "%s %s", wrap1, wrap2 );
00563
00564 shad->passes[currentpass].texwrapu = texwrap_from_string(wrap1);
00565 shad->passes[currentpass].texwrapv = texwrap_from_string(wrap2);
00566 continue;
00567 }
00568
00569
00570 if (!cmd.compare("color1"))
00571 {
00572 vec4_t c;
00573
00574 sscanf(params.c_str(), "%f %f %f %f", &c[0], &c[1], &c[2], &c[3]);
00575 shad->passes[currentpass].color1 = color_from_vec(c);
00576 shad->passes[currentpass].color = true;
00577 continue;
00578 }
00579
00580
00581 if (!cmd.compare("color2"))
00582 {
00583 vec4_t c;
00584
00585 sscanf(params.c_str(), "%f %f %f %f", &c[0], &c[1], &c[2], &c[3]);
00586 shad->passes[currentpass].color2 = color_from_vec(c);
00587 continue;
00588 }
00589
00590
00591 if (!cmd.compare("colorwave"))
00592 {
00593 char form[256];
00594
00595 sscanf(params.c_str(), "%s %f %f %f %f", form,
00596 &shad->passes[currentpass].colorwave.freq,
00597 &shad->passes[currentpass].colorwave.phase,
00598 &shad->passes[currentpass].colorwave.amplitude,
00599 &shad->passes[currentpass].colorwave.bias );
00600
00601 shad->passes[currentpass].colorwave.type = waveform_from_string(form);
00602 shad->dynamic = 1;
00603 shad->passes[currentpass].color = true;
00604 continue;
00605 }
00606
00607
00608 if (!cmd.compare("scalewavex"))
00609 {
00610 char form[256];
00611
00612 sscanf(params.c_str(), "%s %f %f %f %f", form,
00613 &shad->passes[currentpass].scalewavex.freq,
00614 &shad->passes[currentpass].scalewavex.phase,
00615 &shad->passes[currentpass].scalewavex.amplitude,
00616 &shad->passes[currentpass].scalewavex.bias );
00617
00618 shad->passes[currentpass].scalewavex.type = waveform_from_string(form);
00619 shad->dynamic = 1;
00620 shad->passes[currentpass].matrix = true;
00621 continue;
00622 }
00623
00624
00625 if (!cmd.compare("scalewavey"))
00626 {
00627 char form[256];
00628
00629 sscanf(params.c_str(), "%s %f %f %f %f", form,
00630 &shad->passes[currentpass].scalewavey.freq,
00631 &shad->passes[currentpass].scalewavey.phase,
00632 &shad->passes[currentpass].scalewavey.amplitude,
00633 &shad->passes[currentpass].scalewavey.bias );
00634
00635 shad->passes[currentpass].scalewavey.type = waveform_from_string(form);
00636 shad->dynamic = 1;
00637 shad->passes[currentpass].matrix = true;
00638 continue;
00639 }
00640
00641 _log_printf(MSG_ERROR, "ERROR: while parsing shader \"%s\" line %u: "
00642 "invalid keyword \"%s\"",
00643 (char*)fname, linenum, cmd.c_str());
00644
00645 }
00646
00647 gv.fileman->close(f);
00648
00649 return shad;
00650 }