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