summaryrefslogtreecommitdiff
path: root/graphics/asymptote/cudareflect/main.cc
blob: 2450b5dd8466a2bac29f7c6992aa3c4cb8d36bc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/**
 * @file main.cpp
 * @author Supakorn "Jamie" Rassameemasmuang <jamievlin@outlook.com>
 * Program for loading image and writing the irradiated image.
 */

#include "common.h"
#include <fstream>

#ifdef _WIN32
// use vcpkg getopt package for this
#undef _UNICODE
#include <getopt.h>
#include <Windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif

#include "kernel.h"
#include "ReflectanceMapper.cuh"
#include "EXRFiles.h"

size_t const MIN_WIDTH = 2;
size_t const MIN_HEIGHT = 2;


struct Args
{
  char mode = 'a';
  bool webgl = false;
  char const* file_in = nullptr;
  char const* directory = nullptr;

  size_t count;

  bool validate()
  {
    if (mode == 0)
      return false;

    if ((mode == 'a' || mode == 'b' || mode == 'i' || mode == 'r') && !file_in)
      {
        return false;
      }

    return true;
  }
};

void usage()
{
  std::cerr << "reflect [-a|-i|-r|-b] inputEXRFile [-d outputDirectory]" <<
    std::endl;
  std::cerr << "Options: " << std::endl;
  std::cerr << "-h\t\t help" << std::endl;
  std::cerr << "-d\t\t output directory" << std::endl;
  std::cerr << "-a\t\t generate irradiance and reflectance images (default)"
            << std::endl;
  std::cerr << "-i\t\t generate irradiance image diffuse.exr" << std::endl;
  std::cerr << "-r\t\t generate reflectance images reflN.exr" << std::endl;
  std::cerr << "-b\t\t generate brdf image refl.exr (independent of image)"
            << std::endl;
}

Args parseArgs(int argc, char* argv[])
{
  Args arg;
  int c;
  while ((c = getopt(argc, argv, "abd:hir")) != -1)
    {
      switch (c)
        {
          case 'a':
            arg.mode = 'a';
            break;
          case 'i':
            arg.mode = 'i';
            break;
          case 'r':
            arg.mode = 'r';
            break;
          case 'b':
            arg.mode = 'b';
            break;
/*
  case 'c':
  {
  std::stringstream ss;
  ss << optarg;
  ss >> arg.count;
  }
  break;
*/
          case 'd':
            arg.directory = optarg;
            break;
          case 'h':
            usage();
            exit(0);
            break;
          default:
            usage();
            exit(1);
        }
    }

  arg.file_in = argv[optind];

  if (!arg.validate())
    {
      usage();
      exit(1);
    }
  return arg;
}

struct image_t
{
  float4* im;
  int width, height;

  int sz() const { return width * height; }

  image_t(float4* im, int width, int height) :
    im(im), width(std::move(width)), height(std::move(height)) {}
};

void irradiate_im(image_t& im, std::string const& prefix)
{
  std::vector<float3> out_proc(im.sz());
  std::stringstream out_name;
  out_name << prefix;
  std::cout << "Irradiating image..." << std::endl;
  irradiate_ker(im.im, out_proc.data(), im.width, im.height);
  out_name << "diffuse.exr";

  std::string out_name_str(std::move(out_name).str());
  OEXRFile ox(out_proc, im.width, im.height);

  std::cout << "copying data back" << std::endl;
  std::cout << "writing to: " << out_name_str << std::endl;
  ox.write(out_name_str);
}

std::string generate_refl_file(std::string const& prefix, int const& i, std::string const suffix="")
{
  std::stringstream out_name;
  out_name << prefix << "refl" << i << suffix << ".exr";
  return out_name.str();
}

void map_refl_im(image_t& im, std::string const& prefix, float const& step, int const& i, std::pair<size_t, size_t> const& outSize, bool halve=false)
{
  float roughness = step * i;
  auto [outWidth, outHeight] = outSize;
  std::vector<float3> out_proc(outWidth * outHeight);

  std::string out_name_str = generate_refl_file(prefix, i,
                                                halve ? "w" : "");
  std::cout << "Mapping reflectance map..." << std::endl;
  map_reflectance_ker(im.im, out_proc.data(), im.width, im.height, roughness, outWidth, outHeight);
  OEXRFile ox(out_proc, outWidth, outHeight);
  std::cout << "copying data back" << std::endl;
  std::cout << "writing to: " << out_name_str << std::endl;
  ox.write(out_name_str);
}

