GlslEmit.cpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright 2003-2006 Serious Hack Inc.
00004 // 
00005 // This library is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 //
00010 // This library is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this library; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
00018 // MA  02110-1301, USA
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)"}, // Needs ATI work-around
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 void GlslCode::table_substitution(const ShStatement& stmt, const char* code_ptr)
00070 {
00071   // TODO: This should definitely not be done every time a statement
00072   // is emitted, we should cache it under the operation type.
00073 
00074   string code = code_ptr;
00075   stringstream operation;
00076   int param_size=0;
00077 
00078   {
00079     // find the size of the biggest parameter
00080     string::size_type i = 0;
00081     for (string::size_type j=0; (j = code.find_first_of("$", i)) != string::npos; i = j) {
00082       i = j + 1;
00083       j = code.find_first_not_of("012345689", i);
00084       int index = atoi(code.substr(i, j - i).c_str());
00085       const ShVariable& src = stmt.src[index];
00086       if (src.size() > param_size) {
00087         param_size = src.size();
00088       }
00089     }
00090   }
00091 
00092   // Dices up the code string into references #i or $i to 
00093   // src variables and the code fragments between references.
00094   {
00095     string::size_type i = 0;
00096     for (string::size_type j=0; (j = code.find_first_of("$", i)) != string::npos; i = j) {
00097       // print fragment before the variable
00098       operation << code.substr(i, j - i);
00099       i = j + 1;
00100       j = code.find_first_not_of("012345689", i);
00101 
00102       // print the variable
00103       int index = atoi(code.substr(i, j - i).c_str());
00104       const ShVariable& src = stmt.src[index];
00105       operation << resolve(src, -1, param_size);
00106     }
00107 
00108     if (i != string::npos) {
00109       operation << code.substr(i);
00110     }
00111   }
00112 
00113   // create the full line of code
00114   stringstream line;
00115   line << resolve(stmt.dest) << " = ";
00116 
00117   if (param_size != stmt.dest.size()) {
00118     // cast for the destination size  
00119     line << glsl_typename(stmt.dest.valueType(), stmt.dest.size()); 
00120     line << "(" << operation.str() << ")";
00121   } else {
00122     line << operation.str();
00123   }
00124 
00125   append_line(line.str());
00126 }
00127 
00128 bool GlslCode::handle_table_operation(const ShStatement& stmt)
00129 {
00130   const char* code = 0;
00131   {
00132     unsigned i = 0;
00133     for (ShOperation op = opCodeTable[i].op; op != SH_OPERATION_END; op = opCodeTable[++i].op) {
00134       if (stmt.op == op) {
00135         code = opCodeTable[i].code;
00136       }
00137     }
00138   }
00139 
00140   if (code) {
00141     table_substitution(stmt, code);
00142     return true; // mapping was found
00143   } else {
00144     return false; // did not find a mapping in the table
00145   }
00146 }
00147 
00148 void GlslCode::emit(const ShStatement &stmt)
00149 {
00150   if (!handle_table_operation(stmt)) {
00151     // Handle the rest of the operations
00152     switch(stmt.op) {
00153     case SH_OP_CBRT:
00154       emit_cbrt(stmt);
00155       break;
00156     case SH_OP_CMUL:
00157       emit_prod(stmt);
00158       break;
00159     case SH_OP_CSUM:
00160       emit_sum(stmt);
00161       break;
00162     case SH_OP_COND:
00163       emit_cond(stmt);
00164       break;
00165     case SH_OP_EXP10:
00166       emit_exp10(stmt);
00167       break;
00168     case SH_OP_KIL:
00169       emit_discard(stmt, "discard");
00170       break;
00171     case SH_OP_LIT:
00172       emit_lit(stmt);
00173       break;
00174     case SH_OP_LOG:
00175       emit_log(stmt);
00176       break;
00177     case SH_OP_LOG10:
00178       emit_log10(stmt);
00179       break;
00180     case SH_OP_NOISE:
00181       emit_noise(stmt);
00182       break;
00183     case SH_OP_PAL:
00184       emit_pal(stmt);
00185       break;
00186     case SH_OP_RET:
00187       emit_discard(stmt, "return");
00188       break;
00189     case SH_OP_SEQ:
00190     case SH_OP_SGE:
00191     case SH_OP_SGT:
00192     case SH_OP_SLE:
00193     case SH_OP_SLT:
00194     case SH_OP_SNE:
00195       emit_logic(stmt);
00196       break;
00197     case SH_OP_TEX:
00198     case SH_OP_TEXI:
00199     case SH_OP_TEXLOD:
00200       emit_texture(stmt);
00201       break;
00202     case SH_OP_COSH:
00203     case SH_OP_SINH:
00204     case SH_OP_TANH:
00205       emit_hyperbolic(stmt);
00206       break;
00207     case SH_OP_COMMENT:
00208       emit_comment(stmt);
00209       break;
00210     default:
00211       shError(ShBackendException(string("Glsl Code: Unknown operation ") + opInfo[stmt.op].name));
00212       break;
00213     }
00214   }
00215 }
00216 
00217 ShVariableNodePtr GlslCode::allocate_constant(const ShStatement& stmt, double constant, int size) const
00218 {
00219   if (size <= 0) size = stmt.dest.size(); // default size is size of destination variable
00220 
00221   const ShVariableNodePtr& dest_node = stmt.dest.node();
00222   ShVariableNode* node = new ShVariableNode(SH_CONST, size, dest_node->valueType(), dest_node->specialType());
00223   
00224   ShDataVariant<double>* variant = new ShDataVariant<double>(size, constant);
00225   ShVariantCPtr variant_ptr = variant;
00226   node->setVariant(variant_ptr);
00227 
00228   ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00229   return node_ptr;
00230 }
00231 
00232 ShVariableNodePtr GlslCode::allocate_temp(const ShStatement& stmt, int size) const
00233 {
00234   if (size <= 0) size = stmt.dest.size(); // default size is size of destination variable
00235   
00236   const ShVariableNodePtr& dest_node = stmt.dest.node();
00237   ShVariableNode* node = new ShVariableNode(SH_TEMP, size, dest_node->valueType(), dest_node->specialType());
00238   ShVariableNodePtr node_ptr = ShPointer<ShVariableNode>(node);
00239   return node_ptr;
00240 }
00241 
00242 string GlslCode::resolve_constant(double constant, const ShVariable& var, int size) const
00243 {
00244   if (size <= 0) size = var.size(); // default size is size of variable
00245 
00246   stringstream s;
00247   s.precision(16);
00248   s << glsl_typename(var.valueType(), size);
00249 
00250   s << "(";
00251   for (int i=0; i < size; i++) {
00252     if (i > 0) s << ", ";
00253     s << constant;
00254   }
00255   s << ")";
00256 
00257   return s.str();
00258 }
00259 
00260 void GlslCode::emit_ati_workaround(const ShStatement& stmt, double real_answer, const char* code)
00261 {
00262   bool on_ati = false;
00263   const GLubyte* vendor = SH_GL_CHECK_ERROR(glGetString(GL_VENDOR));
00264   if (vendor) {
00265     std::string s(reinterpret_cast<const char*>(vendor));
00266     on_ati = s.find("ATI") != s.npos;
00267   }
00268 
00269   if (on_ati) {
00270     ShVariable tmp(allocate_temp(stmt));
00271     ShVariable constant(allocate_constant(stmt, real_answer));
00272     table_substitution(ShStatement(tmp, stmt.src[0], stmt.op, stmt.src[1]), code);
00273     append_line(resolve(stmt.dest) + " = (" + resolve(stmt.src[0]) + " == " + resolve(stmt.src[1]) + ") ? " + resolve(constant) + " : " + resolve(tmp));
00274   } else {
00275     table_substitution(stmt, code);
00276   }
00277 }
00278 
00279 void GlslCode::emit_cbrt(const ShStatement& stmt)
00280 {
00281   SH_DEBUG_ASSERT(SH_OP_CBRT == stmt.op);
00282 
00283   ShVariable temp(allocate_constant(stmt, 1.0 / 3.0));
00284   emit_pow(stmt.dest, stmt.src[0], temp);
00285 }
00286 
00287 void GlslCode::emit_comment(const ShStatement& stmt)
00288 {
00289   append_line("// " + stmt.get_info<ShInfoComment>()->comment, false);
00290 }
00291 
00292 void GlslCode::emit_cond(const ShStatement& stmt)
00293 {
00294   SH_DEBUG_ASSERT(SH_OP_COND == stmt.op);
00295 
00296   bool on_nvidia = false;
00297   const GLubyte* vendor = SH_GL_CHECK_ERROR(glGetString(GL_VENDOR));
00298   if (vendor) {
00299     string s(reinterpret_cast<const char*>(vendor));
00300     on_nvidia = s.find("NVIDIA") != s.npos;
00301   }
00302 
00303   const int size = stmt.src[0].size();
00304   if (on_nvidia || (1 == size)) {
00305     // CG has a component-wise COND operator
00306     string code = string ("(") + resolve(stmt.src[0]) + " > " + 
00307       resolve_constant(0, stmt.src[0]) + ") ? " + resolve(stmt.src[1]) +
00308       " : " + resolve(stmt.src[2]);
00309   
00310     if (size != stmt.dest.size()) {
00311       code = glsl_typename(stmt.dest.valueType(), stmt.dest.size()) +  "(" + code + ")";
00312     }
00313     append_line(resolve(stmt.dest) + " = " + code);
00314   } else {
00315     // The Glsl spec requires the first argument to COND to be a scalar
00316     for (int i=0; i < size; i++) {
00317       append_line(resolve(stmt.dest, i) + " = (" + resolve(stmt.src[0], i) + " > " + 
00318                   resolve_constant(0, stmt.src[0], 1) + ") ? " + resolve(stmt.src[1], i) +
00319                   " : " + resolve(stmt.src[2], i));
00320     }
00321   }
00322 }
00323 
00324 void GlslCode::emit_discard(const ShStatement& stmt, const string& function)
00325 {
00326   SH_DEBUG_ASSERT((SH_OP_KIL == stmt.op) || (SH_OP_RET == stmt.op));
00327 
00328   // Form a statement consistent with Sh's "discard" semantics
00329   ostringstream oss;
00330   oss << "if (";  
00331   if (stmt.src[0].size() > 1) {
00332     // Vector operand - cast to boolean vector and use "any"
00333     oss << "any(bvec" << stmt.src[0].size() << "(";
00334     oss << resolve(stmt.src[0]);
00335     oss << "))";
00336   } else {
00337     // Scalar operand - simply cast to boolean
00338     oss << "bool(";
00339     oss << resolve(stmt.src[0]);
00340     oss << ")";
00341   }
00342   // Close "if" and output contents
00343   oss << ") " << function;
00344 
00345   // Add the line
00346   append_line(oss.str());
00347 }
00348 
00349 void GlslCode::emit_pow(const ShVariable& dest, const ShVariable& a, const ShVariable& b)
00350 {
00351   // cast each argument's size if necessary
00352   const int size = std::max(a.size(), b.size());
00353   string pow_call = string("pow(") + resolve(a, -1, size) + ", " + resolve(b, -1, size) + ")";
00354   
00355   // cast to the destination size if necessary
00356   if (dest.size() != size) {
00357     pow_call = glsl_typename(dest.valueType(), dest.size()) + "(" + pow_call + ")";
00358   }
00359 
00360   append_line(resolve(dest) + " = " + pow_call);
00361 }
00362 
00363 void GlslCode::emit_exp10(const ShStatement& stmt)
00364 {
00365   SH_DEBUG_ASSERT(SH_OP_EXP10 == stmt.op);
00366   ShVariable c(allocate_constant(stmt, 1.0/std::log10(2.0)));
00367   append_line(resolve(stmt.dest) + " = exp2(" + resolve(c) + " * " + resolve(stmt.src[0]) + ")");
00368 }
00369 
00370 void GlslCode::emit_hyperbolic(const ShStatement& stmt)
00371 {
00372   ShVariable two(allocate_constant(stmt, 2));
00373   ShVariable e(allocate_constant(stmt, M_E));
00374 
00375   ShVariable e_plusX(allocate_temp(stmt));
00376   ShVariable e_minusX(allocate_temp(stmt));
00377   emit_pow(e_plusX, e, stmt.src[0]);
00378   append_line(resolve(e_minusX) + " = pow(" + resolve(e) + ", -(" + resolve(stmt.src[0]) + "))");
00379 
00380   switch (stmt.op) {
00381   case SH_OP_COSH:
00382     // cosh x = [e^x + e^-x] / 2
00383     append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " + " + resolve(e_minusX) + ") / " + resolve(two));
00384     break;
00385   case SH_OP_SINH:
00386     // sinh x = [e^x - e^-x] / 2
00387     append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " - " + resolve(e_minusX) + ") / " + resolve(two));
00388     break;
00389   case SH_OP_TANH:
00390     // tanh x = sinh x / cosh x = [e^x - e^-x] / [e^x + e^-x]
00391     append_line(resolve(stmt.dest) + " = (" + resolve(e_plusX) + " - " + resolve(e_minusX) + ") / " +
00392                                         "(" + resolve(e_plusX) + " + " + resolve(e_minusX) + ")");
00393     break;
00394   default:
00395     SH_DEBUG_ASSERT(0);
00396   }
00397 }
00398 
00399 void GlslCode::emit_lit(const ShStatement& stmt)
00400 {
00401   SH_DEBUG_ASSERT(SH_OP_LIT == stmt.op);
00402   
00403   // Result according to OpenGL spec
00404   append_line(resolve(stmt.dest, 0) + " = " + resolve_constant(1, stmt.dest, 1));
00405 
00406   append_line(resolve(stmt.dest, 1) + " = max(" + resolve_constant(0, stmt.dest, 1) +
00407               ", " + resolve(stmt.src[0], 0) + ")");
00408 
00409   append_line(resolve(stmt.dest, 2) + " = " + resolve(stmt.src[0], 0) + 
00410               " > " + resolve_constant(0, stmt.src[0], 1) + " ? pow(max(" + 
00411               resolve_constant(0, stmt.dest, 1) + ", " + resolve(stmt.src[0], 1) + 
00412               "), clamp(" + resolve(stmt.src[0], 2) + ", " + 
00413               resolve_constant(-128, stmt.dest, 1) + ", " + 
00414               resolve_constant(128, stmt.dest, 1) + ")) : " + resolve_constant(0, stmt.dest, 1));
00415 
00416   append_line(resolve(stmt.dest, 3) + " = " + resolve_constant(1, stmt.dest, 1));
00417 }
00418 
00419 void GlslCode::emit_log(const ShStatement& stmt)
00420 {
00421   SH_DEBUG_ASSERT(SH_OP_LOG == stmt.op);
00422   bool on_ati = false;
00423   const GLubyte* vendor = SH_GL_CHECK_ERROR(glGetString(GL_VENDOR));
00424   if (vendor) {
00425     std::string s(reinterpret_cast<const char*>(vendor));
00426     on_ati = s.find("ATI") != s.npos;
00427   }
00428 
00429   if (on_ati) {
00430     ShVariable tmp(allocate_temp(stmt));
00431     table_substitution(ShStatement(tmp, stmt.op, stmt.src[0]), "log($0)");
00432 
00433     const int size = stmt.dest.size();
00434     if (1 == size) {
00435       // Must be handled separately to preserve the destination swizzle
00436       append_line(resolve(stmt.dest) + " = (" + resolve(stmt.src[0]) + " == " + 
00437                   resolve_constant(1, stmt.src[0], 1) + ") ? " + resolve_constant(0, stmt.src[0], 1) +
00438                   " : " + resolve(tmp, 0));
00439     } else {
00440       for (int i=0; i < size; i++) {
00441         append_line(resolve(stmt.dest, i) + " = (" + resolve(stmt.src[0], i) + " == " + 
00442                     resolve_constant(1, stmt.src[0], 1) + ") ? " + resolve_constant(0, stmt.src[0], 1) +
00443                     " : " + resolve(tmp, i));
00444       }
00445     }
00446   } else {
00447     table_substitution(stmt, "log($0)");
00448   }
00449 }
00450 
00451 void GlslCode::emit_log10(const ShStatement& stmt)
00452 {
00453   SH_DEBUG_ASSERT(SH_OP_LOG10 == stmt.op);
00454   ShVariable c(allocate_constant(stmt, std::log10(2.0))); 
00455   append_line(resolve(stmt.dest) + " = log2(" + resolve(stmt.src[0]) + ") * " + resolve(c) + "");
00456 }
00457 
00458 void GlslCode::emit_logic(const ShStatement& stmt)
00459 {
00460   string code = "";
00461   if ((stmt.src[0].size() > 1) || (stmt.src[1].size() > 1) ) {
00462     switch (stmt.op) {
00463     case SH_OP_SEQ:
00464       code = "equal($0, $1)";
00465       break;
00466     case SH_OP_SGT:
00467       code = "greaterThan($0, $1)";
00468       break;
00469     case SH_OP_SGE:
00470       code = "greaterThanEqual($0, $1)";
00471       break;
00472     case SH_OP_SNE:
00473       code = "notEqual($0, $1)";
00474       break;
00475     case SH_OP_SLT:
00476       code = "lessThan($0, $1)";
00477       break;
00478     case SH_OP_SLE:
00479       code = "lessThanEqual($0, $1)";
00480       break;
00481     default:
00482       SH_DEBUG_ASSERT(0);
00483     }
00484   } else {
00485     switch (stmt.op) {
00486     case SH_OP_SEQ:
00487       code = "$0 == $1";
00488       break;
00489     case SH_OP_SGT:
00490       code = "$0 > $1";
00491       break;
00492     case SH_OP_SGE:
00493       code = "$0 >= $1";
00494       break;
00495     case SH_OP_SNE:
00496       code = "$0 != $1";
00497       break;
00498     case SH_OP_SLT:
00499       code = "$0 < $1";
00500       break;
00501     case SH_OP_SLE:
00502       code = "$0 <= $1";
00503       break;
00504     default:
00505       SH_DEBUG_ASSERT(0);
00506     }
00507   }
00508 
00509   // cast for the destination type
00510   code = glsl_typename(stmt.dest.valueType(), stmt.dest.size()) +  "(" + code + ")";
00511 
00512   table_substitution(stmt, code.c_str());
00513 }
00514 
00515 void GlslCode::emit_noise(const ShStatement& stmt)
00516 {
00517   SH_DEBUG_ASSERT(SH_OP_NOISE == stmt.op);
00518 
00519   int output_size = stmt.dest.size();
00520   SH_DEBUG_ASSERT((output_size <= 4) && (output_size >= 1));
00521   
00522   stringstream line;
00523   line << resolve(stmt.dest) << " = " << "noise" << output_size << "("
00524        << resolve(stmt.src[0]) << ")";
00525   append_line(line.str());
00526 }
00527 
00528 void GlslCode::emit_pal(const ShStatement& stmt)
00529 {
00530   SH_DEBUG_ASSERT(SH_OP_PAL == stmt.op);
00531 
00532   append_line(resolve(stmt.dest) + " = " + resolve(stmt.src[0], stmt.src[1]));
00533 }
00534 
00535 void GlslCode::emit_prod(const ShStatement& stmt)
00536 {
00537   SH_DEBUG_ASSERT(SH_OP_CMUL == stmt.op);
00538 
00539   ShVariable temp(allocate_temp(stmt, 1));
00540   append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00541 
00542   int size = stmt.src[0].size();
00543   for (int i=1; i < size; i++) {
00544     append_line(resolve(temp) + " *= " + resolve(stmt.src[0], i));
00545   }
00546 
00547   append_line(resolve(stmt.dest) + " = " + resolve(temp));
00548 }
00549 
00550 void GlslCode::emit_sum(const ShStatement& stmt)
00551 {
00552   SH_DEBUG_ASSERT(SH_OP_CSUM == stmt.op);
00553 
00554   ShVariable temp(allocate_temp(stmt, 1));
00555   append_line(resolve(temp) + " = " + resolve(stmt.src[0], 0));
00556 
00557   int size = stmt.src[0].size();
00558   for (int i=1; i < size; i++) {
00559     append_line(resolve(temp) + " += " + resolve(stmt.src[0], i));
00560   }
00561 
00562   append_line(resolve(stmt.dest) + " = " + resolve(temp));
00563 }
00564 
00565 void GlslCode::emit_texture(const ShStatement& stmt)
00566 {
00567   SH_DEBUG_ASSERT((SH_OP_TEX == stmt.op) || (SH_OP_TEXI == stmt.op) || (SH_OP_TEXLOD == stmt.op));
00568 
00569   stringstream line;
00570   line << resolve(stmt.dest) << " = texture";
00571 
00572   ShTextureNodePtr texture = shref_dynamic_cast<ShTextureNode>(stmt.src[0].node());
00573   switch (texture->dims()) {
00574   case SH_TEXTURE_1D:
00575     line << "1D";
00576     break;
00577   case SH_TEXTURE_2D:
00578     line << "2D";
00579     break;
00580   case SH_TEXTURE_3D:
00581     line << "3D";
00582     break;
00583   case SH_TEXTURE_CUBE:
00584     line << "Cube";
00585     break;
00586   case SH_TEXTURE_RECT:
00587     line << "2DRect"; // Not supported on ATI, but there is no equivalent
00588     break;
00589   }
00590 
00591   if (SH_OP_TEXLOD == stmt.op) {
00592     line << "Lod";
00593   }
00594   line << "(" << resolve(stmt.src[0]) << ", " << resolve(stmt.src[1]);
00595 
00596   if (SH_OP_TEXLOD == stmt.op) {
00597     line << ", " << resolve(stmt.src[2]);
00598   }
00599 
00600   line << ")";
00601 
00602   // Apply the right swizzle, based on the texture size and destination size
00603   if ((2 == texture->size()) || (stmt.dest.size() != 4)) {
00604     string components = "xyzw";
00605     if (2 == texture->size()) {
00606       components = "xwyz"; // 2-component inputs are uploaded as GL_LUMINANCE_ALPHA
00607     }
00608     
00609     line << ".";
00610     const int swiz_length = stmt.dest.size();
00611     for (int i = 0; i < swiz_length; i++) {
00612       line << components[i];
00613     }
00614   }
00615 
00616   append_line(line.str());
00617 }
00618 
00619 }

Generated on Thu Feb 16 14:51:28 2006 for Sh by  doxygen 1.4.6