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_COND, "($0 > 0) ? $1 : $2"},
00043 {SH_OP_COS, "cos($0)"},
00044 {SH_OP_DOT, "dot($0, $1)"},
00045 {SH_OP_DIV, "$0 / $1"},
00046 {SH_OP_DX, "dFdx($0)"},
00047 {SH_OP_DY, "dFdy($0)"},
00048 {SH_OP_EXP2, "exp2($0)"},
00049 {SH_OP_FLR, "floor($0)"},
00050 {SH_OP_FRAC, "fract($0)"},
00051 {SH_OP_LOG2, "log2($0)"},
00052 {SH_OP_LRP, "mix($2, $1, $0)"},
00053 {SH_OP_MAD, "$0 * $1 + $2"},
00054 {SH_OP_MAX, "max($0, $1)"},
00055 {SH_OP_MIN, "min($0, $1)"},
00056 {SH_OP_MOD, "mod($0, $1)"},
00057 {SH_OP_MUL, "$0 * $1"},
00058 {SH_OP_NEG, "-($0)"},
00059 {SH_OP_NORM, "normalize($0)"},
00060 {SH_OP_POW, "pow($0, $1)"},
00061 {SH_OP_RCP, "1.0 / $0"},
00062 {SH_OP_RND, "floor($0 + 0.5)"},
00063 {SH_OP_RSQ, "inversesqrt($0)"},
00064 {SH_OP_SGN, "sign($0)"},
00065 {SH_OP_SIN, "sin($0)"},
00066 {SH_OP_SQRT, "sqrt($0)"},
00067 {SH_OP_TAN, "tan($0)"},
00068 {SH_OP_XPD, "cross($0, $1)"},
00069
00070 {SH_OPERATION_END, 0}
00071 };
00072
00073 typedef map<SH::ShOperation, GlslOpCodeVecs> GlslOpCodeMap;
00074
00075 GlslOpCodeVecs::GlslOpCodeVecs(const GlslMapping& mapping)
00076 {
00077 string code(mapping.code);
00078
00079
00080
00081 unsigned i, j;
00082 i = j = 0;
00083 for (; (j = code.find_first_of("$", i)) != string::npos;) {
00084 frag.push_back(code.substr(i, j - i));
00085 i = j + 1;
00086 j = code.find_first_not_of("012345689", i);
00087 index.push_back(atoi(code.substr(i, j - i).c_str()));
00088 i = j;
00089 }
00090 if (i == string::npos) {
00091 frag.push_back("");
00092 } else {
00093 frag.push_back(code.substr(i));
00094 }
00095 }
00096
00097 void GlslCode::table_substitution(const ShStatement& stmt, GlslOpCodeVecs codeVecs)
00098 {
00099 stringstream line;
00100 line << resolve(stmt.dest) << " = ";
00101 line << glsl_typename(stmt.dest.valueType(), stmt.dest.size()) << "(";
00102
00103
00104 int param_size=0;
00105 for (unsigned i=0; i < codeVecs.index.size(); i++) {
00106 const ShVariable& src = stmt.src[codeVecs.index[i]];
00107 if (src.size() > param_size) {
00108 param_size = src.size();
00109 }
00110 }
00111
00112
00113 unsigned i;
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 line << codeVecs.frag[i];
00121
00122 line << ")";
00123 append_line(line.str());
00124 }
00125
00126 void GlslCode::emit(const ShStatement &stmt)
00127 {
00128 static GlslOpCodeMap opCodeMap;
00129
00130
00131 if (opCodeMap.empty()) {
00132 for (int i=0; opCodeTable[i].op != SH_OPERATION_END; i++) {
00133 opCodeMap[opCodeTable[i].op] = GlslOpCodeVecs(opCodeTable[i]);
00134 }
00135 }
00136
00137 if(opCodeMap.find(stmt.op) != opCodeMap.end()) {
00138
00139 table_substitution(stmt, opCodeMap[stmt.op]);
00140 }
00141 else {
00142
00143 switch(stmt.op) {
00144 case SH_OP_CBRT:
00145 emit_cbrt(stmt);
00146 break;
00147 case SH_OP_CMUL:
00148 emit_prod(stmt);
00149 break;
00150 case SH_OP_CSUM:
00151 emit_sum(stmt);
00152 break;
00153 case SH_OP_EXP:
00154 emit_exp(stmt, M_E);
00155 break;
00156 case SH_OP_EXP10:
00157 emit_exp(stmt, 10);
00158 break;
00159 case SH_OP_KIL:
00160 emit_discard(stmt);
00161 break;
00162 case SH_OP_LIT:
00163 emit_lit(stmt);
00164 break;
00165 case SH_OP_LOG:
00166 emit_log(stmt, M_E);
00167 break;
00168 case SH_OP_LOG10:
00169 emit_log(stmt, 10);
00170 break;
00171 case SH_OP_PAL:
00172 emit_pal(stmt);
00173 break;
00174 case SH_OP_SEQ:
00175 case SH_OP_SGE:
00176 case SH_OP_SGT:
00177 case SH_OP_SLE:
00178 case SH_OP_SLT:
00179 case SH_OP_SNE:
00180 emit_logic(stmt);
00181 break;
00182 case SH_OP_TEX:
00183 case SH_OP_TEXI:
00184 emit_texture(stmt);
00185 break;
00186 default:
00187 shError(ShException(string("Glsl Code: Unknown operation ") + opInfo[stmt.op].name));
00188 break;
00189 }
00190 }
00191 }
00192
00193 ShVariableNodePtr GlslCode::allocate_constant(const ShStatement& stmt, double constant, int size) const
00194 {
00195 if (size <= 0) size = stmt.dest.size();
00196
00197 const ShVariableNodePtr& dest_node = stmt.dest.node();
00198 ShVariableNode* node = new ShVariableNode(SH_CONST, size, dest_node->valueType(), dest_node->specialType());
00199
00200 ShDataVariant<double>* variant = new ShDataVariant<double>(size, constant);
00201 node->setVariant(variant);
00202
00203 ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00204 return node_ptr;
00205 }
00206
00207 ShVariableNodePtr GlslCode::allocate_temp(const ShStatement& stmt, 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_TEMP, size, dest_node->valueType(), dest_node->specialType());
00213 ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00214 return node_ptr;
00215 }
00216
00217 string GlslCode::resolve_constant(double constant, const ShVariable& var, int size) const
00218 {
00219 if (size <= 0) size = var.size();
00220
00221 stringstream s;
00222 s.precision(16);
00223 s << glsl_typename(var.valueType(), size);
00224
00225 s << "(";
00226 for (int i=0; i < size; i++) {
00227 if (i > 0) s << ", ";
00228 s << constant;
00229 }
00230 s << ")";
00231
00232 return s.str();
00233 }
00234
00235 void GlslCode::emit_cbrt(const ShStatement& stmt)
00236 {
00237 SH_DEBUG_ASSERT(SH_OP_CBRT == stmt.op);
00238
00239 ShVariable temp(allocate_constant(stmt, 1.0 / 3.0));
00240 append_line(resolve(stmt.dest) + " = pow(" + resolve(stmt.src[0]) + ", " + resolve(temp) + ")");
00241 }
00242
00243 void GlslCode::emit_discard(const ShStatement& stmt)
00244 {
00245 SH_DEBUG_ASSERT(SH_OP_KIL == stmt.op);
00246
00247 append_line(string("if (") + resolve(stmt.src[0]) + " > 0) discard");
00248 }
00249
00250 void GlslCode::emit_exp(const ShStatement& stmt, double power)
00251 {
00252 SH_DEBUG_ASSERT((SH_OP_EXP == stmt.op) || (SH_OP_EXP10 == stmt.op));
00253
00254 ShVariable temp(allocate_constant(stmt, power));
00255 append_line(resolve(stmt.dest) + " = pow(" + resolve(temp) + ", " + resolve(stmt.src[0]) + ")");
00256 }
00257
00258 void GlslCode::emit_lit(const ShStatement& stmt)
00259 {
00260 SH_DEBUG_ASSERT(SH_OP_LIT == stmt.op);
00261
00262
00263 append_line(resolve(stmt.dest, 0) + " = " + resolve_constant(1, stmt.dest, 1));
00264
00265 append_line(resolve(stmt.dest, 1) + " = max(" + resolve_constant(0, stmt.dest, 1) +
00266 ", " + resolve(stmt.src[0], 0) + ")");
00267
00268 append_line(resolve(stmt.dest, 2) + " = " + resolve(stmt.src[0], 0) +
00269 " > " + resolve_constant(0, stmt.src[0], 1) + " ? pow(max(" +
00270 resolve_constant(0, stmt.dest, 1) + ", " + resolve(stmt.src[0], 1) +
00271 "), clamp(" + resolve(stmt.src[0], 2) + ", " +
00272 resolve_constant(-128, stmt.dest, 1) + ", " +
00273 resolve_constant(128, stmt.dest, 1) + ")) : " + resolve_constant(0, stmt.dest, 1));
00274
00275 append_line(resolve(stmt.dest, 3) + " = " + resolve_constant(1, stmt.dest, 1));
00276 }
00277
00278 void GlslCode::emit_log(const ShStatement& stmt, double base)
00279 {
00280 SH_DEBUG_ASSERT((SH_OP_LOG == stmt.op) || (SH_OP_LOG10 == stmt.op));
00281
00282 const double log2_base = log(base) / log(2.0);
00283
00284 ShVariable temp(allocate_constant(stmt, log2_base));
00285 append_line(resolve(stmt.dest) + " = log2(" + resolve(stmt.src[0]) + ") / " + resolve(temp) + "");
00286 }
00287
00288 void GlslCode::emit_logic(const ShStatement& stmt)
00289 {
00290 GlslMapping mapping;
00291 mapping.op = stmt.op;
00292
00293 if ((stmt.src[0].size() > 1) || (stmt.src[1].size() > 1) ) {
00294 switch (stmt.op) {
00295 case SH_OP_SEQ:
00296 mapping.code = "equal($0, $1)";
00297 break;
00298 case SH_OP_SGT:
00299 mapping.code = "greaterThan($0, $1)";
00300 break;
00301 case SH_OP_SGE:
00302 mapping.code = "greaterThanEqual($0, $1)";
00303 break;
00304 case SH_OP_SNE:
00305 mapping.code = "notEqual($0, $1)";
00306 break;
00307 case SH_OP_SLT:
00308 mapping.code = "lessThan($0, $1)";
00309 break;
00310 case SH_OP_SLE:
00311 mapping.code = "lessThanEqual($0, $1)";
00312 break;
00313 default:
00314 SH_DEBUG_ASSERT(0);
00315 }
00316 } else {
00317 switch (stmt.op) {
00318 case SH_OP_SEQ:
00319 mapping.code = "$0 == $1";
00320 break;
00321 case SH_OP_SGT:
00322 mapping.code = "$0 > $1";
00323 break;
00324 case SH_OP_SGE:
00325 mapping.code = "$0 >= $1";
00326 break;
00327 case SH_OP_SNE:
00328 mapping.code = "$0 != $1";
00329 break;
00330 case SH_OP_SLT:
00331 mapping.code = "$0 < $1";
00332 break;
00333 case SH_OP_SLE:
00334 mapping.code = "$0 <= $1";
00335 break;
00336 default:
00337 SH_DEBUG_ASSERT(0);
00338 }
00339 }
00340
00341
00342
00343 table_substitution(stmt, mapping);
00344 }
00345
00346 void GlslCode::emit_pal(const ShStatement& stmt)
00347 {
00348 SH_DEBUG_ASSERT(SH_OP_PAL == stmt.op);
00349
00350 append_line(resolve(stmt.dest) + " = " + resolve(stmt.src[0], stmt.src[1]));
00351 }
00352
00353 void GlslCode::emit_prod(const ShStatement& stmt)
00354 {
00355 SH_DEBUG_ASSERT(SH_OP_CMUL == stmt.op);
00356
00357 ShVariable temp(allocate_temp(stmt, 1));
00358 append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00359
00360 int size = stmt.src[0].size();
00361 for (int i=1; i < size; i++) {
00362 append_line(resolve(temp) + " *= " + resolve(stmt.src[0], i));
00363 }
00364
00365 append_line(resolve(stmt.dest) + " = " + resolve(temp));
00366 }
00367
00368 void GlslCode::emit_sum(const ShStatement& stmt)
00369 {
00370 SH_DEBUG_ASSERT(SH_OP_CSUM == stmt.op);
00371
00372 ShVariable temp(allocate_temp(stmt, 1));
00373 append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00374
00375 int size = stmt.src[0].size();
00376 for (int i=1; i < size; i++) {
00377 append_line(resolve(temp) + " += " + resolve(stmt.src[0], i));
00378 }
00379
00380 append_line(resolve(stmt.dest) + " = " + resolve(temp));
00381 }
00382
00383 void GlslCode::emit_texture(const ShStatement& stmt)
00384 {
00385 SH_DEBUG_ASSERT((SH_OP_TEX == stmt.op) || (SH_OP_TEXI == stmt.op));
00386
00387 stringstream line;
00388 line << resolve(stmt.dest) << " = texture";
00389
00390 ShTextureNodePtr texture = shref_dynamic_cast<ShTextureNode>(stmt.src[0].node());
00391 switch (texture->dims()) {
00392 case SH_TEXTURE_1D:
00393 line << "1D";
00394 break;
00395 case SH_TEXTURE_2D:
00396 line << "2D";
00397 break;
00398 case SH_TEXTURE_3D:
00399 line << "3D";
00400 break;
00401 case SH_TEXTURE_CUBE:
00402 line << "Cube";
00403 break;
00404 case SH_TEXTURE_RECT:
00405 line << "2DRect";
00406 break;
00407 }
00408
00409 line << "(" << resolve(stmt.src[0]) << ", " << resolve(stmt.src[1]) << ")";
00410 if (texture->size() != 4) {
00411 line << ".";
00412 for (int i = 0; i < texture->size(); i++) {
00413 line << "xyzw"[i];
00414 }
00415 }
00416
00417 append_line(line.str());
00418 }
00419
00420 }