std::string const INVALID_FILE_ATTRIB = "Intermediate directories do not exist";

void make_dir(std::string const& directory)
{
  // different implementation for windows vs linux
#ifdef _WIN32
  DWORD ret = CreateDirectoryA(directory.c_str(), nullptr);
  if (ret == 0 && GetLastError() != ERROR_ALREADY_EXISTS)
    {
      std::cerr << INVALID_FILE_ATTRIB << std::endl;
      exit(1);
    }
#else
  struct stat st;
  if (stat(directory.c_str(), &st) == -1)
    {
      mkdir(directory.c_str(), 0755);
    }
#endif
}

void copy_file(std::string const& in, std::string const& out)
{
  std::ifstream ifs(in, std::ios::binary);
  std::ofstream ofs(out, std::ios::binary);

  ofs << ifs.rdbuf();

}

void generate_brdf_refl(
  int res, std::string const& outdir, std::string const& outname="refl.exr")
{
  std::vector<float2> out_proc(res * res);
  std::string finalName = outdir + "/" + outname;
  std::cout << "generating Fresnel/Roughness/cos_v data" << std::endl;
  std::cout << "writing to " << finalName << std::endl;
  generate_brdf_integrate_lut_ker(res, res, out_proc.data());
  OEXRFile ox(out_proc, res, res);
  ox.write(finalName);
}

inline float length(float3 v)
{
  return sqrt(v.x*v.x+v.y*v.y+v.z*v.z);
}

int main(int argc, char* argv[])
{
  Args args = parseArgs(argc, argv);
  std::vector<float4> im_proc;
  int width = 0;
  int height = 0;

  std::cout << "Loading file " << args.file_in << std::endl;
  EXRFile im(args.file_in);
  width = im.getWidth();
  height = im.getHeight();
  std::vector<float3> out_proc;
  std::cout << "Image dimensions: " << width << "x" << height << std::endl;
  for (int i = 0; i < height; ++i)
    {
      for (int j = 0; j < width; ++j)
        {
          // index is i*height+j <-> (i,j)
          float3 frag3=im.getPixel3(j, i);
          // Clamp oversaturated values.
          float norm=0.02*length(frag3);
          if(norm > 1.0) {
            frag3.x /= norm;
            frag3.y /= norm;
            frag3.z /= norm;
          }
          out_proc.emplace_back(frag3);
          im_proc.emplace_back(make_float4(frag3.x,frag3.y,frag3.z,1.0f));
        }
      // std::cout << "pushed row " << i << " into array" << std::endl;
    }
  std::cout << "finished converting to float3" << std::endl;

  std::stringstream outss;
  if (args.directory)
    {
      make_dir(args.directory);
    }
  else
    {
      args.directory = ".";
    }

  outss << args.directory << "/";

  if(args.mode != 'b') {
    std::ofstream readme(outss.str()+"README");
    readme << "The image files in this directory were generated from " << args.file_in << std::endl;
    readme.close();
  }

  std::string outprefix(outss.str());

  image_t imt(im_proc.data(), width, height);

  if (args.mode == 'b')
    {
      generate_brdf_refl(200, ".");
    }
  if (args.mode == 'i' || args.mode == 'a')
    {
      irradiate_im(imt, outprefix);
    }
  if (args.mode == 'r' || args.mode == 'a')
    {
      OEXRFile ox(out_proc, width, height);
      std::string out_name_str = generate_refl_file(outprefix, 0);
      std::cout << "writing to: " << out_name_str << std::endl;
      ox.write(out_name_str);

      for(size_t halve=0; halve < 2; ++halve) {
        size_t count=halve ? 8 : 10;
        float step = 1.0f / count;

        unsigned int out_width = width;
        unsigned int out_height = height;

        for (size_t i = 1; i <= count; ++i)
          {
            if (halve && out_width >= MIN_WIDTH && out_height >= MIN_HEIGHT)
              {
                out_width = out_width >> 1;
                out_height = out_height >> 1; // halve
              }
            map_refl_im(imt, outprefix, step, i, std::pair<size_t,size_t>(out_width, out_height), halve);
          }
      }
    }
}