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 */
17 /**
18 @file imageSynth.cpp
19 */
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/Timer.h>
33
34 namespace SeExpr2 {
35 class RandFuncX : public ExprFuncSimple {
36
37 struct Data : public ExprFuncNode::Data {
38 std::vector<std::pair<int, int> > ranges;
39 std::string format;
40 };
41
prep(ExprFuncNode * node,bool wantScalar,ExprVarEnvBuilder & envBuilder) const42 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
evalConstant(const ExprFuncNode * node,ArgHandle args) const49 virtual ExprFuncNode::Data* evalConstant(const ExprFuncNode* node, ArgHandle args) const { return new Data; }
50
eval(ArgHandle args)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:
RandFuncX()59 RandFuncX() : ExprFuncSimple(true) {} // Thread Safe
~RandFuncX()60 virtual ~RandFuncX() {}
61 } rand;
62
63 // map(string name, [float format-arg], [float u], [float v], [int channel])
64 class MapFuncX : public ExprFuncSimple {
65 struct Data : public ExprFuncNode::Data {
66 std::vector<std::pair<int, int> > ranges;
67 std::string format;
68 };
69
prep(ExprFuncNode * node,bool wantScalar,ExprVarEnvBuilder & envBuilder) const70 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
evalConstant(const ExprFuncNode * node,ArgHandle args) const78 virtual ExprFuncNode::Data* evalConstant(const ExprFuncNode* node, ArgHandle args) const { return new Data; }
79
eval(ArgHandle args)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:
MapFuncX()92 MapFuncX() : ExprFuncSimple(true) {} // Thread Safe
~MapFuncX()93 virtual ~MapFuncX() {}
94 } map;
95
96 // triplanar(string name, [vector scale], [float blend], [vector rotation], [vector translation])
97 class TriplanarFuncX : public ExprFuncSimple {
98 struct Data : public ExprFuncNode::Data {
99 std::vector<std::pair<int, int> > ranges;
100 std::string format;
101 };
102
prep(ExprFuncNode * node,bool wantScalar,ExprVarEnvBuilder & envBuilder) const103 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
evalConstant(const ExprFuncNode * node,ArgHandle args) const111 virtual ExprFuncNode::Data* evalConstant(const ExprFuncNode* node, ArgHandle args) const { return new Data; }
112
eval(ArgHandle args)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:
TriplanarFuncX()125 TriplanarFuncX() : ExprFuncSimple(true) {} // Thread Safe
~TriplanarFuncX()126 virtual ~TriplanarFuncX() {}
127 } triplanar;
128 }
129
130 static const char* rand_docstring = "rand\n";
131 static const char* map_docstring = "map\n";
132 static const char* triplanar_docstring = "triplanar\n";
133
134 using namespace SeExpr2;
135
136 //! Simple image synthesizer expression class to support our function grapher
137 class ImageSynthExpr : public Expression {
138 public:
139 //! Constructor that takes the expression to parse
ImageSynthExpr(const std::string & expr)140 ImageSynthExpr(const std::string& expr) : Expression(expr, ExprType().FP(3)) {}
141
142 //! Simple variable that just returns its internal value
143 struct Var : public ExprVarRef {
VarImageSynthExpr::Var144 Var(const double val) : ExprVarRef(ExprType().FP(1).Varying()), val(val) {}
145
VarImageSynthExpr::Var146 Var() : ExprVarRef(ExprType().FP(1).Varying()), val(0.0) {}
147
148 double val; // independent variable
evalImageSynthExpr::Var149 void eval(double* result) { result[0] = val; }
150
evalImageSynthExpr::Var151 void eval(const char** result) { assert(false); }
152 };
153
154 struct VecVar : public ExprVarRef {
VecVarImageSynthExpr::VecVar155 VecVar() : ExprVarRef(ExprType().FP(3).Varying()), val(0.0) {}
156
157 Vec<double, 3, false> val; // independent variable
158
evalImageSynthExpr::VecVar159 void eval(double* result) {
160 for (int k = 0; k < 3; k++) result[k] = val[k];
161 }
162
evalImageSynthExpr::VecVar163 void eval(const char** reuslt) {}
164 };
165
166 //! variable map
167 mutable std::map<std::string, Var> vars;
168 mutable std::map<std::string, VecVar> vecvars;
169
170 //! resolve function that only supports one external variable 'x'
resolveVar(const std::string & name) const171 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
clamp(double x)184 double clamp(double x) { return std::max(0., std::min(255., x)); }
185
main(int argc,char * argv[])186 int 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 }
311