313 lines
8.0 KiB
C++
313 lines
8.0 KiB
C++
/******************************************************************************
|
|
*
|
|
* 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 == nullptr) {
|
|
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 '"<<filename<<"', region="<<minx<<","<<miny<<" to
|
|
// "<<maxx<<","<<maxy<<"; "<<pixCnt, 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SimpleImage::writePpm(std::string filename)
|
|
{
|
|
return writePpm(filename, 0, 0, getSize()[0], getSize()[1]);
|
|
}
|
|
|
|
// read in a ppm file, and init the image accordingly
|
|
bool SimpleImage::initFromPpm(std::string filename)
|
|
{
|
|
// maximum length of a line of text
|
|
const int MAXLINE = 1024;
|
|
|
|
int filetype = 0;
|
|
enum { PGM, PPM }; // possible file types
|
|
|
|
FILE *fp;
|
|
char line[MAXLINE];
|
|
int size, rowsize;
|
|
|
|
// Read in file type
|
|
fp = fopen(filename.c_str(), "rb");
|
|
if (!fp) {
|
|
if (mAbortOnError)
|
|
debMsg("SimpleImage Error - unable to open file '" << filename << "' for reading", 1);
|
|
return 0;
|
|
}
|
|
|
|
// 1st line: PPM or PGM
|
|
if (fgets(line, MAXLINE, fp) == nullptr) {
|
|
if (mAbortOnError)
|
|
debMsg("SimpleImage::initFromPpm fgets failed", 1);
|
|
return 0;
|
|
}
|
|
|
|
if (line[1] == '5')
|
|
filetype = PGM;
|
|
else if (line[1] == '6')
|
|
filetype = PPM;
|
|
else {
|
|
if (mAbortOnError)
|
|
debMsg("SimpleImage Error: need PPM or PGM file as input!", 1);
|
|
return 0;
|
|
}
|
|
|
|
// Read in width and height, & allocate space
|
|
// 2nd line: width height
|
|
if (fgets(line, MAXLINE, fp) == nullptr) {
|
|
if (mAbortOnError)
|
|
errMsg("SimpleImage::initFromPpm fgets failed");
|
|
return 0;
|
|
}
|
|
int windW = 0, windH = 0; // size of the window on the screen
|
|
int intsFound = sscanf(line, "%d %d", &windW, &windH);
|
|
if (intsFound == 1) {
|
|
// only X found, search on next line as well for Y...
|
|
if (sscanf(line, "%d", &windH) != 1) {
|
|
if (mAbortOnError)
|
|
errMsg("initFromPpm Ppm dimensions not found!" << windW << "," << windH);
|
|
return 0;
|
|
}
|
|
else {
|
|
// ok, found 2 lines
|
|
// debMsg("initFromPpm Ppm dimensions found!"<<windW<<","<<windH, 1);
|
|
}
|
|
}
|
|
else if (intsFound == 2) {
|
|
// ok!
|
|
}
|
|
else {
|
|
if (mAbortOnError)
|
|
errMsg("initFromPpm Ppm dimensions not found at all!" << windW << "," << windH);
|
|
return 0;
|
|
}
|
|
|
|
if (filetype == PGM) {
|
|
size = windH * windW; // greymap: 1 byte per pixel
|
|
rowsize = windW;
|
|
}
|
|
else {
|
|
// filetype == PPM
|
|
size = windH * windW * 3; // pixmap: 3 bytes per pixel
|
|
rowsize = windW * 3;
|
|
}
|
|
|
|
unsigned char *pic = new unsigned char[size]; // (GLubyte *)malloc (size);
|
|
|
|
// Read in maximum value (ignore) , could be scanned with sscanf as well, but this should be
|
|
// 255... 3rd line
|
|
if (fgets(line, MAXLINE, fp) == nullptr) {
|
|
if (mAbortOnError)
|
|
errMsg("SimpleImage::initFromPpm fgets failed");
|
|
return 0;
|
|
}
|
|
|
|
// Read in the pixel array row-by-row: 1st row = top scanline */
|
|
unsigned char *ptr = nullptr;
|
|
ptr = &pic[(windH - 1) * rowsize];
|
|
for (int i = windH; i > 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<Real> &density, Grid<Real> &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<Real> &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<Real> 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
|