23#include <SeExpression.h>
24#include <SeExprFunc.h>
25#include <RixInterfaces.h>
31RixTokenStorage* tokenizer;
32inline const char* tokenize(
const char* str) {
33 const char* result = tokenizer->GetToken(str);
37int SeTokenize(RslContext* ctx,
int argc,
const RslArg* argv[]) {
38 RslStringIter result(argv[0]);
39 const char* str = *RslStringIter(argv[1]);
40 *result = (RtString)tokenize(str);
45 immutable_hash_map<const char*, int> indexMap;
46 std::vector<int> groupStarts;
47 std::vector<int> groupCounts;
48 std::vector<int> groupIndices;
50 SeRmanVarMap(
int nvars,
const char** varnames,
int* varindices,
int* groupstarts)
51 : indexMap(varnames, varindices, nvars), groupStarts(groupstarts, groupstarts + nvars), groupCounts(nvars),
53 int groupIndex = 0, i, j;
54 for (i = 0; i < nvars;) {
56 for (j = i + 1; j < nvars; j++) {
57 if (groupStarts[j] != groupStarts[i])
break;
59 int groupCount = j - i;
62 groupCounts[i] = groupCount;
63 groupIndices[i] = groupIndex;
73typedef std::map<const char*, SeRmanVarMap*> SeRmanVarMapMap;
74typedef std::map<const char*, int> SeRmanExprMap;
75typedef std::vector<int> SeVarBinding;
86 SeRmanVarMapMap varmaps;
88 SeRmanVarMap& getVarMap(
const char* varMapHandle) {
89 SeRmanVarMap*& varmap = varmaps[varMapHandle];
92 char* varlist = strdup(varMapHandle);
93 std::vector<const char*> varnames;
94 std::vector<int> groupStarts;
97 char* varlist_end = 0;
98 char* vargroup = strtok_r(varlist,
" ", &varlist_end);
101 int groupStart = varnames.size();
102 char* vargroup_end = 0;
103 char* var = strtok_r(vargroup,
",", &vargroup_end);
105 varnames.push_back(tokenize(var));
106 groupStarts.push_back(groupStart);
107 }
while ((var = strtok_r(0,
",", &vargroup_end)));
108 }
while ((vargroup = strtok_r(0,
" ", &varlist_end)));
111 int nvars = varnames.size();
112 int* varindices = (
int*)alloca(
sizeof(
int) * nvars);
113 for (
int i = 0; i < nvars; i++) {
116 varmap =
new SeRmanVarMap(nvars, &varnames[0], &varindices[0], &groupStarts[0]);
122 void ptError(
char* fmt, ...) {
123 static char strbuf[1024];
126 vsprintf(strbuf, fmt, ap);
127 msgs->Error(
"%s", strbuf);
131 void ptWarn(
char* fmt, ...) {
132 static char strbuf[1024];
135 vsprintf(strbuf, fmt, ap);
136 msgs->Warning(
"%s", strbuf);
140 SeRmanExprMap exprmap;
141 std::vector<SeRmanExpr*> exprs;
147 msgs = (RixMessages*)RxGetRixContext()->GetRixInterface(k_RixMessages);
153ThreadData& getThreadData(RslContext* ctx) {
154 ThreadData* td = (ThreadData*)ctx->GetThreadData();
157 ctx->SetThreadData(td);
163class SeRmanVar :
public SeExprVarRef {
165 SeRmanVar(ThreadData& td) : SeExprVarRef(SeExprType().FP(3).Varying()), td(td),
index(0) {}
167 virtual bool isVec() {
return 1; }
168 void setIndex(
int i) {
index = i; }
169 virtual void eval(
const SeExprVarNode* node, SeVec3d& result) {
170 RtColor& c = td.varValues[
index];
181class AttrVar :
public SeExprVectorVarRef {
186 AttrVar() : name(
""),
value(0.) {}
188 AttrVar(
const std::string& nameIn) :
value(0.) {
190 size_t pos = nameIn.find(
"::");
191 name = nameIn.substr(0, pos) + nameIn.substr(pos + 1, nameIn.size() - (pos - 1));
194 std::string getName() {
return name; }
202 int statusOpt, statusAttr;
205 statusOpt = RxOption(name.c_str(), fbuf16,
sizeof(fbuf16), &rxType, &count);
206 statusAttr = RxAttribute(name.c_str(), fbuf16,
sizeof(fbuf16), &rxType, &count);
208 if (statusAttr != 0 && statusOpt != 0) {
210 value.setValue(0.0, 0.0, 0.0);
218 value.setValue(fbuf16[0], fbuf16[0], fbuf16[0]);
225 value.setValue(fbuf16[0], fbuf16[1], fbuf16[2]);
236 virtual void eval(
const SeExprVarNode* node, SeVec3d& result) { result =
value; }
240class SeRmanExpr :
public SeExpression {
242 SeRmanExpr(
const std::string&
expr, ThreadData& td) : SeExpression(
expr), _td(td), _boundVarMap(-1) {}
244 virtual SeExprVarRef*
resolveVar(
const std::string& name)
const {
245 if (name.find(
"::") != std::string::npos) {
247 for (i = 0, size = _attrrefs.size(); i < size; i++)
249 if (name == _attrrefs[i]->getName())
return _attrrefs[i];
252 AttrVar* attrVar =
new AttrVar( name);
253 _attrrefs.push_back(attrVar);
257 const char* token = tokenize(name.c_str());
258 for (
int i = 0, size = _varrefs.size(); i < size; i++)
259 if (_varnames[i] == token)
return _varrefs[i];
260 SeRmanVar* var =
new SeRmanVar(_td);
261 _varnames.push_back(token);
262 _varrefs.push_back(var);
266 SeVarBinding* bindVars(
const char* varMapHandle) {
267 SeVarBinding*& binding = _bindings[varMapHandle];
269 binding =
new SeVarBinding;
272 SeRmanVarMap& varmap = _td.getVarMap(varMapHandle);
274 int nvars = _varnames.size();
275 binding->resize(nvars);
276 for (
int i = 0; i < nvars; i++) {
277 const char* name = _varnames[i];
278 int index = varmap.indexMap[name];
285 char msg[] =
"SeRmanExpr error: undefined variable \"$%s\"";
286 _td.ptError(msg, name);
288 (*binding)[i] =
index;
291 _bindstack.push_back(binding);
296 int nattrs = _attrrefs.size();
299 for (
int i = 0; i < nattrs; i++) {
300 _attrrefs[i]->doLookup();
304 void setVarIndices() {
307 SeVarBinding* binding = _bindstack.back();
309 for (
int i = 0, size = binding->size(); i < size; i++) _varrefs[i]->setIndex((*binding)[i]);
313 void unbindVars() { _bindstack.pop_back(); }
316 mutable std::vector<const char*> _varnames;
317 mutable std::vector<SeRmanVar*> _varrefs;
318 mutable std::vector<AttrVar*> _attrrefs;
319 mutable std::map<const char*, SeVarBinding*> _bindings;
320 mutable std::vector<SeVarBinding*> _bindstack;
325void init(RixContext* ctx) {
326 tokenizer = (RixTokenStorage*)ctx->GetRixInterface(k_RixGlobalTokenData);
329 char* plugins_ptr = getenv(
"SE_EXPR_PLUGINS");
332 plugins = plugins_ptr;
333 unsetenv(
"SE_EXPR_PLUGINS");
341 if (plugins_ptr) setenv(
"SE_EXPR_PLUGINS", plugins.c_str(), 1);
344int SeExprBind(RslContext* ctx,
int argc,
const RslArg* argv[]) {
345 RslFloatIter result(argv[0]);
346 const char* exprstr = *RslStringIter(argv[1]);
347 const char* varmapHandle = *RslStringIter(argv[2]);
352 argv[3]->GetResizer()->Resize(0);
357 ThreadData& td = getThreadData(ctx);
358 int&
index = td.exprmap[exprstr];
361 static pthread_mutex_t
mutex = PTHREAD_MUTEX_INITIALIZER;
362 pthread_mutex_lock(&
mutex);
363 SeRmanExpr*
expr =
new SeRmanExpr(exprstr, td);
364 bool valid =
expr->isValid();
365 pthread_mutex_unlock(&
mutex);
367 char msg[] =
"SeRmanExpr error: %s";
368 td.ptError(msg,
expr->parseError().c_str());
371 index = td.exprs.size();
373 td.exprs.push_back(
expr);
381 SeVarBinding& binding = *
expr->bindVars(varmapHandle);
382 int nvars = binding.size();
383 argv[3]->GetResizer()->Resize(nvars);
384 float* varIndices = *RslFloatArrayIter(argv[3]);
385 for (
int i = 0; i < nvars; i++) {
386 varIndices[i] = binding[i];
389 argv[3]->GetResizer()->Resize(0);
394int SeExprEval(RslContext* ctx,
int argc,
const RslArg* argv[]) {
395 int index = int(*RslFloatIter(argv[1]));
396 RslColorArrayIter varValuesIter = argv[2];
397 RslColorIter CiIter = argv[3];
399 int numVals = argv[3]->NumValues();
402 for (
int i = 0; i < numVals; i++, CiIter++, varValuesIter++) {
404 Ci[0] = Ci[1] = Ci[2] = 0;
409 ThreadData& td = getThreadData(ctx);
412 expr.setVarIndices();
414 bool isThreadSafe =
expr.isThreadSafe();
416 for (
int i = 0; i < numVals; i++, CiIter++, varValuesIter++) {
417 td.varValues = &varValuesIter[0];
418 float* Ci = td.Ci = *CiIter;
421 static pthread_mutex_t
mutex = PTHREAD_MUTEX_INITIALIZER;
422 if (!isThreadSafe) pthread_mutex_lock(&
mutex);
424 SeVec3d v =
expr.evaluate();
426 if (!isThreadSafe) pthread_mutex_unlock(&
mutex);
428 if (!isfinite(v[0]) || !isfinite(v[1]) || !isfinite(v[2])) {
429 char msg[] =
"Shader Expression: %s: resulted in NAN. Setting val to 1";
430 td.ptWarn(msg,
expr.getExpr().c_str());
431 v[0] = v[1] = v[2] = 1;
447 {
"string SeTokenize(string)", SeTokenize, NULL, NULL},
450 {
"float SeExprBind(string, string, output uniform float[])", SeExprBind, NULL, NULL},
453 {
"void SeExprEval(uniform float, color[], output color)", SeExprEval, NULL, NULL},
virtual void eval(ArgHandle args)
static SeExprInternal2::Mutex mutex
RslFunctionTable RslPublicFunctions(funcs, init)
static RslFunction funcs[]
</pre >< h3 > Binding our variable reference</h3 > If we now tried to use the variable would still not be found by our expressions To make it bindable we need to override the resolveVar() function as follows</pre >< h3 > Variable setting</h3 > Next we need to make a way of setting the variable As the controlling code will use the expression it will repeatedly alternate between setting the independent variables that are used and calling evaluate(). What it has to do depends very much on the application. In this case we only need to set the independent variable x as</pre >< h2 > Evaluating expressions</h2 > Evaluating an expression is pretty easy But before we can do that we need to make an instance< pre > GrapherExpr expr("x+x^2")
</pre > Once we have this we need an instance to store our variable and provide a reference to that We make it because resolveVar() is const . One does not need to store a variable reference in a given expression. In fact
The result is computed int int< br >< div style="margin-left: 40px;"> Picks values randomly between loRange and hiRange based on supplied index(which is automatically hashed).  
For any rgb or hsl value(except for negative s values)