-
Notifications
You must be signed in to change notification settings - Fork 0
/
rtw_stb_image.h
111 lines (89 loc) · 3.6 KB
/
rtw_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
#ifndef RTW_STB_IMAGE_H
#define RTW_STB_IMAGE_H
// Disable strict warnings for this header from the Microsoft Visual C++ compiler.
#ifdef _MSC_VER
#pragma warning (push, 0)
#endif
#define STB_IMAGE_IMPLEMENTATION
#define STBI_FAILURE_USERMSG
#include "stb_image.h"
#include <cstdlib>
#include <iostream>
class rtw_image {
public:
rtw_image() : data(nullptr) {}
rtw_image(const rtw_image&) = delete;
rtw_image& operator=(const rtw_image&) = delete;
rtw_image(rtw_image&& other) noexcept :
data{other.data},
image_width{other.image_width},
image_height{other.image_height},
bytes_per_scanline{other.bytes_per_scanline}
{
other.data = nullptr;
other.image_width = other.image_height = 0;
other.bytes_per_scanline = 0;
}
rtw_image& operator=(rtw_image&& other) noexcept {
std::swap(data, other.data);
std::swap(image_width, other.image_width);
std::swap(image_height, other.image_height);
std::swap(bytes_per_scanline, other.bytes_per_scanline);
return *this;
}
rtw_image(const char* image_filename) {
// Loads image data from the specified file. If the RTW_IMAGES environment variable is
// defined, looks only in that directory for the image file. If the image was not found,
// searches for the specified image file first from the current directory, then in the
// images/ subdirectory, then the _parent's_ images/ subdirectory, and then _that_
// parent, on so on, for six levels up. If the image was not loaded successfully,
// width() and height() will return 0.
auto filename = std::string(image_filename);
auto imagedir = getenv("RTW_IMAGES");
// Hunt for the image file in some likely locations.
if (imagedir && load(std::string(imagedir) + "/" + image_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;
if (load("../../../../../images/" + filename)) return;
if (load("../../../../../../images/" + filename)) return;
std::cerr << "ERROR: Could not load image file '" << image_filename << "'.\n";
}
~rtw_image() { STBI_FREE(data); }
bool load(const std::string filename) {
// Loads image data from the given file name. Returns true if the load succeeded.
auto n = BYTES_PER_PIXEL; // Dummy out parameter: original components per pixel
data = stbi_load(filename.c_str(), &image_width, &image_height, &n, BYTES_PER_PIXEL);
bytes_per_scanline = image_width * BYTES_PER_PIXEL;
return data != nullptr;
}
int width() const { return (data == nullptr) ? 0 : image_width; }
int height() const { return (data == nullptr) ? 0 : image_height; }
const unsigned char* pixel_data(int x, int y) const {
// Return the address of the three bytes of the pixel at x,y (or magenta if no data).
static unsigned char magenta[] = { 255, 0, 255 };
if (data == nullptr) return magenta;
x = clamp(x, 0, image_width);
y = clamp(y, 0, image_height);
return data + y*bytes_per_scanline + x*BYTES_PER_PIXEL;
}
private:
static constexpr int BYTES_PER_PIXEL = 3;
unsigned char *data;
int image_width, image_height;
int bytes_per_scanline;
static int clamp(int x, int low, int high) {
// Return the value clamped to the range [low, high).
if (x < low) return low;
if (x < high) return x;
return high - 1;
}
};
// Restore MSVC compiler warnings
#ifdef _MSC_VER
#pragma warning (pop)
#endif
#endif