From 8cb751ff015271e1844feece5db2113eaec64af3 Mon Sep 17 00:00:00 2001 From: Frederico Linhares Date: Fri, 23 Jun 2023 20:45:23 -0300 Subject: feat Create an interface to read binary files * test/meshes/cube.cgmesh: Store data using Big-Endian order. --- src/binary_reader.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ src/binary_reader.hpp | 54 +++++++++++++++++++++++++++++ src/vk/mesh.cpp | 45 +++++------------------- src/vk/qoi.cpp | 85 ++++++++++++--------------------------------- test/meshes/cube.cgmesh | Bin 920 -> 920 bytes 5 files changed, 175 insertions(+), 99 deletions(-) create mode 100644 src/binary_reader.cpp create mode 100644 src/binary_reader.hpp diff --git a/src/binary_reader.cpp b/src/binary_reader.cpp new file mode 100644 index 0000000..5847328 --- /dev/null +++ b/src/binary_reader.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2022-2023 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "binary_reader.hpp" + +#include + +namespace +{ + +union IntAndFloat32bit{ + uint32_t i; + float f; +}; + +} + +BinaryReader::BinaryReader(std::string file_path): + _pointer{0} +{ + std::ifstream file(file_path, std::ios::binary | std::ios::ate); + if(!file.is_open()) throw std::runtime_error{"failed to open file"}; + + this->_size = file.tellg(); + file.seekg(0); + this->data = new uint8_t[this->_size]; + file.read((char*)data, this->_size); +} + +BinaryReader::BinaryReader(const char *file_path): + BinaryReader{std::string(file_path)} +{ +} + +BinaryReader::~BinaryReader() +{ + delete[] this->data; +} + +uint8_t +BinaryReader::read_ui8() +{ + return this->data[this->_pointer++]; +} + +uint32_t +BinaryReader::read_ui32() +{ + uint8_t b1{this->data[_pointer++]}, b2{this->data[_pointer++]}, + b3{this->data[_pointer++]}, b4{this->data[_pointer++]}; + + return b1 << 24 | b2 << 16 | b3 << 8 | b4; +} + +glm::vec2 +BinaryReader::read_vec2() +{ + IntAndFloat32bit x{read_ui32()}, y{read_ui32()}; + + return glm::vec2{x.f, y.f}; +} + +glm::vec3 +BinaryReader::read_vec3() +{ + IntAndFloat32bit x{read_ui32()}, y{read_ui32()}, z{read_ui32()}; + + return glm::vec3{x.f, y.f, z.f}; +} + +void +BinaryReader::read_chars(char *str, int size) +{ + for(int i{0}; i < size; i++) + str[i] = (char)data[this->_pointer++]; +} + diff --git a/src/binary_reader.hpp b/src/binary_reader.hpp new file mode 100644 index 0000000..b2e4de5 --- /dev/null +++ b/src/binary_reader.hpp @@ -0,0 +1,54 @@ +/* + * Copyright 2022-2023 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "vk/core.hpp" + +class BinaryReader +{ + int _pointer; + int _size; + uint8_t *data; + +public: + + BinaryReader(const std::string file_path); + BinaryReader(const char *file_path); + ~BinaryReader(); + + inline int + pointer(){return this->_pointer;}; + + inline int + size(){return this->_size;}; + + uint8_t + read_ui8(); + + uint32_t + read_ui32(); + + glm::vec2 + read_vec2(); + + glm::vec3 + read_vec3(); + + void + read_chars(char *str, int size); +}; diff --git a/src/vk/mesh.cpp b/src/vk/mesh.cpp index 70b9d45..9afeac3 100644 --- a/src/vk/mesh.cpp +++ b/src/vk/mesh.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022 Frederico de Oliveira Linhares + * Copyright 2022-2023 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,7 @@ #include "mesh.hpp" -#include -#include - +#include "../binary_reader.hpp" #include "../command.hpp" #include "../core.hpp" #include "vertex_3d.hpp" @@ -48,51 +46,26 @@ MeshBuilder::MeshBuilder(VK::Mesh *m, const char *mp): { } -uint32_t read_uint32_from_file(std::ifstream &input_file) -{ - uint32_t data{}; - input_file.read((char*)&data, sizeof(uint32_t)); - return data; -} - -glm::vec2 read_vec2_from_file(std::ifstream &input_file) -{ - glm::vec2 data{}; - input_file.read((char*)&data.x, sizeof(glm::vec2::value_type)); - input_file.read((char*)&data.y, sizeof(glm::vec2::value_type)); - return data; -} - -glm::vec3 read_vec3_from_file(std::ifstream &input_file) -{ - glm::vec3 data{}; - input_file.read((char*)&data.x, sizeof(glm::vec3::value_type)); - input_file.read((char*)&data.y, sizeof(glm::vec3::value_type)); - input_file.read((char*)&data.z, sizeof(glm::vec3::value_type)); - return data; -} - void load_mesh(void *obj) { auto self = static_cast(obj); - std::ifstream input_file{self->mesh_path}; - if(!input_file.is_open()) throw CommandError{"Failed to open file."}; + BinaryReader input{self->mesh_path}; self->mesh->queue_family = cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); // Load vertexes. { - auto vertex_count{read_uint32_from_file(input_file)}; + auto vertex_count{input.read_ui32()}; std::vector vertexes{vertex_count}; for(auto i{0}; i < vertex_count; i++) { - vertexes[i].position = read_vec3_from_file(input_file); - vertexes[i].normal = read_vec3_from_file(input_file); - vertexes[i].texture_coord = read_vec2_from_file(input_file); + vertexes[i].position = input.read_vec3(); + vertexes[i].normal = input.read_vec3(); + vertexes[i].texture_coord = input.read_vec2(); } void *vertexes_data{vertexes.data()}; @@ -106,11 +79,11 @@ load_mesh(void *obj) // Load indexes. { - self->mesh->index_count = read_uint32_from_file(input_file); + self->mesh->index_count = input.read_ui32(); std::vector indexes(self->mesh->index_count); for(auto i{0}; i < self->mesh->index_count; i++) - indexes[i] = read_uint32_from_file(input_file); + indexes[i] = input.read_ui32(); void *indexes_data{indexes.data()}; size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; diff --git a/src/vk/qoi.cpp b/src/vk/qoi.cpp index 8b7ef9e..4e2b2a4 100644 --- a/src/vk/qoi.cpp +++ b/src/vk/qoi.cpp @@ -19,6 +19,8 @@ #include #include +#include "../binary_reader.hpp" + namespace { @@ -88,26 +90,6 @@ color_hash(const RGBA &colors) return colors.red*3 + colors.green*5 + colors.blue*7 + colors.alpha*11; } -void -read_chars(uint8_t *data, int &p, char *str, int size) -{ - for(int i{0}; i < size; i++) str[i] = (char)data[p++]; -} - -void -read_ui8(uint8_t *data, int &p, uint8_t &num) -{ - num = data[p++]; -} - -void -read_ui32(uint8_t *data, int &p, uint32_t &num) -{ - uint8_t b1{data[p++]}, b2{data[p++]}, b3{data[p++]}, b4{data[p++]}; - - num = b1 << 24 | b2 << 16 | b3 << 8 | b4; -} - } namespace VK::QOI @@ -116,38 +98,22 @@ namespace VK::QOI Image::Image(const char *file_path, uint8_t channels): channels{channels} { - int data_p{0}; - int data_size; - uint8_t *data; - if(this->channels != 0 && this->channels != 3 && this->channels != 4) { throw std::invalid_argument{"invalid number of channels"}; } - { // Read data from file. - std::ifstream file(file_path, std::ios::binary | std::ios::ate); - if(!file) - { - throw std::runtime_error{"failed to open QOI file"}; - } - - data_size = file.tellg(); - if(data_size < HEADER_SIZE + (int)sizeof(PADDING)) - { - throw std::runtime_error{"invalid QOI file"}; - } - - file.seekg(0); - data = new uint8_t[data_size]; - file.read((char*)data, data_size); + BinaryReader input{file_path}; + if(input.size() < HEADER_SIZE + (int)sizeof(PADDING)) + { + throw std::runtime_error{"invalid QOI file"}; } - read_chars(data, data_p, this->header.magic, 4); - read_ui32(data, data_p, this->header.width); - read_ui32(data, data_p, this->header.height); - read_ui8(data, data_p, this->header.channels); - read_ui8(data, data_p, this->header.colorspace); + input.read_chars(this->header.magic, 4); + this->header.width = input.read_ui32(); + this->header.height = input.read_ui32(); + this->header.channels = input.read_ui8(); + this->header.colorspace = input.read_ui8(); if(this->header.width == 0 || this->header.height == 0 || this->header.channels < 3 || this->header.channels > 4 || @@ -165,7 +131,7 @@ Image::Image(const char *file_path, uint8_t channels): std::array index; Pixel pixel{}; - int chunks_len = data_size - (int)sizeof(PADDING); + int chunks_len = input.size() - (int)sizeof(PADDING); /* This algorithm is based on the original implementation that is in GitHub: @@ -181,25 +147,22 @@ Image::Image(const char *file_path, uint8_t channels): { run--; } - else if(data_p < chunks_len) + else if(input.pointer() < chunks_len) { - uint8_t output; - int b1; - read_ui8(data, data_p, output); - b1 = output; + int b1 = input.read_ui8(); if (b1 == OP_RGB) { - read_ui8(data, data_p, pixel.colors.red); - read_ui8(data, data_p, pixel.colors.green); - read_ui8(data, data_p, pixel.colors.blue); + pixel.colors.red = input.read_ui8(); + pixel.colors.green = input.read_ui8(); + pixel.colors.blue = input.read_ui8(); } else if (b1 == OP_RGBA) { - read_ui8(data, data_p, pixel.colors.red); - read_ui8(data, data_p, pixel.colors.green); - read_ui8(data, data_p, pixel.colors.blue); - read_ui8(data, data_p, pixel.colors.alpha); + pixel.colors.red = input.read_ui8(); + pixel.colors.green = input.read_ui8(); + pixel.colors.blue = input.read_ui8(); + pixel.colors.alpha = input.read_ui8(); } else if ((b1 & MASK_2_BITS) == OP_INDEX) { @@ -213,9 +176,7 @@ Image::Image(const char *file_path, uint8_t channels): } else if ((b1 & MASK_2_BITS) == OP_LUMA) { - int b2; - read_ui8(data, data_p, output); - b2 = output; + int b2 = input.read_ui8(); int vg = (b1 & 0x3f) - 32; pixel.colors.red += vg - 8 + ((b2 >> 4) & 0x0f); pixel.colors.green += vg; @@ -234,8 +195,6 @@ Image::Image(const char *file_path, uint8_t channels): this->pixels[pixel_p++] = pixel.colors.blue; if(this->channels == 4) this->pixels[pixel_p++] = pixel.colors.alpha; } - - delete[] data; } Image::~Image() diff --git a/test/meshes/cube.cgmesh b/test/meshes/cube.cgmesh index 5b0103e..a75185c 100644 Binary files a/test/meshes/cube.cgmesh and b/test/meshes/cube.cgmesh differ -- cgit v1.2.3