This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/extern/mantaflow/helper/util/simpleimage.cpp
2020-11-06 12:06:05 +01:00

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