/****************************************************************************** * * MantaFlow fluid solver framework * Copyright 2014 Tobias Pfaff, Nils Thuerey * * This program is free software, distributed under the terms of the * Apache License, Version 2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Simple image IO * ******************************************************************************/ #include "vectorbase.h" #include "simpleimage.h" namespace Manta { // write rectangle to ppm bool SimpleImage::writePpm( std::string filename, int minx, int miny, int maxx, int maxy, bool invertXY) { int w = maxx - minx; int h = maxy - miny; if (w <= 0 || h <= 0 || w > mSize[0] || h > mSize[1]) { errMsg("SimpleImage::WritePPM Invalid rect: w=" << w << ", h=" << h << ", size=" << mSize[0] << "," << mSize[1] << " min/max: " << minx << "," << miny << " to " << maxx << "," << maxy << ", resetting... "); minx = miny = 0; maxx = mSize[0] - 1; maxy = mSize[1] - 1; w = mSize[0] - 1; h = mSize[1] - 1; } FILE *fp = fopen(filename.c_str(), "wb"); if (fp == NULL) { errMsg("SimpleImage::WritePPM Unable to open '" << filename << "' for writing"); return false; } fprintf(fp, "P6\n%d %d\n255\n", w, h); int pixCnt = 0; for (int j = maxy - 1; j >= miny; j--) for (int i = minx; i < maxx; i++) { unsigned char col[3]; for (int l = 0; l < 3; l++) { float val; if (invertXY) val = (float)get(j, i)[l]; else val = (float)get(i, j)[l]; val = clamp(val, (float)0., (float)1.); col[l] = (unsigned char)(255. * val); } // col[1] = col[2] = col[0]; // if (fwrite(col,1,3, fp) != 3) errMsg("SimpleImage::writePpm fwrite failed"); fwrite(col, 1, 3, fp); pixCnt++; // fprintf(stderr,"%d %d %d \n",col[0],i,j); } fclose(fp); // debMsg("WritePPM Wrote '"< 0; i--) { assertMsg(fread((void *)ptr, 1, rowsize, fp) == rowsize, "SimpleImage::initFromPpm couldn't read data"); ptr -= rowsize; } // init image this->init(windW, windH); if (filetype == PGM) { // grayscale for (int i = 0; i < windW; i++) { for (int j = 0; j < windH; j++) { double r = (double)pic[(j * windW + i) * 1 + 0] / 255.; (*this)(i, j) = Vec3(r, r, r); } } } else { // convert grid to RGB vec's for (int i = 0; i < windW; i++) { for (int j = 0; j < windH; j++) { // return mpData[y*mSize[0]+x]; double r = (double)pic[(j * windW + i) * 3 + 0] / 255.; double g = (double)pic[(j * windW + i) * 3 + 1] / 255.; double b = (double)pic[(j * windW + i) * 3 + 2] / 255.; //(*this)(i,j) = Vec3(r,g,b); // RGB values have to be rotated to get the right colors!? // this might also be an artifact of photoshop export...? (*this)(i, j) = Vec3(g, b, r); } } } delete[] pic; fclose(fp); return 1; } // check index is valid bool SimpleImage::indexIsValid(int i, int j) { if (i < 0) return false; if (j < 0) return false; if (i >= mSize[0]) return false; if (j >= mSize[1]) return false; return true; } }; // namespace Manta //***************************************************************************** #include "grid.h" namespace Manta { // simple shaded output , note requires grid functionality! static void gridPrecompLight(const Grid &density, Grid &L, Vec3 light = Vec3(1, 1, 1)) { FOR_IJK(density) { Vec3 n = getGradient(density, i, j, k) * -1.; normalize(n); Real d = dot(light, n); L(i, j, k) = d; } } // simple shading with pre-computed gradient static inline void shadeCell( Vec3 &dst, int shadeMode, Real src, Real light, int depthPos, Real depthInv) { switch (shadeMode) { case 1: { // surfaces Vec3 ambient = Vec3(0.1, 0.1, 0.1); Vec3 diffuse = Vec3(0.9, 0.9, 0.9); Real alpha = src; // different color for depth? diffuse[0] *= ((Real)depthPos * depthInv) * 0.7 + 0.3; diffuse[1] *= ((Real)depthPos * depthInv) * 0.7 + 0.3; Vec3 col = ambient + diffuse * light; // img( 0+i, j ) = (1.-alpha) * img( 0+i, j ) + alpha * col; dst = (1. - alpha) * dst + alpha * col; } break; default: { // volumetrics / smoke dst += depthInv * Vec3(src, src, src); } break; } } //! helper to project a grid intro an image (used for ppm export and GUI displauy) void projectImg(SimpleImage &img, const Grid &val, int shadeMode = 0, Real scale = 1.) { Vec3i s = val.getSize(); Vec3 si = Vec3(1. / (Real)s[0], 1. / (Real)s[1], 1. / (Real)s[2]); // init image size int imgSx = s[0]; if (val.is3D()) imgSx += s[2] + s[0]; // mult views in 3D img.init(imgSx, std::max(s[0], std::max(s[1], s[2]))); // precompute lighting Grid L(val); gridPrecompLight(val, L, Vec3(1, 1, 1)); FOR_IJK(val) { Vec3i idx(i, j, k); shadeCell(img(0 + i, j), shadeMode, val(idx), L(idx), k, si[2]); } if (val.is3D()) { FOR_IJK(val) { Vec3i idx(i, j, k); shadeCell(img(s[0] + k, j), shadeMode, val(idx), L(idx), i, si[0]); } FOR_IJK(val) { Vec3i idx(i, j, k); shadeCell(img(s[0] + s[2] + i, k), shadeMode, val(idx), L(idx), j, si[1]); } } // 3d img.mapRange(1. / scale); } }; // namespace Manta