From c70907ced28e4bd1745b9e35a4cf43de6cc7948a Mon Sep 17 00:00:00 2001 From: drewcassidy Date: Mon, 29 Mar 2021 19:38:37 -0700 Subject: [PATCH] Add texture creation from bytes --- quicktex/Texture.h | 15 ++++++++++--- quicktex/_bindings.cpp | 49 ++++++------------------------------------ quicktex/_bindings.h | 27 ++++++++++++++++++++++- 3 files changed, 44 insertions(+), 47 deletions(-) diff --git a/quicktex/Texture.h b/quicktex/Texture.h index eeb256b..74a220e 100644 --- a/quicktex/Texture.h +++ b/quicktex/Texture.h @@ -20,10 +20,13 @@ #pragma once #include +#include #include #include +#include #include #include +#include #include "Block.h" #include "Color.h" @@ -44,12 +47,14 @@ class Texture { */ virtual size_t Size() const noexcept = 0; + virtual const uint8_t *Data() const noexcept = 0; + virtual uint8_t *Data() noexcept = 0; + protected: Texture(int width, int height) : _width(width), _height(height) { if (width <= 0) throw std::invalid_argument("Texture width must be greater than 0"); if (height <= 0) throw std::invalid_argument("Texture height must be greater than 0"); } - virtual uint8_t *DataMutable() = 0; int _width; int _height; @@ -142,8 +147,10 @@ class RawTexture : public Texture { } }; + virtual const uint8_t *Data() const noexcept override { return reinterpret_cast(_pixels); } + virtual uint8_t *Data() noexcept override { return reinterpret_cast(_pixels); } + protected: - virtual uint8_t *DataMutable() override { return reinterpret_cast(_pixels); } Color *_pixels; }; @@ -211,8 +218,10 @@ template class BlockTexture : public Texture { virtual size_t Size() const noexcept override { return (size_t)(BlocksX() * BlocksY()) * sizeof(B); } + virtual const uint8_t *Data() const noexcept override { return reinterpret_cast(_blocks); } + virtual uint8_t *Data() noexcept override { return reinterpret_cast(_blocks); } + protected: - virtual uint8_t *DataMutable() override { return reinterpret_cast(_blocks); } B *_blocks; }; diff --git a/quicktex/_bindings.cpp b/quicktex/_bindings.cpp index 8c8bef5..7a446b6 100644 --- a/quicktex/_bindings.cpp +++ b/quicktex/_bindings.cpp @@ -83,48 +83,6 @@ namespace quicktex::bindings { void InitS3TC(py::module_ &m); -/*py::bytes EncodeImage(const BlockEncoder &self, py::bytes decoded, unsigned image_width, unsigned image_height) { - if (image_width % self.BlockWidth() != 0) throw std::invalid_argument("Width is not an even multiple of block_width"); - if (image_height % self.BlockHeight() != 0) throw std::invalid_argument("Height is not an even multiple of block_height"); - if (image_width == 0 || image_height == 0) throw std::invalid_argument("Image has zero size"); - - size_t size = image_width * image_height; - size_t block_size = (size / (self.BlockHeight() * self.BlockWidth())) * self.BlockSize(); - size_t color_size = size * sizeof(Color); - - std::string encoded_str = std::string(block_size, 0); - std::string decoded_str = (std::string)decoded; // decoded data is copied here, unfortunately - - if (decoded_str.size() != color_size) throw std::invalid_argument("Incompatible data: image width and height do not match the size of the decoded image"); - - self.EncodeImage(reinterpret_cast(encoded_str.data()), reinterpret_cast(decoded_str.data()), image_width, image_height); - - auto bytes = py::bytes(encoded_str); // encoded data is copied here, unfortunately - - return bytes; -} - -py::bytes DecodeImage(const BlockDecoder &self, py::bytes encoded, unsigned image_width, unsigned image_height) { - if (image_width % self.WidthInBlocks() != 0) throw std::invalid_argument("Width is not an even multiple of block_width"); - if (image_height % self.HeightInBlocks() != 0) throw std::invalid_argument("Height is not an even multiple of block_height"); - if (image_width == 0 || image_height == 0) throw std::invalid_argument("Image has zero size"); - - size_t size = image_width * image_height; - size_t block_size = (size / (self.HeightInBlocks() * self.WidthInBlocks())) * self.BlockSize(); - size_t color_size = size * sizeof(Color); - - std::string encoded_str = (std::string)encoded; // encoded data is copied here, unfortunately - std::string decoded_str = std::string(color_size, 0); - - if (encoded_str.size() != block_size) throw std::invalid_argument("Incompatible data: image width and height do not match the size of the encoded image"); - - self.DecodeImage(reinterpret_cast(encoded_str.data()), reinterpret_cast(decoded_str.data()), image_width, image_height); - - auto bytes = py::bytes(decoded_str); // decoded data is copied here, unfortunately - - return bytes; -}*/ - PYBIND11_MODULE(_quicktex, m) { m.doc() = "More Stuff"; @@ -137,13 +95,18 @@ PYBIND11_MODULE(_quicktex, m) { texture.def_property_readonly("width", &Texture::Width); texture.def_property_readonly("height", &Texture::Height); +// texture.def_buffer([](Texture &t) { return py::buffer_info(t.Data(), t.Size()); }); + texture.def("to_bytes", [](const Texture &t) { return py::bytes(reinterpret_cast(t.Data()), t.Size()); }); + py::class_ raw_texture(m, "RawTexture", texture); raw_texture.def(py::init(), "width"_a, "height"_a); raw_texture.def("get_pixel", &RawTexture::GetPixel); raw_texture.def("set_pixel", &RawTexture::SetPixel); - InitS3TC(m); + raw_texture.def_static("from_bytes", &BufferToTexture, "data"_a, "width"_a, "height"_a); + +// InitS3TC(m); } } // namespace quicktex::bindings \ No newline at end of file diff --git a/quicktex/_bindings.h b/quicktex/_bindings.h index 7507e6a..29bdc08 100644 --- a/quicktex/_bindings.h +++ b/quicktex/_bindings.h @@ -21,6 +21,8 @@ #include +#include +#include #include #include @@ -34,9 +36,30 @@ template <> struct type_caster; namespace py = pybind11; namespace quicktex::bindings { - using namespace pybind11::literals; +template T BufferToTexture(py::buffer buf, int width, int height) { + static_assert(std::is_base_of::value); + static_assert(std::is_constructible::value); + + auto info = buf.request(false); + auto output = T(width, height);//std::make_shared(width, height); + auto dst_size = output.Size(); + + if (info.format != py::format_descriptor::format()) throw std::runtime_error("Incompatible format in python buffer: expected a byte array."); + if (info.size < (ssize_t)dst_size) std::runtime_error("Incompatible format in python buffer: Input data is smaller than texture size."); + if (info.ndim == 1) { + if (info.shape[0] < (ssize_t)dst_size) throw std::runtime_error("Incompatible format in python buffer: 1-D buffer has incorrect length."); + if (info.strides[0] != 1) throw std::runtime_error("Incompatible format in python buffer: 1-D buffer is not contiguous."); + } else { + throw std::runtime_error("Incompatible format in python buffer: Incorrect number of dimensions."); + } + + std::memcpy(output.Data(), info.ptr, dst_size); + + return output; +} + template py::class_> BindBlockTexture(py::module_& m, const char* name) { using BTex = BlockTexture; @@ -48,6 +71,8 @@ template py::class_> BindBlockTexture(py::module_& block_texture.def("get_block", &BTex::GetBlock, "x"_a, "y"_a); block_texture.def("set_block", &BTex::SetBlock, "x"_a, "y"_a, "block"_a); + block_texture.def_static("from_bytes", &BufferToTexture, "data"_a, "width"_a, "height"_a); + block_texture.def_property_readonly("blocks_x", &BTex::BlocksX); block_texture.def_property_readonly("blocks_y", &BTex::BlocksY); }