Refactor & Fixes.

Rename to better fit the scope of this project. Allow loading an image from Color3* & Color4*
This commit is contained in:
2024-10-10 11:44:00 -04:00
parent bca63534d1
commit cf90f057fe
6 changed files with 108 additions and 74 deletions

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.18)
project(ReTexture project(ReImage
VERSION 1.0 VERSION 1.0
LANGUAGES CXX LANGUAGES CXX
) )
@@ -11,6 +11,11 @@ include(cmake/CPM.cmake)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
CPMAddPackage(
NAME mcolor
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-4.zip
)
file(GLOB_RECURSE HEADERS "include/*.h") file(GLOB_RECURSE HEADERS "include/*.h")
file(GLOB_RECURSE SOURCES "src/*.cpp") file(GLOB_RECURSE SOURCES "src/*.cpp")
file(COPY "testImages" DESTINATION "${PROJECT_BINARY_DIR}") file(COPY "testImages" DESTINATION "${PROJECT_BINARY_DIR}")
@@ -20,16 +25,22 @@ if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
endif() endif()
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
add_library(ReTexture SHARED ${SOURCES} ${HEADERS}) add_library(ReImage SHARED ${SOURCES} ${HEADERS})
endif() endif()
if (WIN32) if (WIN32)
add_library(ReTexture STATIC ${SOURCES} ${HEADERS}) add_library(ReImage STATIC ${SOURCES} ${HEADERS})
endif() endif()
target_include_directories(ReTexture PUBLIC ${PROJECT_SOURCE_DIR}/include) target_include_directories(
add_executable(ReTextureTest main.cpp) ReImage PUBLIC
${PROJECT_SOURCE_DIR}/include
${mcolor_SOURCE_DIR}/include
set_target_properties(ReTexture PROPERTIES LINKER_LANGUAGE CXX) )
set_target_properties(ReTextureTest PROPERTIES LINKER_LANGUAGE CXX) add_executable(ReImageTest main.cpp)
target_link_libraries(ReTextureTest PUBLIC ReTexture)
set_target_properties(ReImage PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(ReImageTest PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(ReImage PUBLIC mcolor)
target_link_libraries(ReImageTest PUBLIC ReImage)

31
include/ReImage/Image.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include <string>
#include <ReImage/flags.h>
#include <Color4.hpp>
namespace ReImage {
class Image {
private:
unsigned int width = 0;
unsigned int height = 0;
TextureFormat format;
TextureFlag flags;
Image(std::vector<unsigned char>& pixel_data, TextureFormat format, unsigned int width, unsigned int height);
void load(const std::string& file);
void loadBMP(const std::string& file);
void loadPNG(const std::string& file);
void invertY();
public:
std::vector<unsigned char> pixel_data;
Image(const std::string& file, const TextureFlag& flags);
Image(const Color4* data, const size_t& length, unsigned int width, unsigned int height, TextureFlag flags = TextureFlag::NONE);
Image(const Color3* data, const size_t& length, unsigned int width, unsigned int height, TextureFlag flags = TextureFlag::NONE);
Image downscale(unsigned int rhs);
[[nodiscard]] unsigned int getWidth() const;
[[nodiscard]] unsigned int getHeight() const;
TextureFormat getTextureFormat();
TextureFlag getFlags();
};
}

View File

@@ -1,10 +1,9 @@
#pragma once #pragma once
namespace ReTexture { namespace ReImage {
enum TextureFlag { enum TextureFlag {
NONE = 0, NONE = 0,
INVERT_Y = 1, INVERT_Y = 1,
INVERT_X = 2,
}; };
inline TextureFlag operator|(TextureFlag a, TextureFlag b) { inline TextureFlag operator|(TextureFlag a, TextureFlag b) {

View File

@@ -1,29 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <ReTexture/flags.h>
namespace ReTexture {
class SoftwareTexture {
private:
unsigned int width = 0;
unsigned int height = 0;
TextureFormat format;
TextureFlag flags;
void load(const std::string& file);
void loadBMP(const std::string& file);
void loadPNG(const std::string& file);
void invertY();
public:
std::vector<unsigned char> pixelData;
explicit SoftwareTexture(const std::string& file);
SoftwareTexture(const std::string& file, const TextureFlag& flags);
SoftwareTexture(const std::vector<unsigned char>& pixel_data, TextureFormat format, unsigned int width, unsigned int height);
SoftwareTexture downscale(unsigned int rhs);
[[nodiscard]] unsigned int getWidth() const;
[[nodiscard]] unsigned int getHeight() const;
TextureFormat getTextureFormat();
TextureFlag getFlags();
};
}

View File

@@ -1,9 +1,9 @@
#include <ReTexture/Texture.h> #include <ReImage/Image.h>
#include <iostream> #include <iostream>
using namespace ReTexture; using namespace ReImage;
int main() { int main() {
auto* bmp = new SoftwareTexture("testImages/1.bmp", {TextureFlag::INVERT_Y}); auto* bmp = new Image("testImages/1.bmp", {TextureFlag::INVERT_Y});
std::cout << "Bitmap Width: " << bmp->getWidth() << std::endl; std::cout << "Bitmap Width: " << bmp->getWidth() << std::endl;
std::cout << "Bitmap Height: " << bmp->getHeight() << std::endl; std::cout << "Bitmap Height: " << bmp->getHeight() << std::endl;
@@ -14,7 +14,7 @@ int main() {
std::cout << "Bitmap Format: RGBA" << std::endl; std::cout << "Bitmap Format: RGBA" << std::endl;
delete bmp; delete bmp;
auto* png = new SoftwareTexture("testImages/1.png", TextureFlag::INVERT_Y); auto* png = new Image("testImages/1.png", TextureFlag::INVERT_Y);
std::cout << "PNG width: " << png->getWidth() << std::endl; std::cout << "PNG width: " << png->getWidth() << std::endl;
std::cout << "PNG height: " << png->getHeight() << std::endl; std::cout << "PNG height: " << png->getHeight() << std::endl;

View File

@@ -1,35 +1,36 @@
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include <ReTexture/Texture.h> #include <ReImage/Image.h>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h> #include <stb_image.h>
#define STB_IMAGE_RESIZE_IMPLEMENTATION #define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb_image_resize2.h> #include <stb_image_resize2.h>
namespace ReTexture { namespace ReImage {
SoftwareTexture::SoftwareTexture(const std::string &file, const TextureFlag& flags) { Image::Image(const std::string &file, const TextureFlag& flags) {
load(file); load(file);
if (flags & TextureFlag::INVERT_Y) if (flags& TextureFlag::INVERT_Y)
invertY(); invertY();
this->flags = flags; this->flags = flags;
} }
SoftwareTexture::SoftwareTexture(const std::string &file) { Image::Image(const Color4* data, const size_t& length, unsigned int width, unsigned int height, TextureFlag flags) {
*this = SoftwareTexture(file, {}); pixel_data.resize(length * 4);
} memcpy(pixel_data.data(), data, length * sizeof(Color4));
SoftwareTexture::SoftwareTexture(const std::vector<unsigned char>& pixel_data, TextureFormat format, unsigned int width, unsigned int height) {
pixelData = pixel_data;
this->width = width; this->width = width;
this->height = height; this->height = height;
this->format = format; this->format = TextureFormat::RGBA;
this->flags = TextureFlag::NONE; if (flags & INVERT_Y)
invertY();
this->flags = flags;
} }
void SoftwareTexture::load(const std::string &file) { void Image::load(const std::string& file) {
std::ifstream ifStream(file, std::ios::in | std::ios::binary); std::ifstream ifStream(file, std::ios::in | std::ios::binary);
unsigned char bmpFileHeader[14]; unsigned char bmpFileHeader[14];
@@ -45,7 +46,7 @@ namespace ReTexture {
loadPNG(file); loadPNG(file);
} }
void SoftwareTexture::loadBMP(const std::string &file) { void Image::loadBMP(const std::string &file) {
std::ifstream bmpFile(file, std::ios::in | std::ios::binary); std::ifstream bmpFile(file, std::ios::in | std::ios::binary);
if (!bmpFile.is_open()) if (!bmpFile.is_open())
return; return;
@@ -60,22 +61,22 @@ namespace ReTexture {
height = bmpInfoHeader[8] + (bmpInfoHeader[9] << 8) + (bmpInfoHeader[10] << 16) + (bmpInfoHeader[11] << 24); height = bmpInfoHeader[8] + (bmpInfoHeader[9] << 8) + (bmpInfoHeader[10] << 16) + (bmpInfoHeader[11] << 24);
int rowPadded = (width * 3 + 3) & (~3); int rowPadded = (width * 3 + 3) & (~3);
pixelData.resize(width * height * 3); pixel_data.resize(width * height * 3);
std::vector<unsigned char> rowData(rowPadded); std::vector<unsigned char> rowData(rowPadded);
for (int y = height - 1; y >= 0; --y) { for (int y = height - 1; y >= 0; --y) {
bmpFile.read(reinterpret_cast<char *>(rowData.data()), rowPadded); bmpFile.read(reinterpret_cast<char *>(rowData.data()), rowPadded);
for (int x = 0; x < width; ++x) { for (int x = 0; x < width; ++x) {
pixelData[(y * width + x) * 3 + 2] = rowData[x * 3 + 0]; pixel_data[(y * width + x) * 3 + 2] = rowData[x * 3 + 0];
pixelData[(y * width + x) * 3 + 1] = rowData[x * 3 + 1]; pixel_data[(y * width + x) * 3 + 1] = rowData[x * 3 + 1];
pixelData[(y * width + x) * 3 + 0] = rowData[x * 3 + 2]; pixel_data[(y * width + x) * 3 + 0] = rowData[x * 3 + 2];
} }
} }
bmpFile.close(); bmpFile.close();
format = TextureFormat::RGB; format = TextureFormat::RGB;
} }
void SoftwareTexture::loadPNG(const std::string &file) { void Image::loadPNG(const std::string& file) {
int channels, w, h; int channels, w, h;
unsigned char* imageData = stbi_load(file.c_str(), &w, &h, &channels, 0); unsigned char* imageData = stbi_load(file.c_str(), &w, &h, &channels, 0);
@@ -91,11 +92,11 @@ namespace ReTexture {
if (channels == 4) if (channels == 4)
format = TextureFormat::RGBA; format = TextureFormat::RGBA;
pixelData.assign(imageData, imageData + width * height * channels); pixel_data.assign(imageData, imageData + width * height * channels);
stbi_image_free(imageData); stbi_image_free(imageData);
} }
void SoftwareTexture::invertY() { void Image::invertY() {
unsigned int rowSize; unsigned int rowSize;
if (format == TextureFormat::RGB) if (format == TextureFormat::RGB)
rowSize = width * 3; rowSize = width * 3;
@@ -104,41 +105,62 @@ namespace ReTexture {
std::vector<unsigned char> temp(rowSize); std::vector<unsigned char> temp(rowSize);
for (unsigned int y = 0; y < height / 2; ++y) { for (unsigned int y = 0; y < height / 2; ++y) {
unsigned char *topRow = &pixelData[y * rowSize]; unsigned char *topRow = &pixel_data[y * rowSize];
unsigned char *bottomRow = &pixelData[(height - y - 1) * rowSize]; unsigned char *bottomRow = &pixel_data[(height - y - 1) * rowSize];
std::copy(bottomRow, bottomRow + rowSize, temp.begin()); std::copy(bottomRow, bottomRow + rowSize, temp.begin());
std::copy(topRow, topRow + rowSize, bottomRow); std::copy(topRow, topRow + rowSize, bottomRow);
std::copy(temp.begin(), temp.end(), topRow); std::copy(temp.begin(), temp.end(), topRow);
} }
} }
unsigned int SoftwareTexture::getWidth() const { unsigned int Image::getWidth() const {
return width; return width;
} }
unsigned int SoftwareTexture::getHeight() const { unsigned int Image::getHeight() const {
return height; return height;
} }
TextureFormat SoftwareTexture::getTextureFormat() { TextureFormat Image::getTextureFormat() {
return format; return format;
} }
TextureFlag SoftwareTexture::getFlags() { TextureFlag Image::getFlags() {
return flags; return flags;
} }
SoftwareTexture SoftwareTexture::downscale(unsigned int rhs) { Image Image::downscale(unsigned int rhs) {
std::vector<unsigned char> result; std::vector<unsigned char> result;
if (format == TextureFormat::RGB) if (format == TextureFormat::RGB)
result.resize((width / rhs) * (height / rhs) * 3), result.resize((width / rhs) * (height / rhs) * 3),
stbir_resize_uint8_linear(pixelData.data(), width, height, 0, result.data(), (width / rhs), (height / rhs), 0, stbir_pixel_layout::STBIR_RGB); stbir_resize_uint8_linear(pixel_data.data(), width, height, 0, result.data(), (width / rhs), (height / rhs), 0, stbir_pixel_layout::STBIR_RGB);
else if (format == TextureFormat::RGBA) else if (format == TextureFormat::RGBA)
result.resize((width / rhs) * (height / rhs) * 4), result.resize((width / rhs) * (height / rhs) * 4),
stbir_resize_uint8_linear(pixelData.data(), width, height, 0, result.data(), (width / rhs), (height / rhs), 0, stbir_pixel_layout::STBIR_RGBA); stbir_resize_uint8_linear(pixel_data.data(), width, height, 0, result.data(), (width / rhs), (height / rhs), 0, stbir_pixel_layout::STBIR_RGBA);
return SoftwareTexture(result, format, (width / rhs), (height / rhs)); return Image(result, format, (width / rhs), (height / rhs));
}
Image::Image(std::vector<unsigned char>& pixel_data, TextureFormat format, unsigned int width, unsigned int height) {
this->pixel_data = pixel_data;
this->width = width;
this->height = height;
this->format = format;
this->flags = TextureFlag::NONE;
}
Image::Image(const Color3* data, const size_t& length, unsigned int width, unsigned int height, TextureFlag flags) {
pixel_data.resize(length * 3);
memcpy(pixel_data.data(), data, length * sizeof(Color3));
this->width = width;
this->height = height;
this->format = TextureFormat::RGB;
if (flags & INVERT_Y)
invertY();
this->flags = flags;
} }
} }