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