236 lines
7.4 KiB
C++
236 lines
7.4 KiB
C++
// Copyright (c) 2006, Tobias Sargeant
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
//
|
|
// Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the
|
|
// distribution. The names of its contributors may be used to endorse
|
|
// or promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#pragma once
|
|
|
|
#if (defined WIN32) || (defined _WIN32)
|
|
typedef char int8_t;
|
|
typedef short int16_t;
|
|
typedef long int32_t;
|
|
|
|
typedef unsigned char uint8_t;
|
|
typedef unsigned short uint16_t;
|
|
typedef unsigned long uint32_t;
|
|
#else
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
|
|
#include <algorithm>
|
|
#include <istream>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#include "vector.hpp"
|
|
#include "matrix.hpp"
|
|
|
|
#ifdef NTSC
|
|
# define CIE_x_r 0.670 // standard NTSC primaries
|
|
# define CIE_y_r 0.330
|
|
# define CIE_x_g 0.210
|
|
# define CIE_y_g 0.710
|
|
# define CIE_x_b 0.140
|
|
# define CIE_y_b 0.080
|
|
# define CIE_x_w 0.3333 // use true white
|
|
# define CIE_y_w 0.3333
|
|
#else
|
|
# define CIE_x_r 0.640 // nominal CRT primaries
|
|
# define CIE_y_r 0.330
|
|
# define CIE_x_g 0.290
|
|
# define CIE_y_g 0.600
|
|
# define CIE_x_b 0.150
|
|
# define CIE_y_b 0.060
|
|
# define CIE_x_w 0.3333 // use true white
|
|
# define CIE_y_w 0.3333
|
|
#endif
|
|
|
|
|
|
#define CIE_D (CIE_x_r * (CIE_y_g - CIE_y_b) + CIE_x_g * (CIE_y_b - CIE_y_r) + CIE_x_b*(CIE_y_r - CIE_y_g))
|
|
#define CIE_C_rD ((1.0f / CIE_y_w) * (CIE_x_w * (CIE_y_g - CIE_y_b) - CIE_y_w * (CIE_x_g - CIE_x_b) + CIE_x_g * CIE_y_b - CIE_x_b * CIE_y_g))
|
|
#define CIE_C_gD ((1.0f / CIE_y_w) * (CIE_x_w * (CIE_y_b - CIE_y_r) - CIE_y_w * (CIE_x_b - CIE_x_r) - CIE_x_r * CIE_y_b + CIE_x_b * CIE_y_r))
|
|
#define CIE_C_bD ((1.0f / CIE_y_w) * (CIE_x_w * (CIE_y_r - CIE_y_g) - CIE_y_w * (CIE_x_r - CIE_x_g) + CIE_x_r * CIE_y_g - CIE_x_g * CIE_y_r))
|
|
|
|
#define CIE_rf (CIE_y_r * CIE_C_rD / CIE_D)
|
|
#define CIE_gf (CIE_y_g * CIE_C_gD / CIE_D)
|
|
#define CIE_bf (CIE_y_b * CIE_C_bD / CIE_D)
|
|
|
|
|
|
// luminous efficacies over visible spectrum
|
|
#define MAXEFFICACY 683.0f // defined maximum at 550 nm
|
|
#define WHTEFFICACY 179.0f // uniform white light
|
|
#define D65EFFICACY 203.0f // standard illuminant D65
|
|
#define INCEFFICACY 160.0f // illuminant A (incand.)
|
|
#define SUNEFFICACY 208.0f // illuminant B (solar dir.)
|
|
#define SKYEFFICACY D65EFFICACY // skylight (should be 110)
|
|
#define DAYEFFICACY D65EFFICACY // combined sky and solar
|
|
|
|
|
|
namespace gloop {
|
|
|
|
struct chromacity {
|
|
static const chromacity stdprims;
|
|
V2 r, g, b, w;
|
|
|
|
M3 xyz_to_rgb() const;
|
|
M3 rgb_to_xyz() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline double bright(const V3 &col) {
|
|
return CIE_rf * col.r + CIE_gf * col.g + CIE_bf * col.b;
|
|
}
|
|
|
|
static inline double luminance(const V3 &col) {
|
|
return WHTEFFICACY * bright(col);
|
|
}
|
|
|
|
static inline float intens(const V3 &col) {
|
|
return std::max(std::max(col.r, col.g), col.b);
|
|
}
|
|
|
|
|
|
|
|
extern const V3 WHITE;
|
|
extern const V3 BLACK;
|
|
|
|
extern const M3 RGB_to_XYZ;
|
|
extern const M3 XYZ_to_RGB;
|
|
|
|
|
|
|
|
struct packed_colour {
|
|
static const int excess = 128;
|
|
union {
|
|
struct {
|
|
union {
|
|
struct { uint8_t r,g,b; };
|
|
struct { uint8_t x,y,z; };
|
|
};
|
|
uint8_t e;
|
|
};
|
|
uint8_t v[4];
|
|
uint32_t val;
|
|
};
|
|
|
|
packed_colour() { }
|
|
packed_colour(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _e) { r = _r; g = _g; b = _b; e = _e; }
|
|
packed_colour(uint32_t _val) { val = _val; }
|
|
packed_colour(const void *mem) { memcpy(&v, mem, 4); }
|
|
packed_colour(const V3 &col);
|
|
|
|
const static packed_colour white;
|
|
const static packed_colour black;
|
|
|
|
V3 unpack() const {
|
|
if (e) {
|
|
return V3(ldexp(r + 0.5f, (int)e - (excess + 8)),
|
|
ldexp(g + 0.5f, (int)e - (excess + 8)),
|
|
ldexp(b + 0.5f, (int)e - (excess + 8)));
|
|
} else {
|
|
return V3(0.0f, 0.0f, 0.0f);
|
|
}
|
|
}
|
|
|
|
long normbright() {
|
|
return ((long)(CIE_rf * 256.0f + 0.5f) * r + (long)(CIE_gf * 256.0f + 0.5f) * g + (long)(CIE_bf * 256.0f + 0.5f) * b) >> 8;
|
|
}
|
|
|
|
const static packed_colour BLACK;
|
|
const static packed_colour WHITE;
|
|
};
|
|
|
|
template<typename T, typename U>
|
|
static inline void unpack_scanline(T begin, T end, U out) {
|
|
while (begin != end) {
|
|
*out = (*begin).unpack();
|
|
++out; ++begin;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
enum radiance_colour_format {
|
|
RADIANCE_FMT_UNKNOWN = -1,
|
|
RADIANCE_FMT_RGB = 0,
|
|
RADIANCE_FMT_CIE = 1
|
|
};
|
|
|
|
|
|
|
|
struct radiance_reader {
|
|
virtual void header(radiance_colour_format fmt,
|
|
float exposure,
|
|
float pixaspect,
|
|
chromacity prim,
|
|
V3 colour_correction) = 0;
|
|
virtual void image_size(int width, int height, int depth) = 0;
|
|
virtual void scanline(int scan_axis,
|
|
int X, int Y, int Z,
|
|
std::vector<packed_colour> &scanline) = 0;
|
|
virtual ~radiance_reader() {
|
|
}
|
|
};
|
|
|
|
struct floatbuf_radiance_reader : public radiance_reader {
|
|
float *target;
|
|
int width, height, depth;
|
|
M3 cvt;
|
|
bool cvt_set;
|
|
|
|
int stride(int axis) {
|
|
int stride = 3;
|
|
if (axis > 0) stride *= width;
|
|
if (axis > 1) stride *= height;
|
|
return stride;
|
|
}
|
|
float *pixel(int X = 0, int Y = 0, int Z = 0) {
|
|
return target + 3 * (X + width * (Y + height * Z));
|
|
}
|
|
virtual void header(radiance_colour_format fmt,
|
|
float exposure,
|
|
float pixaspect,
|
|
chromacity prim,
|
|
V3 colour_correction);
|
|
virtual void image_size(int _width, int _height, int _depth);
|
|
virtual void scanline(int scan_axis,
|
|
int X, int Y, int Z,
|
|
std::vector<packed_colour> &scanline);
|
|
float *take_buffer();
|
|
floatbuf_radiance_reader();
|
|
virtual ~floatbuf_radiance_reader();
|
|
};
|
|
|
|
|
|
|
|
void read_radiance(std::istream &in, radiance_reader &reader, bool invert_X = false, bool invert_Y = true, bool invert_Z = false);
|
|
|
|
}
|