-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrt_stb_image.h
135 lines (103 loc) · 3.8 KB
/
rt_stb_image.h
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
#pragma once
#ifdef _MSC_VER
// Forbidden all warning
#pragma warning (push, 0)
#endif
#define STB_IMAGE_IMPLEMENTATION
#define STBI_FAILURE_USERMSG
#include "stb_image.h"
#include "rt.h"
#include <cstdlib>
#include <iostream>
#include <string>
class rt_image
{
private:
const int bytes_per_pixel = 3;
float* fdata = nullptr; // Linear floating point pixel - 32bit
unsigned char* bdata = nullptr; // Linear 8-bit pixel data
int image_width = 0; // Loaded image width
int image_height = 0; // Loaded image height
int bytes_per_scanline = 0;
std::string filename;
static unsigned char float_to_byte(float value)
{
// Convert [0, 1] color to [0, 255]
if(value <= 0.0) return 0;
if(value >= 1.0) return 255;
return static_cast<unsigned char>(256.0f * value);
}
void convert_to_bytes()
{
// Convert the linear floating point pixel data to bytes
// Store the result bytes data in the bdata member
int total_bytes = image_width * image_height * bytes_per_pixel;
bdata = new unsigned char[total_bytes];
// Iterate throught all pixel components, converting from [0.0, 1.0]
// float values to unsigned [0, 255] byte values
auto *bptr = bdata;
auto *fptr = fdata;
for(auto i = 0; i < total_bytes; i ++, fptr++, bptr++)
{
*bptr = float_to_byte(*fptr);
}
}
public:
rt_image() {}
~rt_image()
{
delete[] bdata;
STBI_FREE(fdata);
}
rt_image(const rt_image& other)
{
filename = other.filename;
// Deep copy the pixel
load(filename.c_str());
}
rt_image& operator=(const rt_image& other)
{
if(this == &other) return *this;
filename = other.filename;
load(filename.c_str());
}
rt_image(rt_image&& other) = delete;
rt_image& operator=(rt_image&& other) = delete;
explicit rt_image(const char* image_filename)
{
auto filename = std::string(image_filename);
this->filename = filename;
auto imageDir = getenv("RT_IMAGES");
if(imageDir && load(std::string(imageDir) + "/" + filename)) return;
if(load(filename)) return;
if(load("images/" + filename)) return;
if(load("../images/" + filename)) return;
if(load("../../images/" + filename)) return;
if(load("../../../images/" + filename)) return;
if(load("../../../../images/" + filename)) return;
std::cerr << "Failed to load image: " << image_filename << ".\n";
}
bool load(const std::string& filename)
{
auto n = bytes_per_pixel;
fdata = stbi_loadf(filename.c_str(), &image_width, &image_height, &n, n);
if(fdata == nullptr) return false;
bytes_per_scanline = image_width * bytes_per_pixel;
convert_to_bytes();
return true;
}
int width() const {return (fdata == nullptr) ? 0 : image_width;}
int height() const {return (fdata == nullptr) ? 0 : image_height;}
const unsigned char* pixel_data(int x, int y) const
{
static unsigned char default_pixel[3] = {255, 0, 255};
if(bdata == nullptr) return default_pixel;
x = clamp(x, 0, image_width);
y = clamp(y, 0, image_height);
return bdata + y * bytes_per_scanline + x * bytes_per_pixel;
}
};
#ifdef _MSC_VER
// Recovery all exist warning
#pragma warning (pop)
#endif