blob: b268c0a20bd8e623a35189545d4c68b364076e41 [file] [log] [blame]
#ifndef RTW_STB_IMAGE_H
#define RTW_STB_IMAGE_H
//==============================================================================================
// Originally written in 2016 by Peter Shirley <ptrshrl@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy (see file COPYING.txt) of the CC0 Public
// Domain Dedication along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
//
// The original source code is from
// https://github.com/RayTracing/raytracing.github.io/tree/release/src/InOneWeekend
//
// Changes to the original code follow the following license.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//==============================================================================================
// Disable strict warnings for this header from the Microsoft Visual C++
// compiler.
#ifdef _MSC_VER
#pragma warning(push, 0)
#endif
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h"
#include <cstdlib>
#include <iostream>
class rtw_image {
public:
rtw_image() : data(nullptr) {}
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:
const 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