00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00020 #include "GlslCode.hpp"
00021 #include <iostream>
00022 #include <cmath>
00023
00024 namespace shgl {
00025
00026 using namespace SH;
00027 using namespace std;
00028
00029 static GlslMapping opCodeTable[] = {
00030 {SH_OP_ABS, "abs($0)"},
00031 {SH_OP_ACOS, "acos($0)"},
00032 {SH_OP_ADD, "$0 + $1"},
00033 {SH_OP_ASIN, "asin($0)"},
00034 {SH_OP_ASN, "$0"},
00035 {SH_OP_ATAN, "atan($0)"},
00036 {SH_OP_CEIL, "ceil($0)"},
00037 {SH_OP_COS, "cos($0)"},
00038 {SH_OP_DOT, "dot($0, $1)"},
00039 {SH_OP_DIV, "$0 / $1"},
00040 {SH_OP_DX, "dFdx($0)"},
00041 {SH_OP_DY, "dFdy($0)"},
00042 {SH_OP_EXP2, "exp2($0)"},
00043 {SH_OP_FLR, "floor($0)"},
00044 {SH_OP_FRAC, "fract($0)"},
00045 {SH_OP_LOG2, "log2($0)"},
00046 {SH_OP_LRP, "mix($2, $1, $0)"},
00047 {SH_OP_MAD, "$0 * $1 + $2"},
00048 {SH_OP_MAX, "max($0, $1)"},
00049 {SH_OP_MIN, "min($0, $1)"},
00050 {SH_OP_MOD, "mod($0, $1)"},
00051 {SH_OP_MUL, "$0 * $1"},
00052 {SH_OP_NEG, "-($0)"},
00053 {SH_OP_NORM, "normalize($0)"},
00054 {SH_OP_POW, "pow($0, $1)"},
00055 {SH_OP_RCP, "1.0 / $0"},
00056 {SH_OP_RND, "floor($0 + 0.5)"},
00057 {SH_OP_RSQ, "inversesqrt($0)"},
00058 {SH_OP_SGN, "sign($0)"},
00059 {SH_OP_SIN, "sin($0)"},
00060 {SH_OP_SQRT, "sqrt($0)"},
00061 {SH_OP_TAN, "tan($0)"},
00062 {SH_OP_XPD, "cross($0, $1)"},
00063
00064 {SH_OPERATION_END, 0}
00065 };
00066
00067 typedef map<SH::ShOperation, GlslOpCodeVecs> GlslOpCodeMap;
00068
00069 GlslOpCodeVecs::GlslOpCodeVecs(const GlslMapping& mapping)
00070 {
00071 string code(mapping.code);
00072
00073
00074
00075 unsigned i, j;
00076 i = j = 0;
00077 for (; (j = code.find_first_of("$", i)) != string::npos;) {
00078 frag.push_back(code.substr(i, j - i));
00079 i = j + 1;
00080 j = code.find_first_not_of("012345689", i);
00081 index.push_back(atoi(code.substr(i, j - i).c_str()));
00082 i = j;
00083 }
00084 if (i == string::npos) {
00085 frag.push_back("");
00086 } else {
00087 frag.push_back(code.substr(i));
00088 }
00089 }
00090
00091 void GlslCode::table_substitution(const ShStatement& stmt, GlslOpCodeVecs codeVecs)
00092 {
00093 stringstream line;
00094 line << resolve(stmt.dest) << " = ";
00095 line << glsl_typename(stmt.dest.valueType(), stmt.dest.size()) << "(";
00096
00097 unsigned i=0;
00098 if (SH_OP_ASN == stmt.op) {
00099
00100 const ShVariable& src = stmt.src[codeVecs.index[i]];
00101 line << codeVecs.frag[i] << resolve(src);
00102 }
00103 else {
00104
00105 int param_size=0;
00106 for (i=0; i < codeVecs.index.size(); i++) {
00107 const ShVariable& src = stmt.src[codeVecs.index[i]];
00108 if (src.size() > param_size) {
00109 param_size = src.size();
00110 }
00111 }
00112
00113
00114 for (i=0; i < codeVecs.index.size(); i++) {
00115 const ShVariable& src = stmt.src[codeVecs.index[i]];
00116 line << codeVecs.frag[i] << glsl_typename(src.valueType(), param_size)
00117 << "(" << resolve(src) << ")";
00118 }
00119 }
00120
00121 line << codeVecs.frag[i];
00122
00123 line << ")";
00124 append_line(line.str());
00125 }
00126
00127 void GlslCode::emit(const ShStatement &stmt)
00128 {
00129 static GlslOpCodeMap opCodeMap;
00130
00131
00132 if (opCodeMap.empty()) {
00133 for (int i=0; opCodeTable[i].op != SH_OPERATION_END; i++) {
00134 opCodeMap[opCodeTable[i].op] = GlslOpCodeVecs(opCodeTable[i]);
00135 }
00136 }
00137
00138 if(opCodeMap.find(stmt.op) != opCodeMap.end()) {
00139
00140 table_substitution(stmt, opCodeMap[stmt.op]);
00141 }
00142 else {
00143
00144 switch(stmt.op) {
00145 case SH_OP_CBRT:
00146 emit_cbrt(stmt);
00147 break;
00148 case SH_OP_CMUL:
00149 emit_prod(stmt);
00150 break;
00151 case SH_OP_CSUM:
00152 emit_sum(stmt);
00153 break;
00154 case SH_OP_COND:
00155 emit_cond(stmt);
00156 break;
00157 case SH_OP_EXP:
00158 emit_exp(stmt, M_E);
00159 break;
00160 case SH_OP_EXP10:
00161 emit_exp(stmt, 10);
00162 break;
00163 case SH_OP_KIL:
00164 emit_discard(stmt);
00165 break;
00166 case SH_OP_LIT:
00167 emit_lit(stmt);
00168 break;
00169 case SH_OP_LOG:
00170 emit_log(stmt, M_E);
00171 break;
00172 case SH_OP_LOG10:
00173 emit_log(stmt, 10);
00174 break;
00175 case SH_OP_NOISE:
00176 emit_noise(stmt);
00177 break;
00178 case SH_OP_PAL:
00179 emit_pal(stmt);
00180 break;
00181 case SH_OP_SEQ:
00182 case SH_OP_SGE:
00183 case SH_OP_SGT:
00184 case SH_OP_SLE:
00185 case SH_OP_SLT:
00186 case SH_OP_SNE:
00187 emit_logic(stmt);
00188 break;
00189 case SH_OP_TEX:
00190 case SH_OP_TEXI:
00191 emit_texture(stmt);
00192 break;
00193 case SH_OP_COSH:
00194 case SH_OP_SINH:
00195 case SH_OP_TANH:
00196 emit_hyperbolic(stmt);
00197 break;
00198 case SH_OP_COMMENT:
00199 emit_comment(stmt);
00200 break;
00201 default:
00202 shError(ShException(string("Glsl Code: Unknown operation ") + opInfo[stmt.op].name));
00203 break;
00204 }
00205 }
00206 }
00207
00208 ShVariableNodePtr GlslCode::allocate_constant(const ShStatement& stmt, double constant, int size) const
00209 {
00210 if (size <= 0) size = stmt.dest.size();
00211
00212 const ShVariableNodePtr& dest_node = stmt.dest.node();
00213 ShVariableNode* node = new ShVariableNode(SH_CONST, size, dest_node->valueType(), dest_node->specialType());
00214
00215 ShDataVariant<double>* variant = new ShDataVariant<double>(size, constant);
00216 node->setVariant(variant);
00217
00218 ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00219 return node_ptr;
00220 }
00221
00222 ShVariableNodePtr GlslCode::allocate_temp(const ShStatement& stmt, int size) const
00223 {
00224 if (size <= 0) size = stmt.dest.size();
00225
00226 const ShVariableNodePtr& dest_node = stmt.dest.node();
00227 ShVariableNode* node = new ShVariableNode(SH_TEMP, size, dest_node->valueType(), dest_node->specialType());
00228 ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00229 return node_ptr;
00230 }
00231
00232 string GlslCode::resolve_constant(double constant, const ShVariable& var, int size) const
00233 {
00234 if (size <= 0) size = var.size();
00235
00236 stringstream s;
00237 s.precision(16);
00238 s << glsl_typename(var.valueType(), size);
00239
00240 s << "(";
00241 for (int i=0; i < size; i++) {
00242 if (i > 0) s << ", ";
00243 s << constant;
00244 }
00245 s << ")";
00246
00247 return s.str();
00248 }
00249
00250 void GlslCode::emit_cbrt(const ShStatement& stmt)
00251 {
00252 SH_DEBUG_ASSERT(SH_OP_CBRT == stmt.op);
00253
00254 ShVariable temp(allocate_constant(stmt, 1.0 / 3.0));
00255 append_line(resolve(stmt.dest) + " = pow(" + resolve(stmt.src[0]) + ", " + resolve(temp) + ")");
00256 }
00257
00258 void GlslCode::emit_comment(const ShStatement& stmt)
00259 {
00260 append_line("// " + stmt.get_info<ShInfoComment>()->comment, false);
00261 }
00262
00263 void GlslCode::emit_cond(const ShStatement& stmt)
00264 {
00265 SH_DEBUG_ASSERT(SH_OP_COND == stmt.op);
00266 static string vendor((char*)glGetString(GL_VENDOR));
00267
00268 const int size = stmt.src[0].size();
00269 if (("NVIDIA Corporation" == vendor) || (1 == size)) {
00270
00271 append_line(resolve(stmt.dest) + " = (" + resolve(stmt.src[0]) + " > " +
00272 resolve_constant(0, stmt.src[0]) + ") ? " + resolve(stmt.src[1]) +
00273 " : " + resolve(stmt.src[2]));
00274 } else {
00275
00276 for (int i=0; i < size; i++) {
00277 append_line(resolve(stmt.dest, i) + " = (" + resolve(stmt.src[0], i) + " > " +
00278 resolve_constant(0, stmt.src[0], 1) + ") ? " + resolve(stmt.src[1], i) +
00279 " : " + resolve(stmt.src[2], i));
00280 }
00281 }
00282 }
00283
00284 void GlslCode::emit_discard(const ShStatement& stmt)
00285 {
00286 SH_DEBUG_ASSERT(SH_OP_KIL == stmt.op);
00287
00288 append_line(string("if (") + resolve(stmt.src[0]) + " > " +
00289 resolve_constant(0, stmt.src[0]) + ") discard");
00290 }
00291
00292 void GlslCode::emit_exp(const ShStatement& stmt, double power)
00293 {
00294 SH_DEBUG_ASSERT((SH_OP_EXP == stmt.op) || (SH_OP_EXP10 == stmt.op));
00295
00296 ShVariable temp(allocate_constant(stmt, power));
00297 append_line(resolve(stmt.dest) + " = pow(" + resolve(temp) + ", " + resolve(stmt.src[0]) + ")");
00298 }
00299
00300 void GlslCode::emit_hyperbolic(const ShStatement& stmt)
00301 {
00302 ShVariable two(allocate_constant(stmt, 2));
00303 ShVariable e(allocate_constant(stmt, M_E));
00304
00305 ShVariable e_plusX(allocate_temp(stmt));
00306 ShVariable e_minusX(allocate_temp(stmt));
00307 append_line(resolve(e_plusX) + " = pow(" + resolve(e) + ", " + resolve(stmt.src[0]) + ")");
00308 append_line(resolve(e_minusX) + " = pow(" + resolve(e) + ", -(" + resolve(stmt.src[0]) + "))");
00309
00310 switch (stmt.op) {
00311 case SH_OP_COSH:
00312
00313 append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " + " + resolve(e_minusX) + ") / " + resolve(two));
00314 break;
00315 case SH_OP_SINH:
00316
00317 append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " - " + resolve(e_minusX) + ") / " + resolve(two));
00318 break;
00319 case SH_OP_TANH:
00320
00321 append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " - " + resolve(e_minusX) + ") / " +
00322 "(" + resolve(e_plusX) + " + " + resolve(e_minusX) + ")");
00323 break;
00324 default:
00325 SH_DEBUG_ASSERT(0);
00326 }
00327 }
00328
00329 void GlslCode::emit_lit(const ShStatement& stmt)
00330 {
00331 SH_DEBUG_ASSERT(SH_OP_LIT == stmt.op);
00332
00333
00334 append_line(resolve(stmt.dest, 0) + " = " + resolve_constant(1, stmt.dest, 1));
00335
00336 append_line(resolve(stmt.dest, 1) + " = max(" + resolve_constant(0, stmt.dest, 1) +
00337 ", " + resolve(stmt.src[0], 0) + ")");
00338
00339 append_line(resolve(stmt.dest, 2) + " = " + resolve(stmt.src[0], 0) +
00340 " > " + resolve_constant(0, stmt.src[0], 1) + " ? pow(max(" +
00341 resolve_constant(0, stmt.dest, 1) + ", " + resolve(stmt.src[0], 1) +
00342 "), clamp(" + resolve(stmt.src[0], 2) + ", " +
00343 resolve_constant(-128, stmt.dest, 1) + ", " +
00344 resolve_constant(128, stmt.dest, 1) + ")) : " + resolve_constant(0, stmt.dest, 1));
00345
00346 append_line(resolve(stmt.dest, 3) + " = " + resolve_constant(1, stmt.dest, 1));
00347 }
00348
00349 void GlslCode::emit_log(const ShStatement& stmt, double base)
00350 {
00351 SH_DEBUG_ASSERT((SH_OP_LOG == stmt.op) || (SH_OP_LOG10 == stmt.op));
00352
00353 const double log2_base = log(base) / log(2.0);
00354
00355 ShVariable temp(allocate_constant(stmt, log2_base));
00356 append_line(resolve(stmt.dest) + " = log2(" + resolve(stmt.src[0]) + ") / " + resolve(temp) + "");
00357 }
00358
00359 void GlslCode::emit_logic(const ShStatement& stmt)
00360 {
00361 GlslMapping mapping;
00362 mapping.op = stmt.op;
00363
00364 if ((stmt.src[0].size() > 1) || (stmt.src[1].size() > 1) ) {
00365 switch (stmt.op) {
00366 case SH_OP_SEQ:
00367 mapping.code = "equal($0, $1)";
00368 break;
00369 case SH_OP_SGT:
00370 mapping.code = "greaterThan($0, $1)";
00371 break;
00372 case SH_OP_SGE:
00373 mapping.code = "greaterThanEqual($0, $1)";
00374 break;
00375 case SH_OP_SNE:
00376 mapping.code = "notEqual($0, $1)";
00377 break;
00378 case SH_OP_SLT:
00379 mapping.code = "lessThan($0, $1)";
00380 break;
00381 case SH_OP_SLE:
00382 mapping.code = "lessThanEqual($0, $1)";
00383 break;
00384 default:
00385 SH_DEBUG_ASSERT(0);
00386 }
00387 } else {
00388 switch (stmt.op) {
00389 case SH_OP_SEQ:
00390 mapping.code = "$0 == $1";
00391 break;
00392 case SH_OP_SGT:
00393 mapping.code = "$0 > $1";
00394 break;
00395 case SH_OP_SGE:
00396 mapping.code = "$0 >= $1";
00397 break;
00398 case SH_OP_SNE:
00399 mapping.code = "$0 != $1";
00400 break;
00401 case SH_OP_SLT:
00402 mapping.code = "$0 < $1";
00403 break;
00404 case SH_OP_SLE:
00405 mapping.code = "$0 <= $1";
00406 break;
00407 default:
00408 SH_DEBUG_ASSERT(0);
00409 }
00410 }
00411
00412
00413
00414 table_substitution(stmt, mapping);
00415 }
00416
00417 void GlslCode::emit_noise(const ShStatement& stmt)
00418 {
00419 SH_DEBUG_ASSERT(SH_OP_NOISE == stmt.op);
00420
00421 int output_size = stmt.dest.size();
00422 SH_DEBUG_ASSERT((output_size <= 4) && (output_size >= 1));
00423
00424 stringstream line;
00425 line << resolve(stmt.dest) << " = " << "noise" << output_size << "("
00426 << resolve(stmt.src[0]) << ")";
00427 append_line(line.str());
00428 }
00429
00430 void GlslCode::emit_pal(const ShStatement& stmt)
00431 {
00432 SH_DEBUG_ASSERT(SH_OP_PAL == stmt.op);
00433
00434 append_line(resolve(stmt.dest) + " = " + resolve(stmt.src[0], stmt.src[1]));
00435 }
00436
00437 void GlslCode::emit_prod(const ShStatement& stmt)
00438 {
00439 SH_DEBUG_ASSERT(SH_OP_CMUL == stmt.op);
00440
00441 ShVariable temp(allocate_temp(stmt, 1));
00442 append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00443
00444 int size = stmt.src[0].size();
00445 for (int i=1; i < size; i++) {
00446 append_line(resolve(temp) + " *= " + resolve(stmt.src[0], i));
00447 }
00448
00449 append_line(resolve(stmt.dest) + " = " + resolve(temp));
00450 }
00451
00452 void GlslCode::emit_sum(const ShStatement& stmt)
00453 {
00454 SH_DEBUG_ASSERT(SH_OP_CSUM == stmt.op);
00455
00456 ShVariable temp(allocate_temp(stmt, 1));
00457 append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00458
00459 int size = stmt.src[0].size();
00460 for (int i=1; i < size; i++) {
00461 append_line(resolve(temp) + " += " + resolve(stmt.src[0], i));
00462 }
00463
00464 append_line(resolve(stmt.dest) + " = " + resolve(temp));
00465 }
00466
00467 void GlslCode::emit_texture(const ShStatement& stmt)
00468 {
00469 SH_DEBUG_ASSERT((SH_OP_TEX == stmt.op) || (SH_OP_TEXI == stmt.op));
00470
00471 stringstream line;
00472 line << resolve(stmt.dest) << " = texture";
00473
00474 ShTextureNodePtr texture = shref_dynamic_cast<ShTextureNode>(stmt.src[0].node());
00475 switch (texture->dims()) {
00476 case SH_TEXTURE_1D:
00477 line << "1D";
00478 break;
00479 case SH_TEXTURE_2D:
00480 line << "2D";
00481 break;
00482 case SH_TEXTURE_3D:
00483 line << "3D";
00484 break;
00485 case SH_TEXTURE_CUBE:
00486 line << "Cube";
00487 break;
00488 case SH_TEXTURE_RECT:
00489 line << "2DRect";
00490 break;
00491 }
00492
00493 line << "(" << resolve(stmt.src[0]) << ", " << resolve(stmt.src[1]) << ")";
00494 if (2 == texture->size()) {
00495 line << ".xw";
00496 } else if (texture->size() != 4) {
00497 line << ".";
00498 for (int i = 0; i < texture->size(); i++) {
00499 line << "xyzw"[i];
00500 }
00501 }
00502
00503 append_line(line.str());
00504 }
00505
00506 }