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