Initial Commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/cmake-build-debug
|
||||||
|
/.idea
|
33
CMakeLists.txt
Normal file
33
CMakeLists.txt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
project(ReTexture
|
||||||
|
VERSION 1.0
|
||||||
|
LANGUAGES CXX
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
|
# Enable Package Managers
|
||||||
|
include(cmake/CPM.cmake)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE HEADERS "include/*.h")
|
||||||
|
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
||||||
|
file(COPY "testImages" DESTINATION "${PROJECT_BINARY_DIR}")
|
||||||
|
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
|
||||||
|
include_directories("include" "/usr/include/libpng16")
|
||||||
|
|
||||||
|
if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
||||||
|
message(FATAL_ERROR "In-Source builds are not allowed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(ReTexture SHARED ${SOURCES} ${HEADERS})
|
||||||
|
add_executable(ReTextureTest main.cpp)
|
||||||
|
|
||||||
|
set_target_properties(ReTexture PROPERTIES LINKER_LANGUAGE CXX)
|
||||||
|
set_target_properties(ReTextureTest PROPERTIES LINKER_LANGUAGE CXX)
|
||||||
|
|
||||||
|
target_link_libraries(ReTexture PUBLIC PNG::PNG)
|
||||||
|
target_link_libraries(ReTextureTest PUBLIC ReTexture)
|
24
cmake/CPM.cmake
Normal file
24
cmake/CPM.cmake
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
|
||||||
|
|
||||||
|
set(CPM_DOWNLOAD_VERSION 0.38.7)
|
||||||
|
set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5")
|
||||||
|
|
||||||
|
if(CPM_SOURCE_CACHE)
|
||||||
|
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||||
|
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
|
||||||
|
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||||
|
else()
|
||||||
|
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Expand relative path. This is important if the provided path contains a tilde (~)
|
||||||
|
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
|
||||||
|
|
||||||
|
file(DOWNLOAD
|
||||||
|
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
|
||||||
|
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(${CPM_DOWNLOAD_LOCATION})
|
11
include/ReTexture/flags.h
Normal file
11
include/ReTexture/flags.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class RTextureFlag : unsigned int {
|
||||||
|
INVERT_Y = 0,
|
||||||
|
INVERT_X = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class RTextureFormat : bool {
|
||||||
|
RGB = false,
|
||||||
|
RGBA = true
|
||||||
|
};
|
20
include/ReTexture/rTexture.h
Normal file
20
include/ReTexture/rTexture.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <ReTexture/flags.h>
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
|
class RTexture {
|
||||||
|
private:
|
||||||
|
void load(const std::string& file);
|
||||||
|
void loadBMP(const std::string& file);
|
||||||
|
void loadPNG(const std::string& file);
|
||||||
|
void invertY();
|
||||||
|
public:
|
||||||
|
uint width;
|
||||||
|
uint height;
|
||||||
|
RTextureFormat format;
|
||||||
|
std::vector<unsigned char> pixelData;
|
||||||
|
RTexture(const std::string& file, const std::vector<RTextureFlag>& args);
|
||||||
|
};
|
26
main.cpp
Normal file
26
main.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include <ReTexture/rTexture.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto* bmp = new RTexture("testImages/1.bmp", {RTextureFlag::INVERT_Y});
|
||||||
|
std::cout << "Bitmap Width: " << bmp->width << std::endl;
|
||||||
|
std::cout << "Bitmap Height: " << bmp->height << std::endl;
|
||||||
|
|
||||||
|
if (bmp->format == RTextureFormat::RGB)
|
||||||
|
std::cout << "Bitmap Format: RGB" << std::endl;
|
||||||
|
|
||||||
|
if (bmp->format == RTextureFormat::RGBA)
|
||||||
|
std::cout << "Bitmap Format: RGBA" << std::endl;
|
||||||
|
delete bmp;
|
||||||
|
|
||||||
|
auto* png = new RTexture("testImages/1.png", {RTextureFlag::INVERT_Y});
|
||||||
|
std::cout << "PNG width: " << png->width << std::endl;
|
||||||
|
std::cout << "PNG height: " << png->height << std::endl;
|
||||||
|
|
||||||
|
if (png->format == RTextureFormat::RGB)
|
||||||
|
std::cout << "PNG Format: RGB" << std::endl;
|
||||||
|
|
||||||
|
if (png->format == RTextureFormat::RGBA)
|
||||||
|
std::cout << "PNG Format: RGBA" << std::endl;
|
||||||
|
delete png;
|
||||||
|
}
|
147
src/rTexture.cpp
Normal file
147
src/rTexture.cpp
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <ReTexture/rTexture.h>
|
||||||
|
#include <iostream>
|
||||||
|
void RTexture::load(const std::string& file) {
|
||||||
|
std::ifstream ifStream(file, std::ios::in | std::ios::binary);
|
||||||
|
unsigned char bmpFileHeader[14];
|
||||||
|
|
||||||
|
ifStream.read(reinterpret_cast<char*>(bmpFileHeader), 14);
|
||||||
|
if (bmpFileHeader[0] == 'B' && bmpFileHeader[1] == 'M') {
|
||||||
|
ifStream.close();
|
||||||
|
loadBMP(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
if (file.ends_with(".png"))
|
||||||
|
loadPNG(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTexture::loadBMP(const std::string& file) {
|
||||||
|
std::ifstream bmpFile(file, std::ios::in | std::ios::binary);
|
||||||
|
if (!bmpFile.is_open())
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned char bmpFileHeader[14];
|
||||||
|
unsigned char bmpInfoHeader[40];
|
||||||
|
|
||||||
|
bmpFile.read(reinterpret_cast<char*>(bmpFileHeader), 14);
|
||||||
|
bmpFile.read(reinterpret_cast<char*>(bmpInfoHeader), 40);
|
||||||
|
|
||||||
|
width = bmpInfoHeader[4] + (bmpInfoHeader[5] << 8) + (bmpInfoHeader[6] << 16) + (bmpInfoHeader[7] << 24);
|
||||||
|
height = bmpInfoHeader[8] + (bmpInfoHeader[9] << 8) + (bmpInfoHeader[10] << 16) + (bmpInfoHeader[11] << 24);
|
||||||
|
|
||||||
|
int rowPadded = (width * 3 + 3) & (~3);
|
||||||
|
pixelData.resize(width * height * 3);
|
||||||
|
|
||||||
|
std::vector<unsigned char> rowData(rowPadded);
|
||||||
|
for (int y = height - 1; y >= 0; --y) {
|
||||||
|
bmpFile.read(reinterpret_cast<char*>(rowData.data()), rowPadded);
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
pixelData[(y * width + x) * 3 + 2] = rowData[x * 3 + 0];
|
||||||
|
pixelData[(y * width + x) * 3 + 1] = rowData[x * 3 + 1];
|
||||||
|
pixelData[(y * width + x) * 3 + 0] = rowData[x * 3 + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bmpFile.close();
|
||||||
|
format = RTextureFormat::RGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTexture::loadPNG(const std::string &file) {
|
||||||
|
FILE *fp = fopen(file.c_str(), "rb");
|
||||||
|
if (!fp) {
|
||||||
|
fprintf(stderr, "Could not open file %s for reading\n", file.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||||
|
if (!png) {
|
||||||
|
fprintf(stderr, "Could not create png read struct\n");
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_infop info = png_create_info_struct(png);
|
||||||
|
if (!info) {
|
||||||
|
fprintf(stderr, "Could not create png info struct\n");
|
||||||
|
png_destroy_read_struct(&png, nullptr, nullptr);
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png))) {
|
||||||
|
fprintf(stderr, "Error during png creation\n");
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init_io(png, fp);
|
||||||
|
png_read_info(png, info);
|
||||||
|
|
||||||
|
width = png_get_image_width(png, info);
|
||||||
|
height = png_get_image_height(png, info);
|
||||||
|
png_byte color_type = png_get_color_type(png, info);
|
||||||
|
png_byte bit_depth = png_get_bit_depth(png, info);
|
||||||
|
|
||||||
|
if (bit_depth == 16)
|
||||||
|
png_set_strip_16(png);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_palette_to_rgb(png);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||||
|
png_set_expand_gray_1_2_4_to_8(png);
|
||||||
|
|
||||||
|
if (png_get_valid(png, info, PNG_INFO_tRNS))
|
||||||
|
png_set_tRNS_to_alpha(png);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
|
png_set_gray_to_rgb(png);
|
||||||
|
|
||||||
|
png_read_update_info(png, info);
|
||||||
|
|
||||||
|
pixelData.resize(png_get_rowbytes(png, info) * height);
|
||||||
|
std::vector<png_bytep> row_pointers(height);
|
||||||
|
|
||||||
|
for (unsigned y = 0; y < height; ++y) {
|
||||||
|
row_pointers[y] = pixelData.data() + y * png_get_rowbytes(png, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_read_image(png, row_pointers.data());
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
png_destroy_read_struct(&png, &info, nullptr);
|
||||||
|
if (color_type & PNG_COLOR_MASK_ALPHA)
|
||||||
|
format = RTextureFormat::RGBA;
|
||||||
|
|
||||||
|
if (!(color_type & PNG_COLOR_MASK_ALPHA))
|
||||||
|
format = RTextureFormat::RGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTexture::RTexture(const std::string &file, const std::vector<RTextureFlag> &args) {
|
||||||
|
load(file);
|
||||||
|
if (std::find(args.begin(), args.end(), RTextureFlag::INVERT_Y) != args.end())
|
||||||
|
invertY();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTexture::invertY() {
|
||||||
|
unsigned int rowSize;
|
||||||
|
if (format == RTextureFormat::RGB)
|
||||||
|
rowSize = width * 3;
|
||||||
|
if (format == RTextureFormat::RGBA)
|
||||||
|
rowSize = width * 4;
|
||||||
|
|
||||||
|
std::vector<unsigned char> temp(rowSize);
|
||||||
|
for (uint y = 0; y < height / 2; ++y) {
|
||||||
|
unsigned char* topRow = &pixelData[y * rowSize];
|
||||||
|
unsigned char* bottomRow = &pixelData[(height - y - 1) * rowSize];
|
||||||
|
std::copy(bottomRow, bottomRow + rowSize, temp.begin());
|
||||||
|
std::copy(topRow, topRow + rowSize, bottomRow);
|
||||||
|
std::copy(temp.begin(), temp.end(), topRow);
|
||||||
|
}
|
||||||
|
}
|
BIN
testImages/1.bmp
Normal file
BIN
testImages/1.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 MiB |
BIN
testImages/1.png
Normal file
BIN
testImages/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
Reference in New Issue
Block a user