SeExpr
imageSynthForPaint3d.cpp
Go to the documentation of this file.
1/*
2 Copyright Disney Enterprises, Inc. All rights reserved.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License
6 and the following modification to it: Section 6 Trademarks.
7 deleted and replaced with:
8
9 6. Trademarks. This License does not grant permission to use the
10 trade names, trademarks, service marks, or product names of the
11 Licensor and its affiliates, except as required for reproducing
12 the content of the NOTICE file.
13
14 You may obtain a copy of the License at
15 http://www.apache.org/licenses/LICENSE-2.0
16*/
20#include <map>
21#include <cstdlib>
22#include <cstdio>
23#include <cstring>
24#include <png.h>
25#include <fstream>
26
27#include <SeExpr2/Expression.h>
28#include <SeExpr2/Vec.h>
29#include <SeExpr2/Interpreter.h>
30#include <SeExpr2/ExprFunc.h>
31#include <SeExpr2/ExprFuncX.h>
32#include <SeExpr2/Platform.h>
33
34namespace SeExpr2 {
35class RandFuncX : public ExprFuncSimple {
36
37 struct Data : public ExprFuncNode::Data {
38 std::vector<std::pair<int, int> > ranges;
39 std::string format;
40 };
41
42 virtual ExprType prep(ExprFuncNode* node, bool wantScalar, ExprVarEnvBuilder& envBuilder) const {
43 bool valid = true;
44 for (int i = 0; i < node->numChildren(); i++)
45 valid &= node->checkArg(i, ExprType().FP(1).Varying(), envBuilder);
46 return valid ? ExprType().FP(1).Varying() : ExprType().Error();
47 }
48
49 virtual ExprFuncNode::Data* evalConstant(const ExprFuncNode* node, ArgHandle args) const { return new Data; }
50
51 virtual void eval(ArgHandle args) {
52 if (args.nargs() >= 2) {
53 args.outFp = (args.inFp<1>(0)[0] - args.inFp<1>(1)[0]) / 2.0;
54 } else
55 args.outFp = 0.5;
56 }
57
58 public:
59 RandFuncX() : ExprFuncSimple(true) {} // Thread Safe
60 virtual ~RandFuncX() {}
62
63// map(string name, [float format-arg], [float u], [float v], [int channel])
64class MapFuncX : public ExprFuncSimple {
65 struct Data : public ExprFuncNode::Data {
66 std::vector<std::pair<int, int> > ranges;
67 std::string format;
68 };
69
70 virtual ExprType prep(ExprFuncNode* node, bool wantScalar, ExprVarEnvBuilder& envBuilder) const {
71 bool valid = true;
72 valid &= node->checkArg(0, ExprType().String().Constant(), envBuilder);
73 for (int i = 1; i < node->numChildren(); i++)
74 valid &= node->checkArg(i, ExprType().FP(1).Varying(), envBuilder);
75 return valid ? ExprType().FP(3).Varying() : ExprType().Error();
76 }
77
78 virtual ExprFuncNode::Data* evalConstant(const ExprFuncNode* node, ArgHandle args) const { return new Data; }
79
80 virtual void eval(ArgHandle args) {
81 double* out = &args.outFp;
82
83 double val = 0.5;
84 int num = args.nargs();
85 if (num > 2)
86 for (int k = 2; k < num; k++) val += args.inFp<1>(k)[0];
87
88 for (int k = 0; k < 3; k++) out[k] = val;
89 }
90
91 public:
92 MapFuncX() : ExprFuncSimple(true) {} // Thread Safe
93 virtual ~MapFuncX() {}
95
96// triplanar(string name, [vector scale], [float blend], [vector rotation], [vector translation])
98 struct Data : public ExprFuncNode::Data {
99 std::vector<std::pair<int, int> > ranges;
100 std::string format;
101 };
102
103 virtual ExprType prep(ExprFuncNode* node, bool wantScalar, ExprVarEnvBuilder& envBuilder) const {
104 bool valid = true;
105 valid &= node->checkArg(0, ExprType().String().Constant(), envBuilder);
106 for (int i = 1; i < node->numChildren(); i++)
107 valid &= node->checkArg(i, ExprType().FP(1).Varying(), envBuilder);
108 return valid ? ExprType().FP(3).Varying() : ExprType().Error();
109 }
110
111 virtual ExprFuncNode::Data* evalConstant(const ExprFuncNode* node, ArgHandle args) const { return new Data; }
112
113 virtual void eval(ArgHandle args) {
114 double* out = &args.outFp;
115
116 double val = 0.5;
117 int num = args.nargs();
118 if (num > 1)
119 for (int k = 1; k < num; k++) val += (args.inFp<3>(k)[0] + args.inFp<3>(k)[1] + args.inFp<3>(k)[2]);
120
121 for (int k = 0; k < 3; k++) out[k] = val;
122 }
123
124 public:
125 TriplanarFuncX() : ExprFuncSimple(true) {} // Thread Safe
126 virtual ~TriplanarFuncX() {}
128}
129
130static const char* rand_docstring = "rand\n";
131static const char* map_docstring = "map\n";
132static const char* triplanar_docstring = "triplanar\n";
133
134using namespace SeExpr2;
135
137class ImageSynthExpr : public Expression {
138 public:
140 ImageSynthExpr(const std::string& expr) : Expression(expr, ExprType().FP(3)) {}
141
143 struct Var : public ExprVarRef {
144 Var(const double val) : ExprVarRef(ExprType().FP(1).Varying()), val(val) {}
145
146 Var() : ExprVarRef(ExprType().FP(1).Varying()), val(0.0) {}
147
148 double val; // independent variable
149 void eval(double* result) { result[0] = val; }
150
151 void eval(const char** result) { assert(false); }
152 };
153
154 struct VecVar : public ExprVarRef {
155 VecVar() : ExprVarRef(ExprType().FP(3).Varying()), val(0.0) {}
156
157 Vec<double, 3, false> val; // independent variable
158
159 void eval(double* result) {
160 for (int k = 0; k < 3; k++) result[k] = val[k];
161 }
162
163 void eval(const char** reuslt) {}
164 };
165
167 mutable std::map<std::string, Var> vars;
168 mutable std::map<std::string, VecVar> vecvars;
169
171 ExprVarRef* resolveVar(const std::string& name) const {
172 {
173 std::map<std::string, Var>::iterator i = vars.find(name);
174 if (i != vars.end()) return &i->second;
175 }
176 {
177 std::map<std::string, VecVar>::iterator i = vecvars.find(name);
178 if (i != vecvars.end()) return &i->second;
179 }
180 return 0;
181 }
182};
183
184double clamp(double x) { return std::max(0., std::min(255., x)); }
185
186int main(int argc, char* argv[]) {
187 if (argc != 5) {
188 std::cerr << "Usage: " << argv[0] << " <image file> <width> <height> <exprFile>" << std::endl;
189 return 1;
190 }
191
192 ExprFunc::define("rand", ExprFunc(SeExpr2::rand, 0, 3), rand_docstring);
193 ExprFunc::define("map", ExprFunc(SeExpr2::map, 1, 4), map_docstring);
194 ExprFunc::define("triplanar", ExprFunc(SeExpr2::triplanar, 1, 5), triplanar_docstring);
195
196 // parse arguments
197 const char* imageFile = argv[1];
198 const char* exprFile = argv[4];
199 int width = atoi(argv[2]), height = atoi(argv[3]);
200 if (width < 0 || height < 0) {
201 std::cerr << "invalid width/height" << std::endl;
202 return 1;
203 }
204
205 std::ifstream istream(exprFile);
206 if (!istream) {
207 std::cerr << "Cannot read file " << exprFile << std::endl;
208 return 1;
209 }
210 std::string exprStr((std::istreambuf_iterator<char>(istream)), std::istreambuf_iterator<char>());
211 ImageSynthExpr expr(exprStr);
212
213 // make variables
214 expr.vars["u"] = ImageSynthExpr::Var(0.);
215 expr.vars["v"] = ImageSynthExpr::Var(0.);
216 expr.vars["w"] = ImageSynthExpr::Var(width);
217 expr.vars["h"] = ImageSynthExpr::Var(height);
218
219 expr.vars["faceId"] = ImageSynthExpr::Var(0.);
220 expr.vecvars["P"] = ImageSynthExpr::VecVar();
221 expr.vecvars["Cs"] = ImageSynthExpr::VecVar();
222 expr.vecvars["Ci"] = ImageSynthExpr::VecVar();
223
224 // check if expression is valid
225 bool valid = expr.isValid();
226 if (!valid) {
227 std::cerr << "Invalid expression " << std::endl;
228 std::cerr << expr.parseError() << std::endl;
229 return 1;
230 }
231 // if(!expr.returnType().isFP(3)){
232 // std::cerr<<"Expected color FP[3] got type "<<expr.returnType().toString()<<std::endl;
233 // return 1;
234 // }
235
236 // evaluate expression
237 std::cerr << "Evaluating expresion...from " << exprFile << std::endl;
238 unsigned char* image = new unsigned char[width * height * 4];
239 double one_over_width = 1. / width, one_over_height = 1. / height;
240 double& u = expr.vars["u"].val;
241 double& v = expr.vars["v"].val;
242
243 double& faceId = expr.vars["faceId"].val;
244 Vec<double, 3, false>& P = expr.vecvars["P"].val;
245 Vec<double, 3, false>& Cs = expr.vecvars["Cs"].val;
246 Vec<double, 3, false>& Ci = expr.vecvars["Ci"].val;
247
248 unsigned char* pixel = image;
249
250 {
251 PrintTiming timer("eval time: ");
252 for (int row = 0; row < height; row++) {
253 for (int col = 0; col < width; col++) {
254 u = one_over_width * (col + .5);
255 v = one_over_height * (row + .5);
256
257 faceId = floor(u * 5);
258 P[0] = u * 10;
259 P[1] = v * 10;
260 P[2] = 0.5 * 10;
261 Cs[0] = 0.;
262 Cs[1] = 0.4;
263 Cs[2] = 0.6;
264 Ci[0] = 0.;
265 Ci[1] = 0.4;
266 Ci[2] = 0.6;
267
268 const double* result = expr.evalFP();
269
270 // expr._interpreter->print();
271 pixel[0] = clamp(result[0] * 256.);
272 pixel[1] = clamp(result[1] * 256.);
273 pixel[2] = clamp(result[2] * 256.);
274 pixel[3] = 255;
275 pixel += 4;
276 }
277 }
278 }
279
280 // write image as png
281 std::cerr << "Writing image..." << imageFile << std::endl;
282 FILE* fp = fopen(imageFile, "wb");
283 if (!fp) {
284 perror("fopen");
285 return 1;
286 }
287 png_structp png_ptr;
288 png_infop info_ptr;
289 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
290 info_ptr = png_create_info_struct(png_ptr);
291 png_init_io(png_ptr, fp);
292 int color_type = PNG_COLOR_TYPE_RGBA;
293 png_set_IHDR(png_ptr,
294 info_ptr,
295 width,
296 height,
297 8,
298 color_type,
299 PNG_INTERLACE_NONE,
300 PNG_COMPRESSION_TYPE_DEFAULT,
301 PNG_FILTER_TYPE_DEFAULT);
302 const unsigned char* ptrs[height];
303 for (int i = 0; i < height; i++) {
304 ptrs[i] = &image[width * i * 4];
305 }
306 png_set_rows(png_ptr, info_ptr, (png_byte**)ptrs);
307 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
308
309 fclose(fp);
310}
virtual void eval(ArgHandle args)
Platform-specific classes, functions, and includes.
Node that calls a function.
Definition: ExprNode.h:517
bool checkArg(int argIndex, ExprType type, ExprVarEnvBuilder &envBuilder)
Definition: ExprNode.cpp:578
Vec< double, d, true > inFp(int i)
Definition: ExprFuncX.h:85
Function Definition, used in parse tree and func table.
Definition: ExprFunc.h:44
int numChildren() const
Number of children.
Definition: ExprNode.h:114
ExprType & FP(int d)
Mutate this into a floating point type of dimension d.
Definition: ExprType.h:90
ExprType & Error()
Mutate this into an error type.
Definition: ExprType.h:102
ExprType & Varying()
Mutate this into a varying lifetime.
Definition: ExprType.h:122
Variable scope builder is used by the type checking and code gen to track visiblity of variables and ...
Definition: ExprEnv.h:148
abstract class for implementing variable references
Definition: Expression.h:45
main expression class
Definition: Expression.h:76
virtual ExprVarRef * resolveVar(const std::string &name) const
Definition: Expression.h:199
Expression(EvaluationStrategy be=Expression::defaultEvaluationStrategy)
Definition: Expression.cpp:90
virtual ExprType prep(ExprFuncNode *node, bool wantScalar, ExprVarEnvBuilder &envBuilder) const
virtual void eval(ArgHandle args)
virtual ExprFuncNode::Data * evalConstant(const ExprFuncNode *node, ArgHandle args) const
virtual void eval(ArgHandle args)
virtual ExprType prep(ExprFuncNode *node, bool wantScalar, ExprVarEnvBuilder &envBuilder) const
virtual ExprFuncNode::Data * evalConstant(const ExprFuncNode *node, ArgHandle args) const
virtual void eval(ArgHandle args)
virtual ExprFuncNode::Data * evalConstant(const ExprFuncNode *node, ArgHandle args) const
virtual ExprType prep(ExprFuncNode *node, bool wantScalar, ExprVarEnvBuilder &envBuilder) const
int main(int argc, char *argv[])
static const char * rand_docstring
double clamp(double x)
static const char * triplanar_docstring
static const char * map_docstring
SeExpr2::TriplanarFuncX triplanar
SeExpr2::RandFuncX rand
double max(double x, double y)
Definition: ExprBuiltins.h:42
SeExpr2::MapFuncX map
double min(double x, double y)
Definition: ExprBuiltins.h:43
base class for custom instance data
Definition: ExprNode.h:570
std::vector< std::pair< int, int > > ranges
std::vector< std::pair< int, int > > ranges
std::vector< std::pair< int, int > > ranges
</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 >< h3 > A simple variable reference</h3 > This is not a very interesting subclass of expression until we add some additional variables Variables on some applications may be very dynamic In this we only need x
Definition: tutorial.txt:108