From 3a7a35ed3eca5edaad48cfc129caad8650ac06c6 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 18 Jun 2022 22:46:29 +0100 Subject: [PATCH 001/113] Major update/rector to improve memory footprint and performance. --- CMakeLists.txt | 11 +- GraphiteTest/main.cpp | 27 +- libGraphite/compression/packbits.cpp | 112 ++++ libGraphite/compression/packbits.hpp | 59 ++ libGraphite/data/data.cpp | 327 +++++++-- libGraphite/data/data.hpp | 165 ++--- libGraphite/data/encoding.hpp | 43 ++ libGraphite/data/endianess.hpp | 62 ++ libGraphite/data/reader.cpp | 281 ++++---- libGraphite/data/reader.hpp | 274 ++++---- libGraphite/data/writer.cpp | 281 ++++---- libGraphite/data/writer.hpp | 234 +++---- libGraphite/hints.hpp | 5 +- libGraphite/quickdraw/format/cicn.cpp | 194 ++++++ libGraphite/quickdraw/format/cicn.hpp | 61 ++ libGraphite/quickdraw/format/clut.cpp | 133 ++++ libGraphite/quickdraw/format/clut.hpp | 93 +++ libGraphite/quickdraw/format/pict.cpp | 620 ++++++++++++++++++ libGraphite/quickdraw/format/pict.hpp | 99 +++ libGraphite/quickdraw/format/ppat.cpp | 157 +++++ libGraphite/quickdraw/format/ppat.hpp | 58 ++ libGraphite/quickdraw/format/rle.cpp | 356 ++++++++++ libGraphite/quickdraw/format/rle.hpp | 80 +++ .../quickdraw/support/drawing/depth_2_bpp.cpp | 69 ++ .../quickdraw/support/drawing/depth_2_bpp.hpp | 35 + .../quickdraw/support/drawing/depth_4bpp.cpp | 69 ++ .../quickdraw/support/drawing/depth_4bpp.hpp | 35 + .../quickdraw/support/drawing/monochrome.cpp | 62 ++ .../quickdraw/support/drawing/monochrome.hpp | 32 + .../quickdraw/support/drawing/true_color.cpp | 63 ++ .../quickdraw/support/drawing/true_color.hpp | 35 + libGraphite/quickdraw/support/pixmap.cpp | 301 +++++++++ libGraphite/quickdraw/support/pixmap.hpp | 123 ++++ libGraphite/quickdraw/support/surface.cpp | 95 +++ libGraphite/quickdraw/support/surface.hpp | 59 ++ libGraphite/quickdraw/type/coding_type.hpp | 29 + libGraphite/quickdraw/type/color.cpp | 49 ++ libGraphite/quickdraw/type/color.hpp | 57 ++ libGraphite/quickdraw/type/pixel_format.hpp | 38 ++ libGraphite/quickdraw/type/point.hpp | 123 ++++ libGraphite/quickdraw/type/rect.hpp | 81 +++ libGraphite/quickdraw/type/size.hpp | 124 ++++ .../{quickdraw => quickdraw_old}/cicn.cpp | 0 .../{quickdraw => quickdraw_old}/cicn.hpp | 0 .../{quickdraw => quickdraw_old}/clut.cpp | 0 .../{quickdraw => quickdraw_old}/clut.hpp | 0 .../{quickdraw => quickdraw_old}/geometry.cpp | 0 .../{quickdraw => quickdraw_old}/geometry.hpp | 0 .../internal/color.cpp | 0 .../internal/color.hpp | 0 .../internal/packbits.cpp | 0 .../internal/packbits.hpp | 0 .../internal/surface.cpp | 0 .../internal/surface.hpp | 0 .../{quickdraw => quickdraw_old}/pict.cpp | 0 .../{quickdraw => quickdraw_old}/pict.hpp | 0 .../{quickdraw => quickdraw_old}/pixmap.cpp | 0 .../{quickdraw => quickdraw_old}/pixmap.hpp | 0 .../{quickdraw => quickdraw_old}/ppat.cpp | 0 .../{quickdraw => quickdraw_old}/ppat.hpp | 0 .../{quickdraw => quickdraw_old}/rle.cpp | 0 .../{quickdraw => quickdraw_old}/rle.hpp | 0 libGraphite/resources/sound.cpp | 284 -------- libGraphite/resources/sound.hpp | 176 ----- libGraphite/resources/string.cpp | 48 -- libGraphite/resources/string.hpp | 36 - libGraphite/rsrc/attribute.cpp | 58 ++ libGraphite/rsrc/attribute.hpp | 51 ++ libGraphite/rsrc/classic.cpp | 318 --------- libGraphite/rsrc/classic/classic.hpp | 24 + libGraphite/rsrc/classic/parser.cpp | 145 ++++ .../rsrc/{extended.hpp => classic/parser.hpp} | 30 +- libGraphite/rsrc/classic/writer.cpp | 222 +++++++ libGraphite/rsrc/classic/writer.hpp | 30 + libGraphite/rsrc/extended.cpp | 325 --------- libGraphite/rsrc/extended/extended.hpp | 24 + libGraphite/rsrc/extended/parser.cpp | 158 +++++ libGraphite/rsrc/extended/parser.hpp | 29 + libGraphite/rsrc/extended/writer.cpp | 227 +++++++ libGraphite/rsrc/extended/writer.hpp | 30 + libGraphite/rsrc/file.cpp | 259 ++++---- libGraphite/rsrc/file.hpp | 154 ++--- libGraphite/rsrc/manager.cpp | 138 ++-- libGraphite/rsrc/manager.hpp | 133 ++-- libGraphite/rsrc/resource.cpp | 108 +-- libGraphite/rsrc/resource.hpp | 117 +--- libGraphite/rsrc/result.cpp | 128 ++++ libGraphite/rsrc/result.hpp | 110 ++++ libGraphite/rsrc/rez.cpp | 196 ------ libGraphite/rsrc/rez/parser.cpp | 131 ++++ libGraphite/rsrc/rez/parser.hpp | 29 + libGraphite/rsrc/rez/rez.hpp | 24 + libGraphite/rsrc/rez/writer.cpp | 145 ++++ .../rsrc/{classic.hpp => rez/writer.hpp} | 30 +- libGraphite/rsrc/type.cpp | 143 ++-- libGraphite/rsrc/type.hpp | 97 ++- libGraphite/sound/codec/descriptor.hpp | 41 ++ libGraphite/sound/codec/ima4.cpp | 132 ++++ libGraphite/sound/codec/ima4.hpp | 43 ++ libGraphite/sound/sound.cpp | 424 ++++++++++++ libGraphite/sound/sound.hpp | 62 ++ libGraphite/toolbox/string.cpp | 39 ++ libGraphite/toolbox/string.hpp | 35 + libGraphite/toolbox/string_list.cpp | 67 ++ .../{rsrc/rez.hpp => toolbox/string_list.hpp} | 51 +- libGraphite/util/concepts.hpp | 48 ++ libGraphite/util/hashing.cpp | 140 ++++ libGraphite/util/hashing.hpp | 31 + 108 files changed, 7698 insertions(+), 2783 deletions(-) create mode 100644 libGraphite/compression/packbits.cpp create mode 100644 libGraphite/compression/packbits.hpp create mode 100644 libGraphite/data/encoding.hpp create mode 100644 libGraphite/data/endianess.hpp create mode 100644 libGraphite/quickdraw/format/cicn.cpp create mode 100644 libGraphite/quickdraw/format/cicn.hpp create mode 100644 libGraphite/quickdraw/format/clut.cpp create mode 100644 libGraphite/quickdraw/format/clut.hpp create mode 100644 libGraphite/quickdraw/format/pict.cpp create mode 100644 libGraphite/quickdraw/format/pict.hpp create mode 100644 libGraphite/quickdraw/format/ppat.cpp create mode 100644 libGraphite/quickdraw/format/ppat.hpp create mode 100644 libGraphite/quickdraw/format/rle.cpp create mode 100644 libGraphite/quickdraw/format/rle.hpp create mode 100644 libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp create mode 100644 libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp create mode 100644 libGraphite/quickdraw/support/drawing/depth_4bpp.cpp create mode 100644 libGraphite/quickdraw/support/drawing/depth_4bpp.hpp create mode 100644 libGraphite/quickdraw/support/drawing/monochrome.cpp create mode 100644 libGraphite/quickdraw/support/drawing/monochrome.hpp create mode 100644 libGraphite/quickdraw/support/drawing/true_color.cpp create mode 100644 libGraphite/quickdraw/support/drawing/true_color.hpp create mode 100644 libGraphite/quickdraw/support/pixmap.cpp create mode 100644 libGraphite/quickdraw/support/pixmap.hpp create mode 100644 libGraphite/quickdraw/support/surface.cpp create mode 100644 libGraphite/quickdraw/support/surface.hpp create mode 100644 libGraphite/quickdraw/type/coding_type.hpp create mode 100644 libGraphite/quickdraw/type/color.cpp create mode 100644 libGraphite/quickdraw/type/color.hpp create mode 100644 libGraphite/quickdraw/type/pixel_format.hpp create mode 100644 libGraphite/quickdraw/type/point.hpp create mode 100644 libGraphite/quickdraw/type/rect.hpp create mode 100644 libGraphite/quickdraw/type/size.hpp rename libGraphite/{quickdraw => quickdraw_old}/cicn.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/cicn.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/clut.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/clut.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/geometry.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/geometry.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/internal/color.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/internal/color.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/internal/packbits.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/internal/packbits.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/internal/surface.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/internal/surface.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/pict.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/pict.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/pixmap.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/pixmap.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/ppat.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/ppat.hpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/rle.cpp (100%) rename libGraphite/{quickdraw => quickdraw_old}/rle.hpp (100%) delete mode 100644 libGraphite/resources/sound.cpp delete mode 100644 libGraphite/resources/sound.hpp delete mode 100644 libGraphite/resources/string.cpp delete mode 100644 libGraphite/resources/string.hpp create mode 100644 libGraphite/rsrc/attribute.cpp create mode 100644 libGraphite/rsrc/attribute.hpp delete mode 100644 libGraphite/rsrc/classic.cpp create mode 100644 libGraphite/rsrc/classic/classic.hpp create mode 100644 libGraphite/rsrc/classic/parser.cpp rename libGraphite/rsrc/{extended.hpp => classic/parser.hpp} (60%) create mode 100644 libGraphite/rsrc/classic/writer.cpp create mode 100644 libGraphite/rsrc/classic/writer.hpp delete mode 100644 libGraphite/rsrc/extended.cpp create mode 100644 libGraphite/rsrc/extended/extended.hpp create mode 100644 libGraphite/rsrc/extended/parser.cpp create mode 100644 libGraphite/rsrc/extended/parser.hpp create mode 100644 libGraphite/rsrc/extended/writer.cpp create mode 100644 libGraphite/rsrc/extended/writer.hpp create mode 100644 libGraphite/rsrc/result.cpp create mode 100644 libGraphite/rsrc/result.hpp delete mode 100644 libGraphite/rsrc/rez.cpp create mode 100644 libGraphite/rsrc/rez/parser.cpp create mode 100644 libGraphite/rsrc/rez/parser.hpp create mode 100644 libGraphite/rsrc/rez/rez.hpp create mode 100644 libGraphite/rsrc/rez/writer.cpp rename libGraphite/rsrc/{classic.hpp => rez/writer.hpp} (61%) create mode 100644 libGraphite/sound/codec/descriptor.hpp create mode 100644 libGraphite/sound/codec/ima4.cpp create mode 100644 libGraphite/sound/codec/ima4.hpp create mode 100644 libGraphite/sound/sound.cpp create mode 100644 libGraphite/sound/sound.hpp create mode 100644 libGraphite/toolbox/string.cpp create mode 100644 libGraphite/toolbox/string.hpp create mode 100644 libGraphite/toolbox/string_list.cpp rename libGraphite/{rsrc/rez.hpp => toolbox/string_list.hpp} (52%) create mode 100644 libGraphite/util/concepts.hpp create mode 100644 libGraphite/util/hashing.cpp create mode 100644 libGraphite/util/hashing.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ec3e065..816630a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ project(Graphite CXX) set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) if (APPLE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") endif() @@ -38,7 +38,12 @@ add_library(Graphite ${graphite_sources}) file(GLOB_RECURSE graphite_test_sources GraphiteTest/*.cpp -) + libGraphite/fast_data/*.cpp + libGraphite/encoding/*.cpp + libGraphite/new_rsrc/*.cpp + libGraphite/util/*.cpp +) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") add_executable(GraphiteTest ${graphite_test_sources}) -target_link_libraries(GraphiteTest Graphite) +#target_link_libraries(GraphiteTest Graphite) diff --git a/GraphiteTest/main.cpp b/GraphiteTest/main.cpp index 96d3db8..729db0d 100644 --- a/GraphiteTest/main.cpp +++ b/GraphiteTest/main.cpp @@ -18,33 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/writer.hpp" #include +#include "libGraphite/rsrc/manager.hpp" int main(int argc, char const *argv[]) { - auto rf = std::make_shared(); - - auto english = std::make_shared(); - english->write_cstr("Hello, World!"); - rf->add_resource("test", 128, "test resource", english->data(), { - std::make_pair("lang", "en") - }); + auto file = graphite::rsrc::manager::shared_manager().import_file("/Applications/EV Nova.app/Contents/Resources/Nova Files/Nova Data 1.ndat"); - auto french = std::make_shared(); - french->write_cstr("Bonjour, Monde!"); - rf->add_resource("test", 128, "test resource", french->data(), { - std::make_pair("lang", "fr") - }); - - // The resource file should be assembled at this point and just needs writing to disk. - rf->write("test.cdat", graphite::rsrc::file::format::extended); - - - auto in_rf = std::make_shared("test.cdat"); - for (const auto& type : in_rf->types()) { - std::cout << "reading type: " << type->code() << type->attributes_string() << std::endl; - } - return 0; + return 0; } diff --git a/libGraphite/compression/packbits.cpp b/libGraphite/compression/packbits.cpp new file mode 100644 index 0000000..990cc9c --- /dev/null +++ b/libGraphite/compression/packbits.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include "libGraphite/compression/packbits.hpp" +#include "libGraphite/data/reader.hpp" +#include "libGraphite/data/writer.hpp" + +// MARK: - Decompression + +auto graphite::compression::packbits::decompress(const data::block &compressed, std::size_t value_size) -> data::block +{ + data::block decompressed_data; + data::reader reader(&compressed); + data::writer writer(&decompressed_data); + + while (!reader.eof()) { + auto count = reader.read_byte(); + if (count >= 0 && count < 128) { + std::uint16_t run = (1 + count) * value_size; + if ((pos + run) > reader.size()) { + throw std::runtime_error("Unable to decode packbits"); + } + writer.write_data(std::move(reader.read_data(run))); + } + else if (count >= 128) { + std::uint8_t run = 256 - count + 1; + for (std::uint8_t i = 0; i < run; ++i) { + for (std::uint8_t j = 0; j < value_size; ++j) { + writer.write_byte(reader.read_byte(j, data::reader::mode::peek)); + } + } + reader.move(value_size); + } + else { + // No Operation + } + } + + return std::move(decompressed_data); +} + +// MARK: - Compression + +auto graphite::compression::packbits::compress(const data::block &uncompressed) -> data::block +{ + data::block result; + data::block buffer(128); + data::writer writer(&result); + + auto offset = 0; + const auto max = uncompressed.size() - 1; + const auto max_minus_1 = max - 1; + + while (offset <= max) { + // Compressed run + auto run = 1; + auto replicate = uncompressed.get(offset); + while (run < 127 && offset < max && uncompressed.get(offset) == uncompressed.get(offset + 1)) { + ++offset; + ++run; + } + + if (run > 1) { + ++offset; + writer.write_byte(static_cast(-(run - 1))); + writer.write_byte(replicate); + } + + // Literal run + run = 0; + while (run < 128 && ((offset < max && uncompressed.get(offset) != uncompressed.get(offset + 1)) + || (offset < max_minus_1 && uncompressed.get(offset) != uncompressed.get(offset + 2)))) + { + buffer.set(uncompressed.get(offset++), 1, run++); + } + + if (offset == max && run > 0 && run < 128) { + buffer.set(uncompressed.get(offset++), 1, run++); + } + + if (run > 0) { + writer.write_byte(run - 1); + writer.write_data(buffer.slice(0, run)); + buffer.clear(); + } + + if (offset == max && (run <= 0 || run >= 128)) { + writer.write_byte(0); + writer.write_byte(uncompressed.get(offset++)); + } + } + + return std::move(result); +} \ No newline at end of file diff --git a/libGraphite/compression/packbits.hpp b/libGraphite/compression/packbits.hpp new file mode 100644 index 0000000..ef77b09 --- /dev/null +++ b/libGraphite/compression/packbits.hpp @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/data/data.hpp" + +namespace graphite::compression +{ + struct packbits + { + static auto decompress(const data::block& compressed, std::size_t value_size) -> data::block; + static auto compress(const data::block& uncompressed) -> data::block; + }; + + struct packbits8 + { + static auto decompress(const data::block& compressed) -> data::block + { + return std::move(packbits::decompress(compressed, 1)); + } + + static auto compress(const data::block& uncompressed) -> data::block + { + return std::move(packbits::compress(uncompressed)); + } + }; + + struct packbits16 + { + static auto decompress(const data::block& compressed) -> data::block + { + return std::move(packbits::decompress(compressed, 2)); + } + + static auto compress(const data::block& uncompressed) -> data::block + { + return std::move(packbits::compress(uncompressed)); + } + }; +} \ No newline at end of file diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 984787a..1bff4d5 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -19,87 +19,332 @@ // SOFTWARE. #include +#include +#include #include "libGraphite/data/data.hpp" -// MARK: - Constructor +// MARK: - SIMD Support -graphite::data::data::data(enum graphite::data::byte_order bo) - : m_bo(bo), m_data(std::make_shared>(0)), m_start(0), m_size(0) +#if __x86_64__ + typedef __int128 int128_t; + typedef unsigned __int128 uint128_t; + + typedef uint128_t simd_wide_type; + typedef simd_wide_type simd_type; + typedef uint64_t simd_wide_field_type; + + static constexpr std::size_t simd_alignment_width = 16; + static constexpr std::size_t simd_fields = 4; + static constexpr std::size_t simd_wide_fields = 2; + +#elif __arm64__ + typedef uint64_t simd_wide_type; + typedef simd_wide_type simd_type; + typedef simd_type simd_wide_field_type; + + static constexpr std::size_t simd_alignment_width = 8; + static constexpr std::size_t simd_fields = 2; + static constexpr std::size_t simd_wide_fields = 1; + +#else + typedef uint32_t simd_wide_type; + typedef simd_wide_type simd_type; + + static constexpr std::size_t simd_alignment_width = 4; + static constexpr std::size_t simd_fields = 1; + static constexpr std::size_t simd_wide_fields = 0; + +#endif + +typedef uint32_t simd_field_type; +typedef uint16_t simd_half_field_type; +static constexpr std::size_t simd_field_size = sizeof(simd_field_type); + +union alignas(simd_alignment_width) simd_value +{ + simd_type wide; +#if __x86_64__ || __arm64__ + simd_wide_field_type wide_fields[simd_wide_fields]; +#endif + simd_field_type fields[simd_fields]; + uint8_t bytes[sizeof(simd_type)]; +}; + +static constexpr std::size_t simd_alignment_mask = ~(simd_alignment_width - 1); + +template::value>::type* = nullptr> +static inline auto simd_expand_capacity(T capacity) -> T { - + return (capacity + simd_alignment_width - 1) & simd_alignment_mask; } -graphite::data::data::data(std::size_t capacity, enum graphite::data::byte_order bo) - : m_bo(bo), m_data(std::make_shared>(0)), m_start(0), m_size(capacity) +template::value>::type* = nullptr> +static inline auto simd_align(T ptr) -> T +{ + return reinterpret_cast((reinterpret_cast(ptr) + simd_alignment_width - 1) & simd_alignment_mask); +} + +// MARK: - Construction + +graphite::data::block::block(std::size_t capacity, enum byte_order order) + : m_raw_size(simd_expand_capacity(capacity)), + m_data_size(capacity), + m_raw(malloc(m_raw_size)), + m_data(simd_align(m_raw)), + m_allocation_owner(nullptr), + m_byte_order(order) { - } -graphite::data::data::data(std::shared_ptr> bytes, std::size_t size, std::size_t start, enum graphite::data::byte_order bo) - : m_bo(bo), m_data(std::move(bytes)), m_size(size), m_start(start) +graphite::data::block::block(const std::string &path, enum byte_order order) + : m_byte_order(order), + m_allocation_owner(nullptr) { - if ((m_start + m_size) > m_data->size()) { - throw std::out_of_range("Invalid boundaries for data slice."); + std::ifstream file { path, std::ios::binary }; + if (!file.is_open() || file.fail()) { + throw std::runtime_error("Failed to open data file: " + path); } + + file.unsetf(std::ios::skipws); + file.seekg(0, std::ios::end); + m_data_size = file.tellg(); + file.seekg(0, std::ios::beg); + + m_raw_size = simd_expand_capacity(m_data_size); + m_raw = malloc(m_raw_size); + m_data = simd_align(m_raw); + file.read(reinterpret_cast(m_data), m_data_size); + + file.close(); } -// MARK: - Offset Calculations +graphite::data::block::block(const block &source, bool copy) + : m_raw_size(source.m_raw_size), + m_data_size(source.m_data_size), + m_start_position(source.m_start_position), + m_count(source.m_count), + m_byte_order(source.m_byte_order), + m_allocation_owner(copy ? nullptr : &source) +{ + clone_from(source); +} -auto graphite::data::data::relative_offset(int64_t offset) const -> int64_t +graphite::data::block::block(const block &source, block::position pos, std::size_t amount, bool copy) + : m_allocation_owner(copy ? nullptr : &source), + m_byte_order(source.m_byte_order) { - if (offset > m_size || offset < 0) { - throw std::out_of_range("Attempted to calculate an offset that went beyond the boundaries of the data slice."); - } - return m_start + offset; + if (m_allocation_owner) { + m_raw = source.m_raw; + m_data = source.m_data; + m_raw_size = source.m_raw_size; + m_data_size = source.m_data_size; + m_start_position = pos; + m_count = amount; + + const_cast(m_allocation_owner)->m_users++; + } + else { + m_raw_size = simd_expand_capacity(amount); + m_data_size = amount; + m_raw = malloc(m_raw_size); + m_data = simd_align(m_raw); + m_start_position = 0; + m_count = 0; + } } -// MARK: - Size +graphite::data::block::block(const block &data) + : m_raw_size(data.m_raw_size), + m_data_size(data.m_data_size), + m_allocation_owner(nullptr), + m_start_position(data.m_start_position), + m_users(data.m_users), + m_count(data.m_count), + m_byte_order(data.m_byte_order) +{ + m_raw = malloc(m_raw_size); + m_data = simd_align(m_raw); + copy_from(data); +} -auto graphite::data::data::size() const -> std::size_t +graphite::data::block::block(block &&data) + : m_raw_size(data.m_raw_size), + m_data_size(data.m_data_size), + m_raw(data.m_raw), + m_data(data.m_data), + m_allocation_owner(data.m_allocation_owner), + m_start_position(data.m_start_position), + m_users(data.m_users), + m_count(data.m_count), + m_byte_order(data.m_byte_order) { - if (m_size > 0) { - return m_size; - } - else if (m_data != nullptr && m_start == 0) { - return m_data->size(); + data.m_raw = nullptr; + data.m_data = nullptr; + data.m_raw_size = 0; + data.m_data_size = 0; + data.m_users = 0; + data.m_allocation_owner = nullptr; +} + +auto graphite::data::block::operator=(const block &data) -> struct block & +{ + if (this == const_cast(&data)) { + return *this; } - else { - return 0; + + m_raw_size = data.m_raw_size; + m_data_size = data.m_data_size; + m_allocation_owner = nullptr; + m_start_position = data.m_start_position; + m_users = data.m_users; + m_count = data.m_count; + m_byte_order = data.m_byte_order; + + m_raw = malloc(m_raw_size); + m_data = simd_align(m_raw); + copy_from(data); +} + +auto graphite::data::block::operator=(block &&data) noexcept -> struct block & +{ + if (this != &data) { + // Clean up the current data... + if (m_allocation_owner) { + const_cast(m_allocation_owner)->m_users--; + } + else if (!m_allocation_owner) { + assert(m_users == 0); + free(m_raw); + } + + // Move over the data... + m_raw_size = data.m_raw_size; + m_data_size = data.m_data_size; + m_raw = data.m_raw; + m_data = data.m_data; + m_allocation_owner = data.m_allocation_owner; + m_start_position = data.m_start_position; + m_users = data.m_users; + m_count = data.m_count; + m_byte_order = data.m_byte_order; + + data.m_allocation_owner = nullptr; + data.m_raw = nullptr; + data.m_data = nullptr; + } + return *this; } -auto graphite::data::data::start() const -> std::size_t +// MARK: - Destruction + +graphite::data::block::~block() { - return m_start; + if (m_allocation_owner) { + const_cast(m_allocation_owner)->m_users--; + } + else if (!m_allocation_owner) { + assert(m_users == 0); + free(m_raw); + } } -auto graphite::data::data::current_byte_order() const -> enum graphite::data::byte_order +// MARK: - Copy/Clone + +auto graphite::data::block::clone_from(const graphite::data::block &source) -> void { - return m_bo; + if (m_allocation_owner) { + m_raw = source.m_raw; + m_data = source.m_data; + const_cast(m_allocation_owner)->m_users++; + } + else { + m_raw = malloc(m_raw_size); + m_data = simd_align(m_raw); + copy_from(source); + } } -auto graphite::data::data::set_byte_order(enum graphite::data::byte_order bo) -> void +auto graphite::data::block::copy_from(const block &source) const -> void { - m_bo = bo; + auto source_ptr = source.get(); + auto dest_ptr = get(); + + std::size_t len = std::min(source.size(), size()); + std::size_t n = 0; + while (n < len) { + if ((reinterpret_cast(source_ptr) & simd_alignment_width) || (len - n) < simd_fields) { + *dest_ptr = *source_ptr; + ++dest_ptr; + ++source_ptr; + n += simd_field_size; + } + else { + *reinterpret_cast(dest_ptr) = *reinterpret_cast(source_ptr); + dest_ptr += simd_fields; + source_ptr += simd_fields; + n += simd_alignment_width; + } + } } +// MARK: - Operations + +static inline auto inline_set(graphite::data::block *dst, union simd_value v, std::size_t bytes, std::size_t start) -> void +{ + auto len = std::min(dst->size() - start, bytes); + auto ptr = dst->get(start); + std::size_t n = 0; -// MARK: - Plumbing + while (n < len) { + if ((reinterpret_cast(ptr) & simd_alignment_width) || (len - n) < simd_fields) { + *ptr = v.fields[n & (simd_fields - 1)]; + ++ptr; + n += simd_field_size; + } + else { + *reinterpret_cast(ptr) = v.wide; + ptr += simd_fields; + n += simd_alignment_width; + } + } +} -auto graphite::data::data::get() -> std::shared_ptr> +auto graphite::data::block::clear() -> void { - return m_data; + set((uint32_t)0); } -auto graphite::data::data::at(std::size_t offset) const -> char +auto graphite::data::block::set(uint8_t value, std::size_t bytes, block::position start) -> void { - return m_data->at(relative_offset(offset)); + union simd_value v; + for (auto n = 0; n < simd_alignment_width; ++n) { + v.bytes[n] = value; + } + inline_set(this, v, bytes, start); } -// MARK: - Writer Assistance +auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void +{ + union simd_value v; + for (auto n = 0; n < simd_fields; ++n) { + v.fields[n] = (value << 16) | value; + } + inline_set(this, v, bytes, start); +} -auto graphite::data::data::resync_size() -> void +auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::position start) -> void { - m_size = m_data->size(); + union simd_value v; + for (auto n = 0; n < simd_fields; ++n) { + v.fields[n] = value; + } + inline_set(this, v, bytes, start); } +// MARK: - Slicing + +auto graphite::data::block::slice(block::position pos, std::size_t size, bool copy) const -> block +{ + return std::move(data(*this, pos, size, copy)); +} diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index 009c7aa..1874aed 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,97 +18,104 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#if !defined(GRAPHITE_DATA) -#define GRAPHITE_DATA +#pragma once +#include #include #include -#include #include -#include +#include +#include "libGraphite/data/endianess.hpp" namespace graphite::data { + struct block; - /** - * The byte order represents the endianness of a data value. - */ - enum byte_order : int { msb = 0, lsb = 1 }; + template + concept compressible_block = requires(const T& block, const data::block& uncompressed) { + { T::compress(uncompressed) } -> std::same_as; + }; + + template + concept decompressible_block = requires(const T& block, const data::block& compressed) { + { T::decompress(compressed) } -> std::same_as; + }; - /** - * The `graphite::data::data` class is used to store binary data in memory, - * and can be written to and read from disk. - */ - class data: public std::enable_shared_from_this + struct block { - private: - enum graphite::data::byte_order m_bo { msb }; - std::shared_ptr> m_data { nullptr }; - std::size_t m_start { 0 }; - std::size_t m_size { 0 }; + public: + typedef std::int64_t position; + +#if __x86_64__ + static constexpr std::size_t minimum_chunk_size = sizeof(unsigned __int128); +#elif __arm64__ + static constexpr std::size_t minimum_chunk_size = sizeof(uint64_t); +#else + static constexpr std::size_t minimum_chunk_size = sizeof(uint32_t); +#endif public: - /** - * Construct a new empty `graphite::data::data` object. - */ - explicit data(enum graphite::data::byte_order bo = msb); - - /** - * Construct a new `graphite::data::data` object with the specified capacity. - */ - explicit data(std::size_t capacity, enum graphite::data::byte_order bo = msb); - - /** - * Construct a new `graphite::data::data` object with the provided data. - */ - data(std::shared_ptr> bytes, std::size_t size, std::size_t start = 0, enum graphite::data::byte_order bo = msb); - - /** - * Calculate an offset within the receiver's data. - */ - auto relative_offset(int64_t offset) const -> int64_t; - - /** - * Returns the current size of the receiver. - */ - auto size() const -> std::size_t; - - /** - * Returns the start location of the receiver. - */ - auto start() const -> std::size_t; - - /** - * Returns the intended byte order of the receiver. - */ - auto current_byte_order() const -> enum graphite::data::byte_order; - - /** - * Set a new byte order for the receiver. - * - * Warning: This can cause corruption of values being read or written if the - * byte order is set incorrectly. - */ - auto set_byte_order(enum graphite::data::byte_order bo) -> void; - - /** - * Returns a pointer to the internal data vector of the receiver. - */ - auto get() -> std::shared_ptr>; - - /** - * Returns the element at the specified index. - */ - auto at(std::size_t offset) const -> char; - - /** - * Resync the size of the data from the internal data vector. This is required - * when attempting to read back data from a resource that has just been written to. - */ - auto resync_size() -> void; + block() = default; + explicit block(std::size_t capacity, enum byte_order order = byte_order::msb); + explicit block(const std::string& path, enum byte_order order = byte_order::msb); + block(const block& source, bool copy = true); + block(const block& source, block::position pos, std::size_t count, bool copy = true); - }; + block(const block& data); + block(block&& data); + + auto operator=(const block& data) -> struct block&; + auto operator=(block&& data) noexcept -> struct block&; + + ~block(); + + template::value>::type* = nullptr> + [[nodiscard]] inline auto get(block::position offset = 0) const -> T { return reinterpret_cast(get_offset_data(offset)); } + + template::value>::type* = nullptr> + [[nodiscard]] inline auto get(block::position offset = 0) const -> T { return swap(*get(offset), m_byte_order); } + template::value>::type* = nullptr> + [[nodiscard]] inline auto operator[] (block::position offset) const -> T + { + return get(offset); + } + + [[nodiscard]] inline auto raw_size() const -> std::size_t { return m_raw_size; } + [[nodiscard]] inline auto size() const -> std::size_t { return m_count > 0 ? m_count : m_data_size; } + [[nodiscard]] inline auto start() const -> block::position { return m_start_position; } + [[nodiscard]] inline auto byte_order() const -> byte_order { return m_byte_order; } + + auto change_byte_order(enum byte_order order) -> void { m_byte_order = order; } + + auto clear() -> void; + + auto set(uint8_t value, std::size_t bytes = 0, block::position start = 0) -> void; + auto set(uint16_t value, std::size_t bytes = 0, block::position start = 0) -> void; + auto set(uint32_t value, std::size_t bytes = 0, block::position start = 0) -> void; + + auto copy_from(const block& source) const -> void; + + [[nodiscard]] auto slice(block::position pos, std::size_t size, bool copy = false) const -> block; + + private: + enum byte_order m_byte_order { byte_order::msb }; + std::size_t m_raw_size { 0 }; + std::size_t m_data_size { 0 }; + block::position m_start_position { 0 }; + std::size_t m_count { 0 }; + void *m_raw { nullptr }; + void *m_data { nullptr }; + + const block *m_allocation_owner { nullptr }; + std::uint32_t m_users { 0 }; + + [[nodiscard]] inline auto get_offset_data(block::position offset) const -> void * + { + return reinterpret_cast(reinterpret_cast(m_data) + m_start_position + offset); + } + + auto clone_from(const graphite::data::block& source) -> void; + }; } -#endif diff --git a/libGraphite/data/encoding.hpp b/libGraphite/data/encoding.hpp new file mode 100644 index 0000000..dd31414 --- /dev/null +++ b/libGraphite/data/encoding.hpp @@ -0,0 +1,43 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/util/concepts.hpp" + +namespace graphite::data +{ + struct reader; + struct writer; + + template + concept encodable = requires(T& object, data::writer& writer) { + object.encode(writer); + }; + + template + concept decodable = requires(const T& object) { + requires constructible_from; + requires move_constructible; + }; + +} \ No newline at end of file diff --git a/libGraphite/data/endianess.hpp b/libGraphite/data/endianess.hpp new file mode 100644 index 0000000..8e2b2c9 --- /dev/null +++ b/libGraphite/data/endianess.hpp @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +namespace graphite::data +{ + // MARK: - Byte Order Enumeration + + enum class byte_order : uint8_t { msb, lsb }; + + + // MARK: - Compile Time Constants + +#if __LITTLE_ENDIAN__ + static graphite::data::byte_order s_native_byte_order = graphite::data::byte_order::lsb; +#else + static graphite::data::byte_order s_native_byte_order = graphite::data::byte_order::msb; +#endif + + static auto native_byte_order() -> enum byte_order + { + return s_native_byte_order; + } + + + // MARK: - Endian Swap Operations + + template::value>::type* = nullptr> + static auto swap(T value, byte_order from_byte_order, byte_order to_byte_order = native_byte_order(), std::size_t size = sizeof(T)) -> T + { + if (from_byte_order == to_byte_order) { + return value; + } + + T v = 0; + + for (auto i = 0; i < size; ++i) { + auto b = (size - i - 1) << 3ULL; + v |= ((value >> b) & 0xFF) << (i << 3ULL); + } + + return v; + } +} \ No newline at end of file diff --git a/libGraphite/data/reader.cpp b/libGraphite/data/reader.cpp index 153fce6..4cb9c84 100644 --- a/libGraphite/data/reader.cpp +++ b/libGraphite/data/reader.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,267 +18,212 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include +#include +#include +#include +#include #include "libGraphite/data/reader.hpp" -#include "libGraphite/data/data.hpp" +#include "libGraphite/data/endianess.hpp" #include "libGraphite/encoding/macroman/macroman.hpp" -#include -#include -#include -// MARK: - Constructor +// MARK: - Construction -graphite::data::reader::reader(const std::string& path) +graphite::data::reader::reader(const class block *data, block::position pos, bool owns) + : m_data(data), + m_owns_data(owns), + m_position(pos) { - // Attempt to open the file, and throw and exception if we failed to do so. - std::ifstream file(path, std::ios::binary); - if (!file.is_open() || file.fail()) { - throw std::runtime_error("Failed to open resource file: " + path); - } - - // Make sure we don't skip newlines. - file.unsetf(std::ios::skipws); - - // Get the size of the file. - file.seekg(0UL, std::ios::end); - auto file_size = file.tellg(); - file.seekg(0UL, std::ios::beg); - - // Read the contents of the file into the vector. - auto data = std::make_shared>(file_size); - file.read(&(*data)[0], file_size); - m_data = std::make_shared(data, file_size, graphite::data::byte_order::msb); - - // Close the file and clean up. - file.close(); } -graphite::data::reader::reader(std::shared_ptr data, uint64_t pos) - : m_data(std::move(data)), m_pos(pos) +auto graphite::data::reader::file(const std::string &path, block::position pos) -> reader { - + auto data = new class block(path, byte_order::msb); + return std::move(reader(data, pos, true)); } -// MARK: - Byte Order - -template::value>::type*> -auto graphite::data::reader::swap( - T value, - enum graphite::data::byte_order value_bo, - enum graphite::data::byte_order result_bo, - uint64_t size -) -> T { - // Return the value immediately if the value byte order matches the result byte order. - if (value_bo == result_bo) { - return value; - } - - T v = 0; - size = size == -1 ? sizeof(T) : size; - - for (decltype(size) i = 0; i < size; ++i) { - auto b = (size - i - 1) << 3ULL; - v |= ((value >> b) & 0xFF) << (i << 3ULL); - } - - return v; -} +// MARK: - Destruction - -// MARK: - Internal Data - -auto graphite::data::reader::get() -> std::shared_ptr -{ - return m_data; -} - -// MARK: - Size - -auto graphite::data::reader::size() const -> std::size_t -{ - return m_data->size(); -} - -// MARK: - Position - -auto graphite::data::reader::eof() const -> bool +graphite::data::reader::~reader() { - return (m_pos >= m_data->size()); + if (m_owns_data) { + delete m_data; + } } -auto graphite::data::reader::position() const -> uint64_t -{ - return m_pos; -} +// MARK: - Position Management -auto graphite::data::reader::set_position(uint64_t pos) -> void +auto graphite::data::reader::set_position(block::position pos) -> void { - m_pos = pos; + if (pos < 0 || pos > size()) { + throw std::runtime_error("Attempted to set position of data reader out of bounds."); + } + m_position = pos; } -auto graphite::data::reader::move(int64_t delta) -> void +auto graphite::data::reader::move(block::position delta) -> void { - // TODO: Bounds checking - m_pos += delta; + set_position(position() + delta); } auto graphite::data::reader::save_position() -> void { - m_pos_stack.push_back(m_pos); + m_position_stack.emplace_back(m_position); } auto graphite::data::reader::restore_position() -> void { - if (m_pos_stack.empty()) { - throw std::logic_error("Attempted to restore reader position that did not exist."); + if (m_position_stack.empty()) { + throw std::runtime_error("Attempted to restore position of data reader, when no saved positions exist."); } - m_pos = m_pos_stack.back(); - m_pos_stack.pop_back(); + set_position(m_position_stack.back()); + m_position_stack.pop_back(); } -// MARK: - Template Read +// MARK: - Read Operations template::value>::type*> -auto graphite::data::reader::read_integer(int64_t offset, graphite::data::reader::mode mode, uint64_t size) -> T +auto graphite::data::reader::read_integer(block::position offset, mode mode, std::size_t size) -> T { T v = 0; - size = size == -1 ? sizeof(T) : size; if (size <= 0 || size > sizeof(T)) { - throw std::logic_error("Invalid integer read size specified."); + throw std::runtime_error("Invalid integer size specified in data reader."); } - - if (m_data->get() == nullptr) { - throw std::runtime_error("Invalid data being read from."); - } - - for (decltype(size) i = 0; i < size; ++i) { - auto b = static_cast(m_data->at(m_pos + offset + i)); + + for (block::position i = 0; i < size; ++i) { + auto b = m_data->template operator[](m_position + offset + i); v |= static_cast(b) << (i << 3ULL); } - + if (size > 1) { - v = swap(v, m_data->current_byte_order(), m_native_bo, size); + v = swap(v, m_data->byte_order(), native_byte_order(), size); } - - if (mode == graphite::data::reader::mode::advance) { + + if (mode == mode::advance) { move(offset + size); } - + return v; } -// MARK: - Read Integer Functions +template::value>::type*> +auto graphite::data::reader::read_enum(block::position offset, mode mode, std::size_t size) -> E +{ + return read_integer(offset, mode, size); +} -auto graphite::data::reader::read_byte(int64_t offset, graphite::data::reader::mode mode) -> uint8_t +auto graphite::data::reader::read_byte(block::position offset, mode mode) -> uint8_t { return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_byte(int64_t offset, graphite::data::reader::mode mode) -> int8_t +auto graphite::data::reader::read_signed_byte(block::position offset, mode mode) -> int8_t { - return static_cast(read_byte(offset, mode)); + return read_integer(offset, mode); } -auto graphite::data::reader::read_short(int64_t offset, graphite::data::reader::mode mode) -> uint16_t +auto graphite::data::reader::read_short(block::position offset, mode mode) -> uint16_t { return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_short(int64_t offset, graphite::data::reader::mode mode) -> int16_t +auto graphite::data::reader::read_signed_short(block::position offset, mode mode) -> int16_t { - return static_cast(read_short(offset, mode)); + return read_integer(offset, mode); } -auto graphite::data::reader::read_triple(int64_t offset, graphite::data::reader::mode mode) -> uint32_t +auto graphite::data::reader::read_fixed_point(block::position offset, mode mode) -> double +{ + return static_cast(read_signed_long(offset, mode)) / static_cast(1 << 16); +} + +auto graphite::data::reader::read_triple(block::position offset, mode mode) -> uint32_t { return read_integer(offset, mode, 3); } -auto graphite::data::reader::read_long(int64_t offset, graphite::data::reader::mode mode) -> uint32_t +auto graphite::data::reader::read_long(block::position offset, mode mode) -> uint32_t { return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_long(int64_t offset, graphite::data::reader::mode mode) -> int32_t +auto graphite::data::reader::read_signed_long(block::position offset, mode mode) -> int32_t { - return static_cast(read_long(offset, mode)); + return read_integer(offset, mode); } -auto graphite::data::reader::read_quad(int64_t offset, graphite::data::reader::mode mode) -> uint64_t +auto graphite::data::reader::read_quad(block::position offset, mode mode) -> uint64_t { return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_quad(int64_t offset, graphite::data::reader::mode mode) -> int64_t +auto graphite::data::reader::read_signed_quad(block::position offset, mode mode) -> int64_t { - return static_cast(read_quad(offset, mode)); + return read_integer(offset, mode); } -// MARK: - Read String Functions - -auto graphite::data::reader::read_cstr(int64_t size, int64_t offset, graphite::data::reader::mode mode) -> std::string +auto graphite::data::reader::read_pstr(block::position offset, mode mode) -> std::string { - if (size == -1) { - // Read until a NUL byte is encountered. This is the slowest form of - // read, and will required stepping through bytes one by one. - auto vec = std::vector(0); - auto i = 0; - while (m_data->at(m_pos + offset + i)) { - vec.push_back(static_cast(m_data->at(m_pos + offset + i++))); + switch (mode) { + case mode::advance: { + auto length = read_byte(offset, mode); + return read_cstr(length, 0, mode); } - - if (mode == reader::mode::advance) { - m_pos += offset + vec.size() + 1; + case mode::peek: { + auto length = read_byte(offset, mode); + return read_cstr(length, offset + 1, mode); } - - return graphite::encoding::mac_roman::to_utf8(vec); - } - else { - // Read a fixed chunk of memory and convert it to a string. - auto data = read_bytes(size, offset, mode); - std::vector bytes(data.begin(), data.end()); - while (!bytes.empty() && bytes.back() == 0) { - bytes.pop_back(); + default: { + return ""; } - return graphite::encoding::mac_roman::to_utf8(bytes); } } -auto graphite::data::reader::read_pstr(int64_t offset, graphite::data::reader::mode mode) -> std::string +auto graphite::data::reader::read_cstr(std::size_t length, block::position offset, mode mode) -> std::string { - switch (mode) { - case advance: { - auto length = read_byte(offset, advance); - return read_cstr(length, 0, advance); - } - - case peek: { - auto length = read_byte(offset, peek); - return read_cstr(length, offset + 1, peek); + std::vector bytes; + + if (length == 0) { + block::position i = 0; + while (read_byte(offset + i, mode::peek)) { + bytes.push_back(read_byte(offset + i++, mode::peek)); } - default: { - return ""; + if (mode == mode::advance) { + move(offset + bytes.size() + 1); + } + } + else { + auto data = std::move(read_bytes(length, offset, mode)); + for (const auto& byte : data) { + if (byte == '\0') { + break; + } + bytes.emplace_back(static_cast(byte)); } } -} -// MARK: - Read Data Functions + return encoding::mac_roman::to_utf8(bytes); +} -auto graphite::data::reader::read_data(int64_t size, int64_t offset, graphite::data::reader::mode mode) -> std::shared_ptr +auto graphite::data::reader::read_data(std::size_t length, block::position offset, mode mode) -> class block { - auto data = std::make_shared(m_data->get(), size, m_data->start() + m_pos + offset); - move(offset + size); - return data; + auto sliced = std::move(m_data->slice(m_position + offset, length)); + if (mode == mode::advance) { + move(offset + length); + } + return std::move(sliced); } -auto graphite::data::reader::read_bytes(int64_t size, int64_t offset, graphite::data::reader::mode mode) -> std::vector +auto graphite::data::reader::read_bytes(std::size_t length, block::position offset, mode mode) -> std::vector { - char *start = &(*m_data->get())[m_data->relative_offset(m_pos + offset)]; - char *end = &(*m_data->get())[m_data->relative_offset(m_pos + offset + size)]; - - if (mode == graphite::data::reader::mode::advance) { - m_pos += offset + size; + auto start = m_data->get(m_position + offset); + auto end = m_data->get(m_position + offset + length); + move(offset + length); + + std::vector bytes(std::max(length, static_cast(28)), '\0'); + for (auto idx = 0; idx < length; ++idx) { + bytes[idx] = start[idx]; } - - return std::vector(start, end); -} + return std::move(bytes); +} \ No newline at end of file diff --git a/libGraphite/data/reader.hpp b/libGraphite/data/reader.hpp index 261b8de..493b6e3 100644 --- a/libGraphite/data/reader.hpp +++ b/libGraphite/data/reader.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,180 +18,134 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#if !defined(GRAPHITE_DATA_READER) -#define GRAPHITE_DATA_READER +#pragma once -#include +#include +#include #include "libGraphite/data/data.hpp" +#include "libGraphite/util/concepts.hpp" +#include "libGraphite/data/encoding.hpp" -namespace graphite::data { +namespace graphite::data +{ + class reader; + + template + concept readable_resource_type = resource_type && decodable; -/** - * The `graphite::data::reader` class is used to read values from a - * `graphite::data::data` object. - */ class reader { public: - /** - * The reading mode of the receiver. - * - * ::peek - peek at a value at the specified offset from the current - * position, without affecting the current position. - * ::advance - advance the current position after reading the value at - * the specified offset from the current position. - */ - enum mode { advance, peek }; + enum class mode { advance, peek }; - private: - graphite::data::byte_order m_native_bo { lsb }; - std::shared_ptr m_data { nullptr }; - std::vector m_pos_stack; - uint64_t m_pos { 0 }; + public: + explicit reader(const class block *data, block::position pos = 0, bool owns = false); + ~reader(); - template::value>::type* = nullptr> - auto read_integer(int64_t offset, reader::mode mode = advance, uint64_t size = -1) -> T; + static auto file(const std::string& path, block::position pos = 0) -> reader; - /** - * Swap the bytes of an integer value from the source byte order to the specified - * destination byte order. - */ - template::value>::type* = nullptr> - auto swap( - T value, - enum graphite::data::byte_order value_bo, - enum graphite::data::byte_order result_bo, - uint64_t size = -1 - ) -> T; + [[nodiscard]] inline auto data() const -> const class block * { return m_data; } + [[nodiscard]] inline auto owns_data() const -> bool { return m_owns_data; } - public: + [[nodiscard]] inline auto position() const -> block::position { return m_position; } + [[nodiscard]] inline auto size() const -> std::size_t { return m_data->size(); } + [[nodiscard]] inline auto eof() const -> bool { return position() >= size(); } + [[nodiscard]] inline auto byte_order() const -> byte_order { return m_data->byte_order(); } - /** - * Construct a new `graphite::data::reader` object using the data in - * the specified file. - */ - explicit reader(const std::string& path); - - /** - * Construct a new `graphite::data::reader` object using the - * specified `graphite::data::data` object, constraining the available - * read region of the data. - */ - explicit reader(std::shared_ptr data, uint64_t pos = 0); - - /** - * Returns a shared copy of the raw data being used by the data slice. - */ - auto get() -> std::shared_ptr; - - /** - * Returns the current size of the underlying `graphite::data::data` object - * being referenced by the reader. - * - * Note: This size will be the _constrained_ size, if the reader was - * constrained. - */ - [[nodiscard]] auto size() const -> std::size_t; - - /** - * Reports if the position of the receiver is at or past the end of the - * the underlying data. - */ - [[nodiscard]] auto eof() const -> bool; - - /** - * Reports the current position of the receiver relative to its own - * constraints. - */ - [[nodiscard]] auto position() const -> uint64_t; - - /** - * Set the position of the receiver, relative to its own constraints. - */ - auto set_position(uint64_t pos) -> void; - - /** - * Move the current position of the receiver by the specified amount. - */ - auto move(int64_t delta = 1) -> void; - - /** - * Read a single unsigned byte from data. - */ - auto read_byte(int64_t offset = 0, reader::mode mode = advance) -> uint8_t; - - /** - * Read a single signed byte from data. - */ - auto read_signed_byte(int64_t offset = 0, reader::mode mode = advance) -> int8_t; - - /** - * Read a single unsigned short from data. - */ - auto read_short(int64_t offset = 0, reader::mode mode = advance) -> uint16_t; - - /** - * Read a single signed short from data. - */ - auto read_signed_short(int64_t offset = 0, reader::mode mode = advance) -> int16_t; - - /** - * Read a single unsigned triple from data. (3 bytes) - */ - auto read_triple(int64_t offset = 0, reader::mode mode = advance) -> uint32_t; - - /** - * Read a single unsigned long from data. - */ - auto read_long(int64_t offset = 0, reader::mode mode = advance) -> uint32_t; - - /** - * Read a single signed long from data. - */ - auto read_signed_long(int64_t offset = 0, reader::mode mode = advance) -> int32_t; - - /** - * Read a single unsigned quad from data. - */ - auto read_quad(int64_t offset = 0, reader::mode mode = advance) -> uint64_t; - - /** - * Read a single signed quad from data. - */ - auto read_signed_quad(int64_t offset = 0, reader::mode mode = advance) -> int64_t; - - /** - * Read a C-String from data. - */ - auto read_cstr(int64_t size = -1, int64_t offset = 0, reader::mode mode = advance) -> std::string; - - /** - * Read a Pascal String from data. - */ - auto read_pstr(int64_t offset = 0, reader::mode mode = advance) -> std::string; - - /** - * Read a chunk of data from the source data. - */ - auto read_data(int64_t size, int64_t offset = 0, reader::mode mode = advance) -> std::shared_ptr; - - /** - * Read a series of bytes from the source data. - */ - auto read_bytes(int64_t size, int64_t offset = 0, reader::mode mode = advance) -> std::vector; - - /** - * Save the current position of the reader. - */ - auto save_position() -> void; + auto change_byte_order(enum byte_order order) -> void { const_cast(m_data)->change_byte_order(order); } + + auto set_position(block::position pos) -> void; + auto move(block::position delta = 1) -> void; - /** - * Restore a previous position of the reader. - */ + auto save_position() -> void; auto restore_position() -> void; + template::value && std::is_signed::value>> + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> T { return 0; } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::int8_t { return read_signed_byte(offset, mode); } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::int16_t { return read_signed_short(offset, mode); } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::int32_t { return read_signed_long(offset, mode); } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::int64_t { return read_signed_quad(offset, mode); } + + template::value>> + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> T { return 0; } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::uint8_t { return read_byte(offset, mode); } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::uint16_t { return read_short(offset, mode); } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::uint32_t { return read_long(offset, mode); } + + template + auto read_integer(block::position offset = 0, mode mode = mode::advance) -> std::uint64_t { return read_quad(offset, mode); } + + auto read_byte(block::position offset = 0, mode mode = mode::advance) -> uint8_t; + auto read_signed_byte(block::position offset = 0, mode mode = mode::advance) -> int8_t; + + auto read_short(block::position offset = 0, mode mode = mode::advance) -> uint16_t; + auto read_signed_short(block::position offset = 0, mode mode = mode::advance) -> int16_t; + + auto read_fixed_point(block::position offset = 0, mode mode = mode::advance) -> double; + + auto read_triple(block::position offset = 0, mode mode = mode::advance) -> uint32_t; + + auto read_long(block::position offset = 0, mode mode = mode::advance) -> uint32_t; + auto read_signed_long(block::position offset = 0, mode mode = mode::advance) -> int32_t; + + auto read_quad(block::position offset = 0, mode mode = mode::advance) -> uint64_t; + auto read_signed_quad(block::position offset = 0, mode mode = mode::advance) -> int64_t; + + auto read_cstr(std::size_t length = 0, block::position offset = 0, mode mode = mode::advance) -> std::string; + auto read_pstr(block::position offset = 0, mode mode = mode::advance) -> std::string; + + auto read_data(std::size_t length, block::position offset = 0, mode mode = mode::advance) -> class block; + auto read_bytes(std::size_t length, block::position offset = 0, mode mode = mode::advance) -> std::vector; + + template + auto read(block::position offset = 0, mode mode = mode::advance) -> T + { + if (mode == mode::peek) { + save_position(); + } + + move(offset); + auto object = T(*this); + + if (mode == mode::peek) { + restore_position(); + } + + return std::move(object); + } + + template + auto read_compressed_data(std::size_t length, block::position offset = 0, mode mode = mode::advance) -> class block + { + return T::decompress(std::move(read_data(length, offset, mode))); + } + + template::value>::type* = nullptr> + auto read_integer(block::position offset = 0, mode mode = mode::advance, std::size_t size = sizeof(T)) -> T; + + template::value>::type* = nullptr> + auto read_enum(block::position offset = 0, mode mode = mode::advance, std::size_t size = sizeof(E)) -> E; + + private: + bool m_owns_data { false }; + const class block *m_data { nullptr }; + std::vector m_position_stack; + block::position m_position; }; } - -#endif diff --git a/libGraphite/data/writer.cpp b/libGraphite/data/writer.cpp index c21db15..d8427a2 100644 --- a/libGraphite/data/writer.cpp +++ b/libGraphite/data/writer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,225 +18,234 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include +#include +#include #include "libGraphite/data/writer.hpp" -#include "libGraphite/data/data.hpp" #include "libGraphite/encoding/macroman/macroman.hpp" -#include -#include -#include -// MARK: - Constructors +// MARK: - Construction -graphite::data::writer::writer() - : m_data(std::make_shared()) +graphite::data::writer::writer(enum byte_order order) + : m_owns_data(true), + m_data(new class block(0, order)) { - + } -graphite::data::writer::writer(std::shared_ptr data) - : m_data(std::move(data)) +graphite::data::writer::writer(const class block *data) + : m_owns_data(false), + m_data(data) { - + } -// MARK: - Byte Order +// MARK: - Destruction -template::value>::type*> -auto graphite::data::writer::swap( - T value, - enum graphite::data::byte_order value_bo, - enum graphite::data::byte_order result_bo -) -> T { - // Return the value immediately if the value byte order matches the result byte order. - if (value_bo == result_bo) { - return value; - } - - T v = 0; - unsigned int size = sizeof(T); - - for (unsigned int i = 0; i < size; ++i) { - auto b = (size - i - 1) << 3U; - v |= ((value >> b) & 0xFF) << (i << 3U); +graphite::data::writer::~writer() +{ + if (m_owns_data) { + delete m_data; } - - return v; } -// MARK: - Data +// MARK: - Storage Management -auto graphite::data::writer::data() -> std::shared_ptr +auto graphite::data::writer::expand_storage(std::size_t amount) -> void { - return m_data; -} + // NOTE: We only allow resizing of data objects that we own. + assert(m_owns_data); -// MARK: - Size + // Construct a new data object with the appropriate new size, and copy in the old data. + auto required_size = size() + amount; + auto new_data = new class block(required_size, m_data->byte_order()); + new_data->set(static_cast(0), required_size); + new_data->copy_from(*m_data); -auto graphite::data::writer::size() const -> std::size_t -{ - return m_data->size(); + // Replace the old data with the new object. + delete m_data; + m_data = new_data; } -// MARK: - Position - -auto graphite::data::writer::position() const -> uint64_t +auto graphite::data::writer::ensure_required_space(block::position position, std::size_t amount) -> void { - return m_pos; + auto remaining = static_cast(this->size()) - position; + auto delta = amount; + if (amount > remaining) { + delta -= remaining; + } + expand_storage(delta); } -auto graphite::data::writer::set_position(uint64_t pos) -> void +// MARK: - Position Management + +auto graphite::data::writer::set_position(block::position pos) -> void { - m_pos = pos; + if (pos < 0 || pos > size()) { + throw std::runtime_error("Attempted to set position of data reader out of bounds."); + } + m_position = pos; } -auto graphite::data::writer::move(int64_t delta) -> void +auto graphite::data::writer::move(block::position delta) -> void { - // TODO: Bounds checking - m_pos += delta; + set_position(m_position + delta); } -// MARK: - Template Write +// MARK: - Write Operations template::value>::type*> -auto graphite::data::writer::write_integer(T value) -> void -{ - unsigned int size = sizeof(T); - auto swapped = swap(value, m_native_bo, m_data->current_byte_order()); - auto data = m_data->get(); - - for (unsigned int i = 0; i < size; ++i) { - auto b = i << 3U; - - // Two modes for writing. If we're at the very end of data then we need to insert. - // If we're not at the end of the data then we can either overwrite the current byte - // or insert a new byte. - if (m_pos >= data->size()) { - data->push_back((swapped >> b) & 0xFF); - m_pos++; - } - else { - (*data)[m_pos++] = (swapped >> b) & 0xFF; +auto graphite::data::writer::write_integer(T value, std::size_t count, std::size_t size) -> void +{ + auto swapped = swap(value, native_byte_order(), m_data->byte_order()); + + ensure_required_space(position(), size * count); + auto ptr = m_data->template get(position()); + + for (auto n = 0; n < count; ++n) { + for (auto i = 0; i < size; ++i) { + auto b = i << 3ULL; + *ptr++ = (swapped >> b) & 0xFF; + move(); } } - - m_data->resync_size(); } +template::value>::type*> +auto graphite::data::writer::write_enum(E value, std::size_t count, std::size_t size) -> E +{ + return write_integer(value, count, size); +} -// MARK: - Write Integer Functions auto graphite::data::writer::write_byte(uint8_t value, std::size_t count) -> void { - for (auto i = 0; i < count; ++i) { - write_integer(value); - } + write_integer(value, count); } -auto graphite::data::writer::write_signed_byte(int8_t value) -> void +auto graphite::data::writer::write_signed_byte(int8_t value, std::size_t count) -> void { - write_byte(static_cast(value)); + write_integer(static_cast(value), count); } -auto graphite::data::writer::write_short(uint16_t value) -> void +auto graphite::data::writer::write_short(uint16_t value, std::size_t count) -> void { - write_integer(value); + write_integer(value, count); } -auto graphite::data::writer::write_signed_short(int16_t value) -> void +auto graphite::data::writer::write_signed_short(int16_t value, std::size_t count) -> void { - write_short(static_cast(value)); -} + write_integer(static_cast(value), count); +}; -auto graphite::data::writer::write_long(uint32_t value) -> void +auto graphite::data::writer::write_fixed_point(double value, std::size_t count) -> void { - write_integer(value); + auto integral_value = static_cast(value * (1 << 16)); + write_integer(integral_value, count); } -auto graphite::data::writer::write_signed_long(int32_t value) -> void +auto graphite::data::writer::write_triple(uint32_t value, std::size_t count) -> void { - write_long(static_cast(value)); -} + write_integer(value, count, 3); +}; -auto graphite::data::writer::write_quad(uint64_t value) -> void +auto graphite::data::writer::write_long(uint32_t value, std::size_t count) -> void { - write_integer(value); -} + write_integer(value, count); +}; + +auto graphite::data::writer::write_signed_long(int32_t value, std::size_t count) -> void +{ + write_integer(static_cast(value), count); +}; -auto graphite::data::writer::write_signed_quad(int64_t value) -> void +auto graphite::data::writer::write_quad(uint64_t value, std::size_t count) -> void { - write_quad(static_cast(value)); + write_integer(value, count); +}; + +auto graphite::data::writer::write_signed_quad(int64_t value, std::size_t count) -> void +{ + write_integer(static_cast(value), count); } -// MARK: - Write Strings +auto graphite::data::writer::write_pstr(const std::string &str) -> std::size_t +{ + auto bytes = encoding::mac_roman::from_utf8(str); + + if (bytes.size() > 0xFF) { + bytes.resize(0xFF); + } -auto graphite::data::writer::write_cstr(const std::string& str, std::size_t size) -> void + write_byte(static_cast(bytes.size())); + write_bytes(bytes); + return bytes.size(); +} + +auto graphite::data::writer::write_cstr(const std::string &str, std::size_t size) -> std::size_t { - std::vector bytes; - + std::vector bytes { encoding::mac_roman::from_utf8(str) }; + if (size == 0) { - // NUL Terminated C-String. - bytes = graphite::encoding::mac_roman::from_utf8(str); - bytes.push_back(0); + // NULL terminated C-String + bytes.push_back( '\0' ); } else { // Fixed length C-String - bytes = graphite::encoding::mac_roman::from_utf8(str); - bytes.resize(size, 0x00); + bytes.resize(size, '\0'); } - + write_bytes(bytes); + return bytes.size(); } -auto graphite::data::writer::write_pstr(const std::string& str) -> void +auto graphite::data::writer::write_bytes(const std::vector &bytes) -> void { - auto bytes = graphite::encoding::mac_roman::from_utf8(str); - - if (bytes.size() > 0xFF) { - bytes.resize(0xFF); + ensure_required_space(position(), bytes.size()); + auto ptr = m_data->template get(position()); + + for (auto v : bytes) { + *ptr++ = v; + move(); } - auto size = static_cast(bytes.size()); - write_byte(static_cast(size)); - write_bytes(bytes); } -// MARK: - Write Bytes - - auto graphite::data::writer::write_bytes(const std::vector& bytes) -> void +auto graphite::data::writer::write_bytes(const std::vector &bytes) -> void { - std::vector converted_bytes(bytes.begin(), bytes.end()); - write_bytes(converted_bytes); + write_bytes(std::move(std::vector(bytes.begin(), bytes.end()))); } - auto graphite::data::writer::write_bytes(const std::vector& bytes) -> void +auto graphite::data::writer::write_data(const class block *data) -> void { - auto vec = m_data->get(); - vec->insert(vec->end(), bytes.begin(), bytes.end()); - m_pos += bytes.size(); - m_data->resync_size(); -} + assert(data != m_data); -auto graphite::data::writer::write_data(const std::shared_ptr& data) -> void -{ - auto bytes = data->get(); - auto vec = m_data->get(); - vec->insert(vec->end(), bytes->begin() + data->start(), bytes->begin() + data->start() + data->size()); - m_pos += data->size(); - m_data->resync_size(); + ensure_required_space(position(), data->size()); + auto ptr = m_data->template get(position()); + + for (auto i = 0; i < data->size(); ++i) { + ptr[i] = *data->get(i); + move(); + } } +// MARK: - Padding + auto graphite::data::writer::pad_to_size(std::size_t size) -> void { - while (m_data->size() < size) { - write_byte(0); + if (this->size() >= size) { + return; } + + auto required = size - this->size(); + set_position(this->size()); + write_byte(0, required); } -// MARK: - Saving +// MARK: - Saving / File Access -auto graphite::data::writer::save(const std::string& path) const -> void +auto graphite::data::writer::save(const std::string &path, std::size_t size) const -> void { - std::ofstream f(path, std::ios::out | std::ios::binary); - auto data = m_data->get()->data(); - f.write(data, m_data->size()); - f.close(); -} + std::ofstream file { path, std::ios::out | std::ios::binary }; + file.write(m_data->get(), size == 0 ? m_data->size() : size); + file.close(); +} \ No newline at end of file diff --git a/libGraphite/data/writer.hpp b/libGraphite/data/writer.hpp index f65de60..7d6a72e 100644 --- a/libGraphite/data/writer.hpp +++ b/libGraphite/data/writer.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,153 +18,119 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include "libGraphite/data/data.hpp" - -#if !defined(GRAPHITE_DATA_WRITER) -#define GRAPHITE_DATA_WRITER +#pragma once -namespace graphite::data { +#include +#include +#include "libGraphite/data/data.hpp" +#include "libGraphite/util/concepts.hpp" +#include "libGraphite/data/encoding.hpp" -/** - * The `graphite::data::writer` class is used to write values into a - * `graphite::data::data` object. - */ +namespace graphite::data +{ class writer { - private: - graphite::data::byte_order m_native_bo { lsb }; - std::shared_ptr m_data { nullptr }; - uint64_t m_pos { 0 }; + public: + explicit writer(enum byte_order order = native_byte_order()); + explicit writer(const class block *data); - template::value>::type* = nullptr> - auto write_integer(T value) -> void; + ~writer(); - /** - * Swap the bytes of an integer value from the source byte order to the specified - * destination byte order. - */ - template::value>::type* = nullptr> - auto swap( - T value, - enum graphite::data::byte_order value_bo, - enum graphite::data::byte_order result_bo - ) -> T; + [[nodiscard]] inline auto data() const -> const class data * { return m_data; }; + [[nodiscard]] inline auto owns_data() const -> bool { return m_owns_data; } + + [[nodiscard]] inline auto position() const -> block::position { return m_position; } + [[nodiscard]] inline auto size() const -> std::size_t { return m_data->size(); } + + auto change_byte_order(enum byte_order order) -> void { const_cast(m_data)->change_byte_order(order); } + + auto expand_storage(std::size_t amount) -> void; + auto ensure_required_space(block::position position, std::size_t amount) -> void; + + auto set_position(block::position pos) -> void; + auto move(block::position delta = 1) -> void; + + template::value && std::is_signed::value>> + auto write_integer(T value, std::size_t count = 1) -> void { } + + template + auto write_integer(std::int8_t value, std::size_t count = 1) -> void { write_signed_byte(value, count); } + + template + auto write_integer(std::int16_t value, std::size_t count = 1) -> void { write_signed_short(value, count); } + + template + auto write_integer(std::int32_t value, std::size_t count = 1) -> void { write_signed_long(value, count); } + + template + auto write_integer(std::int64_t value, std::size_t count = 1) -> void { write_signed_quad(value, count); } + + template::value>> + + auto write_integer(T value, std::size_t count = 1) -> void { } + + template + auto write_integer(std::uint8_t value, std::size_t count = 1) -> void { write_byte(value, count); } + + template + auto write_integer(std::uint16_t value, std::size_t count = 1) -> void { write_short(value, count); } + + template + auto write_integer(std::uint32_t value, std::size_t count = 1) -> void { write_long(value, count); } + + template + auto write_integer(std::uint64_t value, std::size_t count = 1) -> void { write_quad(value, count); } + + auto write_byte(std::uint8_t value, std::size_t count = 1) -> void; + auto write_signed_byte(std::int8_t value, std::size_t count = 1) -> void; + + auto write_short(std::uint16_t value, std::size_t count = 1) -> void; + auto write_signed_short(std::int16_t value, std::size_t count = 1) -> void; + + auto write_fixed_point(double value, std::size_t count = 1) -> void; + + auto write_triple(std::uint32_t value, std::size_t count = 1) -> void; + + auto write_long(std::uint32_t value, std::size_t count = 1) -> void; + auto write_signed_long(std::int32_t value, std::size_t count = 1) -> void; + + auto write_quad(std::uint64_t value, std::size_t count = 1) -> void; + auto write_signed_quad(std::int64_t value, std::size_t count = 1) -> void; + + auto write_pstr(const std::string& str) -> std::size_t; + auto write_cstr(const std::string& str, std::size_t size = 0) -> std::size_t; - public: - /** - * Construct a new `graphite::data::writer` object and the underlying - * `graphite::data::data` object. - */ - writer(); - - /** - * Construct a new `graphite::data::writer` object using the specified - * `graphite::data::data` object. - */ - explicit writer(std::shared_ptr data); - - /** - * Returns the internal data object. - */ - auto data() -> std::shared_ptr; - - /** - * Returns the current size of the underlying `graphite::data::data:: object. - */ - [[nodiscard]] auto size() const -> std::size_t; - - /** - * Returns the current insertion position of the receiver within the underlying - * `graphite::data::data` object. - */ - [[nodiscard]] auto position() const -> uint64_t; - - /** - * Set the insertion position of the receiver within the underlying - * `graphite::data::data` object. - */ - auto set_position(uint64_t pos) -> void; - - /** - * Move the current insertion position of the receiver by the specified amount. - */ - auto move(int64_t delta = 1) -> void; - - /** - * Write a single unsigned byte into the data. - */ - auto write_byte(uint8_t value, std::size_t count = 1) -> void; - - /** - * Write a singled signed byte into the data. - */ - auto write_signed_byte(int8_t value) -> void; - - /** - * Write a single unsigned short into the data. - */ - auto write_short(uint16_t value) -> void; - - /** - * Write a singled signed short into the data. - */ - auto write_signed_short(int16_t value) -> void; - - /** - * Write a single unsigned long into the data. - */ - auto write_long(uint32_t value) -> void; - - /** - * Write a singled signed long into the data. - */ - auto write_signed_long(int32_t value) -> void; - - /** - * Write a single unsigned quad into the data. - */ - auto write_quad(uint64_t value) -> void; - - /** - * Write a singled signed quad into the data. - */ - auto write_signed_quad(int64_t value) -> void; - - /** - * Write a C-String into the data. - */ - auto write_cstr(const std::string& str, std::size_t size = 0) -> void; - - /** - * Write a Pascal String into the data. - */ - auto write_pstr(const std::string& str) -> void; - - /** - * Write a series of bytes into the data. - */ auto write_bytes(const std::vector& bytes) -> void; auto write_bytes(const std::vector& bytes) -> void; - /** - * Write the specified `graphite::data::data` object into the output - * data stream. - */ - auto write_data(const std::shared_ptr& data) -> void; + auto write_data(const class block *data) -> void; + + template + auto write_compressed_data(const class block *data) -> class block + { + return T::compress(data); + } + + template + auto write(T& value) -> void + { + value.encode(*this); + } - /** - * Pad the contents of the underlying data object to the specified number of bytes. - */ auto pad_to_size(std::size_t size) -> void; - /** - * Write the contents of the data to the specified file. - */ - auto save(const std::string& path) const -> void; + auto save(const std::string& path, std::size_t size = 0) const -> void; - }; + template::value>::type* = nullptr> + auto write_integer(T value, std::size_t count = 1, std::size_t size = sizeof(T)) -> void; + + template::value>::type* = nullptr> + auto write_enum(E value, std::size_t count = 1, std::size_t size = sizeof(E)) -> E; + private: + bool m_owns_data { false }; + const class block *m_data { nullptr }; + block::position m_position { 0 }; + }; } -#endif diff --git a/libGraphite/hints.hpp b/libGraphite/hints.hpp index c7d0272..1874311 100644 --- a/libGraphite/hints.hpp +++ b/libGraphite/hints.hpp @@ -2,13 +2,10 @@ // Created by Tom Hancocks on 24/03/2020. // -#if !defined(GRAPHITE_HINTS_HPP) -#define GRAPHITE_HINTS_HPP +#pragma once #if _MSC_VER # define GRAPHITE_UNUSED #else # define GRAPHITE_UNUSED __attribute__((unused)) #endif - -#endif diff --git a/libGraphite/quickdraw/format/cicn.cpp b/libGraphite/quickdraw/format/cicn.cpp new file mode 100644 index 0000000..33be7c5 --- /dev/null +++ b/libGraphite/quickdraw/format/cicn.cpp @@ -0,0 +1,194 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include "libGraphite/quickdraw/format/cicn.hpp" +#include "libGraphite/quickdraw/support/drawing/monochrome.hpp" +#include "libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp" +#include "libGraphite/quickdraw/support/drawing/depth_4bpp.hpp" +#include "libGraphite/quickdraw/support/drawing/true_color.hpp" + +// MARK: - Construction + +graphite::quickdraw::cicn::cicn(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::quickdraw::cicn::cicn(data::reader &reader) +{ + decode(reader); +} + +// MARK: - Accessors + +auto graphite::quickdraw::cicn::surface() const -> const quickdraw::surface& +{ + return m_surface; +} + +auto graphite::quickdraw::cicn::data() -> data::block +{ + data::block data; + data::writer writer(&data); + encode(writer); + return std::move(data); +} + +// MARK: - Coding + +auto graphite::quickdraw::cicn::encode(data::writer &writer) -> void +{ + auto width = m_surface.size().width; + auto height = m_surface.size().height; + + m_mask_row_bytes = (width - 1) / 8 + 1; + m_bmap_row_bytes = 0; + + data::block color_values(width * height * sizeof(std::uint16_t)); + data::block mask_data(m_mask_row_bytes * height); + data::writer colors(&color_values); + data::writer mask(&mask_data); + + std::uint8_t pass = 0; + std::uint8_t scratch = 0; + + do { + if (pass++ > 0) { + for (std::int16_t y = 0; y < height; ++y) { + for (std::int16_t x = 0; x < width; ++x) { + auto color = m_surface.at(x, y); + m_surface.set(x, y, rgb( + color.components.red & ~(1 << pass), + color.components.green & ~(1 << pass), + color.components.blue & ~(1 << pass), + color.components.alpha + )); + } + } + } + + m_clut = {}; + colors.set_position(0); + mask.set_position(0); + color_values.set(static_cast(0)); + mask_data.set(static_cast(0)); + + for (std::int16_t y = 0; y < height; ++y) { + scratch = 0; + for (std::int16_t x = 0; x < width; ++x) { + auto color = m_surface.at(x, y); + colors.write_short(m_clut.set(color)); + + auto bit_offset = x % 8; + if (bit_offset == 0 && x != 0) { + mask.write_byte(scratch); + scratch = 0; + } + + auto mask_value = (color.components.alpha & 0x80) == 0x1; + mask_value <<= (7 - bit_offset); + scratch |= mask_value; + } + mask.write_byte(scratch); + } + } + while (m_clut.size() > 256); + + // Determine what component configuration we need. + m_pixmap = pixmap(rect({ 0, 0 }, { width, height })); + data::block pmap_data; + + if (m_clut.size() > 256) { + throw std::runtime_error("Implementation does not currently handle more than 256 colors in a CICN"); + } + else if (m_clut.size() > 16) { + pmap_data = m_pixmap.build_pixel_data(color_values, 8); + } + else if (m_clut.size() > 4) { + pmap_data = m_pixmap.build_pixel_data(color_values, 4); + } + else if (m_clut.size() > 2) { + pmap_data = m_pixmap.build_pixel_data(color_values, 2); + } + else { + pmap_data = m_pixmap.build_pixel_data(color_values, 1); + } + + // Calculate some offsets + m_mask_base_address = 4; + m_bmap_base_address = m_mask_base_address + mask_data.size(); + + // Write out the image data for the CICN. + writer.write(m_pixmap); + writer.write_long(0); + writer.write_short(m_mask_row_bytes); + m_pixmap.bounds().encode(writer); + writer.write_long(0); + writer.write_short(m_bmap_row_bytes); + m_pixmap.bounds().encode(writer); + writer.write_long(0); + + writer.write_data(&mask_data); + writer.write(m_clut); + writer.write_data(&pmap_data); +} + +auto graphite::quickdraw::cicn::decode(data::reader &reader) -> void +{ + m_pixmap = reader.read(); + + auto cfg = std::move(m_pixmap.basic_draw_configuration()); + cfg.mask.base_address = reader.read_long(); + cfg.mask.row_bytes = reader.read_short(); + cfg.mask.bounds = reader.read>(); + cfg.bitmap.base_address = reader.read_long(); + cfg.bitmap.row_bytes = reader.read_short(); + cfg.bitmap.bounds = reader.read>(); + + reader.move(4); + + auto mask_data = reader.read_data(cfg.mask.expected_data_size()); + auto bmap_data = reader.read_data(cfg.bitmap.expected_data_size()); + cfg.color_table = &(m_clut = reader.read()); + auto pmap_data = reader.read_data(cfg.pixmap.expected_data_size()); + + m_surface = quickdraw::surface(cfg.pixmap.bounds.size); + + if (m_pixmap.total_component_width() == 1) { + drawing::monochrome::pixmap::draw(cfg, m_surface); + } + else if (m_pixmap.total_component_width() == 2) { + drawing::depth_2bpp::pixmap::draw(cfg, m_surface); + } + else if (m_pixmap.total_component_width() == 4) { + drawing::depth_4bpp::pixmap::draw(cfg, m_surface); + } + else if (m_pixmap.total_component_width() == 8) { + drawing::true_color::pixmap::draw(cfg, m_surface); + } + else { + throw std::runtime_error("Currently unsupported cicn configuration: cmp_size=" + + std::to_string(m_pixmap.component_size()) + + ", cmp_count=" + std::to_string(m_pixmap.component_count())); + } +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/cicn.hpp b/libGraphite/quickdraw/format/cicn.hpp new file mode 100644 index 0000000..cdce169 --- /dev/null +++ b/libGraphite/quickdraw/format/cicn.hpp @@ -0,0 +1,61 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" +#include "libGraphite/quickdraw/support/pixmap.hpp" +#include "libGraphite/quickdraw/format/clut.hpp" + +namespace graphite::quickdraw +{ + struct cicn + { + public: + static auto type_code() -> std::string { return "cicn"; } + + public: + cicn() = default; + explicit cicn(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit cicn(data::reader& reader); + + [[nodiscard]] auto surface() const -> const surface&; + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + private: + rsrc::resource::identifier m_id; + std::string m_name; + quickdraw::pixmap m_pixmap; + std::uint32_t m_mask_base_address; + std::uint16_t m_mask_row_bytes; + rect m_mask_bounds; + std::uint32_t m_bmap_base_address; + std::uint16_t m_bmap_row_bytes; + rect m_bmap_bounds; + quickdraw::surface m_surface; + quickdraw::clut m_clut; + + auto decode(data::reader& reader) -> void; + }; +} diff --git a/libGraphite/quickdraw/format/clut.cpp b/libGraphite/quickdraw/format/clut.cpp new file mode 100644 index 0000000..9e28653 --- /dev/null +++ b/libGraphite/quickdraw/format/clut.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quickdraw/format/clut.hpp" +#include "libGraphite/data/writer.hpp" +#include "libGraphite/data/reader.hpp" + +// MARK: - Construction + +graphite::quickdraw::clut::clut(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::quickdraw::clut::clut(data::reader &reader) + : m_id(0), m_name("Embedded `clut` resource") +{ + decode(reader); +} + +// MARK: - Accessors + +auto graphite::quickdraw::clut::size() const -> size_type +{ + return m_entries.size(); +} + +auto graphite::quickdraw::clut::at(index_type index) const -> union color +{ + const auto& it = m_entries.find(index); + return (it != m_entries.end()) ? it->second : colors::black(); +} + +auto graphite::quickdraw::clut::set(union color color) -> index_type +{ + index_type value = 0; + for (const auto& entry : m_entries) { + if (entry.second.value == color.value) { + return entry.first; + } + else { + value = std::max(value, entry.first); + } + } + m_entries.emplace_back(std::pair(value, color)); + m_size = m_entries.size(); + return value; +} + +auto graphite::quickdraw::clut::set(index_type index, union color color) -> void +{ + for (auto& entry : m_entries) { + if (entry.first == index) { + entry.second = color; + return; + } + } + m_entries.emplace_back(std::pair(index, color)); +} + +// MARK: - Coding + +auto graphite::quickdraw::clut::encode(data::writer &writer) -> void +{ + writer.write_long(m_seed); + writer.write_enum(m_flags); + writer.write_short(m_size - 1); + + for (auto entry : m_entries) { + writer.write_short(entry.first); + writer.write_short(static_cast((entry.second.components.red / 255.0) * 65535.0)); + writer.write_short(static_cast((entry.second.components.green / 255.0) * 65535.0)); + writer.write_short(static_cast((entry.second.components.blue / 255.0) * 65535.0)); + } +} + +auto graphite::quickdraw::clut::decode(data::reader &reader) -> void +{ + m_seed = reader.read_long(); + m_flags = reader.read_enum(); + m_size = reader.read_short() + 1; + + for (std::uint16_t i = 0; i < m_size; ++i) { + auto value = reader.read_short(); + std::uint16_t index = m_flags == device ? i : value; + m_entries.emplace_back(std::pair(index, rgb( + static_cast((reader.read_short() / 65535.0) * 255.0), + static_cast((reader.read_short() / 65535.0) * 255.0), + static_cast((reader.read_short() / 65535.0) * 255.0) + ))); + } +} + +// MARK: - Iterators + +auto graphite::quickdraw::clut::begin() -> iterator +{ + return { this, 0 }; +} + +auto graphite::quickdraw::clut::end() -> iterator +{ + return { this, m_size }; +} + +auto graphite::quickdraw::clut::begin() const -> iterator +{ + return { const_cast(this), 0 }; +} + +auto graphite::quickdraw::clut::end() const -> iterator +{ + return { const_cast(this), m_size }; +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/clut.hpp b/libGraphite/quickdraw/format/clut.hpp new file mode 100644 index 0000000..b36357a --- /dev/null +++ b/libGraphite/quickdraw/format/clut.hpp @@ -0,0 +1,93 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/data/reader.hpp" +#include "libGraphite/quickdraw/type/color.hpp" + +namespace graphite::quickdraw +{ + struct clut + { + public: + typedef std::uint16_t size_type; + typedef std::uint16_t index_type; + + static auto type_code() -> std::string { return "clut"; } + + enum flags : std::uint16_t + { + pixmap = 0x0000, + device = 0x8000 + }; + + struct iterator + { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = union color; + using pointer = value_type*; + using reference = value_type&; + + iterator(struct clut *clut, index_type idx) : m_clut(clut), m_idx(idx) {} + + auto operator*() const -> reference { return m_clut->m_entries[m_idx].second; } + auto operator->() -> pointer { return &m_clut->m_entries[m_idx].second; } + auto operator++() -> iterator& { ++m_idx; return *this; } + auto operator++(int) -> iterator { iterator tmp = *this; ++(*this); return tmp; } + friend auto operator==(const iterator& a, const iterator& b) -> bool { return (a.m_clut == b.m_clut) && (a.m_idx == b.m_idx); } + friend auto operator!=(const iterator& a, const iterator& b) -> bool { return (a.m_clut != b.m_clut) && (a.m_idx == b.m_idx); } + + private: + struct clut *m_clut; + index_type m_idx; + }; + + public: + clut() = default; + explicit clut(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit clut(data::reader& reader); + + [[nodiscard]] auto size() const -> size_type; + + [[nodiscard]] auto at(index_type index) const -> union color; + auto set(union color color) -> index_type; + auto set(index_type index, union color color) -> void; + + auto begin() -> iterator; + auto end() -> iterator; + [[nodiscard]] auto begin() const -> iterator; + [[nodiscard]] auto end() const -> iterator; + + auto encode(data::writer& writer) -> void; + + private: + rsrc::resource::identifier m_id; + std::string m_name; + std::uint32_t m_seed; + enum flags m_flags { pixmap }; + size_type m_size; + std::vector> m_entries; + + auto decode(data::reader& reader) -> void; + }; +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/pict.cpp b/libGraphite/quickdraw/format/pict.cpp new file mode 100644 index 0000000..4042f3e --- /dev/null +++ b/libGraphite/quickdraw/format/pict.cpp @@ -0,0 +1,620 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quickdraw/format/pict.hpp" +#include "libGraphite/quickdraw/support/pixmap.hpp" +#include "libGraphite/quickdraw/format/clut.hpp" +#include "libGraphite/compression/packbits.hpp" + +// MARK: - Constants + +namespace graphite::quickdraw::constants +{ + static constexpr std::uint16_t pict_v1_magic = 0x1101; + static constexpr std::uint32_t pict_v2_magic = 0x001102ff; +} + +// MARK: - Construction + +graphite::quickdraw::pict::pict(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::quickdraw::pict::pict(data::reader &reader) +{ + decode(reader); +} + +graphite::quickdraw::pict::pict(quickdraw::surface &surface) + : m_surface(std::move(surface)) +{ +} + +// MARK: - Accessors + +auto graphite::quickdraw::pict::surface() const -> const quickdraw::surface & +{ + return m_surface; +} + +// MARK: - Decoding + +auto graphite::quickdraw::pict::decode(data::reader &reader) -> void +{ + reader.move(2); + + m_frame = reader.read>(); + bool v1 = false; + + if (reader.read_short(0, data::reader::mode::peek) == constants::pict_v1_magic) { + reader.move(2); + v1 = true; + } + else { + if (reader.read_long() != constants::pict_v2_magic) { + throw std::runtime_error("Invalid PICT resource. Incorrect header: " + std::to_string(m_id) + ", " + m_name); + } + + // The very first thing we should find is an extended header opcode. Read this + // outside of the main opcode loop as it should only appear once. + if (reader.read_enum() != opcode::ext_header) { + throw std::runtime_error("Expected to find PICT Extended Header."); + } + + if ((reader.read_long() >> 16) != 0xFFFE) { + // Standard header variant + auto rect = reader.read>(); + m_dpi.x = m_frame.size.width / rect.size.width; + m_dpi.y = m_frame.size.height / rect.size.height; + } + else { + // Extended header variant + reader.move(sizeof(std::uint32_t) * 2); + auto rect = reader.read>(); + m_dpi.x = static_cast(m_frame.size.width) / rect.size.width; + m_dpi.y = static_cast(m_frame.size.height) / rect.size.height; + + // This isn't strictly correct, but it allows us to decode some images which would otherwise + // fail due to mismatched frame sizes. QuickDraw would normally scale such images down to fit the frame + // but here we just expand the frame. + // TODO: Make this a setting, so that we can handle scaling + m_frame.size = rect.size; + } + + if (m_dpi.x <= 0 || m_dpi.y <= 0) { + throw std::runtime_error("Invalid PICT resource. Content aspect ratio is not valid: " + std::to_string(m_id) + ", " + m_name); + } + + reader.move(4); + } + + // Begin parsing PICT opcodes + auto opcode = opcode::eof; + quickdraw::rect clipping_rect; + m_size = 0; + m_surface = quickdraw::surface(m_frame.size); + auto has_bits = false; + + while (!reader.eof()) { + if (v1) { + opcode = static_cast(reader.read_byte()); + } + else { + reader.move(reader.position() % sizeof(std::uint16_t)); + opcode = reader.read_enum(); + } + + if (opcode == opcode::eof) { + break; + } + + switch (opcode) { + case opcode::clip_region: { + clipping_rect = read_region(reader); + break; + } + case opcode::origin: { + m_frame.origin = point::read(reader, coding_type::macintosh); + break; + } + case opcode::bits_rect: { + read_indirect_bits_rect(reader, false, false); + break; + } + case opcode::bits_region: { + read_indirect_bits_rect(reader, false, true); + break; + } + case opcode::pack_bits_rect: { + read_indirect_bits_rect(reader, true, false); + break; + } + case opcode::pack_bits_region: { + read_indirect_bits_rect(reader, true, true); + break; + } + case opcode::direct_bits_rect: { + read_direct_bits_rect(reader, false); + break; + } + case opcode::direct_bits_region: { + read_direct_bits_rect(reader, true); + break; + } + case opcode::long_comment: { + read_long_comment(reader); + break; + } + case opcode::short_comment: { + read_short_comment(reader); + break; + } + case opcode::rgb_fg_color: + case opcode::rgb_bg_color: + case opcode::hilite_color: + case opcode::op_color: { + reader.move(6); + break; + } + case opcode::frame_region: + case opcode::paint_region: + case opcode::erase_region: + case opcode::invert_region: + case opcode::fill_region: { + read_region(reader); + break; + } + case opcode::nop: + case opcode::eof: + case opcode::ext_header: + case opcode::hilite_mode: + case opcode::def_hilite: { + break; + } + case opcode::compressed_quicktime: { + // Compressed QuickTime data is often followed by drawing routines telling you that you need QuickTime + // to decode the image. We should skip these for now and just return after a successful decode. + read_compressed_quicktime(reader); + break; + } + case opcode::uncompressed_quicktime: { + read_uncompressed_quicktime(reader); + break; + } + default: { + throw std::runtime_error("Encountered an incompatible PICT: " + std::to_string(m_id) + ", " + m_name); + } + } + } + + // This is a safety check for QuickTime RLE which is skipped over. If no other image data was found, throw an error. + if (!has_bits) { + throw std::runtime_error("Encountered an incompatible PICT: " + std::to_string(m_id) + ", " + m_name); + } +} + +// MARK: - Encoding + +auto graphite::quickdraw::pict::encode(data::writer &writer) -> void +{ + write_header(writer); + write_def_hilite(writer); + write_clip_region(writer); + write_direct_bits_rect(writer); + + // Make sure we're word aligned and put out the end of picture opcode. + auto align_adjust = writer.position() % sizeof(std::uint16_t); + for (auto n = 0; n < align_adjust; ++n) { + writer.write_byte(0); + } + writer.write_enum(opcode::eof); +} + +// MARK: - Reading Functions + +auto graphite::quickdraw::pict::read_region(data::reader &reader) const -> rect +{ + auto size = reader.read_short(); + auto rect = reader.read>(); + + rect.origin.x /= m_dpi.x; + rect.origin.y /= m_dpi.y; + rect.size.width /= m_dpi.x; + rect.size.height /= m_dpi.y; + + reader.move(size - 10); + + return rect; +} + +auto graphite::quickdraw::pict::read_long_comment(data::reader &reader) const -> void +{ + reader.move(2); + reader.move(reader.read_short()); +} + +auto graphite::quickdraw::pict::read_short_comment(data::reader &reader) const -> void +{ + reader.move(2); +} + +auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bool packed, bool region) -> void +{ + quickdraw::pixmap pm; + quickdraw::clut color_table; + + // Determine if we're dealing with a PixMap or an old style BitMap. + bool is_pixmap = reader.read_short(0, data::reader::mode::peek) & 0x8000; + if (is_pixmap) { + // The PixMap base address is omitted here, step back when reading. + pm = reader.read(-4); + color_table = reader.read(); + } + else { + // Old style Bitmap + pm.set_pack_type(1); + pm.set_component_count(1); + pm.set_component_size(1); + pm.set_row_bytes(reader.read_short()); + pm.set_bounds(reader.read>()); + + // Monochrome color table + color_table.set(colors::white()); + color_table.set(colors::black()); + } + + // Read the source and destination bounds + auto source_rect = reader.read>(); + auto destination_rect = reader.read>(); + + auto transfer_mode = reader.read_short(); + if (region) { + read_region(reader); + } + + // Setup pixel buffer for raw values + data::block raw_data; + auto row_bytes = pm.row_bytes(); + auto width = pm.bounds().size.width; + auto height = pm.bounds().size.height; + + if (packed) { + data::writer raw(&raw_data); + for (std::int16_t scanline = 0; scanline < height; ++scanline) { + auto data = reader.read_compressed_data(row_bytes > 250 ? reader.read_short() : reader.read_byte()); + raw.write_data(&data); + } + } + else { + raw_data = reader.read_data(row_bytes * height); + } + + destination_rect.origin.x -= m_frame.origin.x; + destination_rect.origin.y -= m_frame.origin.y; + pm.build_surface(m_surface, raw_data, color_table, destination_rect); + m_size += width * height; +} + +auto graphite::quickdraw::pict::read_direct_bits_rect(data::reader &reader, bool region) -> void +{ + auto pm = reader.read(); + auto pack_type = pm.pack_type(); + auto component_count = pm.component_count(); + auto color_model = pm.pixel_format(); + auto row_bytes = pm.row_bytes(); + auto bounds = pm.bounds(); + + // Read the source and destination bounds + auto source_rect = reader.read>(); + auto destinationm_rect = reader.read>(); + + if (region) { + read_region(reader); + } + + // Verify the type of PixMap. We can only accept certain types for the time being, until support for decoding + // other types is added. + data::block raw_data; + switch (pack_type) { + case 1: + case 2: + case 3: { + raw_data = data::block(row_bytes); + break; + } + case 4: { + raw_data = data::block(component_count * row_bytes / 4); + break; + } + default: { + throw std::runtime_error("Unsupported pack type " + std::to_string(pack_type) + " encountered in PICT: " + + std::to_string(m_id) + ", " + m_name); + } + } + + // Allocate a private memory buffer before going to the surface. + data::block pixel_buffer_data; + data::writer pixel_buffer(&pixel_buffer_data); + std::uint32_t width = source_rect.size.width; + std::uint32_t height = source_rect.size.height; + std::uint32_t bounds_width = bounds.size.width; + std::uint32_t source_length = width * height; + + if (pack_type == 3) { + pixel_buffer.write_short(0, source_length); + } + else { + pixel_buffer.write_long(0, source_length); + } + + auto packing_enabled = ((pack_type == 3 ? 2 : 1) + (row_bytes > 250 ? 2 : 1)) <= bounds_width; + + for (std::uint32_t scanline = 0; scanline < height; ++scanline) { + if (pack_type > 2 && packing_enabled) { + if (pack_type == 3) { + raw_data = std::move(reader.read_compressed_data(row_bytes > 250 ? reader.read_short() : reader.read_byte())); + } + else { + raw_data = std::move(reader.read_compressed_data(row_bytes > 250 ? reader.read_short() : reader.read_byte())); + } + } + else { + raw_data = std::move(reader.read_data(row_bytes)); + } + + if (pack_type == 3) { + for (std::uint32_t x = 0; x < width; ++x) { + pixel_buffer.write_short( + (0xFF& raw_data.get(2 * x + 1)) | ((0xFF & raw_data.get(2 * x)) << 8) + ); + } + } + else if (component_count == 3) { + // RGB Formatted Data + for (std::uint32_t x = 0; x < width; ++x) { + pixel_buffer.write_long( + 0xFF000000 + | ((raw_data.get(x) & 0xFF) << 16) + | ((raw_data.get(bounds_width + x) & 0xFF) << 8) + | (raw_data.get(2 * bounds_width + x) & 0xFF) + ); + } + } + else if (component_count == 4) { + // ARGB Formatted Data + for (std::uint32_t x = 0; x < width; ++x) { + pixel_buffer.write_long( + ((raw_data.get(x) & 0xFF) << 24) + | ((raw_data.get(bounds_width + x) & 0xFF) << 16) + | ((raw_data.get(2 * bounds_width + x) & 0xFF) << 8) + | (raw_data.get(3 * bounds_width + x) & 0xFF) + ); + } + } + } + + data::reader pixel_buffer_reader(&pixel_buffer_data); + if (pack_type == 3) { + while (!pixel_buffer_reader.eof()) { + auto value = pixel_buffer_reader.read_short(); + auto color = rgb( + static_cast(((value & 0x7c00) >> 10) * 0xFF / 0x1F), + static_cast(((value & 0x03e0) >> 5) * 0xFF / 0x1F), + static_cast((value & 0x001f) * 0xFF / 0x1F) + ); + m_surface.set(m_size++, color); + } + } + else { + while (!pixel_buffer_reader.eof()) { + while (!pixel_buffer_reader.eof()) { + auto value = pixel_buffer_reader.read_short(); + auto color = rgb( + static_cast((value & 0xFF0000) >> 16), + static_cast((value & 0xFF00) >> 8), + static_cast(value & 0xFF), + static_cast((value & 0xFF000000) >> 24) + ); + m_surface.set(m_size++, color); + } + } + } +} + +auto graphite::quickdraw::pict::read_compressed_quicktime(data::reader &reader) -> void +{ + auto length = reader.read_long(); + reader.move(38); + auto matte_size = reader.read_long(); + auto matte_rect = reader.read>(); + reader.move(2); + auto resource_rect = reader.read>(); + reader.move(4); + auto mask_size = reader.read_long(); + + if (matte_size > 0) { + read_image_description(reader); + } + + if (mask_size > 0) { + reader.move(mask_size); + } + + read_image_description(reader); +} + +auto graphite::quickdraw::pict::read_uncompressed_quicktime(data::reader &reader) -> void +{ + auto length = reader.read_long(); + reader.move(38); + auto matte_size = reader.read_long(); + auto matte_rect = reader.read>(); + + if (matte_size > 0) { + read_image_description(reader); + } +} + +auto graphite::quickdraw::pict::read_image_description(data::reader &reader) -> void +{ + auto length = reader.read_long(); + if (length != 86) { + throw std::runtime_error("Invalid QuickTime image description in PICT: " + std::to_string(m_id) + ", " + m_name); + } + + auto compressor = reader.read_long(); + reader.move(24); + auto size = reader.read>(); + reader.move(8); + auto data_size = reader.read_long(); + reader.move(34); + auto depth = reader.read_short(); + if (depth > 32) { + depth -= 32; // Grayscale + } + + auto color_table = reader.read(); + + if (compressor == 'rle ') { + // RLE is often garbage or redundant, skip over it and hope we find other image data later. + reader.move(data_size); + return; + } + + switch (compressor) { + default: { + std::string compressor_name; + compressor_name.push_back(compressor >> 24); + compressor_name.push_back(compressor >> 16); + compressor_name.push_back(compressor >> 8); + compressor_name.push_back(compressor); + + throw std::runtime_error("Unsupported QuickTime compressor '" + compressor_name + "' at offset " + std::to_string(reader.position()) + + " in PICT: " + std::to_string(m_id) + ", " + m_name); + } + } +} + +// MARK: - Writing Functions + +auto graphite::quickdraw::pict::write_header(data::writer &writer) -> void +{ + // Write the size of zero. This seems to be fine. + writer.write_short(0); + + // Set the image frame + writer.write>(m_frame); + + // We're only dealing with PICT version 2 currently. + writer.write_long(constants::pict_v2_magic); + writer.write_enum(opcode::ext_header); + writer.write_long(0xFFFE0000); + + // Image resolution (72dpi + writer.write_short(72); + writer.write_short(0); + writer.write_short(72); + writer.write_short(0); + + // Optimal source frame. (Identical to the image frame) + writer.write>(m_frame); + + // Reserved + writer.write_long(0); +} + +auto graphite::quickdraw::pict::write_def_hilite(data::writer &writer) -> void +{ + writer.write_enum(opcode::def_hilite); +} + +auto graphite::quickdraw::pict::write_clip_region(data::writer &writer) -> void +{ + writer.write_enum(opcode::clip_region); + writer.write_short(10); + writer.write>(m_frame); +} + +auto graphite::quickdraw::pict::write_direct_bits_rect(data::writer &writer) -> void +{ + writer.write_enum(opcode::direct_bits_rect); + + quickdraw::pixmap pm(m_frame); + writer.write(pm); + + // Source and destination frames - identical to the image frame. + writer.write>(m_frame); + writer.write>(m_frame); + + // Specify the transfer mode. + writer.write_short(0); + + // Prepare to write out the actual image data. + data::block scanline_data(m_frame.size.width * pm.component_count()); + data::writer scanline(&scanline_data); + + for (std::int16_t y = 0; y < m_frame.size.height; ++y) { + scanline_data.set(static_cast(0)); + + if (pm.component_count() == 3) { + for (std::int16_t x = 0; x < m_frame.size.width; ++x) { + auto pixel = m_surface.at(x, y); + + scanline.set_position(x); + writer.write_byte(pixel.components.red); + + scanline.set_position(x + m_frame.size.width); + writer.write_byte(pixel.components.green); + + scanline.set_position(x + m_frame.size.width * 2); + writer.write_byte(pixel.components.blue); + } + } + else if (pm.component_count() == 4) { + for (std::int16_t x = 0; x < m_frame.size.width; ++x) { + auto pixel = m_surface.at(x, y); + + scanline.set_position(x); + writer.write_byte(pixel.components.alpha); + + scanline.set_position(x + m_frame.size.width); + writer.write_byte(pixel.components.red); + + scanline.set_position(x + m_frame.size.width * 2); + writer.write_byte(pixel.components.green); + + scanline.set_position(x + m_frame.size.width * 3); + writer.write_byte(pixel.components.blue); + } + } + + auto packed = std::move(compression::packbits8::compress(scanline_data)); + if (pm.row_bytes() > 250) { + writer.write_short(packed.size()); + } + else { + writer.write_byte(packed.size()); + } + writer.write_data(&packed); + } +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/pict.hpp b/libGraphite/quickdraw/format/pict.hpp new file mode 100644 index 0000000..bf4312f --- /dev/null +++ b/libGraphite/quickdraw/format/pict.hpp @@ -0,0 +1,99 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" + +namespace graphite::quickdraw +{ + struct pict + { + public: + static auto type_code() -> std::string { return "PICT"; } + + public: + pict() = default; + explicit pict(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit pict(data::reader& reader); + explicit pict(quickdraw::surface& surface); + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + [[nodiscard]] auto surface() const -> const quickdraw::surface&; + + private: + enum class opcode : std::uint16_t { + nop = 0x0000, + clip_region = 0x0001, + origin = 0x000c, + bits_rect = 0x0090, + bits_region = 0x0091, + pack_bits_rect = 0x0098, + pack_bits_region = 0x0099, + direct_bits_rect = 0x009a, + direct_bits_region = 0x009b, + eof = 0x00ff, + rgb_fg_color = 0x001a, + rgb_bg_color = 0x001b, + hilite_mode = 0x001c, + hilite_color = 0x001d, + def_hilite = 0x001e, + op_color = 0x001f, + frame_region = 0x0080, + paint_region = 0x0081, + erase_region = 0x0082, + invert_region = 0x0083, + fill_region = 0x0084, + short_comment = 0x00a0, + long_comment = 0x00a1, + ext_header = 0x0c00, + compressed_quicktime = 0x8200, + uncompressed_quicktime = 0x8201, + }; + + private: + rsrc::resource::identifier m_id { 0 }; + std::string m_name; + quickdraw::surface m_surface; + rect m_frame; + point m_dpi; + std::size_t m_size; + + auto decode(data::reader& reader) -> void; + auto read_region(data::reader& reader) const -> rect; + auto read_long_comment(data::reader& reader) const -> void; + auto read_short_comment(data::reader& reader) const -> void; + auto read_direct_bits_rect(data::reader& reader, bool region) -> void; + auto read_indirect_bits_rect(data::reader& reader, bool packed, bool region) -> void; + auto read_compressed_quicktime(data::reader& reader) -> void; + auto read_uncompressed_quicktime(data::reader& reader) -> void; + auto read_image_description(data::reader& reader) -> void; + + auto write_header(data::writer& writer) -> void; + auto write_def_hilite(data::writer& writer) -> void; + auto write_clip_region(data::writer& writer) -> void; + auto write_direct_bits_rect(data::writer& writer) -> void; + + }; +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/ppat.cpp b/libGraphite/quickdraw/format/ppat.cpp new file mode 100644 index 0000000..76ee943 --- /dev/null +++ b/libGraphite/quickdraw/format/ppat.cpp @@ -0,0 +1,157 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include "libGraphite/quickdraw/format/ppat.hpp" +#include "libGraphite/quickdraw/support/surface.hpp" + +// MARK: - Construction + +graphite::quickdraw::ppat::ppat(const data::block &data, rsrc::resource::identifier id, const std::string& name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::quickdraw::ppat::ppat(data::reader &reader) +{ + decode(reader); +} + +// MARK: - Accessors + +auto graphite::quickdraw::ppat::surface() const -> const struct surface & +{ + return m_surface; +} + +auto graphite::quickdraw::ppat::data() -> data::block +{ + data::block data; + data::writer writer(&data); + encode(writer); + return std::move(data); +} + +// MARK: - Coding + +auto graphite::quickdraw::ppat::encode(data::writer &writer) -> void +{ + auto width = m_surface.size().width; + auto height = m_surface.size().height; + + // TODO: This is a brute force method of bringing down the color depth/number of colors required, + // for a ppat image. It doesn't optimise for image quality at all, and should be replaced at some point. + data::block color_data(width * height * sizeof(std::uint16_t)); + data::writer colors(&color_data); + + std::uint8_t pass = 0; + do { + if (pass++ > 0) { + for (std::int16_t y = 0; y < height; ++y) { + for (std::int16_t x = 0; x < width; ++x) { + auto color = m_surface.at(x, y); + m_surface.set(x, y, rgb( + color.components.red & ~(1 << pass), + color.components.green & ~(1 << pass), + color.components.blue & ~(1 << pass), + color.components.alpha + )); + } + } + } + + // Rebuild the color table for the surface. To do this we want to create an empty table and populate it. + m_clut = {}; + colors.set_position(0); + color_data.set(static_cast(0)); + for (std::int16_t y = 0; y < height; ++y) { + for (std::int16_t x = 0; x < width; ++x) { + auto color = m_surface.at(x, y); + colors.write_short(m_clut.set(color)); + } + } + } + while (m_clut.size() > 256); + + // Determine what component configuration we need + m_pixmap = pixmap(rect({ 0, 0 }, { width, height })); + data::block pmap_data; + + if (m_clut.size() > 256) { + throw std::runtime_error("Implementation does not currently handle more than 256 colors in a PPAT"); + } + else if (m_clut.size() > 16) { + pmap_data = m_pixmap.build_pixel_data(color_data, 8); + } + else if (m_clut.size() > 4) { + pmap_data = m_pixmap.build_pixel_data(color_data, 4); + } + else if (m_clut.size() > 2) { + pmap_data = m_pixmap.build_pixel_data(color_data, 2); + } + else { + pmap_data = m_pixmap.build_pixel_data(color_data, 1); + } + + // Calculate some offsets + m_pat_type = 1; + m_pmap_base_address = 28; + m_pat_base_address = m_pmap_base_address + 50; + m_pixmap.set_pm_table(m_pat_base_address + pmap_data.size()); + + // Write out the image data for the ppat. + writer.write_short(m_pat_type); + writer.write_long(m_pmap_base_address); + writer.write_long(m_pat_base_address); + writer.write_long(0); + writer.write_short(0); + writer.write_long(0); + writer.write_quad(0); + writer.write(m_pixmap); + writer.write_data(&pmap_data); + writer.write(m_clut); +} + +auto graphite::quickdraw::ppat::decode(data::reader &reader) -> void +{ + m_pat_type = reader.read_short(); + if (m_pat_type != 1) { + throw std::runtime_error("Currently unsupported ppat configuration: pat_type=" + std::to_string(m_pat_type)); + } + + m_pmap_base_address = reader.read_long(); + m_pat_base_address = reader.read_long(); + + reader.set_position(m_pmap_base_address); + m_pixmap = reader.read(); + + reader.set_position(m_pat_base_address); + auto pmap_data_size = m_pixmap.row_bytes() * m_pixmap.bounds().size.height; + auto pmap_data = reader.read_data(pmap_data_size); + + reader.set_position(m_pixmap.pm_table()); + m_clut = reader.read(); + + auto surface_size = m_pixmap.bounds().size; + m_surface = quickdraw::surface(surface_size); + m_pixmap.build_surface(m_surface, pmap_data, m_clut, m_pixmap.bounds()); +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/ppat.hpp b/libGraphite/quickdraw/format/ppat.hpp new file mode 100644 index 0000000..7d4886d --- /dev/null +++ b/libGraphite/quickdraw/format/ppat.hpp @@ -0,0 +1,58 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/quickdraw/type/rect.hpp" +#include "libGraphite/quickdraw/format/clut.hpp" +#include "libGraphite/quickdraw/support/pixmap.hpp" +#include "libGraphite/quickdraw/support/surface.hpp" + +namespace graphite::quickdraw +{ + struct ppat + { + public: + static auto type_code() -> std::string { return "ppat"; } + + public: + ppat() = default; + explicit ppat(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit ppat(data::reader& reader); + + [[nodiscard]] auto surface() const -> const quickdraw::surface&; + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + private: + rsrc::resource::identifier m_id; + std::string m_name; + std::uint16_t m_pat_type; + std::uint32_t m_pmap_base_address; + std::uint32_t m_pat_base_address; + quickdraw::pixmap m_pixmap; + quickdraw::surface m_surface; + quickdraw::clut m_clut; + + auto decode(data::reader& reader) -> void; + }; +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/rle.cpp b/libGraphite/quickdraw/format/rle.cpp new file mode 100644 index 0000000..89d9be0 --- /dev/null +++ b/libGraphite/quickdraw/format/rle.cpp @@ -0,0 +1,356 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quickdraw/format/rle.hpp" +#include + +// MARK: - Constants + +namespace graphite::quickdraw::constants +{ + static constexpr std::uint16_t rle_grid_width = 6; + static constexpr std::size_t advance = 2; +} + +// MARK: - Construction + +graphite::quickdraw::rle::rle(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::quickdraw::rle::rle(data::reader &reader) +{ + decode(reader); +} + +graphite::quickdraw::rle::rle(const size &size, std::uint16_t frame_count) + : m_id(0), m_name("RLE"), m_frame_size(size), m_frame_count(frame_count), m_bpp(16), m_palette_id(0) +{ + // Determine what the grid will be. We need to round up to the next whole number and have blank tiles + // if the frame count is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); +} + +// MARK: - Accessors + +auto graphite::quickdraw::rle::surface() const -> const quickdraw::surface& +{ + return m_surface; +} + +auto graphite::quickdraw::rle::frames() const -> std::vector> +{ + return m_frames; +} + +auto graphite::quickdraw::rle::frame_count() const -> std::size_t +{ + return m_frame_count; +} + +auto graphite::quickdraw::rle::data() -> data::block +{ + data::block data; + data::writer writer(&data); + encode(writer); + return std::move(data); +} + +// MARK: - Operations + +auto graphite::quickdraw::rle::frame_rect(std::uint32_t frame) const -> rect +{ + return { + point( + static_cast(frame % constants::rle_grid_width) * m_frame_size.width, + static_cast(frame / constants::rle_grid_width) * m_frame_size.height + ), + m_frame_size + }; +} + +auto graphite::quickdraw::rle::frame_surface(std::uint32_t frame) const -> quickdraw::surface +{ + quickdraw::surface surface(m_frame_size); + rect src_rect(frame_rect(frame)); + + // Extract the frame area of the origin surface + for (std::int16_t y = 0; y < src_rect.size.height; ++y) { + for (std::int16_t x = 0; x < src_rect.size.width; ++x) { + surface.set(x, y, m_surface.at(x + src_rect.origin.x, y + src_rect.origin.y)); + } + } + + return std::move(surface); +} + +auto graphite::quickdraw::rle::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +{ + rect dst_rect = frame_rect(frame); + size src_size = surface.size(); + + if (src_size.width != m_frame_size.width || src_size.height != m_frame_size.height) { + throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width) + "x" + std::to_string(src_size.height) + + ", expected " + std::to_string(m_frame_size.width) + "x" + std::to_string(m_frame_size.height)); + } + + // Copy from the source surfac e into the destination frame + for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { + for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { + m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); + } + } +} + +// MARK: - Decoding + +auto graphite::quickdraw::rle::decode(data::reader &reader) -> void +{ + // Read the header of the RLE information. This will tell us what we need to do in order to actually + // decode the frames. + m_frame_size = size::read(reader, coding_type::macintosh); + m_bpp = reader.read_short(); + m_palette_id = reader.read_short(); + m_frame_count = reader.read_short(); + reader.move(6); + + // Ensure that the RLE has a BPP of 16. This is the only format that we support currently. + if (m_bpp != 16) { + throw std::runtime_error("Incorrect color depth for rlëD resource: " + std::to_string(m_id) + ", " + m_name); + } + + // Determine what the grid will be. We need to round up to the next whole and have blank tiles if the frame count + // is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface in which all frame will be draw to, and other working variables required to parse and decode + // the RLE data correctly. + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); + rle::opcode opcode = opcode::eof; + std::uint64_t position = 0; + std::uint32_t row_start = 0; + std::int32_t current_line = -1; + std::uint64_t current_offset = 0; + std::int32_t count = 0; + std::uint16_t pixel = 0; + std::int32_t current_frame = 0; + std::uint32_t pixel_run = 0; + + while (!reader.eof()) { + if ((row_start != 0) && ((position - row_start) & 0x03)) { + position += 4 - ((position - row_start) & 0x03); + reader.move(4 - (count & 0x03)); + } + + opcode = reader.read_enum(); + count = reader.read_triple(); + + switch (opcode) { + case opcode::eof: { + // Check that we're not erroneously an EOF. + if (current_line != m_frame_size.height - 1) { + throw std::runtime_error("Incorrect number of scanlines in rlëD resource: " + std::to_string(m_id) + ", " + m_name); + } + + // Have we finished decoding the last frame in the data? + if (++current_frame >= m_frame_count) { + goto COMPLETED_LAST_FRAME; + } + + // Prepare for the next frame + current_line = -1; + break; + } + + case opcode::line_start: { + current_offset = surface_offset(current_frame, ++current_line); + row_start = reader.position(); + break; + } + + case opcode::pixel_data: { + for (auto i = 0; i < count; i += 2) { + pixel = reader.read_short(); + write_pixel(pixel, 0xFF, current_offset); + ++current_offset; + } + + if (count & 0x03) { + reader.move(4 - (count & 0x03)); + } + + break; + } + + case opcode::pixel_run: { + pixel_run = reader.read_long(); + for (auto i = 0; i < count; i += 4) { + write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type1); + ++current_offset; + if (i + 2 < count) { + write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type2); + ++current_offset; + } + } + break; + } + + case opcode::transparent_run: { + current_offset += count >> 1; + break; + } + } + } + + COMPLETED_LAST_FRAME: + return; +} + +// MARK: - Encoding + +auto graphite::quickdraw::rle::encode(data::writer &writer) -> void +{ + // Write out the header + m_frame_size.encode(writer, coding_type::macintosh); + writer.write_short(m_bpp); + writer.write_short(m_palette_id); + writer.write_short(m_frame_count); + + // Reserved fields + writer.write_short(0, 3); + + // Write out the RLE frames + for (auto f = 0; f < m_frame_count; ++f) { + auto frame = frame_rect(f); + + for (std::int16_t y = 0; y < frame.size.height; ++y) { + auto line_start_pos = writer.position(); + writer.write_long(0); + + rle::opcode run_state = opcode::line_start; + auto run_start_pos = line_start_pos + 4; + auto run_count = 0; + + for (std::int16_t x = 0; x < frame.size.width; ++x) { + auto pixel = m_surface.at(frame.origin.x + x, frame.origin.y + y); + + if (pixel.components.alpha == 0) { + if (run_state == opcode::line_start) { + // Start of a transparent run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::transparent_run; + run_count = constants::advance; + } + else if (run_state == opcode::transparent_run) { + // Continue transparent run + run_count += constants::advance; + } + else { + // End of pixel run, start of transparent run. + auto run_end_pos = writer.position(); + writer.set_position(run_start_pos); + writer.write_enum(opcode::pixel_data); + writer.write_triple(run_count); + writer.set_position(run_end_pos); + + // Pad to nearest 4-byte boundary + if (run_count & 0x3) { + writer.move(4 - (run_count & 0x3)); + } + + // Start transparent run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::transparent_run; + run_count = constants::advance; + } + } + else { + if (run_state == opcode::line_start) { + // Start of pixel run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::pixel_data; + run_count = constants::advance; + } + else if (run_state == opcode::transparent_run) { + // End of transparent run, start of pixel run + writer.move(-4); + writer.write_enum(opcode::transparent_run); + writer.write_triple(run_count); + + // Start pixel run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::pixel_data; + run_count = constants::advance; + } + else { + // Continue pixel run + run_count += constants::advance; + } + + // Write the pixel + writer.write_short( + (pixel.components.blue >> 3) | + ((pixel.components.green >> 3) << 5) | + ((pixel.components.red >> 3) << 10) + ); + } + } + + // Terminate the current opcode + if (run_state == opcode::pixel_data) { + auto run_end_pos = writer.position(); + writer.set_position(run_start_pos); + writer.write_enum(opcode::pixel_data); + writer.write_triple(run_count); + + // Pad to the nearest 4-byte boundary + if ((run_end_pos - line_start_pos) & 0x3) { + writer.move(4 - ((run_end_pos - line_start_pos) & 0x3)); + } + } + else if (run_state == opcode::transparent_run) { + // Erase the transparent run opcode placeholder -- remaining data is assumed transparent + writer.set_position(run_start_pos); + } + + // Write out the opcode and the size at the start of the line + auto line_end_pos = writer.position(); + writer.set_position(line_start_pos); + writer.write_enum(opcode::line_start); + writer.write_triple(line_end_pos - line_start_pos - 4); + writer.set_position(line_end_pos); + } + + writer.write_enum(opcode::eof); + writer.write_triple(0); + } +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/rle.hpp b/libGraphite/quickdraw/format/rle.hpp new file mode 100644 index 0000000..f46674a --- /dev/null +++ b/libGraphite/quickdraw/format/rle.hpp @@ -0,0 +1,80 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" + +namespace graphite::quickdraw +{ + struct rle + { + public: + static auto type_code() -> std::string { return "rlëD"; } + + public: + rle() = default; + rle(const size& size, std::uint16_t frame_count); + explicit rle(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit rle(data::reader& reader); + + [[nodiscard]] auto surface() const -> const quickdraw::surface&; + [[nodiscard]] auto frames() const -> std::vector>; + + [[nodiscard]] auto frame_count() const -> std::size_t; + [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> rect; + [[nodiscard]] auto frame_surface(std::uint32_t idx) const -> quickdraw::surface; + auto write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void; + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + private: + enum class pixel_type { type1, type2 }; + + enum class opcode : std::uint8_t + { + eof = 0x00, + line_start = 0x01, + pixel_data = 0x02, + transparent_run = 0x03, + pixel_run = 0x04, + }; + + rsrc::resource::identifier m_id { 0 }; + std::string m_name; + std::vector> m_frames; + quickdraw::surface m_surface; + size m_frame_size { 0 }; + size m_grid_size { 0 }; + std::uint16_t m_frame_count { 0 }; + std::uint16_t m_bpp { 0 }; + std::uint16_t m_palette_id { 0 }; + + auto decode(data::reader& reader) -> void; + + [[nodiscard]] auto surface_offset(std::uint32_t frame, std::uint64_t offset) -> std::uint64_t; + auto write_pixel(std::uint16_t pixel, std::uint8_t mask, std::uint64_t offset) -> void; + auto write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void; + }; +} diff --git a/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp b/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp new file mode 100644 index 0000000..a7eba88 --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + +#include "libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp" +#include "libGraphite/data/data.hpp" + +static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); + +// MARK: - Drawing + +auto graphite::quickdraw::drawing::depth_2bpp::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + if (cfg.mask.data) { + draw_masked(cfg, surface); + return; + } + + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto byte_offset = (3 - (x % 4)) << 1; + + auto byte = cfg.pixmap.data->get(y_offset + (x / 4)); + auto value = (byte >> byte_offset) & 0x3; + + surface.set(x, y, cfg.color_table->at(value)); + } + } +} + +auto graphite::quickdraw::drawing::depth_2bpp::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + auto mask_y_offset = y * cfg.mask.row_bytes; + + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto byte_offset = (3 - (x % 4)) << 1; + auto mask_offset = (7 - (x % 8)); + + auto byte = cfg.pixmap.data->get(y_offset + (x / 4)); + auto mask = cfg.mask.data->get(mask_y_offset + (x / 8)); + auto value = (byte >> byte_offset) & 0x3; + + if ((mask >> mask_offset) & 0x1) { + surface.set(x, y, cfg.color_table->at(value)); + } + } + } +} diff --git a/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp b/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp new file mode 100644 index 0000000..a3d1fde --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp @@ -0,0 +1,35 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/support/pixmap.hpp" +#include "libGraphite/data/data.hpp" + +namespace graphite::quickdraw::drawing::depth_2bpp::pixmap +{ + auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; + auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; +} + + + diff --git a/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp b/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp new file mode 100644 index 0000000..9954561 --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + +#include "libGraphite/quickdraw/support/drawing/depth_4bpp.hpp" +#include "libGraphite/data/data.hpp" + +static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); + +// MARK: - Drawing + +auto graphite::quickdraw::drawing::depth_4bpp::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + if (cfg.mask.data) { + draw_masked(cfg, surface); + return; + } + + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto byte_offset = (1 - (x % 2)) << 2; + + auto byte = cfg.pixmap.data->get(y_offset + (x / 2)); + auto value = (byte >> byte_offset) & 0xF; + + surface.set(x, y, cfg.color_table->at(value)); + } + } +} + +auto graphite::quickdraw::drawing::depth_4bpp::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + auto mask_y_offset = y * cfg.mask.row_bytes; + + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto byte_offset = (1 - (x % 2)) <<2; + auto mask_offset = (7 - (x % 8)); + + auto byte = cfg.pixmap.data->get(y_offset + (x / 2)); + auto mask = cfg.mask.data->get(mask_y_offset + (x / 8)); + auto value = (byte >> byte_offset) & 0xF; + + if ((mask >> mask_offset) & 0x1) { + surface.set(x, y, cfg.color_table->at(value)); + } + } + } +} diff --git a/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp b/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp new file mode 100644 index 0000000..92db50c --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp @@ -0,0 +1,35 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/support/pixmap.hpp" +#include "libGraphite/data/data.hpp" + +namespace graphite::quickdraw::drawing::depth_4bpp::pixmap +{ + auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; + auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; +} + + + diff --git a/libGraphite/quickdraw/support/drawing/monochrome.cpp b/libGraphite/quickdraw/support/drawing/monochrome.cpp new file mode 100644 index 0000000..66319bf --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/monochrome.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quickdraw/support/drawing/monochrome.hpp" +#include "libGraphite/data/data.hpp" + +static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); + +// MARK: - Drawing + +auto graphite::quickdraw::drawing::monochrome::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + if (cfg.mask.data) { + draw_masked(cfg, surface); + return; + } + + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto byte_offset = y - (x % CHAR_BIT); + auto byte = cfg.pixmap.data->get(y_offset + (x / CHAR_BIT)); + auto value = (byte >> byte_offset) & 0x1; + surface.set(x, y, cfg.color_table->at(value)); + } + } +} + +auto graphite::quickdraw::drawing::monochrome::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + auto mask_y_offset = y * cfg.mask.row_bytes; + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto byte_offset = y - (x % CHAR_BIT); + auto byte = cfg.pixmap.data->get(y_offset + (x / CHAR_BIT)); + auto mask = cfg.mask.data->get(mask_y_offset + (x / CHAR_BIT)); + auto value = (byte >> byte_offset) & 0x1; + + if ((mask >> byte_offset) & 0x1) { + surface.set(x, y, cfg.color_table->at(value)); + } + } + } +} diff --git a/libGraphite/quickdraw/support/drawing/monochrome.hpp b/libGraphite/quickdraw/support/drawing/monochrome.hpp new file mode 100644 index 0000000..95fbd63 --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/monochrome.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/support/pixmap.hpp" +#include "libGraphite/data/data.hpp" + +namespace graphite::quickdraw::drawing::monochrome::pixmap +{ + auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; + auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; +} diff --git a/libGraphite/quickdraw/support/drawing/true_color.cpp b/libGraphite/quickdraw/support/drawing/true_color.cpp new file mode 100644 index 0000000..9ac75f1 --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/true_color.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + +#include "libGraphite/quickdraw/support/drawing/true_color.hpp" +#include "libGraphite/data/data.hpp" + +static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); + +// MARK: - Drawing + +auto graphite::quickdraw::drawing::true_color::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + if (cfg.mask.data) { + draw_masked(cfg, surface); + return; + } + + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto byte = cfg.pixmap.data->get(y_offset + x); + surface.set(x, y, cfg.color_table->at(byte)); + } + } +} + +auto graphite::quickdraw::drawing::true_color::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +{ + for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { + auto y_offset = y * cfg.pixmap.row_bytes; + auto mask_y_offset = y * cfg.mask.row_bytes; + + for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { + auto mask_offset = (7 - (x % 8)); + + auto byte = cfg.pixmap.data->get(y_offset + x); + auto mask = cfg.mask.data->get(mask_y_offset + (x / 8)); + + if ((mask >> mask_offset) & 0x1) { + surface.set(x, y, cfg.color_table->at(byte)); + } + } + } +} diff --git a/libGraphite/quickdraw/support/drawing/true_color.hpp b/libGraphite/quickdraw/support/drawing/true_color.hpp new file mode 100644 index 0000000..5ca54f5 --- /dev/null +++ b/libGraphite/quickdraw/support/drawing/true_color.hpp @@ -0,0 +1,35 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/support/pixmap.hpp" +#include "libGraphite/data/data.hpp" + +namespace graphite::quickdraw::drawing::true_color::pixmap +{ + auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; + auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; +} + + + diff --git a/libGraphite/quickdraw/support/pixmap.cpp b/libGraphite/quickdraw/support/pixmap.cpp new file mode 100644 index 0000000..97af90b --- /dev/null +++ b/libGraphite/quickdraw/support/pixmap.cpp @@ -0,0 +1,301 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quickdraw/support/pixmap.hpp" + +// MARK: - Construction + +graphite::quickdraw::pixmap::pixmap(const rect& frame) + : m_bounds(frame), + m_row_bytes(frame.size.width * constants::color_width) +{ +} + +graphite::quickdraw::pixmap::pixmap(const data::block &data, rsrc::resource::identifier id, const std::string &name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::quickdraw::pixmap::pixmap(data::reader &reader) +{ + decode(reader); +} + +// MARK: - Accessors + +auto graphite::quickdraw::pixmap::bounds() const -> rect +{ + return m_bounds; +} + +auto graphite::quickdraw::pixmap::row_bytes() const -> std::int16_t +{ + return m_row_bytes; +} + +auto graphite::quickdraw::pixmap::pack_type() const -> std::int16_t +{ + return m_pack_type; +} + +auto graphite::quickdraw::pixmap::pack_size() const -> std::int16_t +{ + return m_pack_size; +} + +auto graphite::quickdraw::pixmap::pixel_type() const -> std::int16_t +{ + return m_pixel_type; +} + +auto graphite::quickdraw::pixmap::pixel_size() const -> std::int16_t +{ + return m_pixel_size; +} + +auto graphite::quickdraw::pixmap::component_count() const -> std::int16_t +{ + return m_component_count; +} + +auto graphite::quickdraw::pixmap::component_size() const -> std::int16_t +{ + return m_component_size; +} + +auto graphite::quickdraw::pixmap::pixel_format() const -> enum pixel_format +{ + return m_pixel_format; +} + +auto graphite::quickdraw::pixmap::pm_table() const -> std::uint32_t +{ + return m_pm_table; +} + +auto graphite::quickdraw::pixmap::set_bounds(const rect& rect) -> void +{ + m_bounds = rect; +} + +auto graphite::quickdraw::pixmap::set_row_bytes(std::int16_t row_bytes) -> void +{ + m_row_bytes = row_bytes; +} + +auto graphite::quickdraw::pixmap::set_pack_type(std::int16_t pack_type) -> void +{ + m_pack_type = pack_type; +} + +auto graphite::quickdraw::pixmap::set_pack_size(std::int16_t pack_size) -> void +{ + m_pack_size = pack_size; +} + +auto graphite::quickdraw::pixmap::set_pixel_type(std::int16_t pixel_type) -> void +{ + m_pixel_type = pixel_type; +} + +auto graphite::quickdraw::pixmap::set_pixel_size(std::int16_t pixel_size) -> void +{ + m_pixel_size = pixel_size; +} + +auto graphite::quickdraw::pixmap::set_component_count(std::int16_t component_count) -> void +{ + m_component_count = component_count; +} + +auto graphite::quickdraw::pixmap::set_component_size(std::int16_t component_size) -> void +{ + m_component_size = component_size; +} + +auto graphite::quickdraw::pixmap::set_pixel_format(enum pixel_format format) -> void +{ + m_pixel_format = format; +} + +auto graphite::quickdraw::pixmap::set_pm_table(std::uint32_t table) -> void +{ + m_pm_table = table; +} + +// MARK: - Calculations + +auto graphite::quickdraw::pixmap::total_component_width() const -> std::size_t +{ + return m_component_size * m_component_count; +} + +// MARK: - Draw Configuration + +auto graphite::quickdraw::pixmap::basic_draw_configuration() const -> struct draw_configuration +{ + struct draw_configuration cfg; + cfg.pixmap.base_address = m_base_address; // Check that this is actually the correct value here? + cfg.pixmap.row_bytes = m_row_bytes; + cfg.pixmap.bounds = m_bounds; + return std::move(cfg); +} + +auto graphite::quickdraw::pixmap::draw_configuration::aspect::expected_data_size() const -> std::size_t +{ + return row_bytes * bounds.size.height; +} + +// MARK: - Encoding / Decoding + +auto graphite::quickdraw::pixmap::decode(data::reader &reader) -> void +{ + m_base_address = reader.read_long(); + m_row_bytes = static_cast(static_cast(reader.read_signed_short()) & 0x7FFF); + m_bounds = reader.read>(); + m_pm_version = reader.read_signed_short(); + m_pack_type = reader.read_signed_short(); + m_pack_size = reader.read_signed_long(); + m_dpi = reader.read>(); + m_pixel_type = reader.read_signed_short(); + m_pixel_size = reader.read_signed_short(); + m_component_count = reader.read_signed_short(); + m_component_size = reader.read_signed_short(); + m_pixel_format = reader.read_enum(); + m_pm_table = reader.read_long(); + m_pm_extension = reader.read_long(); +} + +auto graphite::quickdraw::pixmap::encode(data::writer &writer) -> void +{ + writer.write_long(m_base_address); + writer.write_short(0x8000 | m_row_bytes); + writer.write>(m_bounds); + writer.write_signed_short(m_pm_version); + writer.write_signed_short(m_pack_type); + writer.write_signed_long(m_pack_size); + writer.write>(m_dpi); + writer.write_signed_short(m_pixel_type); + writer.write_signed_short(m_pixel_size); + writer.write_signed_short(m_component_count); + writer.write_signed_short(m_component_size); + writer.write_enum(m_pixel_format); + writer.write_long(m_pm_table); + writer.write_long(m_pm_extension); +} + +// MARK: - Surface / Image + +auto graphite::quickdraw::pixmap::build_pixel_data(const data::block& color_data, std::uint16_t pixel_size) -> data::block +{ + data::block pixel_map_data; + data::writer pmap(&pixel_map_data); + data::reader colors(&color_data); + + m_pixel_size = static_cast(pixel_size); + m_component_count = 1; + + if (pixel_size == 8) { + m_row_bytes = m_bounds.size.width; + while (!colors.eof()) { + pmap.write_byte(colors.read_short() & 0xFF); + } + } + else { + auto width = m_bounds.size.width; + auto mod = 8 / pixel_size; + auto mask = (1 << pixel_size) - 1; + auto diff = 8 - pixel_size; + m_row_bytes = (width - 1) / mod + 1; + + for (std::int16_t y = 0; y < m_bounds.size.height; ++y) { + std::uint8_t scratch = 0; + for (std::int16_t x = 0; x < width; ++x) { + auto bit_offset = x % mod; + if (bit_offset == 0 && x != 0) { + pmap.write_byte(scratch); + scratch = 0; + } + + auto value = static_cast(colors.read_short() & mask); + value <<= (diff - (bit_offset * pixel_size)); + scratch |= value; + } + pmap.write_byte(scratch); + } + } + + return std::move(pixel_map_data); +} + +auto graphite::quickdraw::pixmap::build_surface(surface &surface, const data::block &pixel_data, const clut &clut, const rect &destination) -> void +{ + if (pixel_data.size() < destination.size.height * m_row_bytes) { + throw std::runtime_error("Insufficient data to build surface from PixMap"); + } + auto pixel_size = m_component_count * m_component_size; + + if (pixel_size == 8) { + for (std::int16_t y = 0; y < destination.size.height; ++y) { + auto y_offset = (y * m_row_bytes); + for (std::int16_t x = 0; x < destination.size.width; ++x) { + auto byte = pixel_data.get(y_offset + x); + surface.set(destination.origin.x + x, destination.origin.y + y, clut.at(byte)); + } + } + } + else { + auto mod = 8 / pixel_size; + auto mask = (1 << pixel_size) - 1; + auto diff = 8 - pixel_size; + + for (std::int16_t y = 0; y < destination.size.height; ++y) { + auto y_offset = (y * m_row_bytes); + for (std::int16_t x = 0; x < destination.size.width; ++x) { + auto byte = pixel_data.get(y_offset + (x / mod)); + auto byte_offset = diff - ((x % mod) * pixel_size); + auto v = (byte >> byte_offset) & mask; + surface.set(destination.origin.x + x, destination.origin.y + y, clut.at(v)); + } + } + } +} + +auto graphite::quickdraw::pixmap::draw(quickdraw::surface& surface) -> void +{ + if (m_component_size == 1 && m_component_count == 1) { + + } + else if ((m_component_size = 1 && m_component_count == 2) || (m_component_size == 2 && m_component_count == 1)) { + + } + else if ((m_component_size == 1 && m_component_count == 4) || (m_component_size == 4 || m_component_count == 1)) { + + } + else if ((m_component_size == 1 && m_component_count == 8) || (m_component_size == 8 || m_component_count == 1)) { + + } + else { + throw std::runtime_error("Currently unsupported pixel map configuration: " + "cmp_size=" + std::to_string(m_component_size) + + ", cmp_count=" + std::to_string(m_component_count)); + } +} \ No newline at end of file diff --git a/libGraphite/quickdraw/support/pixmap.hpp b/libGraphite/quickdraw/support/pixmap.hpp new file mode 100644 index 0000000..f3ecc8a --- /dev/null +++ b/libGraphite/quickdraw/support/pixmap.hpp @@ -0,0 +1,123 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include "libGraphite/data/data.hpp" +#include "libGraphite/data/reader.hpp" +#include "libGraphite/quickdraw/format/clut.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/type/pixel_format.hpp" + +namespace graphite::quickdraw +{ + struct pixmap + { + public: + + struct draw_configuration + { + struct aspect { + data::block *data { nullptr }; + std::uint32_t base_address { 0 }; + std::uint16_t row_bytes { 0 }; + rect bounds; + + [[nodiscard]] auto expected_data_size() const -> std::size_t; + }; + + struct aspect pixmap; + struct aspect bitmap; + struct aspect mask; + + struct clut *color_table { nullptr }; + }; + + public: + static constexpr std::size_t length = 50; + + pixmap() = default; + explicit pixmap(const rect& frame); + explicit pixmap(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit pixmap(data::reader& reader); + pixmap(const pixmap&) noexcept = default; + + auto operator=(pixmap&&) -> pixmap& = default; + auto operator=(const pixmap&) -> pixmap& = default; + + [[nodiscard]] auto basic_draw_configuration() const -> struct draw_configuration; + + [[nodiscard]] auto bounds() const -> rect; + [[nodiscard]] auto row_bytes() const -> std::int16_t; + [[nodiscard]] auto pack_type() const -> std::int16_t; + [[nodiscard]] auto pack_size() const -> std::int16_t; + [[nodiscard]] auto pixel_type() const -> std::int16_t; + [[nodiscard]] auto pixel_size() const -> std::int16_t; + [[nodiscard]] auto component_count() const -> std::int16_t; + [[nodiscard]] auto component_size() const -> std::int16_t; + [[nodiscard]] auto pixel_format() const -> enum pixel_format; + [[nodiscard]] auto pm_table() const -> std::uint32_t; + + [[nodiscard]] auto total_component_width() const -> std::size_t; + + auto set_bounds(const rect& rect) -> void; + auto set_row_bytes(std::int16_t row_bytes) -> void; + auto set_pack_type(std::int16_t pack_type) -> void; + auto set_pack_size(std::int16_t pack_size) -> void; + auto set_pixel_type(std::int16_t pixel_type) -> void; + auto set_pixel_size(std::int16_t pixel_size) -> void; + auto set_component_count(std::int16_t component_count) -> void; + auto set_component_size(std::int16_t component_size) -> void; + auto set_pixel_format(enum pixel_format format) -> void; + auto set_pm_table(std::uint32_t table) -> void; + + auto draw(quickdraw::surface& surface) -> void; + + auto build_surface(surface& surface, const data::block& pixel_data, const clut& clut, const rect& destination) -> void; + auto build_pixel_data(const data::block& color_data, std::uint16_t pixel_size) -> data::block; + + + + auto encode(data::writer& writer) -> void; + + private: + // Resource Data + std::uint32_t m_base_address { 0xFF }; + std::int16_t m_row_bytes { 0 }; + rect m_bounds; + std::int16_t m_pm_version { 0 }; + std::int16_t m_pack_type { 4 }; + std::int32_t m_pack_size { 0 }; + quickdraw::size m_dpi { 0.001098632812 }; + std::int16_t m_pixel_type { 16 }; + std::int16_t m_pixel_size { 32 }; + std::int16_t m_component_count { 3 }; + std::int16_t m_component_size { 8 }; + enum pixel_format m_pixel_format { unknown }; + std::uint32_t m_pm_table { 0 }; + std::uint32_t m_pm_extension { 0 }; + + auto decode(data::reader& reader) -> void; + }; +} diff --git a/libGraphite/quickdraw/support/surface.cpp b/libGraphite/quickdraw/support/surface.cpp new file mode 100644 index 0000000..8653825 --- /dev/null +++ b/libGraphite/quickdraw/support/surface.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quickdraw/support/surface.hpp" + +// MARK: - Construction + +graphite::quickdraw::surface::surface(const quickdraw::size &size) + : m_size(size), + m_data(size.width * size.height * constants::color_width) +{ + +} + +graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) + : m_size(width, height), + m_data(width * height * constants::color_width) +{ + +} + +graphite::quickdraw::surface::surface(const quickdraw::size& size, union color color) + : m_size(size), + m_data(size.width * size.height * constants::color_width) +{ + m_data.set(color.value); +} + +graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, union color color) + : m_size(width, height), + m_data(width * height * constants::color_width) +{ + m_data.set(color.value); +} + +// MARK: - Accessors + +auto graphite::quickdraw::surface::raw() const -> const data::block& +{ + return m_data; +} + +auto graphite::quickdraw::surface::size() const -> struct quickdraw::size +{ + return m_size; +} + +// MARK: - Pixel Access + +auto graphite::quickdraw::surface::at(const point &p) const -> union color +{ + return at(p.x, p.y); +} + +auto graphite::quickdraw::surface::at(std::int16_t x, std::int16_t y) const -> union color +{ + return at(y * m_size.width + x); +} + +auto graphite::quickdraw::surface::at(std::uint32_t offset) const -> union color +{ + return m_data.get()[offset]; +} + +auto graphite::quickdraw::surface::set(const point& p, union color color) -> void +{ + set(p.x, p.y, color); +} + +auto graphite::quickdraw::surface::set(std::int16_t x, std::int16_t y, union color color) -> void +{ + set(y * m_size.width + x, color); +} + +auto graphite::quickdraw::surface::set(std::uint32_t offset, union color color) -> void +{ + m_data.set(color.value, 4, offset); +} \ No newline at end of file diff --git a/libGraphite/quickdraw/support/surface.hpp b/libGraphite/quickdraw/support/surface.hpp new file mode 100644 index 0000000..87f1e94 --- /dev/null +++ b/libGraphite/quickdraw/support/surface.hpp @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/quickdraw/type/point.hpp" +#include "libGraphite/quickdraw/type/size.hpp" +#include "libGraphite/quickdraw/type/color.hpp" +#include "libGraphite/data/data.hpp" + +namespace graphite::quickdraw +{ + struct surface + { + public: + surface() = default; + explicit surface(const size& size); + surface(std::int16_t width, std::int16_t height); + surface(const size& size, union color color); + surface(std::int16_t width, std::int16_t height, union color color); + surface(const surface& surface) = default; + surface(surface&& surface) noexcept = default; + + auto operator=(const surface&) -> surface& = default; + auto operator=(surface&&) -> surface& = default; + + [[nodiscard]] auto raw() const -> const data::block&; + [[nodiscard]] auto size() const -> struct size; + + [[nodiscard]] auto at(const point& p) const -> union color; + [[nodiscard]] auto at(std::uint32_t offset) const -> union color; + [[nodiscard]] auto at(std::int16_t x, std::int16_t y) const -> union color; + + auto set(const point& p, union color color) -> void; + auto set(std::int16_t x, std::int16_t y, union color color) -> void; + auto set(std::uint32_t offset, union color color) -> void; + + private: + quickdraw::size m_size; + data::block m_data; + }; +} diff --git a/libGraphite/quickdraw/type/coding_type.hpp b/libGraphite/quickdraw/type/coding_type.hpp new file mode 100644 index 0000000..353c815 --- /dev/null +++ b/libGraphite/quickdraw/type/coding_type.hpp @@ -0,0 +1,29 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +namespace graphite::quickdraw +{ + enum class coding_type + { + quickdraw, macintosh + }; +} diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp new file mode 100644 index 0000000..7c8aa4b --- /dev/null +++ b/libGraphite/quickdraw/type/color.cpp @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quickdraw/type/color.hpp" + +// MARK: - Construction + +auto graphite::quickdraw::rgb(color_component r, color_component g, color_component b, color_component a) -> union color +{ + return { + .components = { + .red = r, .green = g, .blue = b, .alpha = a + }; + } +} + +// MARK: - Pre-defined Colors + +auto graphite::quickdraw::colors::white() -> union color +{ + return rgb(255, 255, 255); +} + +auto graphite::quickdraw::colors::black() -> union color +{ + return rgb(0, 0, 0); +} + +auto graphite::quickdraw::colors::clear() -> union color +{ + return rgb(0, 0, 0, 0); +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/color.hpp b/libGraphite/quickdraw/type/color.hpp new file mode 100644 index 0000000..040d366 --- /dev/null +++ b/libGraphite/quickdraw/type/color.hpp @@ -0,0 +1,57 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace graphite::quickdraw +{ + typedef std::uint8_t color_component; + + union color + { + std::uint32_t value; + struct { + color_component red; + color_component green; + color_component blue; + color_component alpha; + } components; + }; + + auto operator==(const union color& lhs, const union color& rhs) -> bool { return lhs.value == rhs.value; } + auto operator!=(const union color& lhs, const union color& rhs) -> bool { return lhs.value != rhs.value; } + + [[nodiscard]] auto rgb(color_component r, color_component g, color_component b, color_component a = 255) -> union color; + + namespace constants + { + constexpr std::size_t color_width = sizeof(union color); + } + + namespace colors + { + [[nodiscard]] auto black() -> union color; + [[nodiscard]] auto white() -> union color; + [[nodiscard]] auto clear() -> union color; + } +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/pixel_format.hpp b/libGraphite/quickdraw/type/pixel_format.hpp new file mode 100644 index 0000000..83a185c --- /dev/null +++ b/libGraphite/quickdraw/type/pixel_format.hpp @@ -0,0 +1,38 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace graphite::quickdraw +{ + enum pixel_format : std::uint8_t + { + unknown = 0x00, + monochrome = 0x01, + indexed_2bit = 0x02, + indexed_4bit = 0x04, + indexed_8bit = 0x08, + rgb555 = 0x10, + true_color = 0x18, + true_color_alpha = 0x20 + }; +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/point.hpp b/libGraphite/quickdraw/type/point.hpp new file mode 100644 index 0000000..2830bd2 --- /dev/null +++ b/libGraphite/quickdraw/type/point.hpp @@ -0,0 +1,123 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/data/encoding.hpp" +#include "libGraphite/quickdraw/type/coding_type.hpp" + +namespace graphite::quickdraw +{ + template::value>::type* = nullptr> + struct point + { + public: + T x { 0 }; + T y { 0 }; + + point() = default; + explicit point(T v) : x(v), y(v) {} + point(T x, T y) : x(x), y(y) {} + point(const point&) = default; + point(point&&) noexcept = default; + + explicit point(data::reader& reader) + { + y = read_component(reader); + x = read_component(reader); + } + + point(data::reader& reader, coding_type type) + { + switch (type) { + case coding_type::macintosh: { + x = read_component(reader); + y = read_component(reader); + break; + } + case coding_type::quickdraw: { + y = read_component(reader); + x = read_component(reader); + break; + } + } + } + + static auto read(data::reader& reader, coding_type type) -> point { return { reader, type }; } + + auto encode(data::writer& writer) -> void + { + encode(writer, coding_type::quickdraw); + } + + auto encode(data::writer& writer, coding_type type) -> void + { + switch (type) { + case coding_type::macintosh: { + write_component(x, writer); + write_component(y, writer); + break; + } + case coding_type::quickdraw: { + write_component(y, writer); + write_component(x, writer); + break; + } + } + } + + auto operator=(const point& p) -> point& { x = p.x; y = p.y; return *this; } + auto operator=(point&& p) noexcept -> point& { x = p.x; y = p.y; return *this; } + + auto operator==(const point& p) const -> bool { return x == p.x && y == p.y; } + auto operator!=(const point& p) const -> bool { return x != p.x && y != p.y; } + + auto operator+(const point& p) const -> point { return { x + p.x, y + p.y }; } + auto operator-(const point& p) const -> point { return { x - p.x, y - p.y }; } + + template::value>> + auto operator*(U v) const -> point { return { x * static_cast(v), y * static_cast(v) }; } + + template::value>> + auto operator/(U v) const -> point { return { x / static_cast(v), y / static_cast(v) }; } + + template::value>> + auto cast() const -> point { return { static_cast(x), static_cast(y) }; } + + private: + auto read_component(data::reader& reader) -> T { return reader.read_integer(); } + auto write_component(T value, data::writer& writer) -> void { writer.write_integer(value); } + }; + + template<> + auto point::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } + + template<> + auto point::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } + + template<> + auto point::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } + + template<> + auto point::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } + +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/rect.hpp b/libGraphite/quickdraw/type/rect.hpp new file mode 100644 index 0000000..3dc22a1 --- /dev/null +++ b/libGraphite/quickdraw/type/rect.hpp @@ -0,0 +1,81 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/data/reader.hpp" +#include "libGraphite/data/writer.hpp" +#include "libGraphite/quickdraw/type/coding_type.hpp" +#include "libGraphite/quickdraw/type/point.hpp" +#include "libGraphite/quickdraw/type/size.hpp" + +namespace graphite::quickdraw +{ + template::value>::type* = nullptr> + struct rect + { + public: + point origin { 0 }; + size size { 0 }; + + rect() = default; + explicit rect(T v) : origin(v), size(v) {} + rect(struct point origin, struct quickdraw::size size) : origin(origin), size(size) {} + rect(const rect&) = default; + rect(rect&&) noexcept = default; + + explicit rect(data::reader& reader) : origin(reader), size(reader) {} + rect(data::reader& reader, coding_type type) : origin(reader, type), size(reader, type) {} + + static auto read(data::reader& reader, coding_type type) -> rect { return { reader, type }; } + + auto encode(data::writer& writer) -> void + { + encode(writer, coding_type::quickdraw); + } + + auto encode(data::writer& writer, coding_type type) -> void + { + origin.encode(writer, type); + size.encode(writer, type); + } + + auto operator=(const rect& r) -> rect& { origin = r.origin; size = r.size; return *this; } + auto operator=(rect&& r) noexcept -> rect& { origin = r.origin; size = r.size; return *this; } + + auto operator==(const rect& r) const -> bool { return origin == r.origin && size == r.size; } + auto operator!=(const rect& r) const -> bool { return origin != r.origin && size != r.size; } + + auto operator+(const rect& r) const -> rect { return { origin + r.origin, size + r.size }; } + auto operator-(const rect& r) const -> rect { return { origin - r.origin, size - r.size }; } + + template::value>> + auto operator*(U v) const -> rect { return { origin * static_cast(v), size * static_cast(v) }; } + + template::value>> + auto operator/(U v) const -> rect { return { origin / static_cast(v), size / static_cast(v) }; } + + template::value>> + auto cast() const -> rect { return { origin.cast(), size.cast() }; } + }; + +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/size.hpp b/libGraphite/quickdraw/type/size.hpp new file mode 100644 index 0000000..37e7d22 --- /dev/null +++ b/libGraphite/quickdraw/type/size.hpp @@ -0,0 +1,124 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/data/reader.hpp" +#include "libGraphite/data/writer.hpp" +#include "libGraphite/quickdraw/type/coding_type.hpp" + +namespace graphite::quickdraw +{ + template::value>::type* = nullptr> + struct size + { + public: + T width { 0 }; + T height { 0 }; + + size() = default; + explicit size(T v) : width(v), height(v) {} + size(T width, T height) : width(width), height(height) {} + size(const size&) = default; + size(size&&) noexcept = default; + + explicit size(data::reader& reader) + { + height = read_component(reader); + width = read_component(reader); + } + + size(data::reader& reader, coding_type type) + { + switch (type) { + case coding_type::macintosh: { + width = read_component(reader); + height = read_component(reader); + break; + } + case coding_type::quickdraw: { + height = read_component(reader); + width = read_component(reader); + break; + } + } + } + + static auto read(data::reader& reader, coding_type type) -> size { return { reader, type }; } + + auto encode(data::writer& writer) -> void + { + encode(writer, coding_type::quickdraw); + } + + auto encode(data::writer& writer, coding_type type) -> void + { + switch (type) { + case coding_type::macintosh: { + write_component(width, writer); + write_component(height, writer); + break; + } + case coding_type::quickdraw: { + write_component(height, writer); + write_component(width, writer); + break; + } + } + } + + auto operator=(const size& s) -> size& { width = s.width; height = s.height; return *this; } + auto operator=(size&& s) noexcept -> size& { width = s.width; height = s.height; return *this; } + + auto operator==(const size& s) const -> bool { return width == s.width && height == s.height; } + auto operator!=(const size& s) const -> bool { return width != s.width && height != s.height; } + + auto operator+(const size& s) const -> size { return { width + s.width, height + s.height }; } + auto operator-(const size& s) const -> size { return { width - s.width, height - s.height }; } + + template::value>> + auto operator*(U v) const -> size { return { width * static_cast(v), height * static_cast(v) }; } + + template::value>> + auto operator/(U v) const -> size { return { width / static_cast(v), height / static_cast(v) }; } + + template::value>> + auto cast() const -> size { return { static_cast(width), static_cast(height) }; } + + private: + auto read_component(data::reader& reader) -> T { return reader.read_integer(); } + auto write_component(T value, data::writer& writer) -> void { writer.write_integer(value); } + }; + + template<> + auto size::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } + + template<> + auto size::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } + + template<> + auto size::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } + + template<> + auto size::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } + +} \ No newline at end of file diff --git a/libGraphite/quickdraw/cicn.cpp b/libGraphite/quickdraw_old/cicn.cpp similarity index 100% rename from libGraphite/quickdraw/cicn.cpp rename to libGraphite/quickdraw_old/cicn.cpp diff --git a/libGraphite/quickdraw/cicn.hpp b/libGraphite/quickdraw_old/cicn.hpp similarity index 100% rename from libGraphite/quickdraw/cicn.hpp rename to libGraphite/quickdraw_old/cicn.hpp diff --git a/libGraphite/quickdraw/clut.cpp b/libGraphite/quickdraw_old/clut.cpp similarity index 100% rename from libGraphite/quickdraw/clut.cpp rename to libGraphite/quickdraw_old/clut.cpp diff --git a/libGraphite/quickdraw/clut.hpp b/libGraphite/quickdraw_old/clut.hpp similarity index 100% rename from libGraphite/quickdraw/clut.hpp rename to libGraphite/quickdraw_old/clut.hpp diff --git a/libGraphite/quickdraw/geometry.cpp b/libGraphite/quickdraw_old/geometry.cpp similarity index 100% rename from libGraphite/quickdraw/geometry.cpp rename to libGraphite/quickdraw_old/geometry.cpp diff --git a/libGraphite/quickdraw/geometry.hpp b/libGraphite/quickdraw_old/geometry.hpp similarity index 100% rename from libGraphite/quickdraw/geometry.hpp rename to libGraphite/quickdraw_old/geometry.hpp diff --git a/libGraphite/quickdraw/internal/color.cpp b/libGraphite/quickdraw_old/internal/color.cpp similarity index 100% rename from libGraphite/quickdraw/internal/color.cpp rename to libGraphite/quickdraw_old/internal/color.cpp diff --git a/libGraphite/quickdraw/internal/color.hpp b/libGraphite/quickdraw_old/internal/color.hpp similarity index 100% rename from libGraphite/quickdraw/internal/color.hpp rename to libGraphite/quickdraw_old/internal/color.hpp diff --git a/libGraphite/quickdraw/internal/packbits.cpp b/libGraphite/quickdraw_old/internal/packbits.cpp similarity index 100% rename from libGraphite/quickdraw/internal/packbits.cpp rename to libGraphite/quickdraw_old/internal/packbits.cpp diff --git a/libGraphite/quickdraw/internal/packbits.hpp b/libGraphite/quickdraw_old/internal/packbits.hpp similarity index 100% rename from libGraphite/quickdraw/internal/packbits.hpp rename to libGraphite/quickdraw_old/internal/packbits.hpp diff --git a/libGraphite/quickdraw/internal/surface.cpp b/libGraphite/quickdraw_old/internal/surface.cpp similarity index 100% rename from libGraphite/quickdraw/internal/surface.cpp rename to libGraphite/quickdraw_old/internal/surface.cpp diff --git a/libGraphite/quickdraw/internal/surface.hpp b/libGraphite/quickdraw_old/internal/surface.hpp similarity index 100% rename from libGraphite/quickdraw/internal/surface.hpp rename to libGraphite/quickdraw_old/internal/surface.hpp diff --git a/libGraphite/quickdraw/pict.cpp b/libGraphite/quickdraw_old/pict.cpp similarity index 100% rename from libGraphite/quickdraw/pict.cpp rename to libGraphite/quickdraw_old/pict.cpp diff --git a/libGraphite/quickdraw/pict.hpp b/libGraphite/quickdraw_old/pict.hpp similarity index 100% rename from libGraphite/quickdraw/pict.hpp rename to libGraphite/quickdraw_old/pict.hpp diff --git a/libGraphite/quickdraw/pixmap.cpp b/libGraphite/quickdraw_old/pixmap.cpp similarity index 100% rename from libGraphite/quickdraw/pixmap.cpp rename to libGraphite/quickdraw_old/pixmap.cpp diff --git a/libGraphite/quickdraw/pixmap.hpp b/libGraphite/quickdraw_old/pixmap.hpp similarity index 100% rename from libGraphite/quickdraw/pixmap.hpp rename to libGraphite/quickdraw_old/pixmap.hpp diff --git a/libGraphite/quickdraw/ppat.cpp b/libGraphite/quickdraw_old/ppat.cpp similarity index 100% rename from libGraphite/quickdraw/ppat.cpp rename to libGraphite/quickdraw_old/ppat.cpp diff --git a/libGraphite/quickdraw/ppat.hpp b/libGraphite/quickdraw_old/ppat.hpp similarity index 100% rename from libGraphite/quickdraw/ppat.hpp rename to libGraphite/quickdraw_old/ppat.hpp diff --git a/libGraphite/quickdraw/rle.cpp b/libGraphite/quickdraw_old/rle.cpp similarity index 100% rename from libGraphite/quickdraw/rle.cpp rename to libGraphite/quickdraw_old/rle.cpp diff --git a/libGraphite/quickdraw/rle.hpp b/libGraphite/quickdraw_old/rle.hpp similarity index 100% rename from libGraphite/quickdraw/rle.hpp rename to libGraphite/quickdraw_old/rle.hpp diff --git a/libGraphite/resources/sound.cpp b/libGraphite/resources/sound.cpp deleted file mode 100644 index 8733b1e..0000000 --- a/libGraphite/resources/sound.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// -// Created by Tom Hancocks on 24/03/2020. -// - -#include "libGraphite/resources/sound.hpp" -#include "libGraphite/rsrc/manager.hpp" -#include "libGraphite/data/reader.hpp" -#include -#include - -// MARK: - IMA4 Decoding - -// Refer to https://wiki.multimedia.cx/index.php?title=IMA_ADPCM, -// http://www.cs.columbia.edu/~hgs/audio/dvi/IMA_ADPCM.pdf - -inline int32_t ima_step_index(int32_t index, int8_t nibble) -{ - static int32_t ima_index_table[16] = { - -1, -1, -1, -1, 2, 4, 6, 8, - -1, -1, -1, -1, 2, 4, 6, 8 - }; - - return std::min(std::max(0, index + ima_index_table[nibble]), 88); -} - -inline int32_t ima_predictor(int32_t predictor, int8_t nibble, int32_t index) -{ - static int32_t ima_step_table[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, - 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, - 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, - 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, - 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, - 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 - }; - - int32_t diff = 0; - auto stepsize = ima_step_table[index]; - - if (nibble & 4) diff += stepsize; - if (nibble & 2) diff += stepsize >> 1; - if (nibble & 1) diff += stepsize >> 2; - diff += stepsize >> 3; - if (nibble & 8) diff = -diff; - - return std::min(std::max(-32768, predictor + diff), 32767); -} - -// MARK: - Constructor - -graphite::resources::sound::sound(std::shared_ptr data, int64_t id, std::string name) - : m_ref_count(0), m_name(std::move(name)), m_id(id) -{ - // Setup a reader for the snd data, and then parse it. - data::reader snd_reader(std::move(data)); - parse(snd_reader); -} - -graphite::resources::sound::sound(uint32_t sample_rate, uint8_t sample_bits, std::vector> sample_data) - : m_ref_count(0), m_name("Sound"), m_id(0), m_sample_rate_int(sample_rate), m_sample_rate_frac(0), m_sample_bits(sample_bits), m_sample_data(std::move(sample_data)) -{ - -} - -auto graphite::resources::sound::load_resource(int64_t id) -> std::shared_ptr -{ - if (auto snd_res = graphite::rsrc::manager::shared_manager().find("snd ", id).lock()) { - return std::make_shared(snd_res->data(), id, snd_res->name()); - } - return nullptr; -} - -// MARK: - Accessors - -auto graphite::resources::sound::sample_bits() const -> uint8_t -{ - return m_sample_bits; -} - -auto graphite::resources::sound::sample_rate() const -> uint32_t -{ - return m_sample_rate_int; -} - -auto graphite::resources::sound::samples() -> std::vector> -{ - return m_sample_data; -} - -auto graphite::resources::sound::data() -> std::shared_ptr -{ - auto data = std::make_shared(); - graphite::data::writer writer(data); - encode(writer); - return data; -} - -// MARK: - Parsing/Reading - -auto graphite::resources::sound::parse(graphite::data::reader& snd_reader) -> void -{ - // Save the position because our buffer commands reference data by offset from the record start - auto reader_pos = snd_reader.position(); - - auto snd_format = static_cast(snd_reader.read_short()); - - uint16_t channel_init_option = 0; - if (snd_format == type1) { - // We only support sampled sounds; validate the format 1 sound type now - auto num_data_formats = snd_reader.read_short(); - if (num_data_formats != 1) { - throw std::runtime_error("Encountered an incompatble snd format: " + std::to_string(num_data_formats) + - " formats, 1 expected, " + m_name); - } - - auto data_format_id = snd_reader.read_short(); - if (data_format_id != sampledSynth) { - throw std::runtime_error("Encountered an incompatble snd format: format " + std::to_string(data_format_id) + - ", 5 expected, " + m_name); - } - - channel_init_option = snd_reader.read_long(); - } - else if (snd_format == type2) { - m_ref_count = snd_reader.read_short(); - } - else { - throw std::runtime_error("Encountered an incompatble snd format: " + std::to_string(snd_format) + ", " + m_name); - } - - // Read command array - auto num_commands = snd_reader.read_short(); - std::vector commands; - for (auto i = 0; i < num_commands; i++) { - auto cmd = snd_reader.read_short(); - commands.emplace_back(static_cast(cmd & 0x7FFF), snd_reader.read_short(), snd_reader.read_long(), cmd & 0x8000); - } - - // We only support sounds with a single buffer command -- validate that now - if (commands.size() != 1 || commands[0].cmd != buffer) { - throw std::runtime_error("Encountered an incompatble snd format: " + std::to_string(commands.size()) + - " commands, first command " + std::to_string(static_cast(commands[0].cmd)) + - ", " + m_name); - } - - // Move the reader to the buffer command's data offset - snd_reader.set_position(reader_pos + commands[0].param2); - - sound_header_record std_header {}; - - std_header.data_pointer = snd_reader.read_long(); - std_header.length = snd_reader.read_long(); - std_header.sample_rate = snd_reader.read_long(); - std_header.loop_start = snd_reader.read_long(); - std_header.loop_end = snd_reader.read_long(); - std_header.sample_encoding = static_cast(snd_reader.read_byte()); - std_header.base_frequency = snd_reader.read_byte(); - - m_sample_rate_int = std_header.sample_rate >> 16; - m_sample_rate_frac = std_header.sample_rate & 0xFFFF; - - if (std_header.sample_encoding == extSH) { - extended_sound_header_record ext_header {}; - ext_header.num_frames = snd_reader.read_long(); - // skip aiff_sample_rate, marker_chunk, instrument_chunks, aes_recording - snd_reader.move(22); - ext_header.sample_size = snd_reader.read_short(); - // skip future_use values - snd_reader.move(14); - - m_sample_bits = ext_header.sample_size; - // Resize the data vector to fit the channel/frame count - m_sample_data.resize(std_header.length, std::vector(ext_header.num_frames)); - - // Raw sound data follows, channels interleaved - for (auto f = 0; f < ext_header.num_frames; f++) { - for (auto c = 0; c < std_header.length; c++) { - m_sample_data[c][f] = ext_header.sample_size == 8 ? snd_reader.read_byte() : snd_reader.read_short(); - } - } - } - else if (std_header.sample_encoding == cmpSH) { - compressed_sound_header_record cmp_header {}; - cmp_header.num_frames = snd_reader.read_long(); - // skip aiff_sample_rate, marker_chunk - snd_reader.move(14); - cmp_header.format = snd_reader.read_long(); - // skip future_use_2, state_vars, leftover_samples - snd_reader.move(12); - cmp_header.compression_id = static_cast(snd_reader.read_signed_short()); - cmp_header.packet_size = snd_reader.read_short(); - // skip snth_id - snd_reader.move(2); - cmp_header.sample_size = snd_reader.read_short(); - - // We only support fixed ima4 compression - if (cmp_header.compression_id != fixedCompression || cmp_header.format != 0x696D6134) { - throw std::runtime_error("Encountered an incompatble snd format: " + std::to_string(cmp_header.compression_id) + - " compression ID, format " + std::to_string(cmp_header.format) + - ", expecting fixed ima4 compression, " + m_name); - } - - m_sample_bits = 16; - // Resize the data vector to fit the channel count; sample count is frame count * 64 - m_sample_data.resize(std_header.length, std::vector(cmp_header.num_frames * 64)); - - // Iterate over frames and expand into samples - for (auto f = 0; f < cmp_header.num_frames; f++) { - for (auto c = 0; c < std_header.length; c++) { - // Apple IMA4 parameters described in TN1081: - // https://www.fenestrated.net/mirrors/Apple%20Technotes%20(As%20of%202002)/tn/tn1081.html - auto preamble = snd_reader.read_short(); - int32_t predictor = static_cast(preamble & 0xFF80); - int32_t step_index = preamble & 0x007F; - - for (auto i = 0; i < 32; i++) { - uint8_t byte = snd_reader.read_byte(); - uint8_t lower_nibble = byte & 0x0F; - uint8_t upper_nibble = byte >> 4; - - predictor = ima_predictor(predictor, lower_nibble, step_index); - step_index = ima_step_index(step_index, lower_nibble); - m_sample_data[c][f * 64 + i * 2] = 32768 + predictor; - - predictor = ima_predictor(predictor, upper_nibble, step_index); - step_index = ima_step_index(step_index, upper_nibble); - m_sample_data[c][f * 64 + i * 2 + 1] = 32768 + predictor; - } - } - } - } - else { - m_sample_bits = 8; - // Resize the data vector to fit the channel/frame count - m_sample_data.resize(1, std::vector(std_header.length)); - - // Raw 8-bit mono sound data follows - for (auto f = 0; f < std_header.length; f++) { - m_sample_data[0][f] = snd_reader.read_byte(); - } - } -} - -// MARK: - Encoder / Writing - -auto graphite::resources::sound::encode(graphite::data::writer& snd_writer) -> void -{ - // Write the snd header for a format 1 sound - snd_writer.write_short(static_cast(type1)); - snd_writer.write_short(1); // num_data_formats - snd_writer.write_short(static_cast(sampledSynth)); // first_data_format_id - snd_writer.write_long(static_cast(initMono)); // channel_init_option - snd_writer.write_short(1); // num_commands - snd_writer.write_short(0x8000 | static_cast(buffer)); // command: cmd, high bit set to indicate offset - snd_writer.write_short(0); // command: param1 - snd_writer.write_long(20); // command: param2, offset from start of record to sound data - - auto num_samples = m_sample_data.size() ? m_sample_data[0].size() : 0; - - // Write the standard sampled sound header fields - snd_writer.write_long(0); // data pointer - snd_writer.write_long(num_samples); // number of samples - snd_writer.write_long(m_sample_rate_int << 16 | m_sample_rate_frac); // sample rate (fixed-point) - snd_writer.write_long(0); // loop start - snd_writer.write_long(0); // loop end - snd_writer.write_byte(static_cast(stdSH)); // encoding option - snd_writer.write_byte(0); // base frequency - - // Truncate and write the sound data as 8-bit mono - for (auto f = 0; f < num_samples; f++) { - snd_writer.write_byte(m_sample_data[0][f] >> (m_sample_bits - 8)); - } -} - -// MARK: - Sound record construction - -graphite::resources::sound::command_record::command_record(command cmd, uint16_t param1, uint32_t param2, bool data_offset_flag) - : cmd(cmd), param1(param1), param2(param2), data_offset_flag(data_offset_flag) -{ - -} diff --git a/libGraphite/resources/sound.hpp b/libGraphite/resources/sound.hpp deleted file mode 100644 index 9a07f60..0000000 --- a/libGraphite/resources/sound.hpp +++ /dev/null @@ -1,176 +0,0 @@ -// -// Created by Tom Hancocks on 24/03/2020. -// - -#if !defined(GRAPHITE_SOUND_HPP) -#define GRAPHITE_SOUND_HPP - -#include -#include -#include -#include "libGraphite/data/data.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" - -namespace graphite::resources { - - class sound - { - private: - enum format : uint16_t { type1 = 0x0001, type2 = 0x0002 }; - - enum command : uint16_t - { - null = 0, // Do nothing - quiet = 3, // Stop a sound that is playing - flush = 4, // Flush a sound channel - reinit = 5, // Reinitialise a sound channel - wait = 10, // Suspend processing in a channel - pause = 11, // Pause processing in a channel - resume = 12, // Resume processing in a channel - callback = 13, // Execute a callback procedure - sync = 14, // Synchronise channels - available = 24, // See if initialisation options are supported. - version = 25, // Determine version - totalLoad = 26, // Report total cpu load - load = 27, // Report cpu load for a new channel - freqDuration = 40, // Play a note for a duration - rest = 41, // Rest a channel for a duration - freq = 42, // Change pitch of a sound - amp = 43, // Change the amplitude of a sound - timbre = 44, // Change the timbre of a sound - getAmp = 45, // Get the amplitude of a sound - volume = 46, // Set the volume - getVolume = 47, // Get the volume - waveTable = 60, // Install a wave table as a voice - play_sound = 80, // Install a sampled sound as a voice - buffer = 81, // Play a sampled sound - rate = 82, // Set the pitch of a sampled sound - getRate = 83, // Get the pitch of a sampled sound - }; - - enum data_format : uint16_t { - squareWaveSynth = 1, // Square-wave data - waveTableSynth = 3, // Wave-table data - sampledSynth = 5, // Sampled-sound data - }; - - enum channel_init_option : uint32_t { - initChanLeft = 0x0002, // Left stereo channel - initChanRight = 0x0003, // Right stereo channel - waveInitChannel0 = 0x0004, // Wave-table channel 0 - waveInitChannel1 = 0x0005, // Wave-table channel 1 - waveInitChannel2 = 0x0006, // Wave-table channel 2 - waveInitChannel3 = 0x0007, // Wave-table channel 3 - initMono = 0x0080, // Monophonic channel - initStereo = 0x00C0, // Stereo channel - initMACE3 = 0x0300, // 3:1 compression - initMACE6 = 0x0400, // 6:1 compression - initNoInterp = 0x0004, // No linear interpolation - initNoDrop = 0x0008, // No drop-sample conversion - }; - - enum sound_encoding : uint8_t { - stdSH = 0x00, // Standard sound header - extSH = 0xFF, // Extended sound header - cmpSH = 0xFE, // Compressed sound header - }; - - enum compression_id : int16_t { - variableCompression = -2, // Variable-ratio compression - fixedCompression = -1, // Fixed-ratio compression - notCompressed = 0, // Non-compressed samples - threeToOne = 3, // 3:1 compressed samples - sixToOne = 6, // 6:1 compressed samples - }; - - struct command_record - { - public: - enum command cmd; - uint16_t param1; - uint32_t param2; - bool data_offset_flag; - - command_record(command cmd, uint16_t param1, uint32_t param2, bool data_offset_flag); - }; - - struct sound_header_record - { - public: - uint32_t data_pointer; // If nil, samples follow header - uint32_t length; // Number of samples in array - uint32_t sample_rate; // Sample rate (Fixed) - uint32_t loop_start; // Loop start point sample byte number - uint32_t loop_end; // Loop end point sample byte number - enum sound_encoding sample_encoding; // Sample encoding option - uint8_t base_frequency; // Base frequency of sample - }; - - struct extended_sound_header_record - { - public: - // The length field in standard_header is interpreted as num_channels - uint32_t num_frames; // The number of frames in the sampled-sound data. - // Each frame contains num_channels bytes for 8-bit sound data. - uint8_t aiff_sample_rate[10]; // The sample rate at which the frames were sampled before compression, - // as expressed in the 80-bit extended data type representation - uint32_t marker_chunk; // Pointer to synchronization information. Unused, set to NIL. - uint32_t instrument_chunks; // Pointer to instrument information. - uint32_t aes_recording; // Pointer to information related to audio recording devices. - uint16_t sample_size; // The number of bits in each sample frame. - uint16_t future_use_1; // Reserved - uint32_t future_use_2; // Reserved - uint32_t future_use_3; // Reserved - uint32_t future_use_4; // Reserved - }; - - struct compressed_sound_header_record - { - public: - // The length field in standard_header is interpreted as num_channels - uint32_t num_frames; // The number of frames in the sampled-sound data. - // Each frame contains num_channels bytes for 8-bit sound data. - uint8_t aiff_sample_rate[10]; // The sample rate at which the frames were sampled before compression, - // as expressed in the 80-bit extended data type representation - uint32_t marker_chunk; // Pointer to synchronization information. Unused, set to NIL. - uint32_t format; // OSType, e.g. 'MAC3' for MACE3:1 - uint32_t future_use_2; // Reserved - uint32_t state_vars; // Pointer to StateBlock - uint32_t leftover_samples; // Pointer to LeftOverBlock - enum compression_id compression_id; // The compression algorithm used on the samples in the compressed sound header. - uint16_t packet_size; // The size, in bits, of the smallest element that a given expansion algorithm can work with. - uint16_t snth_id; // This field is unused. You should set it to 0. - uint16_t sample_size; // The size of the sample before it was compressed. - }; - - // Basic resource information - int16_t m_id {}; - std::string m_name; - - // Sound information - uint16_t m_ref_count {}; - uint32_t m_sample_rate_int {}; - uint16_t m_sample_rate_frac {}; - uint8_t m_sample_bits {}; - std::vector> m_sample_data; - - auto parse(graphite::data::reader& snd_reader) -> void; - auto encode(graphite::data::writer& snd_writer) -> void; - - public: - explicit sound(std::shared_ptr data, int64_t id = 0, std::string name = ""); - sound(uint32_t sample_rate, uint8_t sample_bits, std::vector> sample_data); - - static auto load_resource(int64_t id) -> std::shared_ptr; - - [[nodiscard]] auto sample_bits() const -> uint8_t; - [[nodiscard]] auto sample_rate() const -> uint32_t; - auto samples() -> std::vector>; - - auto data() -> std::shared_ptr; - }; - -} - -#endif diff --git a/libGraphite/resources/string.cpp b/libGraphite/resources/string.cpp deleted file mode 100644 index f58b017..0000000 --- a/libGraphite/resources/string.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Created by Tom Hancocks on 24/03/2020. -// - -#include "libGraphite/resources/string.hpp" -#include "libGraphite/rsrc/manager.hpp" -#include "libGraphite/data/reader.hpp" - -// MARK: - Constructor - -graphite::resources::string::string(std::string str, std::shared_ptr data, int64_t id, std::string name) - : m_str(std::move(str)), m_name(std::move(name)), m_id(id) -{ - // TODO: Add implementation to extract a new copy of the data that is not a pointer. -} - -auto graphite::resources::string::load_resource(int64_t id) -> std::shared_ptr -{ - if (auto str_res = graphite::rsrc::manager::shared_manager().find("STR ", id).lock()) { - auto reader = graphite::data::reader(str_res->data()); - auto str = reader.read_pstr(); - // TODO: Rest of the resource is data - return std::make_shared(str, nullptr, id, str_res->name()); - } - return nullptr; -} - -// MARK: - Accessor - -auto graphite::resources::string::value() const -> std::string -{ - return m_str; -} - -auto graphite::resources::string::data() const -> graphite::data::data -{ - return m_data; -} - -auto graphite::resources::string::set_string(const std::string& str) -> void -{ - m_str = str; -} - -auto graphite::resources::string::set_data(const data::data& data) -> void -{ - m_data = data; -} diff --git a/libGraphite/resources/string.hpp b/libGraphite/resources/string.hpp deleted file mode 100644 index c408d59..0000000 --- a/libGraphite/resources/string.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// -// Created by Tom Hancocks on 24/03/2020. -// - -#if !defined(GRAPHITE_STRING_HPP) -#define GRAPHITE_STRING_HPP - -#include -#include "libGraphite/data/data.hpp" - -namespace graphite::resources { - - struct string - { - private: - int64_t m_id {}; - std::string m_name; - std::string m_str; - data::data m_data; - - public: - string(std::string str, std::shared_ptr data, int64_t id = 0, std::string name = ""); - - static auto load_resource(int64_t id) -> std::shared_ptr; - - auto value() const -> std::string; - auto data() const -> data::data; - - auto set_string(const std::string& str) -> void; - auto set_data(const data::data& data) -> void; - }; - -} - - -#endif //GRAPHITE_STRING_HPP diff --git a/libGraphite/rsrc/attribute.cpp b/libGraphite/rsrc/attribute.cpp new file mode 100644 index 0000000..a89d9fa --- /dev/null +++ b/libGraphite/rsrc/attribute.cpp @@ -0,0 +1,58 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/attribute.hpp" +#include "libGraphite/util/hashing.hpp" + +// MARK: - Construction + +graphite::rsrc::attribute::attribute(const std::string &name, const std::string &value) + : m_name(name), m_value(value) +{ +} + +template::value>::type*> +graphite::rsrc::attribute::attribute(const std::string &name, T value) + : m_name(name), m_value(std::to_string(value)) +{ +} + +// MARK: - Accessors + +auto graphite::rsrc::attribute::hash_value() const -> hash +{ + return hashing::xxh64(m_name.c_str(), m_name.size()); +} + +auto graphite::rsrc::attribute::name() const -> const std::string& +{ + return m_name; +} + +auto graphite::rsrc::attribute::string_value() const -> const std::string& +{ + return m_value; +} + +template::value>::type*> +auto graphite::rsrc::attribute::value() const -> T +{ + return std::to_integer(m_value); +} \ No newline at end of file diff --git a/libGraphite/rsrc/attribute.hpp b/libGraphite/rsrc/attribute.hpp new file mode 100644 index 0000000..0780277 --- /dev/null +++ b/libGraphite/rsrc/attribute.hpp @@ -0,0 +1,51 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace graphite::rsrc +{ + struct attribute + { + public: + typedef std::uint64_t hash; + + public: + attribute(const std::string& name, const std::string& value); + + template::value>::type* = nullptr> + attribute(const std::string& name, T value); + + [[nodiscard]] auto hash_value() const -> hash; + [[nodiscard]] auto name() const -> const std::string&; + [[nodiscard]] auto string_value() const -> const std::string&; + + template::value>::type* = nullptr> + [[nodiscard]] auto value() const -> T; + + private: + std::string m_name; + std::string m_value; + }; +} + diff --git a/libGraphite/rsrc/classic.cpp b/libGraphite/rsrc/classic.cpp deleted file mode 100644 index f6e3b49..0000000 --- a/libGraphite/rsrc/classic.cpp +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2020 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include -#include "libGraphite/hints.hpp" -#include "libGraphite/rsrc/classic.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" - -// MARK: - Parsing / Reading - -auto graphite::rsrc::classic::parse(const std::shared_ptr& reader) -> std::vector> -{ - // 1. Resource File preamble, - auto data_offset = reader->read_long(); - auto map_offset = reader->read_long(); - auto data_length = reader->read_long(); - auto map_length = reader->read_long(); - - // Before proceeding any further, we need to verify that the resource file is valid. - // We can do this in two ways. We can check the corresponding second header/preamble - // at the start of the resource map, and we can check the lengths provided equal the - // size of the file. - if (data_offset == 0 || map_offset == 0 || map_length == 0) { - throw std::runtime_error("[Classic Resource File] Invalid Preamble."); - } - - auto rsrc_size = data_offset + data_length + map_length; - if (map_offset != data_offset + data_length) { - throw std::runtime_error("[Classic Resource File] ResourceMap starts at the unexpected location."); - } - - if (rsrc_size > reader->size()) { - throw std::runtime_error("[Classic Resource File] ResourceFile has unexpected length."); - } - - // Now move to the start of the resource map, and verify the contents of the preamble. - reader->set_position(map_offset); - - auto data_offset2 = reader->read_long(); - auto map_offset2 = reader->read_long(); - auto data_length2 = reader->read_long(); - auto map_length2 = reader->read_long(); - - // Ignore second preamble if all zero, as this can happen sometimes. - if (data_offset2 != 0 || map_offset2 != 0 || data_length2 != 0 || map_length2 != 0) { - if (data_offset2 != data_offset) { - throw std::runtime_error("[Classic Resource File] Second Preamble 'data_offset' mismatch."); - } - - if (map_offset2 != map_offset) { - throw std::runtime_error("[Classic Resource File] Second Preamble 'map_offset' mismatch."); - } - - if (data_length2 != data_length) { - throw std::runtime_error("[Classic Resource File] Second Preamble 'data_length' mismatch."); - } - - if (map_length2 != map_length) { - throw std::runtime_error("[Classic Resource File] Second Preamble 'map_length' mismatch."); - } - } - - // 2. Now that the preamble is parsed and verified, parse the contents - // of the ResourceMap. The first two fields are used by the actual Resource Manager in - // the Classic Macintosh OS, but are not used by this implementation. - GRAPHITE_UNUSED auto next_map = reader->read_long(); - GRAPHITE_UNUSED auto reference = reader->read_short(); - - // Start to read the actual content of the resource map. This is the content that - // we actually care about. The first field is the flags/attributes of the resource - // fork. - GRAPHITE_UNUSED auto flags = static_cast(reader->read_short()); - - // The next fields are the offsets of the type list and the name list. - auto type_list_offset = static_cast(reader->read_short()); - auto name_list_offset = static_cast(reader->read_short()); - - // 3. Parse the list of Resource Types. - reader->set_position(map_offset + type_list_offset); - auto type_count = static_cast(reader->read_short() + 1); - std::vector> types; - - for (auto type_idx = 0; type_idx < type_count; ++type_idx) { - auto code = reader->read_cstr(4); - auto count = static_cast(reader->read_short() + 1); - auto first_resource_offset = static_cast(reader->read_short()); - - auto type = std::make_shared(code); - - // 4. Parse the list of Resources for the current resource type. - reader->save_position(); - reader->set_position(map_offset + type_list_offset + first_resource_offset); - - for (auto res_idx = 0; res_idx < count; ++res_idx) { - auto id = static_cast(reader->read_signed_short()); - auto name_offset = reader->read_short(); - GRAPHITE_UNUSED auto flags = reader->read_byte(); - auto resource_data_offset = reader->read_triple(); - GRAPHITE_UNUSED auto handle = reader->read_long(); - - // 5. Parse out of the name of the resource. - std::string name; - if (name_offset != std::numeric_limits::max()) { - reader->save_position(); - reader->set_position(map_offset + name_list_offset + name_offset); - name = reader->read_pstr(); - reader->restore_position(); - } - - // 6. Create a data slice for the resource's data. - reader->save_position(); - reader->set_position(data_offset + resource_data_offset); - auto data_size = reader->read_long(); - auto slice = reader->read_data(data_size); - reader->restore_position(); - - // 7. Construct a new resource instance, and add it to the type. - auto resource = std::make_shared(id, type, name, slice); - type->add_resource(resource); - } - - reader->restore_position(); - - // 8. Save the resource type into the list of types and return it. - types.push_back(type); - } - - return types; -} - -// MARK: - Writing - -auto graphite::rsrc::classic::write(const std::string& path, const std::vector>& types) -> void -{ - auto writer = std::make_shared(); - - // 1. Begin setting up the preamble. - uint32_t data_offset = 256; - uint32_t map_offset = 0; - uint32_t data_length = 0; - uint32_t map_length = 0; - - writer->write_long(data_offset); - writer->write_long(map_offset); - writer->write_long(data_length); - writer->write_long(map_length); - writer->pad_to_size(data_offset); - - // 2. Iterate through all of the resources and write their data blobs to the file data. - // When doing this we need to record the starting points of each resources data, as - uint16_t resource_count = 0; - for (const auto& type : types) { - resource_count += type->count(); - - for (const auto& resource : type->resources()) { - // Get the data for the resource and determine its size. - auto data = resource->data(); - auto size = data->size(); - resource->set_data_offset(writer->size() - data_offset); - writer->write_long(static_cast(size)); - writer->write_data(data); - } - } - - // 3. Start writing the ResourceMap. This consists of several characteristics, - // The first of which is a secondary preamble. We can now calculate the map_offset and - // the data_length, but we're still waiting on the map_length. For now, write these values - // as zeros. - map_offset = static_cast(writer->size()); - data_length = map_offset - data_offset; - - writer->write_long(data_offset); - writer->write_long(map_offset); - writer->write_long(data_length); - writer->write_long(map_length); - - // The next six bytes are used by the MacOS ResourceManager and thus not important to - // us. - writer->write_byte(0x00, 6); - - // 4. We're now writing the primary map information, which includes flags, and offsets for - // the type list and the name list. We can calculate where each of these will be. - const uint16_t resource_type_length = 8; - const uint16_t resource_length = 12; - uint16_t type_list_offset = 28; // The type list is 28 bytes from the start of the resource map. - uint16_t name_list_offset = type_list_offset + (types.size() * resource_type_length) + (resource_count * resource_length) + sizeof(uint16_t); - - writer->write_short(0x0000); - writer->write_short(type_list_offset); - writer->write_short(name_list_offset); - - // Now moving on to actually writing each of the type descriptors into the data. - uint16_t resource_offset = sizeof(uint16_t) + (types.size() * resource_type_length); - writer->write_short(types.size() - 1); - for (const auto& type : types) { - // We need to ensure that the type code is 4 characters -- otherwise this file will be - // massively corrupt when produced. - auto mac_roman = graphite::encoding::mac_roman::from_utf8(type->code()); - if (mac_roman.size() != 4) { - throw std::runtime_error("Attempted to write invalid type code to Resource File '" + type->code() + "'"); - } - writer->write_bytes(mac_roman); - writer->write_short(type->count() - 1); - writer->write_short(resource_offset); - - resource_offset += type->count() * resource_length; - } - - // 5. Now we're writing the actual resource headers. - uint16_t name_offset = 0; - uint16_t name_len = 0; - for (const auto& type : types) { - for (const auto& resource : type->resources()) { - - auto id = resource->id(); - if (id < std::numeric_limits::min() || id > std::numeric_limits::max()) { - throw std::runtime_error("Attempted to write resource id outside of valid range."); - } - writer->write_signed_short(static_cast(id)); - - // The name is actually stored in the name list, and the resource stores an offset - // to that name. If no name is assigned to the resource then the offset is encoded as - // 0xFFFF. - if (resource->name().empty()) { - writer->write_short(0xFFFF); - } - else { - if (name_offset + name_len >= 0xFFFF) { - throw std::runtime_error("Attempted to write name offset exceeding maximum value."); - } - name_offset += name_len; - writer->write_short(name_offset); - - // Convert the name to MacRoman so that we can get the length of it when encoded. - auto mac_roman = graphite::encoding::mac_roman::from_utf8(resource->name()); - name_len = mac_roman.size() + 1; - if (name_len > 0x100) { - name_len = 0x100; - } - } - - // Write the resource attributes - these are currently hard coded as nothing. - writer->write_byte(0x00); - - // The data offset is a 3 byte (24-bit) value. This means the hi-byte needs discarding - // and then a swap performing. - auto offset = static_cast(resource->data_offset()); - if (offset > 0xFFFFFF) { - throw std::runtime_error("Attempted to write resource file exceeding maximum size."); - } - writer->write_byte((offset >> 16) & 0xFF); - writer->write_byte((offset >> 8) & 0xFF); - writer->write_byte((offset >> 0) & 0xFF); - - // Finally this is a reserved field for use by the ResourceManager. - writer->write_long(0x00000000); - - } - } - - // 6. Finally we write out each of the resource names, and calculate the map length. - name_offset = 0; - for (const auto& type : types) { - for (const auto& resource : type->resources()) { - if (resource->name().empty()) { - continue; - } - - auto mac_roman = graphite::encoding::mac_roman::from_utf8(resource->name()); - if (mac_roman.size() >= 0x100) { - mac_roman.resize(0xFF); - } - name_offset += mac_roman.size() + 1; - - writer->write_byte(static_cast(mac_roman.size())); - writer->write_bytes(mac_roman); - } - } - // Even if the data fits the spec, the resource manager will still not read files larger than 16MB - if (writer->size() > 0xFFFFFF) { - throw std::runtime_error("Attempted to write resource file exceeding maximum size."); - } - map_length = static_cast(writer->size() - map_offset); - - // 7. Fix the preamble values. - writer->set_position(0); - writer->write_long(data_offset); - writer->write_long(map_offset); - writer->write_long(data_length); - writer->write_long(map_length); - - writer->set_position(map_offset); - writer->write_long(data_offset); - writer->write_long(map_offset); - writer->write_long(data_length); - writer->write_long(map_length); - - // Finish by writing the contents of the Resource File to disk. - writer->save(path); -} diff --git a/libGraphite/rsrc/classic/classic.hpp b/libGraphite/rsrc/classic/classic.hpp new file mode 100644 index 0000000..3b663cc --- /dev/null +++ b/libGraphite/rsrc/classic/classic.hpp @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/classic/parser.hpp" +#include "libGraphite/rsrc/classic/writer.hpp" \ No newline at end of file diff --git a/libGraphite/rsrc/classic/parser.cpp b/libGraphite/rsrc/classic/parser.cpp new file mode 100644 index 0000000..b28aa48 --- /dev/null +++ b/libGraphite/rsrc/classic/parser.cpp @@ -0,0 +1,145 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/classic/parser.hpp" + +#include +#include +#include "libGraphite/hints.hpp" +#include "libGraphite/encoding/macroman/macroman.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" + +// MARK: - Parsing + +auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> bool +{ + std::vector types; + + // 1. Resource Preamble + auto data_offset = reader.read_long(); + auto map_offset = reader.read_long(); + auto data_length = reader.read_long(); + auto map_length = reader.read_long(); + + // Verify that the resource file is valid. + if (data_offset == 0 || map_offset == 0 || map_length == 0) { + return false; + } + + auto rsrc_size = data_offset + data_length + map_length; + if (map_offset != data_offset + data_length) { + return false; + } + + if (rsrc_size > reader.size()) { + return false; + } + + // Move to the start of the ResourceMap, and verify the preamble contents. + reader.set_position(map_offset); + + auto data_offset2 = reader.read_long(); + auto map_offset2 = reader.read_long(); + auto data_length2 = reader.read_long(); + auto map_length2 = reader.read_long(); + + // Ignore the second preamble if all values are equal to zero. + if (data_offset2 != 0 || map_offset2 != 0 || data_length2 != 0 || map_length2 != 0) { + if (data_offset2 != data_offset) { + return false; + } + + if (map_offset2 != map_offset) { + return false; + } + + if (data_length2 != data_length) { + return false; + } + + if (map_length2 != map_length) { + return false; + } + } + + // 2. Now that the preamble is parsed and verified, parse the contents + // of the ResourceMap. The first two fields are used by the actual Resource Manager in + // the Classic Macintosh OS, but are not used by this implementation. + GRAPHITE_UNUSED auto next_map = reader.read_long(); + GRAPHITE_UNUSED auto reference = reader.read_short(); + + // Start to read the actual content of the resource map. This is the content that + // we actually care about. The first field is the flags/attributes of the resource + // fork. + GRAPHITE_UNUSED auto flags = reader.read_short(); + + auto type_list_offset = static_cast(reader.read_short()); + auto name_list_offset = static_cast(reader.read_short()); + + // 3. Parse the list of Resource Types. + reader.set_position(map_offset + type_list_offset); + auto type_count = reader.read_short() + 1; + + for (auto type_idx = 0; type_idx < type_count; ++type_idx) { + auto code = reader.read_cstr(4); + auto count = reader.read_short() + 1; + auto first_resource_offset = static_cast(reader.read_short()); + + struct type type { code }; + + // 4. Parse the list of resources for the current resource type. + reader.save_position(); + reader.set_position(map_offset + type_list_offset + first_resource_offset); + + for (auto res_idx = 0; res_idx < count; ++res_idx) { + auto id = static_cast(reader.read_signed_short()); + auto name_offset = reader.read_short(); + GRAPHITE_UNUSED auto flags = reader.read_byte(); + auto resource_data_offset = reader.read_triple(); + GRAPHITE_UNUSED auto handle = reader.read_long(); + + reader.save_position(); + // 5. Parse the name out of the list of resource names. + std::string name; + if (name_offset != std::numeric_limits::max()) { + reader.set_position(map_offset + name_list_offset + name_offset); + name = std::move(reader.read_pstr()); + } + + // 6. Create a data slice for the resources data. + reader.set_position(data_offset + resource_data_offset); + auto data_size = reader.read_long(); + auto slice = reader.read_data(data_size); + reader.restore_position(); + + // 7. Construct a new resource instance and add it to the type. + struct resource resource { &type, id, name, slice }; + type.add_resource(std::move(resource)); + } + + reader.restore_position(); + types.emplace_back(std::move(type)); + } + + file.add_types(std::move(types)); + return true; +} + diff --git a/libGraphite/rsrc/extended.hpp b/libGraphite/rsrc/classic/parser.hpp similarity index 60% rename from libGraphite/rsrc/extended.hpp rename to libGraphite/rsrc/classic/parser.hpp index 758dac1..2157d06 100644 --- a/libGraphite/rsrc/extended.hpp +++ b/libGraphite/rsrc/classic/parser.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,30 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include -#include +#pragma once + #include "libGraphite/rsrc/file.hpp" #include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" - -#if !defined(GRAPHITE_RSRC_EXTENDED) -#define GRAPHITE_RSRC_EXTENDED - -namespace graphite::rsrc::extended { - - /** - * Parse the specified/provided data object that represents a resource file - * into a list of resource types. - */ - auto parse(const std::shared_ptr& reader) -> std::vector>; - - /** - * Build a data object that represents a resource file from the provided list - * of resource types. - */ - auto write(const std::string& path, const std::vector>& types) -> void; +namespace graphite::rsrc::format::classic +{ + auto parse(data::reader& reader, file& file) -> bool; } - -#endif \ No newline at end of file diff --git a/libGraphite/rsrc/classic/writer.cpp b/libGraphite/rsrc/classic/writer.cpp new file mode 100644 index 0000000..577fe5d --- /dev/null +++ b/libGraphite/rsrc/classic/writer.cpp @@ -0,0 +1,222 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/classic/writer.hpp" + +#include +#include +#include "libGraphite/encoding/macroman/macroman.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" + +// MARK: - Constants + +namespace graphite::rsrc::format::classic::constants::defaults +{ + constexpr uint32_t data_offset = 256; + constexpr uint32_t map_offset = 0; + constexpr uint32_t data_length = 0; + constexpr uint32_t map_length = 0; +} + +namespace graphite::rsrc::format::classic::constants +{ + + constexpr uint16_t resource_type_length = 8; + constexpr uint16_t resource_length = 12; + constexpr uint16_t type_list_offset = 28; +} + +// MARK: - Writing + +auto graphite::rsrc::format::classic::write(file &file) -> bool +{ + return write(file, file.path()); +} + +auto graphite::rsrc::format::classic::write(file &file, const std::string &path) -> bool +{ + graphite::data::writer writer(data::byte_order::msb); + + // 1. Begin setting up the preamble + auto data_offset = constants::defaults::data_offset; + auto map_offset = constants::defaults::map_offset; + auto data_length = constants::defaults::data_length; + auto map_length = constants::defaults::map_length; + + writer.write_long(data_offset); + writer.write_long(map_offset); + writer.write_long(data_length); + writer.write_long(map_length); + writer.pad_to_size(data_offset); + + // 2. Iterate through all of the resources and write their data blobs to the file data. + // When doing this we need to record the starting points of each resources data. + uint16_t resource_count = 0; + + std::vector types(file.type_count()); + auto type_ptr = types.begin(); + + for (const auto& type_code : file.types()) { + auto type = *type_ptr = const_cast(file.type(type_code)); + resource_count += type->count(); + + // If the type has attributes then abort and return false + if (!type->attributes().empty()) { + return false; + } + + for (auto& resource : *type) { + auto data = resource.data(); + auto size = data.size(); + resource.set_data_offset(writer.size() - data_offset); + writer.write_long(static_cast(size)); + writer.write_data(&data); + } + + type_ptr++; + } + + // 3. Start writing the ResourceMap. This consists of several characteristics, the first of which is a secondary + // preamble. We can now calculate the map offset and data length, but we're still waiting on the map length. For + // now, write these values as zero. + map_offset = static_cast(writer.size()); + data_length = map_offset - data_offset; + writer.write_long(data_offset); + writer.write_long(map_offset); + writer.write_long(data_length); + writer.write_long(map_length); + + // The next size bytes are used by the MacOS ResourceManager and thus not important to us. + writer.write_byte(0x00, 6); + + // 4. We're now writing the primary map information, which includes flags, and offsets for the type list and the + // name list. We can calculate where each of these will be. + auto name_list_offset = constants::type_list_offset + (file.type_count() * constants::resource_type_length); + name_list_offset += (resource_count * constants::resource_length) + sizeof(uint16_t); + + writer.write_short(0x0000); + writer.write_short(constants::type_list_offset); + writer.write_short(name_list_offset); + + // Now moving on to actually write each of the type descriptors into the data. + auto resource_offset = sizeof(uint16_t) + (file.type_count() * constants::resource_type_length); + writer.write_short(file.type_count() - 1); + for (const auto type : types) { + // We need to ensure that the type code is 4 characters -- otherwise this file will be massively corrupt + // when produced. + auto mac_roman = encoding::mac_roman::from_utf8(type->code()); + if (mac_roman.size() != 4) { + return false; + } + writer.write_bytes(mac_roman); + writer.write_short(type->count() - 1); + writer.write_short(resource_offset); + + resource_offset += type->count() * constants::resource_length; + } + + // 5. Now we're writing the actual resource headers. + uint16_t name_offset = 0; + uint16_t name_len = 0; + for (const auto type : types) { + for (const auto& resource : *type) { + auto id = resource.id(); + + if (id < std::numeric_limits::min() || id > std::numeric_limits::max()) { + return false; + } + writer.write_signed_short(static_cast(id)); + + // The name is actually stored in the name list, and the resource stores and offset to that name. + // If no name is assigned to the resource then the offset is encoded as 0xFFFF + if (resource.name().empty()) { + writer.write_short(0xFFFF); + } + else { + if (name_offset + name_len >= 0xFFFF) { + return false; + } + name_offset += name_len; + writer.write_short(name_offset); + + // Convert the name to MacRoman so that we can get the length of it when encoded. + auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + name_len = mac_roman.size() + 1; + if (name_len > 0x100) { + name_len = 0x100; + } + } + + // Write the resource attributes - these are currently hard coded as nothing. + writer.write_byte(0x00); + + // The data offset is a 3 byte (24-bit) value. This means the hi-byte needs discarding and then a swap + // performing. + auto offset = static_cast(resource.data_offset()); + if (offset > 0xFFFFFF) { + return false; + } + writer.write_triple(offset); + + // Finally this is a reserved field for use by the ResourceManager. + writer.write_long(0x0000'0000); + } + } + + // 6. Finally we write out each of the resource names, and calculate the map length. + name_offset = 0; + for (const auto type : types) { + for (const auto& resource : *type) { + if (resource.name().empty()) { + continue; + } + + auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + if (mac_roman.size() >= 0x100) { + mac_roman.resize(0xFF); + } + name_offset += writer.write_pstr(resource.name()) + 1; + } + } + + // Even if the data fits the spex, the resource manager will still not read files larger than 16MB. + if (writer.size() > 0xFFFFFF) { + return false; + } + map_length = static_cast(writer.size() - map_offset); + + // 7. Fix the preamble values. + writer.set_position(0); + writer.write_long(data_offset); + writer.write_long(map_offset); + writer.write_long(data_length); + writer.write_long(map_length); + + writer.set_position(map_offset); + writer.write_long(data_offset); + writer.write_long(map_offset); + writer.write_long(data_length); + writer.write_long(map_length); + + // Finish by writing the contents of the Resource File to disk. + writer.save(path); + return true; +} diff --git a/libGraphite/rsrc/classic/writer.hpp b/libGraphite/rsrc/classic/writer.hpp new file mode 100644 index 0000000..86f18c9 --- /dev/null +++ b/libGraphite/rsrc/classic/writer.hpp @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/file.hpp" +#include "libGraphite/data/writer.hpp" + +namespace graphite::rsrc::format::classic +{ + auto write(file& file) -> bool; + auto write(file& file, const std::string& path) -> bool; +} diff --git a/libGraphite/rsrc/extended.cpp b/libGraphite/rsrc/extended.cpp deleted file mode 100644 index 3f2ef77..0000000 --- a/libGraphite/rsrc/extended.cpp +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright (c) 2020 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include -#include "libGraphite/hints.hpp" -#include "libGraphite/rsrc/extended.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" - -// MARK: - Parsing / Reading - -auto graphite::rsrc::extended::parse(const std::shared_ptr& reader) -> std::vector> -{ - // 1. Resource File preamble, - GRAPHITE_UNUSED auto version = reader->read_quad(); - auto data_offset = reader->read_quad(); - auto map_offset = reader->read_quad(); - auto data_length = reader->read_quad(); - auto map_length = reader->read_quad(); - - // Before proceeding any further, we need to verify that the resource file is valid. - // We can do this in two ways. We can check the corresponding second header/preamble - // at the start of the resource map, and we can check the lengths provided equal the - // size of the file. - auto rsrc_size = data_offset + data_length + map_length; - if (map_offset != data_offset + data_length) { - throw std::runtime_error("[Extended Resource File] ResourceMap starts at the unexpected location."); - } - - if (rsrc_size != reader->size()) { - throw std::runtime_error("[Extended Resource File] ResourceFile has unexpected length."); - } - - // Now move to the start of the resource map, and verify the contents of the preamble. - reader->set_position(map_offset); - - if (reader->read_quad() != data_offset) { - throw std::runtime_error("[Extended Resource File] Second Preamble 'data_offset' mismatch."); - } - - if (reader->read_quad() != map_offset) { - throw std::runtime_error("[Extended Resource File] Second Preamble 'map_offset' mismatch."); - } - - if (reader->read_quad() != data_length) { - throw std::runtime_error("[Extended Resource File] Second Preamble 'data_length' mismatch."); - } - - if (reader->read_quad() != map_length) { - throw std::runtime_error("[Extended Resource File] Second Preamble 'map_length' mismatch."); - } - - // 2. Now that the preamble is parsed and verified, parse the contents - // of the ResourceMap. The first two fields are used by the actual Resource Manager in - // the Classic Macintosh OS, but are not used by this implementation. - GRAPHITE_UNUSED auto next_map = reader->read_long(); - GRAPHITE_UNUSED auto reference = reader->read_short(); - - // Start to read the actual content of the resource map. This is the content that - // we actually care about. The first field is the flags/attributes of the resource - // fork. - GRAPHITE_UNUSED auto flags = static_cast(reader->read_short()); - - // The next fields are the offsets of the type list and the name list. - auto type_list_offset = static_cast(reader->read_quad()); - auto name_list_offset = static_cast(reader->read_quad()); - auto attribute_list_offset = static_cast(reader->read_quad()); - - // 3. Parse the list of Resource Types. - reader->set_position(map_offset + type_list_offset); - auto type_count = static_cast(reader->read_quad() + 1); - std::vector> types; - - for (auto type_idx = 0; type_idx < type_count; ++type_idx) { - auto code = reader->read_cstr(4); - auto count = static_cast(reader->read_quad() + 1); - auto first_resource_offset = static_cast(reader->read_quad()); - auto attribute_count = static_cast(reader->read_quad()); - auto attribute_offset = static_cast(reader->read_quad()); - - // 4. Extract the list of attributes before we create the type, as they are needed for actually building the - // type. - reader->save_position(); - - std::map attributes; - if (attribute_count > 0) { - reader->set_position(attribute_list_offset + attribute_offset); - for (auto i = 0; i < attribute_count; ++i) { - attributes.insert(std::make_pair(reader->read_cstr(), reader->read_cstr())); - } - } - - auto type = std::make_shared(code, attributes); - - // 5. Parse the list of Resources for the current resource type. - reader->set_position(map_offset + type_list_offset + first_resource_offset); - - for (auto res_idx = 0; res_idx < count; ++res_idx) { - auto id = static_cast(reader->read_signed_quad()); - auto name_offset = reader->read_quad(); - GRAPHITE_UNUSED auto flags = reader->read_byte(); - auto resource_data_offset = reader->read_quad(); - GRAPHITE_UNUSED auto handle = reader->read_long(); - - // 6. Parse out of the name of the resource. - std::string name; - if (name_offset != std::numeric_limits::max()) { - reader->save_position(); - reader->set_position(map_offset + name_list_offset + name_offset); - name = reader->read_pstr(); - reader->restore_position(); - } - - // 7. Create a data slice for the resource's data. - reader->save_position(); - reader->set_position(data_offset + resource_data_offset); - auto data_size = reader->read_quad(); - auto slice = reader->read_data(data_size); - reader->restore_position(); - - // 8. Construct a new resource instance, and add it to the type. - auto resource = std::make_shared(id, type, name, slice); - type->add_resource(resource); - } - - reader->restore_position(); - - // 9. Save the resource type into the list of types and return it. - types.push_back(type); - } - - return types; -} - -// MARK: - Writing - -auto graphite::rsrc::extended::write(const std::string& path, const std::vector>& types) -> void -{ - auto writer = std::make_shared(); - - // 1. Begin setting up the preamble. - uint64_t data_offset = 256; - uint64_t map_offset = 0; - uint64_t data_length = 0; - uint64_t map_length = 0; - - writer->write_quad(1); - writer->write_quad(data_offset); - writer->write_quad(map_offset); - writer->write_quad(data_length); - writer->write_quad(map_length); - writer->pad_to_size(data_offset); - - // 2. Iterate through all of the resources and write their data blobs to the file data. - // When doing this we need to record the starting points of each resources data, as - uint16_t resource_count = 0; - for (const auto& type : types) { - resource_count += type->count(); - - for (const auto& resource : type->resources()) { - // Get the data for the resource and determine its size. - auto data = resource->data(); - auto size = data->size(); - resource->set_data_offset(writer->size() - data_offset); - writer->write_quad(size); - writer->write_data(data); - } - } - - // 3. Start writing the ResourceMap. This consists of several characteristics, - // The first of which is a secondary preamble. We can now calculate the map_offset and - // the data_length, but we're still waiting on the map_length. For now, write these values - // as zeros. - map_offset = writer->size(); - data_length = map_offset - data_offset; - - writer->write_quad(data_offset); - writer->write_quad(map_offset); - writer->write_quad(data_length); - writer->write_quad(map_length); - - // The next six bytes are reserved. - writer->write_byte(0x00, 6); - - // 4. We're now writing the primary map information, which includes flags, and offsets for - // the type list and the name list. We can calculate where each of these will be. - const uint64_t resource_type_length = 36; - const uint64_t resource_length = 29; - uint64_t type_list_offset = 64; // The type list is 64 bytes from the start of the resource map. - uint64_t name_list_offset = type_list_offset + (types.size() * resource_type_length) + (resource_count * resource_length) + sizeof(uint64_t); - uint64_t attribute_list_offset_position = 0; - - writer->write_short(0x0000); - writer->write_quad(type_list_offset); - writer->write_quad(name_list_offset); - - attribute_list_offset_position = writer->position(); - writer->write_quad(attribute_list_offset_position); - - // Now moving on to actually writing each of the type descriptors into the data. - uint64_t attribute_offset = 0; - uint64_t resource_offset = sizeof(uint64_t) + (types.size() * resource_type_length); - writer->write_quad(types.size() - 1); - for (const auto& type : types) { - // We need to ensure that the type code is 4 characters -- otherwise this file will be - // massively corrupt when produced. - auto mac_roman = graphite::encoding::mac_roman::from_utf8(type->code()); - if (mac_roman.size() != 4) { - throw std::runtime_error("Attempted to write invalid type code to Resource File '" + type->code() + "'"); - } - writer->write_bytes(mac_roman); - writer->write_quad(type->count() - 1); - writer->write_quad(resource_offset); - writer->write_quad(type->attributes().size()); - writer->write_quad(attribute_offset); - - for (const auto& attribute : type->attributes()) { - attribute_offset += attribute.first.size() + attribute.second.size() + 2; - } - resource_offset += type->count() * resource_length; - } - - // 5. Now we're writing the actual resource headers. - uint64_t name_offset = 0; - for (const auto& type : types) { - for (const auto& resource : type->resources()) { - - writer->write_signed_quad(resource->id()); - - // The name is actually stored in the name list, and the resource stores an offset - // to that name. If no name is assigned to the resource then the offset is encoded as - // 0xFFFFFFFFFFFFFFFF. - if (resource->name().empty()) { - writer->write_quad(std::numeric_limits::max()); - } - else { - // Convert the name to MacRoman so that we can get the length of it when encoded. - auto mac_roman = graphite::encoding::mac_roman::from_utf8(resource->name()); - uint16_t len = mac_roman.size(); - - writer->write_quad(name_offset); - name_offset += (len >= 0x100 ? 0xFF : len) + 1; - } - writer->write_byte(0x00); // Resource Attribtues - writer->write_quad(resource->data_offset()); - - // Finally this is a reserved field for use by the ResourceManager. - writer->write_long(0x00000000); - - } - } - - // 6. Write out each of the resource names, and calculate the map length. - name_offset = 0; - for (const auto& type : types) { - for (const auto& resource : type->resources()) { - if (resource->name().empty()) { - continue; - } - - auto mac_roman = graphite::encoding::mac_roman::from_utf8(resource->name()); - if (mac_roman.size() >= 0x100) { - mac_roman.resize(0xFF); - } - name_offset += mac_roman.size() + 1; - - writer->write_byte(static_cast(mac_roman.size())); - writer->write_bytes(mac_roman); - } - } - - // 7. Finally write out a list of attributes, but make sure the actual location of this attribute list is - // kept correct. - auto pos = writer->position(); - writer->set_position(attribute_list_offset_position); - writer->write_quad(pos); - writer->set_position(pos); - - attribute_offset = 0; - for (const auto& type : types) { - const auto& attributes = type->attributes(); - - auto initial = writer->position(); - for (const auto& attribute : attributes) { - writer->write_cstr(attribute.first); - writer->write_cstr(attribute.second); - } - - attribute_offset += (writer->position() - initial); - } - map_length = static_cast(writer->size() - map_offset); - - // 8. Fix the preamble values. - writer->set_position(sizeof(uint64_t)); - writer->write_quad(data_offset); - writer->write_quad(map_offset); - writer->write_quad(data_length); - writer->write_quad(map_length); - - writer->set_position(map_offset); - writer->write_quad(data_offset); - writer->write_quad(map_offset); - writer->write_quad(data_length); - writer->write_quad(map_length); - - // Finish by writing the contents of the Resource File to disk. - writer->save(path); -} diff --git a/libGraphite/rsrc/extended/extended.hpp b/libGraphite/rsrc/extended/extended.hpp new file mode 100644 index 0000000..a4ced1e --- /dev/null +++ b/libGraphite/rsrc/extended/extended.hpp @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/extended/parser.hpp" +#include "libGraphite/rsrc/extended/writer.hpp" \ No newline at end of file diff --git a/libGraphite/rsrc/extended/parser.cpp b/libGraphite/rsrc/extended/parser.cpp new file mode 100644 index 0000000..3681bd3 --- /dev/null +++ b/libGraphite/rsrc/extended/parser.cpp @@ -0,0 +1,158 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/extended/parser.hpp" + +#include +#include +#include "libGraphite/hints.hpp" +#include "libGraphite/encoding/macroman/macroman.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" + +// MARK: - Parsing + +auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) -> bool +{ + std::vector types; + + // 1. Resource Preamble + if (reader.read_quad(0, data::reader::mode::peek) != 1) { + return false; + } + + reader.move(sizeof(uint64_t)); + auto data_offset = reader.read_quad(); + auto map_offset = reader.read_quad(); + auto data_length = reader.read_quad(); + auto map_length = reader.read_quad(); + + // Verify that the resource file is valid. + if (data_offset == 0 || map_offset == 0 || map_length == 0) { + return false; + } + + auto rsrc_size = data_offset + data_length + map_length; + if (map_offset != data_offset + data_length) { + return false; + } + + if (rsrc_size > reader.size()) { + return false; + } + + // Move to the start of the ResourceMap, and verify the preamble contents. + reader.set_position(map_offset); + auto data_offset2 = reader.read_quad(); + auto map_offset2 = reader.read_quad(); + auto data_length2 = reader.read_quad(); + auto map_length2 = reader.read_quad(); + + if (data_offset2 != data_offset) { + return false; + } + + if (map_offset2 != map_offset) { + return false; + } + + if (data_length2 != data_length) { + return false; + } + + if (map_length2 != map_length) { + return false; + } + + // 2. Now that the preamble is parsed and verified, parse the contents + // of the ResourceMap. The first two fields are used by the actual Resource Manager in + // the Classic Macintosh OS, but are not used by this implementation. + GRAPHITE_UNUSED auto next_map = reader.read_long(); + GRAPHITE_UNUSED auto reference = reader.read_short(); + + // Start to read the actual content of the resource map. This is the content that + // we actually care about. The first field is the flags/attributes of the resource + // fork. + GRAPHITE_UNUSED auto flags = reader.read_short(); + + // The next fields are the offsets of the type list and the name list. + auto type_list_offset = static_cast(reader.read_quad()); + auto name_list_offset = static_cast(reader.read_quad()); + auto attribute_list_offset = static_cast(reader.read_quad()); + + // 3. Parse the list of Resource Types. + reader.set_position(map_offset + type_list_offset); + auto type_count = reader.read_quad() + 1; + + for (auto type_idx = 0; type_idx < type_count; ++type_idx) { + auto code = reader.read_cstr(4); + auto count = reader.read_quad() + 1; + auto first_resource_offset = reader.read_quad(); + auto attribute_count = reader.read_quad(); + auto attribute_offset = reader.read_quad(); + + struct type type { code }; + + // 4. Extract the list of attributes before we create the type, as they are needed for actually building the + // type. + reader.save_position(); + if (attribute_count > 0) { + reader.set_position(attribute_list_offset + attribute_offset); + for (auto i = 0; i < attribute_count; ++i) { + type.add_attribute(reader.read_cstr(), reader.read_cstr()); + } + } + + // 5. Parse the list of resources for the current resource type. + reader.set_position(map_offset + type_list_offset + first_resource_offset); + + for (auto res_idx = 0; res_idx < count; ++res_idx) { + auto id = static_cast(reader.read_signed_quad()); + auto name_offset = reader.read_quad(); + GRAPHITE_UNUSED auto flags = reader.read_byte(); + auto resource_data_offset = reader.read_quad(); + GRAPHITE_UNUSED auto handle = reader.read_long(); + + reader.save_position(); + // 6. Parse the name out of the list of resource names. + std::string name; + if (name_offset != std::numeric_limits::max()) { + reader.set_position(map_offset + name_list_offset + name_offset); + name = std::move(reader.read_pstr()); + } + + // 6. Create a data slice for the resources data. + reader.set_position(data_offset + resource_data_offset); + auto data_size = reader.read_quad(); + auto slice = reader.read_data(data_size); + reader.restore_position(); + + // 7. Construct a new resource instance and add it to the type. + struct resource resource { &type, id, name, std::move(slice) }; + type.add_resource(std::move(resource)); + } + + reader.restore_position(); + types.emplace_back(std::move(type)); + } + + file.add_types(std::move(types)); + return true; +} diff --git a/libGraphite/rsrc/extended/parser.hpp b/libGraphite/rsrc/extended/parser.hpp new file mode 100644 index 0000000..cbca92e --- /dev/null +++ b/libGraphite/rsrc/extended/parser.hpp @@ -0,0 +1,29 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/file.hpp" +#include "libGraphite/data/reader.hpp" + +namespace graphite::rsrc::format::extended +{ + auto parse(data::reader& reader, file& file) -> bool; +} \ No newline at end of file diff --git a/libGraphite/rsrc/extended/writer.cpp b/libGraphite/rsrc/extended/writer.cpp new file mode 100644 index 0000000..b97b702 --- /dev/null +++ b/libGraphite/rsrc/extended/writer.cpp @@ -0,0 +1,227 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/extended/writer.hpp" + +#include +#include +#include "libGraphite/encoding/macroman/macroman.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" + +// MARK: - Constants + +namespace graphite::rsrc::format::extended::constants::defaults +{ + constexpr uint64_t version = 1; + constexpr uint64_t data_offset = 256; + constexpr uint64_t map_offset = 0; + constexpr uint64_t data_length = 0; + constexpr uint64_t map_length = 0; +} + +namespace graphite::rsrc::format::extended::constants +{ + + constexpr uint16_t resource_type_length = 36; + constexpr uint16_t resource_length = 29; + constexpr uint16_t type_list_offset = 64; +} + +// MARK: - Writing + +auto graphite::rsrc::format::extended::write(file &file) -> bool +{ + return write(file, file.path()); +} + +auto graphite::rsrc::format::extended::write(file &file, const std::string &path) -> bool +{ + graphite::data::writer writer(data::byte_order::msb); + + // 1. Begin setting up the preamble + auto data_offset = constants::defaults::data_offset; + auto map_offset = constants::defaults::map_offset; + auto data_length = constants::defaults::data_length; + auto map_length = constants::defaults::map_length; + + writer.write_quad(constants::defaults::version); + writer.write_quad(data_offset); + writer.write_quad(map_offset); + writer.write_quad(data_length); + writer.write_quad(map_length); + writer.pad_to_size(data_offset); + + // 2. Iterate through all of the resources and write their data blobs to the file data. + // When doing this we need to record the starting points of each resources data. + uint64_t resource_count = 0; + + std::vector types(file.type_count()); + auto type_ptr = types.begin(); + + for (const auto& type_code : file.types()) { + auto type = *type_ptr = const_cast(file.type(type_code)); + resource_count += type->count(); + + for (auto& resource : *type) { + auto data = resource.data(); + auto size = data.size(); + resource.set_data_offset(writer.size() - data_offset); + writer.write_quad(size); + writer.write_data(&data); + } + + type_ptr++; + } + + // 3. Start writing the ResourceMap. This consists of several characteristics, + // The first of which is a secondary preamble. We can now calculate the map_offset and + // the data_length, but we're still waiting on the map_length. For now, write these values + // as zeros. + map_offset = writer.size(); + data_length = map_offset - data_offset; + + writer.write_quad(data_offset); + writer.write_quad(map_offset); + writer.write_quad(data_length); + writer.write_quad(map_length); + + // The next six bytes are reserved. + writer.write_byte(0, 6); + + // 4. We're now writing the primary map information, which includes flags and offsets for the + // type list and the name list. We can calculate where each of these will be. + auto name_list_offset = constants::type_list_offset + (types.size() * constants::resource_type_length); + name_list_offset += (resource_count * constants::resource_length) + sizeof(uint64_t); + uint64_t attribute_list_offset_position = 0; + + writer.write_short(0); + writer.write_quad(constants::type_list_offset); + writer.write_quad(name_list_offset); + + attribute_list_offset_position = writer.position(); + writer.write_quad(attribute_list_offset_position); + + // No moving on to actually writing each of the type descriptors into the data. + uint64_t attribute_offset = 0; + uint64_t resource_offset = sizeof(uint64_t) + (types.size() * constants::resource_type_length); + writer.write_quad(types.size() - 1); + for (const auto type : types) { + // We need to ensure that the type code is 4 characters -- otherwise this file be massively corrupt + // when produced. + auto mac_roman = encoding::mac_roman::from_utf8(type->code()); + if (mac_roman.size() != 4) { + return false; + } + + writer.write_bytes(mac_roman); + writer.write_quad(type->count() - 1); + writer.write_quad(resource_offset); + writer.write_quad(type->attributes().size()); + writer.write_quad(attribute_offset); + + for (const auto& attribute : type->attributes()) { + attribute_offset += attribute.second.name().size() + attribute.second.string_value().size() + 2; + } + resource_offset += type->count() * constants::resource_length; + } + + // 5. Now we're writing the actual resource headers. + uint64_t name_offset = 0; + for (const auto type : types) { + for (const auto& resource : *type) { + writer.write_signed_quad(resource.id()); + + // The name is actually stored in the name list, and the resource stores an offset to that name. + // If no name is assigned to the resource then the offset is encoded as 0xFFFFFFFFFFFFFFFF. + if (resource.name().empty()) { + writer.write_quad(std::numeric_limits::max()); + } + else { + // Convert the name to MacRoman so that we can get the length of it when encoded. + auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + auto len = mac_roman.size(); + + writer.write_quad(name_offset); + name_offset += (len >= 0x100 ? 0xFF : len) + 1; + } + + writer.write_byte(0); + writer.write_quad(resource.data_offset()); + writer.write_long(0); + } + } + + // 6. Write out each of the resource names, and calculate the map length. + name_offset = 0; + for (const auto type : types) { + for (const auto& resource : *type) { + if (resource.name().empty()) { + continue; + } + + auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + if (mac_roman.size() >= 0x100) { + mac_roman.resize(0xFF); + } + name_offset += mac_roman.size() + 1; + writer.write_byte(static_cast(mac_roman.size())); + writer.write_bytes(mac_roman); + } + } + + // 7. Finally write out a list of attributes, but make sure the actual location of this attribute list is + // kept correct. + auto pos = writer.position(); + writer.set_position(attribute_list_offset_position); + writer.write_quad(pos); + writer.set_position(pos); + + attribute_offset = 0; + for (const auto type : types) { + const auto& attributes = type->attributes(); + + auto initial = writer.position(); + for (const auto& attribute : attributes) { + writer.write_cstr(attribute.second.name()); + writer.write_cstr(attribute.second.string_value()); + } + + attribute_offset += (writer.position() - initial); + } + map_length = static_cast(writer.size() - map_offset); + + // 8. Fix the preamble sizes. + writer.set_position(sizeof(uint64_t)); + writer.write_quad(data_offset); + writer.write_quad(map_offset); + writer.write_quad(data_length); + writer.write_quad(map_length); + + writer.set_position(map_offset); + writer.write_quad(data_offset); + writer.write_quad(map_offset); + writer.write_quad(data_length); + writer.write_quad(map_length); + + // Finish by writing the contents of the resource file to disk. + writer.save(path, data_offset + data_length + map_length); + return true; +} diff --git a/libGraphite/rsrc/extended/writer.hpp b/libGraphite/rsrc/extended/writer.hpp new file mode 100644 index 0000000..004567c --- /dev/null +++ b/libGraphite/rsrc/extended/writer.hpp @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/file.hpp" +#include "libGraphite/data/writer.hpp" + +namespace graphite::rsrc::format::extended +{ + auto write(file& file) -> bool; + auto write(file& file, const std::string& path) -> bool; +} diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 1a2454d..c3e6e55 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,188 +18,165 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include #include "libGraphite/rsrc/file.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" #include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/classic.hpp" -#include "libGraphite/rsrc/extended.hpp" -#include "libGraphite/rsrc/rez.hpp" -// MARK: - Construct +#include "libGraphite/rsrc/classic/classic.hpp" +#include "libGraphite/rsrc/extended/extended.hpp" +#include "libGraphite/rsrc/rez/rez.hpp" -graphite::rsrc::file::file(std::string path) - : m_path(std::move(path)) +#include "libGraphite/util/hashing.hpp" + +// MARK: - Construction + +graphite::rsrc::file::file(const std::string &path) { - read(m_path); + read(path); +} + +// MARK: - Hashing + +auto graphite::rsrc::file::hash_for_path(const std::string &path) -> hash +{ + return hashing::xxh64(path.c_str(), path.size()); } // MARK: - Accessors -auto graphite::rsrc::file::type_count() const -> std::size_t +auto graphite::rsrc::file::name() const -> std::string { - return m_types.size(); + auto pos = m_path.find_last_of('/'); + return m_path.substr(pos + 1); } -auto graphite::rsrc::file::types() const -> std::vector> +auto graphite::rsrc::file::path() const -> const std::string& { - return m_types; + return m_path; } -auto graphite::rsrc::file::current_format() const -> graphite::rsrc::file::format +auto graphite::rsrc::file::type_count() const -> std::size_t { - return m_format; + return m_types.size(); } -auto graphite::rsrc::file::name() const -> std::string +auto graphite::rsrc::file::types() const -> std::vector { - std::string out; - auto path = m_path; - - while (!m_path.empty()) { - if (path.back() == '.') { - out.clear(); - path.pop_back(); - } - else if (path.back() == '/') { - return out; - } - else { - out.insert(out.begin(), path.back()); - path.pop_back(); - } + std::vector types; + for (const auto& type : m_types) { + types.emplace_back(type.first); } + return std::move(types); +} - return out; +auto graphite::rsrc::file::type_codes() const -> std::vector +{ + std::vector types; + for (const auto& type : m_types) { + types.emplace_back(type.second.code()); + } + return std::move(types); } -auto graphite::rsrc::file::path() const -> std::string +auto graphite::rsrc::file::format() const -> enum format { - return m_path; + return m_format; +} + +auto graphite::rsrc::file::hash_value() const -> hash +{ + return hash_for_path(m_path); } -// MARK: - File Reading +// MARK: - Type Management -auto graphite::rsrc::file::read(const std::string& path) -> void +auto graphite::rsrc::file::add_type(const struct type &type) -> void { - // Load the file data and prepare to parse the contents of the resource - // file. We also need to keep hold of the actual internal data. - auto reader = std::make_shared(path); - m_data = reader->get(); + m_types.emplace(std::pair(type.hash_value(), std::move(type))); +} - // 1. Determine the file format and validity. - if (reader->read_quad(0, graphite::data::reader::mode::peek) == 1) { - m_format = graphite::rsrc::file::format::extended; - } - else if (reader->read_long(0, graphite::data::reader::mode::peek) == 'BRGR') { - m_format = graphite::rsrc::file::format::rez; - } - else { - m_format = graphite::rsrc::file::format::classic; - } - - // 2. Launch the appropriate parser for the current format of the file. - switch (m_format) { - case graphite::rsrc::file::format::classic: { - m_types = graphite::rsrc::classic::parse(reader); - break; - } - case graphite::rsrc::file::format::extended: { - m_types = graphite::rsrc::extended::parse(reader); - break; - } - case graphite::rsrc::file::format::rez: { - m_types = graphite::rsrc::rez::parse(reader); - break; - } - - default: - throw std::runtime_error("Resource File format not currently handled."); - break; - } -} - -// MARK: - File Writing - -auto graphite::rsrc::file::write(const std::string& path, enum graphite::rsrc::file::format fmt) -> void -{ - // Determine the correct location to save to, or throw an error. - auto write_path = path; - if (path.empty()) { - if (m_path.empty()) { - throw std::runtime_error("Unable to write resource file to disk. No save location provided."); - } - write_path = m_path; - } - - // Update the file path accordingly. - m_path = write_path; - - // Perform the write operation... - switch (fmt) { - case graphite::rsrc::file::format::classic: { - graphite::rsrc::classic::write(write_path, m_types); - break; - } - case graphite::rsrc::file::format::extended: { - graphite::rsrc::extended::write(write_path, m_types); - break; - } - case graphite::rsrc::file::format::rez: { - graphite::rsrc::rez::write(write_path, m_types); - break; - } - } - -} - -// MARK: - Resource Managemnet - -auto graphite::rsrc::file::add_resource(const std::string &code, const int64_t &id, const std::string &name, - const std::shared_ptr &data, - const std::map &attributes) -> void -{ - // Get the container - if (auto type = type_container(code, attributes).lock()) { - // Add the resource... - auto resource = std::make_shared(id, type, name, data); - type->add_resource(resource); - return; +auto graphite::rsrc::file::add_types(const std::vector &types) -> void +{ + for (const auto& type : types) { + m_types.emplace(std::pair(type.hash_value(), std::move(type))); + + // We need to resync all of the type references inside the resources for the type. + m_types.at(type.hash_value()).sync_resource_type_references(); } +} - throw std::runtime_error("Failed to find or create resource type container for " + code); +auto graphite::rsrc::file::type(const std::string &code) const -> const struct type * +{ + auto it = m_types.find(type::hash_for_type_code(code)); + return (it == m_types.end()) ? nullptr : &it->second; } -auto graphite::rsrc::file::type_container(const std::string &code, - const std::map &attributes) -> std::weak_ptr +auto graphite::rsrc::file::type(type::hash hash) const -> const struct type * { - for (const auto& type : m_types) { - if (type->code() == code && type->attributes() == attributes) { - // Note: Not sure if this is the correct solution here (if not the solution will need some further though)t - // This currently assumes that the attributes are part of the type definition, and that - // `alph` != `alph:lang=en` != `alph:lang=en:bar=2` - return type; - } - } + auto it = m_types.find(hash); + return (it == m_types.end()) ? nullptr : &it->second; +} - auto type = std::make_shared(code, attributes); - m_types.push_back(type); - return type; +auto graphite::rsrc::file::find(const std::string &type_code, resource::identifier id) const -> const struct resource * +{ + if (auto type = this->type(type_code)) { + return type->resource_with_id(id); + } + return nullptr; } -auto graphite::rsrc::file::find(const std::string& type, const int64_t& id, const std::map &attributes) -> std::weak_ptr +// MARK: - File Access + +auto graphite::rsrc::file::read(const std::string &path) -> void { - if (auto container = type_container(type, attributes).lock()) { - return container->get(id); + m_path = path; + m_data = new graphite::data::block(m_path); + graphite::data::reader reader { m_data }; + + if (rsrc::format::extended::parse(reader, *this)) { + m_format = format::extended; + } + else if (rsrc::format::rez::parse(reader, *this)) { + m_format = format::rez; + } + else if (rsrc::format::classic::parse(reader, *this)) { + m_format = format::classic; + } + else { + throw std::runtime_error("Failed to read resource file. Format not recognised: " + m_path); } - return {}; } -auto graphite::rsrc::file::find(const std::string &type, const std::string &name_prefix, - const std::map &attributes) -> std::vector> +auto graphite::rsrc::file::write() -> bool +{ + return write(m_path, m_format); +} + +auto graphite::rsrc::file::write(const std::string &path) -> bool +{ + return write(path, m_format); +} + +auto graphite::rsrc::file::write(const std::string &path, enum format format) -> bool { - if (auto container = type_container(type, attributes).lock()) { - return container->get(name_prefix); + if (m_path != path) { + m_path = path; + } + m_format = format; + + switch (m_format) { + case format::extended: + return rsrc::format::extended::write(*this, m_path); + + case format::rez: + return rsrc::format::rez::write(*this, m_path); + + case format::classic: + return rsrc::format::classic::write(*this, m_path); + + default: + return false; } - return {}; } \ No newline at end of file diff --git a/libGraphite/rsrc/file.hpp b/libGraphite/rsrc/file.hpp index 17b186b..afe91ef 100644 --- a/libGraphite/rsrc/file.hpp +++ b/libGraphite/rsrc/file.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,128 +18,68 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#pragma once + #include -#include -#include -#include +#include +#include #include "libGraphite/data/data.hpp" #include "libGraphite/rsrc/type.hpp" +#include "libGraphite/util/concepts.hpp" -#if !defined(GRAPHITE_RSRC_FILE) -#define GRAPHITE_RSRC_FILE - -namespace graphite::rsrc { - - /** - * The `graphite::rsrc::file` represents a ResourceFork file. - */ +namespace graphite::rsrc +{ class file { public: - - enum flags : uint8_t { }; - - /** - * Denotes the format of a resource file being represented. - * - * + classic - * The classic resource file format is that found in the original Macintosh - * operating systems. This is the only format used by the Diamond Project. - * - * + extended - * The extended resource file format is extremely similar to the classic - * format, but has a number of extensions for modern use. This is primarily - * used by Kestrel. - * - * + rez - * The rez resource file format was a format that was created for use within - * EV Nova for Windows. This is used as a compatibility option for Kestrel. - */ - enum format { classic, extended, rez }; - - private: - std::string m_path; - std::vector> m_types; - std::shared_ptr m_data { nullptr }; - format m_format { classic }; + typedef std::uint64_t hash; + enum class format { classic, extended, rez }; public: - /** - * Construct a new blank `graphite::rsrc::file`. - */ file() = default; + explicit file(const std::string& path); - /** - * Construct a new `graphite::rsrc::file` by loading the contents of the specified - * file. - */ - explicit file(std::string path); + static auto hash_for_path(const std::string& path) -> hash; - /** - * Read and parse the contents of the resource file at the specified location. - * Warning: This will destroy all existing information in the resource file. - */ auto read(const std::string& path) -> void; + auto write() -> bool; + auto write(const std::string& path) -> bool; + auto write(const std::string& path, enum format format) -> bool; - /** - * Write the contents of the the resource file to disk. If no location is specified, - * then it will use the original read path (if it exists). - */ - auto write(const std::string& path = "", enum format fmt = classic) -> void; - - /** - * Returns the name of the file. - */ [[nodiscard]] auto name() const -> std::string; - - /** - * Returns the path of the file. - */ - [[nodiscard]] auto path() const -> std::string; - - /** - * Returns the number of types contained in the resource file. - */ + [[nodiscard]] auto path() const -> const std::string&; [[nodiscard]] auto type_count() const -> std::size_t; - - /** - * Returns the list of all types contained in the resource file. - */ - [[nodiscard]] auto types() const -> std::vector>; - - /** - * Reports the current format of the resource file. - */ - [[nodiscard]] auto current_format() const -> format; - - /** - * Add a resource into the receiver. - */ - auto add_resource(const std::string& type, - const int64_t& id, - const std::string& name, - const std::shared_ptr& data, - const std::map& attributes = {}) -> void; - - /** - * Retrieve a type container for the specified type code. If a container - * does not exist then create one. - */ - auto type_container(const std::string& code, - const std::map& attributes = {}) -> std::weak_ptr; - - /** - * Attempt to get the resource of the specified type, id and attributes - */ - auto find(const std::string& type, const int64_t& id, const std::map &attributes) -> std::weak_ptr; + [[nodiscard]] auto types() const -> std::vector; + [[nodiscard]] auto type_codes() const -> std::vector; + [[nodiscard]] auto format() const -> enum format; + [[nodiscard]] auto hash_value() const -> hash; + + auto add_type(const struct type &type) -> void; + auto add_types(const std::vector& types) -> void; + [[nodiscard]] auto type(const std::string& code) const -> const struct type *; + [[nodiscard]] auto type(type::hash hash) const -> const struct type *; + + template + [[nodiscard]] auto find(resource::identifier id) const -> const struct resource * + { + return find(T::type_code(), id); + } + + [[nodiscard]] auto find(const std::string& type_code, resource::identifier id) const -> const struct resource *; + + template + [[nodiscard]] auto load(resource::identifier id) const -> T + { + if (const auto resource = find(id)) { + return std::move(T(resource->data(), resource->id(), resource->name())); + } + throw std::runtime_error("Resource not found: " + T::type_code() + ".#" + std::to_string(id)); + } - /** - * Retrieve a set of resources from the file, whose name begin with the specified prefix (or match exactly) - * for the specified type and attributes. - */ - auto find(const std::string& type, const std::string& name_prefix, const std::map& attributes) -> std::vector>; + private: + std::string m_path; + std::unordered_map m_types; + data::block *m_data { nullptr }; + enum format m_format { format::classic }; }; - } - -#endif diff --git a/libGraphite/rsrc/manager.cpp b/libGraphite/rsrc/manager.cpp index d87cf1e..3b15780 100644 --- a/libGraphite/rsrc/manager.cpp +++ b/libGraphite/rsrc/manager.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,15 +18,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include #include "libGraphite/rsrc/manager.hpp" -#include "libGraphite/rsrc/file.hpp" -// MARK: - Singleton +// MARK: - Singleton / Construction - -auto graphite::rsrc::manager::shared_manager() -> graphite::rsrc::manager& +auto graphite::rsrc::manager::shared_manager() -> manager & { static rsrc::manager manager; return manager; @@ -34,62 +30,120 @@ auto graphite::rsrc::manager::shared_manager() -> graphite::rsrc::manager& // MARK: - File Management -auto graphite::rsrc::manager::import_file(const std::shared_ptr& file) -> void +auto graphite::rsrc::manager::import_file(class file file) -> class file * { - m_files.push_back(file); + auto hash = file.hash_value(); + m_files.emplace(std::pair(hash, std::move(file))); + return &m_files.at(hash); } -auto graphite::rsrc::manager::files() const -> std::vector> +auto graphite::rsrc::manager::import_file(const std::string &path) -> class file * { - return m_files; + graphite::rsrc::file file(path); + return import_file(std::move(file)); +} + +auto graphite::rsrc::manager::unload_file(file::hash file) -> void +{ + m_files.erase(file); +} + +auto graphite::rsrc::manager::unload_file(class file *file) -> void +{ + if (file) { + unload_file(file->hash_value()); + } } auto graphite::rsrc::manager::unload_file(const std::string &path) -> void { - std::vector> updated_files; - for (const auto& file : m_files) { - if (file->path() != path) { - updated_files.emplace_back(file); - } + unload_file(file::hash_for_path(path)); +} + +auto graphite::rsrc::manager::file(file::hash file) -> class file * +{ + auto it = m_files.find(file); + if (it != m_files.end()) { + return &it->second; } - m_files = updated_files; + return nullptr; } -// MARK: - Resource Look Up +auto graphite::rsrc::manager::file(const std::string &path) -> class file * +{ + return file(file::hash_for_path(path)); +} -auto graphite::rsrc::manager::find(const std::string& type, const int64_t& id, const std::map& attributes) const -> std::weak_ptr +auto graphite::rsrc::manager::files() const -> std::vector { - for (auto i = m_files.rbegin(); i != m_files.rend(); ++i) { - auto res = (*i)->find(type, id, attributes); - if (!res.expired()) { - return res; - } + std::vector files; + for (const auto& it : m_files) { + files.emplace_back(it.first); } - return std::weak_ptr(); + return std::move(files); } -auto graphite::rsrc::manager::get_type(const std::string &type, const std::map& attributes) const -> std::vector> +auto graphite::rsrc::manager::file_references() const -> std::vector { - std::vector> v; - for (const auto& file : m_files) { - v.emplace_back(file->type_container(type, attributes)); + std::vector files; + for (const auto& it : m_files) { + files.emplace_back(const_cast(&it.second)); } - return v; + return std::move(files); } -auto graphite::rsrc::manager::find(const std::string &type, const std::string &name_prefix, - const std::map &attributes) -> std::vector> +// MARK: - Searching + +auto graphite::rsrc::manager::all_types(const std::string &type_code, const std::vector &attributes) const -> std::vector { - std::vector> v; - for (auto i = m_files.rbegin(); i != m_files.rend(); ++i) { - auto resources = (*i)->find(type, name_prefix, attributes); - for (const auto& r : resources) { - // The resource in the most recently loaded files, wins here. We're traversing the files in reverse order, - // and using the resource, only if it hasn't already been seen. - if (std::none_of(v.cbegin(), v.cend(), [r, v] (const std::shared_ptr& e) { return e->id() == r->id(); })) { - v.emplace_back(r); - } + std::vector types; + for (const auto& it : m_files) { + auto type = it.second.type(type_code); + + // TODO: Attribute matching... + + if (type) { + types.emplace_back(const_cast(type)); + } + } + return types; +} + +auto graphite::rsrc::manager::find(const std::string &type_code, const std::vector &attributes) const -> resource_result +{ + std::unordered_map resources; + resource_result result; + + // Gather all of the resources for the type into a single location to draw upon. + const auto& types = all_types(type_code, attributes); + for (const auto type : types) { + for (const auto& resource : *type) { + result.add(const_cast(&resource)); } } - return v; + + return std::move(result); } + +auto graphite::rsrc::manager::find(const std::string &type_code, resource::identifier id, const std::vector &attributes) const -> struct resource * +{ + auto resources = std::move(find(type_code, attributes)); + return resources.resource(type_code, id); +} + +auto graphite::rsrc::manager::find(const std::string &type_code, const std::string &name_prefix, const std::vector &attributes) const -> resource_result +{ + auto resources = std::move(find(type_code, attributes)); + return std::move(resources.filter([&] (struct resource *subject) -> bool { + const auto& name = subject->name(); + if (name.length() == name_prefix.length() && name == name_prefix) { + return true; + } + else if (name.length() >= name_prefix.length() && name.substr(0, name_prefix.length()) == name_prefix) { + return true; + } + else { + return false; + } + })); +} \ No newline at end of file diff --git a/libGraphite/rsrc/manager.hpp b/libGraphite/rsrc/manager.hpp index 7b54f33..6a643ae 100644 --- a/libGraphite/rsrc/manager.hpp +++ b/libGraphite/rsrc/manager.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,78 +18,85 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include -#include -#include -#include "libGraphite/rsrc/file.hpp" - -#if !defined(GRAPHITE_RSRC_MANAGER) -#define GRAPHITE_RSRC_MANAGER +#pragma once -namespace graphite::rsrc { +#include +#include +#include "libGraphite/rsrc/file.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/rsrc/attribute.hpp" +#include "libGraphite/rsrc/result.hpp" +#include "libGraphite/util/concepts.hpp" - /** - * The Manager is a shared object within an application that is keeps track of - * all loaded resources. - * - * Resources are loaded in through a resource file and then placed into the - * resource manager to be "managed" if a newly imported resource conflicts with - * an existing resource, the existing resource will be replaced by the newer - */ +namespace graphite::rsrc +{ class manager { - private: - std::vector> m_files; - manager() = default; - public: - manager(const manager&) = delete; - manager& operator=(const manager &) = delete; - manager(manager &&) = delete; - manager & operator=(manager &&) = delete; - - /** - * The Resource Manager is a singleton due to the "resource space" - * of a process being shared. All resource files loaded into a process - * occupy the same space and are able to override each other, depending - * on load order. - */ + manager(const manager&) = delete; + manager(manager&&) = delete; + auto operator=(const manager&) -> manager& = delete; + auto operator=(manager&&) -> manager& = delete; + static auto shared_manager() -> manager&; - /** - * Import the specified file into the Manager. This will trigger a parsing - * of the file if it hasn't already occurred. - */ - auto import_file(const std::shared_ptr& file) -> void; + auto import_file(file file) -> class file *; + auto import_file(const std::string& path) -> class file *; - /** - * Unload the specified file from the Manager. - */ + auto unload_file(class file *file) -> void; + auto unload_file(file::hash file) -> void; auto unload_file(const std::string& path) -> void; - /** - * - */ - [[nodiscard]] auto files() const -> std::vector>; - - /** - * Attempt to get the resource of the specified type and id. - */ - [[nodiscard]] auto find(const std::string& type, const int64_t& id, const std::map& attributes = {}) const -> std::weak_ptr; - - /** - * Returns a list of type containers for the specified type code. - */ - [[nodiscard]] auto get_type(const std::string& type, const std::map& attributes = {}) const -> std::vector>; - - /** - * Retrieve a set of resources from the manager, whose name begin with the specified prefix (or match exactly) - * for the specified type and attributes. - */ - [[nodiscard]] auto find(const std::string& type, const std::string& name_prefix, const std::map& attributes) -> std::vector>; - }; + auto file(file::hash file) -> class file *; + auto file(const std::string& path) -> class file *; + + [[nodiscard]] auto files() const -> std::vector; + [[nodiscard]] auto file_references() const -> std::vector; + + [[nodiscard]] auto find(const std::string& type_code, const std::vector& attributes = {}) const -> resource_result; + [[nodiscard]] auto find(const std::string& type_code, resource::identifier id, const std::vector& attributes = {}) const -> struct resource *; + [[nodiscard]] auto find(const std::string& type_code, const std::string& name_prefix, const std::vector& attributes = {}) const -> resource_result; + template + [[nodiscard]] auto find(const std::vector& attributes = {}) const -> resource_result + { + return find(T::type_code(), attributes); + } + + template + [[nodiscard]] auto find(resource::identifier id, const std::vector& attributes = {}) const -> struct resource * + { + return find(T::type_code(), id, attributes); + } + + template + [[nodiscard]] auto find(const std::string& name_prefix, const std::vector& attributes = {}) const -> resource_result + { + return find(T::type_code(), name_prefix, attributes); + } + + [[nodiscard]] auto all_types(const std::string& type_code, const std::vector& attributes = {}) const -> std::vector; + + template + [[nodiscard]] auto all_types(const std::vector& attributes = {}) const -> std::vector + { + return all_types(T::type_code(), attributes); + } + + template + [[nodiscard]] auto load(resource::identifier id, const std::vector& attributes = {}) const -> T + { + if (const auto resource = find(id, attributes)) { + return std::move(T(resource->data(), resource->id(), resource->name())); + } + throw std::runtime_error("Resource not found: " + T::type_code() + ".#" + std::to_string(id)); + }; + + private: + std::unordered_map m_files; + + manager() = default; + }; } -#endif \ No newline at end of file diff --git a/libGraphite/rsrc/resource.cpp b/libGraphite/rsrc/resource.cpp index 844934e..5cbd04d 100644 --- a/libGraphite/rsrc/resource.cpp +++ b/libGraphite/rsrc/resource.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -20,91 +20,111 @@ #include "libGraphite/rsrc/resource.hpp" #include "libGraphite/rsrc/type.hpp" +#include "libGraphite/util/hashing.hpp" -// MARK: - Constructor -graphite::rsrc::resource::resource(int64_t id, std::string name) - : m_id(id), m_name(std::move(name)) +// MARK: - Construction + +graphite::rsrc::resource::resource(resource::identifier id, const std::string &name) + : m_id(id), m_name(name) { - } -graphite::rsrc::resource::resource( - int64_t id, - std::weak_ptr type, - std::string name, - std::shared_ptr data -) - : m_id(id), m_name(std::move(name)), m_type(std::move(type)), m_data(std::move(data)) +graphite::rsrc::resource::resource(struct type *type, resource::identifier id, const std::string &name, data::block data) + : m_type(type), m_id(id), m_name(name), m_data(std::move(data)) { - } -// MARK: - Resource Metadata Accessors +graphite::rsrc::resource::resource(const resource &resource) + : m_type(resource.m_type), + m_id(resource.m_id), + m_name(resource.m_name), + m_data(fast_data::data(resource.m_data, true)) +{ +} -auto graphite::rsrc::resource::id() const -> int64_t +graphite::rsrc::resource::resource(resource &&resource) noexcept + : m_type(resource.m_type), + m_id(resource.m_id), + m_name(resource.m_name), + m_data(std::move(resource.m_data)) { - return m_id; + resource.m_type = nullptr; } -auto graphite::rsrc::resource::set_id(int64_t id) -> void +// MARK: - Destruction + +graphite::rsrc::resource::~resource() { - m_id = id; } -auto graphite::rsrc::resource::name() const -> std::string +// MARK: - Accessors + +auto graphite::rsrc::resource::id() const -> resource::identifier { - return m_name; + return m_id; } -auto graphite::rsrc::resource::set_name(const std::string& name) -> void +auto graphite::rsrc::resource::type() const -> struct type * { - m_name = name; + return m_type; } -// MARK: - Resource Type +auto graphite::rsrc::resource::name() const -> const std::string& +{ + return m_name; +} -auto graphite::rsrc::resource::type() const -> std::weak_ptr +auto graphite::rsrc::resource::type_code() const -> std::string { - return m_type; + if (m_type) { + return m_type->code(); + } + else { + return "????"; + } } -auto graphite::rsrc::resource::set_type(const std::weak_ptr& type) -> void +auto graphite::rsrc::resource::data() const -> const data::block& { - m_type = type; + return m_data; } -auto graphite::rsrc::resource::type_code() const -> std::string +auto graphite::rsrc::resource::set_id(resource::identifier id) -> void { - if (auto type = m_type.lock()) { - return type->code(); - } - else { - return "????"; - } + m_id = id; } +auto graphite::rsrc::resource::set_name(const std::string &name) -> void +{ + m_name = name; +} -// MARK: - Data +auto graphite::rsrc::resource::set_type(struct type *type) -> void +{ + m_type = type; +} + +// MARK: - Hashing -auto graphite::rsrc::resource::data() -> std::shared_ptr +auto graphite::rsrc::resource::hash(identifier id) -> identifier_hash { - return m_data; + return hashing::xxh64(&id, sizeof(id)); } -auto graphite::rsrc::resource::set_data(const std::shared_ptr& data) -> void +auto graphite::rsrc::resource::hash(const std::string &name) -> name_hash { - m_data = data; + return hashing::xxh64(name.c_str(), name.size()); } -// MARK: - +// MARK: - Data Offsets -auto graphite::rsrc::resource::set_data_offset(const std::size_t& offset) -> void +auto graphite::rsrc::resource::set_data_offset(std::size_t offset) -> void { - m_data_offset = offset; + m_data_offset = offset; } auto graphite::rsrc::resource::data_offset() const -> std::size_t { - return m_data_offset; -} + return m_data_offset; +} \ No newline at end of file diff --git a/libGraphite/rsrc/resource.hpp b/libGraphite/rsrc/resource.hpp index c6a55b9..bd7b945 100644 --- a/libGraphite/rsrc/resource.hpp +++ b/libGraphite/rsrc/resource.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,99 +18,54 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#pragma once + #include -#include -#include +#include #include "libGraphite/data/data.hpp" -#if !defined(GRAPHITE_RSRC_RESOURCE) -#define GRAPHITE_RSRC_RESOURCE - -namespace graphite::rsrc { +namespace graphite::rsrc +{ + struct type; - class type; - - /** - * The `graphite::rsrc::resource` class represents a single resource within - * a resource file. - */ - class resource + struct resource { - private: - int64_t m_id {}; - std::weak_ptr m_type; - std::string m_name; - std::shared_ptr m_data; - std::size_t m_data_offset { 0 }; - public: - /** - * Construct a new resource instance, without an explicit type or - * data. - */ - resource(int64_t id, std::string name); - - /** - * Construct a new resource instance with the specified type, and data. - */ - resource(int64_t id, std::weak_ptr type, std::string name, std::shared_ptr data); + typedef std::int64_t identifier; + typedef std::uint64_t identifier_hash; + typedef std::uint64_t name_hash; - /** - * Returns the ID of the resource. - */ - [[nodiscard]] auto id() const -> int64_t; + static constexpr resource::identifier default_resource_id { 128 }; - /** - * Set the ID of the resource. - */ - auto set_id(int64_t id) -> void; - - /** - * Returns the name of the resource. - */ - [[nodiscard]] auto name() const -> std::string; - - /** - * Set the name of the resource. - */ - auto set_name(const std::string& name) -> void; + public: + resource(resource::identifier id = default_resource_id, const std::string& name = ""); + resource(struct type *type, resource::identifier id = default_resource_id, const std::string& name = "", data::block data = {}); + explicit resource(const resource& resource); + resource(resource&& resource) noexcept; - /** - * Returns the type container of the resource. - */ - [[nodiscard]] auto type() const -> std::weak_ptr; + ~resource(); - /** - * Set the type container of the resource. - */ - auto set_type(const std::weak_ptr& type) -> void; + [[nodiscard]] auto id() const -> resource::identifier; + [[nodiscard]] auto type() const -> struct type *; + [[nodiscard]] auto name() const -> const std::string&; + [[nodiscard]] auto type_code() const -> std::string; + [[nodiscard]] auto data() const -> const data::block&; - /** - * Returns the type code of the resource. - */ - [[nodiscard]] auto type_code() const -> std::string; + auto set_id(resource::identifier id) -> void; + auto set_name(const std::string& name) -> void; + auto set_type(struct type *type) -> void; - /** - * Returns a shared pointer to the contained data. - */ - auto data() -> std::shared_ptr; - - /** - * Set the name of the resource. - */ - auto set_data(const std::shared_ptr& data) -> void; + static auto hash(identifier id) -> identifier_hash; + static auto hash(const std::string& name) -> name_hash; - /** - * Store the location of the data within the resource file. - */ - auto set_data_offset(const std::size_t& offset) -> void; + auto set_data_offset(std::size_t offset) -> void; + [[nodiscard]] auto data_offset() const -> std::size_t; - /** - * The location of the data within the resource file. - */ - [[nodiscard]] auto data_offset() const -> std::size_t; + private: + resource::identifier m_id { default_resource_id }; + struct type *m_type { nullptr }; + std::string m_name; + data::block m_data; + std::size_t m_data_offset { 0 }; }; - } - -#endif diff --git a/libGraphite/rsrc/result.cpp b/libGraphite/rsrc/result.cpp new file mode 100644 index 0000000..0911610 --- /dev/null +++ b/libGraphite/rsrc/result.cpp @@ -0,0 +1,128 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/result.hpp" +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/util/hashing.hpp" + +// MARK: - Hashing + +auto graphite::rsrc::resource_result::sort_key(struct resource *resource) -> hash +{ + return sort_key(resource->type_code(), resource->id()); +} + +auto graphite::rsrc::resource_result::sort_key(const std::string& type_code, resource::identifier id) -> hash +{ + std::string key { type_code + "." + std::to_string(id) }; + return hashing::xxh64(key.c_str(), key.size()); +} + +// MARK: - Item Management + +auto graphite::rsrc::resource_result::add(struct resource *resource) -> void +{ + if (!resource) { + return; + } + + if (m_finalized) { + // TODO: Issue a warning + return; + } + + auto key = resource_result::sort_key(resource); + m_resources.emplace(std::pair(key, resource)); + m_sorted_keys.emplace_back(key); +} + +auto graphite::rsrc::resource_result::finalize() -> void +{ + m_finalized = true; + sort(); +} + +auto graphite::rsrc::resource_result::size() const -> std::size_t +{ + return m_resources.size(); +} + +// MARK: - Sorting + +auto graphite::rsrc::resource_result::sort() -> void +{ + if (!m_finalized) { + // TODO: Issue a warning + return; + } + + // TODO: Make this customisable in the future and more advanced? + std::sort(m_sorted_keys.begin(), m_sorted_keys.end(), [&] (resource_sort_key lhs, resource_sort_key rhs) { + const auto& lhs_resource = m_resources.at(lhs); + const auto& rhs_resource = m_resources.at(rhs); + return lhs_resource->id() < rhs_resource->id(); + }); +} + +// MARK: - Look up + +auto graphite::rsrc::resource_result::begin() -> iterator +{ + return { this, 0 }; +} + +auto graphite::rsrc::resource_result::end() -> iterator +{ + return { this, std::numeric_limits::max() }; +} + +auto graphite::rsrc::resource_result::at(std::uint64_t idx) const -> struct resource * +{ + return m_resources.at(m_sorted_keys.at(idx)); +} + +auto graphite::rsrc::resource_result::id(resource::identifier id) const -> struct resource * +{ + for (const auto resource : m_resources) { + if (resource.second->id() == id) { + return resource.second; + } + } + return nullptr; +} + +auto graphite::rsrc::resource_result::resource(const std::string &type_code, resource::identifier id) const -> struct resource * +{ + return m_resources.at(resource_result::sort_key(type_code, id)); +} + +auto graphite::rsrc::resource_result::filter(const std::functionbool>& fn) const -> :resource_result +{ + resource_result result; + + for (const auto resource : m_resources) { + if (fn(resource.second)) { + result.add(resource.second); + } + } + result.sort(); + + return std::move(result); +} diff --git a/libGraphite/rsrc/result.hpp b/libGraphite/rsrc/result.hpp new file mode 100644 index 0000000..54b17da --- /dev/null +++ b/libGraphite/rsrc/result.hpp @@ -0,0 +1,110 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include "libGraphite/rsrc/resource.hpp" + +namespace graphite::rsrc +{ + struct resource_result + { + public: + typedef std::uint64_t hash; + + struct iterator + { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = struct resource; + using pointer = value_type*; + using reference = value_type&; + + iterator(resource_result *ptr, std::uint64_t index) : m_ptr(ptr), m_index(index) {}; + + auto operator*() const -> reference { return *get(); } + auto operator->() -> pointer { return const_cast(get()); } + + auto operator++() -> iterator& { + m_index++; + if (m_index >= m_ptr->m_sorted_keys.size()) { + m_index = std::numeric_limits::max(); + } + return *this; + } + auto operator++(int) -> iterator { auto tmp = *this; ++(*this); return tmp; } + + friend auto operator==(const iterator& lhs, const iterator& rhs) -> bool + { + return (lhs.m_ptr == rhs.m_ptr) && (lhs.m_index == rhs.m_index); + } + + friend auto operator!= (const iterator& lhs, const iterator& rhs) -> bool + { + return (lhs.m_ptr != rhs.m_ptr) || (lhs.m_index != rhs.m_index); + } + + private: + resource_result *m_ptr { nullptr }; + std::uint64_t m_index { 0 }; + + auto get() const -> pointer + { + if (m_index == std::numeric_limits::max()) { + return nullptr; + } + auto key = m_ptr->m_sorted_keys.at(m_index); + auto value = m_ptr->m_resources.at(key); + return value; + }; + }; + + public: + resource_result() = default; + + static auto sort_key(struct resource *resource) -> hash; + static auto sort_key(const std::string& type_code, resource::identifier id) -> hash; + + auto add(struct resource *resource) -> void; + + auto finalize() -> void; + auto sort() -> void; + + auto begin() -> iterator; + auto end() -> iterator; + + [[nodiscard]] auto filter(const std::functionbool>& fn) const -> resource_result; + + [[nodiscard]] auto size() const -> std::size_t; + [[nodiscard]] auto at(std::uint64_t idx) const -> struct resource *; + [[nodiscard]] auto id(resource::identifier id) const -> struct resource *; + [[nodiscard]] auto resource(const std::string& type_code, resource::identifier id) const -> struct resource *; + + private: + typedef std::uint64_t resource_sort_key; + bool m_finalized { false }; + std::unordered_map m_resources; + std::vector m_sorted_keys; + }; + +} diff --git a/libGraphite/rsrc/rez.cpp b/libGraphite/rsrc/rez.cpp deleted file mode 100644 index 8c550a9..0000000 --- a/libGraphite/rsrc/rez.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2020 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include "libGraphite/rsrc/rez.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" - -// MARK: - Parsing / Reading - -auto graphite::rsrc::rez::parse(const std::shared_ptr& reader) -> std::vector> -{ - // Read the preamble - if (reader->read_long() != rez_signature) { - throw std::runtime_error("[Rez File] Preamble 'signature' mismatch."); - } - reader->get()->set_byte_order(graphite::data::byte_order::lsb); - if (reader->read_long() != rez_version) { - throw std::runtime_error("[Rez File] Preamble 'version' mismatch."); - } - auto header_length = reader->read_long(); - - // Read the header - reader->move(4); // Unknown value - auto first_index = reader->read_long(); - auto count = reader->read_long(); - uint32_t expected_header_length = 12 + (count * resource_offset_length) + map_name.size()+1; - if (header_length != expected_header_length) { - throw std::runtime_error("[Rez File] Preamble 'header_length' mismatch."); - } - - // Record the offsets - std::vector offsets; - std::vector sizes; - for (auto res_idx = 0; res_idx < count; res_idx++) { - offsets.push_back(static_cast(reader->read_long())); - sizes.push_back(static_cast(reader->read_long())); - reader->move(4); // Unknown value - } - if (reader->read_cstr() != map_name) { - throw std::runtime_error("[Rez File] Header 'map_name' mismatch."); - } - - // Read the resource map header - reader->get()->set_byte_order(graphite::data::byte_order::msb); - auto map_offset = offsets.back(); - reader->set_position(map_offset); - reader->move(4); // Unknown value - auto type_count = reader->read_long(); - - // Read the types - std::vector> types; - for (auto type_idx = 0; type_idx < type_count; type_idx++) { - auto code = reader->read_cstr(4); - auto type_offset = static_cast(reader->read_long()); - auto count = reader->read_long(); - auto type = std::make_shared(code); - - reader->save_position(); - reader->set_position(map_offset + type_offset); - - // Read the resource info - for (auto res_idx = 0; res_idx < count; res_idx++) { - auto index = reader->read_long(); - auto code = reader->read_cstr(4); - if (code != type->code()) { - throw std::runtime_error("[Rez File] Resource 'type' mismatch."); - } - auto id = static_cast(reader->read_signed_short()); - // The name is padded to 256 bytes - note the end position before reading the cstr - auto nextOffset = reader->position() + 256; - auto name = reader->read_cstr(); - - // Read the resource's data - reader->set_position(offsets[index-first_index]); - auto slice = reader->read_data(sizes[index-first_index]); - reader->set_position(nextOffset); - - auto resource = std::make_shared(id, type, name, slice); - type->add_resource(resource); - } - - reader->restore_position(); - types.push_back(type); - } - - return types; -} - -// MARK: - Writing - -auto graphite::rsrc::rez::write(const std::string& path, const std::vector>& types) -> void -{ - auto writer = std::make_shared(); - - // Count up the total number of resources - uint32_t resource_count = 0; - for (const auto& type : types) { - resource_count += type->count(); - } - - // The resource map itself is considered an entry for the offsets in the header - uint32_t entry_count = resource_count + 1; - - // Calculate header length - this is from the end of the preamble to the start of the resource data - uint32_t header_length = 12 + (entry_count * resource_offset_length) + map_name.size()+1; - - // Write the preamble - writer->write_long(rez_signature); - writer->data()->set_byte_order(graphite::data::byte_order::lsb); - writer->write_long(rez_version); - writer->write_long(header_length); - - // Calculate the offset to the first resource data - uint32_t resource_offset = static_cast(writer->size()) + header_length; - - // Write the header - uint32_t index = 1; // Index of first resource, starting at 1 - writer->write_long(1); // Unknown value - writer->write_long(index); - writer->write_long(entry_count); - for (const auto& type : types) { - for (const auto& resource : type->resources()) { - // Get the data for the resource and determine its size. - auto data = resource->data(); - auto size = data->size(); - writer->write_long(resource_offset); - writer->write_long(static_cast(size)); - writer->write_long(0); // Unknown value - resource_offset += size; - } - } - - uint32_t type_count = types.size(); - // Calculate offset within map to start of resource info - uint32_t type_offset = map_header_length + (type_count * type_info_length); - uint32_t map_length = type_offset + (resource_count * resource_info_length); - // Write the offset and size of the resource map - writer->write_long(resource_offset); - writer->write_long(map_length); - writer->write_long(12 + (entry_count * resource_offset_length)); // Unknown value - - // Write the name of the resource map - writer->write_cstr(map_name); - - // Write each resource - for (const auto& type : types) { - for (const auto& resource : type->resources()) { - writer->write_data(resource->data()); - } - } - - // Write the resource map as big endian - // Map header - writer->data()->set_byte_order(graphite::data::byte_order::msb); - writer->write_long(8); // Unknown value - writer->write_long(type_count); - - // Type counts and offsets - for (const auto& type : types) { - auto count = type->count(); - writer->write_cstr(type->code(), 4); - writer->write_long(type_offset); - writer->write_long(count); - type_offset += resource_info_length * count; - } - - // Info for each resource - for (const auto& type : types) { - for (const auto& resource : type->resources()) { - writer->write_long(index++); - writer->write_cstr(type->code(), 4); - writer->write_signed_short(static_cast(resource->id())); - writer->write_cstr(resource->name(), 256); - } - } - - // Finish by writing the contents of the Rez file to disk. - writer->save(path); -} diff --git a/libGraphite/rsrc/rez/parser.cpp b/libGraphite/rsrc/rez/parser.cpp new file mode 100644 index 0000000..f85a0bb --- /dev/null +++ b/libGraphite/rsrc/rez/parser.cpp @@ -0,0 +1,131 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/rez/parser.hpp" + +#include +#include +#include "libGraphite/hints.hpp" +#include "libGraphite/encoding/macroman/macroman.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" + +// MARK: - Constants + +namespace graphite::rsrc::format::rez::constants +{ + const std::string map_name = "resource.map"; + constexpr uint32_t signature = 'BRGR'; + constexpr uint32_t version = 1; + constexpr uint32_t resource_offset_length = 12; + constexpr uint32_t map_header_length = 8; + constexpr uint32_t type_info_length = 12; + constexpr uint32_t resource_info_length = 266; +}; + +// MARK: - Parsing + +auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> bool +{ + std::vector types; + + // 1. Read the preamble + if (reader.read_long() != constants::signature) { + reader.set_position(0); + return false; + } + + reader.change_byte_order(data::byte_order::lsb); + if (reader.read_long() != constants::version) { + reader.set_position(0); + return false; + } + + // 2. Read the header + auto header_length = reader.read_long(); + reader.move(4); // Skip over an unknown value. + + auto first_index = reader.read_long(); + auto count = reader.read_long(); + auto expected_header_length = 12 + (count * constants::resource_offset_length) + constants::map_name.size() + 1; + if (header_length != expected_header_length) { + reader.set_position(0); + return false; + } + + // 3. Record the offsets + std::vector offsets; + std::vector sizes; + for (auto res_idx = 0; res_idx < count; ++res_idx) { + offsets.emplace_back(static_cast(reader.read_long())); + sizes.push_back(static_cast(reader.read_long())); + reader.move(4); // Skip over an unknown value. + } + + if (reader.read_cstr() != constants::map_name) { + reader.set_position(0); + return false; + } + + // 4. Read the resource map header. + reader.change_byte_order(data::byte_order::msb); + auto map_offset = offsets.back(); + reader.set_position(map_offset); + reader.move(4); // Skip over an unknown value. + auto type_count = reader.read_long(); + + // 5. Read the resource types. + for (auto type_idx = 0; type_idx < type_count; ++type_idx) { + auto code = reader.read_cstr(4); + auto type_offset = static_cast(reader.read_long()); + auto count = reader.read_long(); + + struct type type { code }; + reader.save_position(); + reader.set_position(map_offset + type_offset); + + // 6. Read the resource info. + for (auto res_idx = 0; res_idx < count; ++res_idx) { + auto index = reader.read_long(); + if (code != reader.read_cstr()) { + reader.set_position(0); + return false; + } + + auto id = static_cast(reader.read_signed_short()); + auto next_offset = reader.position() + 256; + auto name = reader.read_cstr(); + + reader.set_position(offsets[index - first_index]); + auto slice = reader.read_data(sizes[index - first_index]); + reader.set_position(next_offset); + + // 7. Construct a new resource instance and add it to the type. + struct resource resource { &type, id, name, slice }; + type.add_resource(std::move(resource)); + } + + reader.restore_position(); + types.emplace_back(std::move(type)); + } + + file.add_types(std::move(types)); + return true; +} diff --git a/libGraphite/rsrc/rez/parser.hpp b/libGraphite/rsrc/rez/parser.hpp new file mode 100644 index 0000000..2b38189 --- /dev/null +++ b/libGraphite/rsrc/rez/parser.hpp @@ -0,0 +1,29 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/file.hpp" +#include "libGraphite/data/reader.hpp" + +namespace graphite::rsrc::format::rez +{ + auto parse(data::reader& reader, file& file) -> bool; +} \ No newline at end of file diff --git a/libGraphite/rsrc/rez/rez.hpp b/libGraphite/rsrc/rez/rez.hpp new file mode 100644 index 0000000..b0a458d --- /dev/null +++ b/libGraphite/rsrc/rez/rez.hpp @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/rsrc/rez/parser.hpp" +#include "libGraphite/rsrc/rez/writer.hpp" \ No newline at end of file diff --git a/libGraphite/rsrc/rez/writer.cpp b/libGraphite/rsrc/rez/writer.cpp new file mode 100644 index 0000000..e440a9f --- /dev/null +++ b/libGraphite/rsrc/rez/writer.cpp @@ -0,0 +1,145 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/rsrc/rez/writer.hpp" + +#include +#include +#include "libGraphite/encoding/macroman/macroman.hpp" +#include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" + +// MARK: - Constants + +namespace graphite::rsrc::format::rez::constants +{ + const std::string map_name = "resource.map"; + constexpr uint32_t signature = 'BRGR'; + constexpr uint32_t version = 1; + constexpr uint32_t header_length = 12; + constexpr uint32_t resource_offset_length = 12; + constexpr uint32_t map_header_length = 8; + constexpr uint32_t type_info_length = 12; + constexpr uint32_t resource_info_length = 266; +} + +// MARK: - Writing + +auto graphite::rsrc::format::rez::write(file &file) -> bool +{ + return write(file, file.path()); +} + +auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> bool +{ + graphite::data::writer writer(data::byte_order::msb); + + // Count up the total number of resources + uint32_t resource_count = 0; + for (const auto type_hash : file.types()) { + auto type = file.type(type_hash); + resource_count += type->count(); + } + + // The resource map itself is considered an entry for the offsets in the header. + uint32_t entry_count = resource_count + 1; + + // Calculate header length - this is from the end of the preamble to the start of the resource data + uint32_t header_length = constants::header_length + (entry_count * constants::resource_offset_length) + constants::map_name.size() + 1; + + // Write the preamble + writer.write_long(constants::signature); + writer.change_byte_order(data::byte_order::lsb); + writer.write_long(constants::version); + writer.write_long(header_length); + + // Calculate the offset to the first resource data + uint32_t resource_offset = writer.size() + header_length; + + // Write the header + uint32_t index = 1; // Index of the first resource, starting at 1. + writer.write_long(1); // Unknown value + writer.write_long(index); + writer.write_long(entry_count); + for (const auto type_hash : file.types()) { + auto type = const_cast(file.type(type_hash)); + + // If the type has attributes then abort and return false + if (!type->attributes().empty()) { + return false; + } + + for (const auto& resource : *type) { + // Get the data for the resource and determine its size. + auto size = resource.data().size(); + writer.write_long(resource_offset); + writer.write_long(static_cast(size)); + writer.write_long(0); + resource_offset += size; + } + } + + uint32_t type_count = file.type_count(); + + // Calculate the offset within map to start of resource info + uint32_t type_offset = constants::map_header_length + (type_count * constants::type_info_length); + uint32_t map_length = type_offset + (resource_count & constants::resource_info_length); + + // Write the offset and size of the resource map + writer.write_long(resource_offset); + writer.write_long(map_length); + writer.write_long(12 + (entry_count * constants::resource_offset_length)); // Unknown value? + writer.write_cstr(constants::map_name); + + // Write each of the resources + for (const auto type_hash : file.types()) { + auto type = const_cast(file.type(type_hash)); + for (const auto& resource : *type) { + writer.write_data(&resource.data()); + } + } + + // Write the resource map as big endian + writer.change_byte_order(data::byte_order::msb); + writer.write_long(0); // Unknown value + writer.write_long(type_count); + + for (const auto type_hash : file.types()) { + auto type = file.type(type_hash); + auto count = type->count(); + writer.write_cstr(type->code(), 4); + writer.write_long(type_offset); + writer.write_long(count); + type_offset += constants::resource_info_length * count; + } + + for (const auto type_hash : file.types()) { + auto type = const_cast(file.type(type_hash)); + for (const auto& resource : *type) { + writer.write_long(index++); + writer.write_cstr(type->code(), 4); + writer.write_signed_short(static_cast(resource.id())); + writer.write_cstr(resource.name(), 256); + } + } + + writer.save(path); + return true; +} \ No newline at end of file diff --git a/libGraphite/rsrc/classic.hpp b/libGraphite/rsrc/rez/writer.hpp similarity index 61% rename from libGraphite/rsrc/classic.hpp rename to libGraphite/rsrc/rez/writer.hpp index 583c995..1a52cca 100644 --- a/libGraphite/rsrc/classic.hpp +++ b/libGraphite/rsrc/rez/writer.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,30 +18,14 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include -#include +#pragma once + #include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/reader.hpp" #include "libGraphite/data/writer.hpp" -#if !defined(GRAPHITE_RSRC_CLASSIC) -#define GRAPHITE_RSRC_CLASSIC - -namespace graphite::rsrc::classic { - - /** - * Parse the specified/provided data object that represents a resource file - * into a list of resource types. - */ - auto parse(const std::shared_ptr& reader) -> std::vector>; - - /** - * Build a data object that represents a resource file from the provided list - * of resource types. - */ - auto write(const std::string& path, const std::vector>& types) -> void; - +namespace graphite::rsrc::format::rez +{ + auto write(file& file) -> bool; + auto write(file& file, const std::string& path) -> bool; } -#endif \ No newline at end of file diff --git a/libGraphite/rsrc/type.cpp b/libGraphite/rsrc/type.cpp index 5276154..a8c279f 100644 --- a/libGraphite/rsrc/type.cpp +++ b/libGraphite/rsrc/type.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,85 +18,142 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include #include "libGraphite/rsrc/type.hpp" +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/util/hashing.hpp" +// MARK: - Construction -// MARK: - Constructor +graphite::rsrc::type::type(const std::string &code) + : m_code(code) +{ +} + +// MARK: - Accessors -graphite::rsrc::type::type(std::string code, std::map attributes) - : m_code(std::move(code)), m_attributes(std::move(attributes)) +auto graphite::rsrc::type::hash_for_type_code(const std::string &code) -> hash { - + return hashing::xxh64(code.c_str(), code.size()); } -// MARK: - Metadata Accessors +auto graphite::rsrc::type::hash_value() const -> hash +{ + std::string code { m_code }; + if (!m_attributes.empty()) { + code += ":" + attribute_descriptor_string(); + } + return hash_for_type_code(code); +} -auto graphite::rsrc::type::code() const -> std::string +auto graphite::rsrc::type::code() const -> const std::string& { - return m_code; + return m_code; } -auto graphite::rsrc::type::attributes() const -> std::map +auto graphite::rsrc::type::attributes() const -> const std::unordered_map& { return m_attributes; } -auto graphite::rsrc::type::attributes_string() const -> std::string +auto graphite::rsrc::type::count() const -> std::size_t { - std::string text; + return m_resources.size(); +} - for (const auto& m_attribute : m_attributes) { - text.append(":" + m_attribute.first + "=" + (m_attribute.second)); +auto graphite::rsrc::type::attribute_descriptor_string() const -> std::string +{ + std::string descriptor; + for (const auto& attribute : m_attributes) { + descriptor += "<" + attribute.second.name() + ":" + attribute.second.string_value() + ">"; } + return std::move(descriptor); +} + +// MARK: - Attribute Management + +auto graphite::rsrc::type::add_attribute(const std::string& name, const std::string& value) -> void +{ + attribute attr { name, value }; + m_attributes.emplace(std::pair(attr.hash_value(), std::move(attr))); +} - return text; +template::value>::type*> +auto graphite::rsrc::type::add_attribute(const std::string &name, T value) -> void +{ + attribute attr { name, value }; + m_attributes.template emplace(std::pair(attr.hash_value(), std::move(attr))); } // MARK: - Resource Management -auto graphite::rsrc::type::count() const -> std::size_t +auto graphite::rsrc::type::has_resource(resource::identifier id) const -> bool { - return m_resources.size(); + auto hash = hashing::xxh64(&id, sizeof(id)); + return (m_resource_id_map.find(hash) != m_resource_id_map.end()); } -auto graphite::rsrc::type::add_resource(const std::shared_ptr& resource) -> void +auto graphite::rsrc::type::has_resource(const std::string &name) const -> bool { - // Search for an existing instance of this resource (same id) - m_resources.erase(std::remove_if(m_resources.begin(), m_resources.end(), [resource] (const auto& item) { - return item->id() == resource->id(); - }), m_resources.end()); + auto hash = hashing::xxh64(name.c_str(), name.size()); + return (m_resource_name_map.find(hash) != m_resource_name_map.end()); +} - m_resources.push_back(resource); +auto graphite::rsrc::type::add_resource(const resource &resource) -> void +{ + m_resources.emplace_back(std::move(resource)); + + auto& ref = m_resources.back(); + auto id_hash = resource::hash(ref.id()); + auto name_hash = resource::hash(ref.name()); + + m_resource_id_map[id_hash] = &ref; + m_resource_name_map[name_hash] = &ref; +} + +auto graphite::rsrc::type::remove_resource(resource::identifier id) -> void +{ + // TODO: } -auto graphite::rsrc::type::resources() const -> std::vector> +auto graphite::rsrc::type::resource_with_id(resource::identifier id) const -> resource * { - return m_resources; + auto it = m_resource_id_map.find(hashing::xxh64(&id, sizeof(id))); + if (it != m_resource_id_map.end()) { + return it->second; + } + return nullptr; } -auto graphite::rsrc::type::get(int16_t id) const -> std::weak_ptr +auto graphite::rsrc::type::resource_with_name(const std::string &name) const -> resource * { - for (const auto& resource : m_resources) { - if (resource->id() == id) { - return resource; - } + auto it = m_resource_name_map.find(hashing::xxh64(name.c_str(), name.size())); + if (it != m_resource_id_map.end()) { + return it->second; } - return std::weak_ptr(); + return nullptr; +} + +auto graphite::rsrc::type::begin() -> std::vector::iterator +{ + return m_resources.begin(); +} + +auto graphite::rsrc::type::end() -> std::vector::iterator +{ + return m_resources.end(); } -auto graphite::rsrc::type::get(const std::string &name_prefix) const -> std::vector> +auto graphite::rsrc::type::at(int64_t idx) -> resource * { - std::vector> v; - for (const auto& resource : m_resources) { - const auto& name = resource->name(); - if (name.length() == name_prefix.length() && name == name_prefix) { - v.emplace_back(resource); - } - else if (name.length() >= name_prefix.length() && name.substr(0, name_prefix.length()) == name_prefix) { - v.emplace_back(resource); - } + if (idx < 0 || idx >= m_resources.size()) { + return nullptr; } - return v; + return &m_resources.at(idx); } + +auto graphite::rsrc::type::sync_resource_type_references() -> void +{ + for (auto& resource : *this) { + resource.set_type(this); + } +} \ No newline at end of file diff --git a/libGraphite/rsrc/type.hpp b/libGraphite/rsrc/type.hpp index f79eec3..bf7d41b 100644 --- a/libGraphite/rsrc/type.hpp +++ b/libGraphite/rsrc/type.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,75 +18,58 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#pragma once + #include -#include -#include -#include +#include +#include +#include "libGraphite/rsrc/attribute.hpp" #include "libGraphite/rsrc/resource.hpp" -#if !defined(GRAPHITE_RSRC_TYPE) -#define GRAPHITE_RSRC_TYPE - -namespace graphite::rsrc { - - /** - * - */ - class type +namespace graphite::rsrc +{ + struct type { - private: - std::string m_code; - std::vector> m_resources; - std::map m_attributes; + public: + typedef std::uint64_t hash; public: - /** - * Construct a new a resource type container with the specified - * type code. - */ - explicit type(std::string code, std::map attributes = {}); + explicit type(const std::string& code); - /** - * Returns the type code of the receiver. - */ - [[nodiscard]] auto code() const -> std::string; + static auto hash_for_type_code(const std::string& code) -> hash; - /** - * Returns the attribute map of the receiver. - */ - [[nodiscard]] auto attributes() const -> std::map; + [[nodiscard]] auto hash_value() const -> hash; + [[nodiscard]] auto code() const -> const std::string&; + [[nodiscard]] auto attributes() const -> const std::unordered_map&; + [[nodiscard]] auto count() const -> std::size_t; + [[nodiscard]] auto attribute_descriptor_string() const -> std::string; - /** - * Returns the attribute map of the receiver as a string. - */ - [[nodiscard]] auto attributes_string() const -> std::string; + auto add_attribute(const std::string& name, const std::string& value) -> void; - /** - * Returns a count of the number of resources associated to this type. - */ - [[nodiscard]] auto count() const -> std::size_t; + template::value>::type* = nullptr> + auto add_attribute(const std::string& name, T value) -> void; - /** - * Add a new resource to the receiver. - */ - auto add_resource(const std::shared_ptr& resource) -> void; + [[nodiscard]] auto has_resource(resource::identifier id) const -> bool; + [[nodiscard]] auto has_resource(const std::string& name) const -> bool; - /** - * Returns an vector containing all of the resources - */ - [[nodiscard]] auto resources() const -> std::vector>; + auto add_resource(const resource& resource) -> void; + auto remove_resource(resource::identifier id) -> void; - /** - * Returns the resource with the specified ID. - */ - [[nodiscard]] auto get(int16_t id) const -> std::weak_ptr; + [[nodiscard]] auto resource_with_id(resource::identifier id) const -> resource *; + [[nodiscard]] auto resource_with_name(const std::string& name) const -> resource *; - /** - * Returns a set of resources whose name begins with the specified text, or matches wholly. - */ - [[nodiscard]] auto get(const std::string& name_prefix) const -> std::vector>; - }; + auto begin() -> std::vector::iterator; + auto end() -> std::vector::iterator; + auto at(int64_t idx) -> resource *; -} + auto sync_resource_type_references() -> void; + + private: + std::string m_code; + std::vector m_resources; + std::unordered_map m_resource_id_map {}; + std::unordered_map m_resource_name_map {}; + std::unordered_map m_attributes {}; -#endif \ No newline at end of file + }; +} diff --git a/libGraphite/sound/codec/descriptor.hpp b/libGraphite/sound/codec/descriptor.hpp new file mode 100644 index 0000000..72dc7c0 --- /dev/null +++ b/libGraphite/sound/codec/descriptor.hpp @@ -0,0 +1,41 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace graphite::sound_manager::codec +{ + struct descriptor + { + std::uint32_t sample_rate { 0 }; + std::uint32_t channels { 0 }; + std::uint32_t format_id { 0 }; + std::uint32_t format_flags { 0 }; + std::uint32_t bit_width { 0 }; + std::uint32_t bytes_per_frame { 0 }; + std::uint32_t frames_per_packet { 0 }; + std::uint32_t bytes_per_packet { 0 }; + std::uint32_t packet_count { 0 }; + + descriptor() = default; + }; +} \ No newline at end of file diff --git a/libGraphite/sound/codec/ima4.cpp b/libGraphite/sound/codec/ima4.cpp new file mode 100644 index 0000000..4c931f3 --- /dev/null +++ b/libGraphite/sound/codec/ima4.cpp @@ -0,0 +1,132 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/sound/codec/ima4.hpp" +#include "libGraphite/data/writer.hpp" + +// MARK: - Look Up Tables + +namespace graphite::sound_manager::codec::ima4::lut +{ + constexpr std::int8_t index_table[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 + }; + + constexpr std::int32_t step_table[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + }; +} + +// MARK: - Construction + +graphite::sound_manager::codec::ima4::sound::sound(const codec::descriptor &descriptor, data::reader &reader) +{ + decode(descriptor, reader); +} + +// MARK: - Decoder + +auto graphite::sound_manager::codec::ima4::sound::decode(const codec::descriptor &descriptor, data::reader &reader) -> void +{ + // TODO: This is relying on hard-coded constants and really shouldn't. + // Determine the best way to calculate these values in the future. + m_descriptor = descriptor; + m_descriptor.bytes_per_packet = 34; + m_descriptor.frames_per_packet = 64; + m_descriptor.bytes_per_frame = 0; + + m_samples = data::block((m_descriptor.packet_count * (m_descriptor.bytes_per_packet - 2)) << 2, data::native_byte_order()); + data::writer writer(&m_samples); + + // Prepare to read and parse the IMA4 data and decode it to LPCM 16 + // Iterate through all the expected packets and decode them + for (std::uint32_t n = 0; n < m_descriptor.packet_count; ++n) { + auto preamble = reader.read_short(); + auto packet = reader.read_data(m_descriptor.bytes_per_packet - 2); + + auto predictor = static_cast(preamble & 0xFF80); + auto step_index = static_cast(preamble & 0x007F); + auto step = lut::step_table[step_index]; + std::uint8_t nibble = 0; + std::int32_t diff = 0; + + for (std::uint32_t i = 0; i < packet.size(); ++i) { + auto v = packet.get(i); + + nibble = v & 0xF; + step_index = static_cast(std::min(88, step_index + lut::index_table[nibble])); + std::uint8_t sign = nibble & 0x8; + std::uint8_t delta = nibble & 0x7; + diff = static_cast(step >> 3); + if (delta & 4) diff += step; + if (delta & 2) diff += (step >> 1); + if (delta & 1) diff += (step >> 2); + if (sign) predictor -= diff; + else predictor += diff; + + predictor = std::min(std::numeric_limits::max(), std::max(std::numeric_limits::min(), predictor)); + writer.write_short(predictor); + step = lut::step_table[step_index]; + + nibble = (v >> 4) & 0xF; + step_index = static_cast(std::min(88, std::max(0, step_index + lut::index_table[nibble]))); + sign = nibble & 0x8; + delta = nibble & 0x7; + diff = static_cast(step >> 3); + if (delta & 4) diff += step; + if (delta & 3) diff += (step >> 1); + if (delta & 2) diff += (step >> 2); + if (sign) predictor -= diff; + else predictor += diff; + + predictor = std::min(std::numeric_limits::max(), std::max(std::numeric_limits::min(), predictor)); + writer.write_short(predictor); + step = lut::step_table[step_index]; + } + } + + m_descriptor.bytes_per_packet = 128; + m_descriptor.bit_width = 16; + m_descriptor.frames_per_packet = descriptor.channels; + m_descriptor.bytes_per_frame = (m_descriptor.bit_width >> 3) * m_descriptor.channels; + m_descriptor.format_id = 'lpcm'; + m_descriptor.format_flags = 0x4; +} + +// MARK: - Accessors + +auto graphite::sound_manager::codec::ima4::sound::samples() const -> const data::block& +{ + return m_samples; +} + +auto graphite::sound_manager::codec::ima4::sound::descriptor() const -> const codec::descriptor & +{ + return m_descriptor; +} \ No newline at end of file diff --git a/libGraphite/sound/codec/ima4.hpp b/libGraphite/sound/codec/ima4.hpp new file mode 100644 index 0000000..1b9f379 --- /dev/null +++ b/libGraphite/sound/codec/ima4.hpp @@ -0,0 +1,43 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/data/reader.hpp" +#include "libGraphite/sound/codec/descriptor.hpp" + +namespace graphite::sound_manager::codec::ima4 +{ + struct sound + { + public: + sound(const codec::descriptor& descriptor, data::reader& reader); + + [[nodiscard]] auto samples() const -> const data::block&; + [[nodiscard]] auto descriptor() const -> const codec::descriptor&; + + private: + data::block m_samples; + codec::descriptor m_descriptor; + + auto decode(const codec::descriptor& descriptor, data::reader& reader) -> void; + }; + +} diff --git a/libGraphite/sound/sound.cpp b/libGraphite/sound/sound.cpp new file mode 100644 index 0000000..361ec82 --- /dev/null +++ b/libGraphite/sound/sound.cpp @@ -0,0 +1,424 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include "libGraphite/sound/sound.hpp" +#include "libGraphite/sound/codec/descriptor.hpp" +#include "libGraphite/sound/codec/ima4.hpp" + +// MARK: - Constants / Enumerations + +namespace graphite::sound_manager +{ + enum bitrate : std::uint32_t + { + rate_48khz = 0xbb800000, + rate_44khz = 0xac440000, + rate_32khz = 0x7d000000, + rate_22050hz = 0x56220000, + rate_22khz = 0x56ee8ba3, + rate_16khz = 0x3e800000, + rate_11khz = 0x2b7745d1, + rate_11025hz = 0x2b110000, + rate_8khz = 0x1f400000, + }; + + enum synthesizer : std::uint16_t + { + sampled_sound = 5, + }; + + enum midi : std::uint8_t + { + middle_c = 60, + }; + + enum flags : std::uint16_t + { + data_offset = 0x8000, + }; + + enum compression : std::int16_t // TODO: Is the name of this enum correct? + { + not_compressed = 0, + fixed_compression = -1, + variable_compression = -2, + two_to_one = 1, + eight_to_three = 2, + three_to_one = 3, + six_to_one = 4, + six_to_one_packet_size = 8, + three_to_one_packet_size = 16, + }; + + enum sound_format : std::int16_t + { + general = 1, + hypercard = 2, + }; + + enum header : std::uint8_t + { + standard = 0x00, + extended = 0xFF, + compressed = 0xFE, + }; + + enum command : std::uint16_t + { + null_cmd = 0, + quiet_cmd = 3, + flush_cmd = 4, + re_init_cmd = 5, + wait_cmd = 10, + pause_cmd = 11, + resume_cmd = 12, + call_back_cmd = 13, + sync_cmd = 14, + available_cmd = 24, + version_cmd = 25, + volume_cmd = 46, // sound manager 3.0 or later only + get_volume_cmd = 47, // sound manager 3.0 or later only + clock_component_cmd = 50, // sound manager 3.2.1 or later only + get_clock_component_cmd = 51, // sound manager 3.2.1 or later only + scheduled_sound_cmd = 52, // sound manager 3.3 or later only + link_sound_components_cmd = 53, // sound manager 3.3 or later only + sound_cmd = 80, + buffer_cmd = 81, + rate_multiplier_cmd = 86, + get_rate_multiplier_cmd = 87, + }; + + enum init_flags : std::int32_t + { + init_chan_left = 0x0002, // left stereo channel + init_chan_right = 0x0003, // right stereo channel + init_no_interp = 0x0004, // no linear interpolation + init_no_drop = 0x0008, // no drop-sample conversion + init_mono = 0x0080, // monophonic channel + init_stereo = 0x00C0, // stereo channel + init_m_a_c_e3 = 0x0300, // MACE 3:1 + init_m_a_c_e6 = 0x0400, // MACE 6:1 + }; + + enum format_type : std::uint32_t + { + sound_format_not_compressed = 0x4E4F4E45, // 'NONE' sound is not compressed + sound_format_8_bit_offset = 0x72617720, // 'raw ' 8-bit offset binary + sound_format_16_bit_be = 0x74776F73, // 'twos' 16-bit big endian + sound_format_16_bit_le = 0x736F7774, // 'sowt' 16-bit little endian + sound_format_ima4 = 'ima4', + }; +} + +// MARK: - Internal Helper Types + +namespace graphite::sound_manager +{ + struct sound_command + { + enum command command; + std::int16_t param1; + std::int16_t param2; + }; + + struct modifier_reference + { + std::uint16_t number; + std::int32_t init; + }; + + struct sound_list_resource + { + std::int16_t format; + std::int16_t modifier_count; + struct modifier_reference modifier; + std::int16_t command_count; + struct sound_command command; + }; + + struct hypercard_sound_list_resource + { + std::int16_t format; + std::int16_t ref_count; + std::int16_t command_count; + struct sound_command command; + }; + + struct sound_header + { + std::uint32_t sample_ptr; + std::uint32_t length; + std::uint32_t sample_rate_fixed; + std::uint32_t loop_start; + std::uint32_t loop_end; + std::uint8_t encode; + std::uint8_t base_frequency; + }; + + struct compressed_sound_header + { + std::uint32_t frame_count; + std::int16_t aiff_sample_rate_exp; + std::uint64_t aiff_sample_rate_man; + std::uint32_t marker_chunk; + std::uint32_t format; + std::uint32_t future_use; + std::uint32_t state_vars; + std::uint32_t left_over_samples; + std::uint16_t compression_id; + std::uint16_t packet_size; + std::uint16_t synth_id; + std::uint16_t sample_size; + }; + + struct extended_sound_header + { + std::uint32_t frame_count; + std::int16_t aiff_sample_rate_exp; + std::uint64_t aiff_sample_rate_man; + std::uint32_t marker_chunk; + std::uint32_t instrument_chunks; + std::uint32_t aes_recording; + std::uint16_t sample_size; + }; +} + +// MARK: - Construction + +graphite::sound_manager::sound::sound(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +// MARK: - Decoding + +auto graphite::sound_manager::sound::decode(data::reader &reader) -> void +{ + auto sound_format = reader.read_signed_short(); + + switch (sound_format) { + case sound_format::general: { + sound_list_resource list; + list.format = sound_format; + list.modifier_count = reader.read_signed_short(); + list.modifier.number = reader.read_signed_short(); + list.modifier.init = reader.read_signed_long(); + list.command_count = reader.read_signed_short(); + list.command.command = static_cast(reader.read_short()); + list.command.param1 = reader.read_signed_short(); + list.command.param2 = reader.read_signed_long(); + + if (list.modifier_count != 1 + || list.modifier.number != synthesizer::sampled_sound + || list.command_count != 1 + || list.command.command != (static_cast(flags::data_offset) + static_cast(buffer_cmd))) + { + throw std::runtime_error("Only sampled sound synthesizers are supported."); + } + + break; + } + case sound_format::hypercard: { + hypercard_sound_list_resource list; + list.format = sound_format; + list.ref_count = reader.read_signed_short(); + list.command_count = reader.read_signed_short(); + list.command.command = static_cast(reader.read_short()); + list.command.param1 = reader.read_signed_short(); + list.command.param2 = reader.read_signed_long(); + + if (list.command_count != 1 + || list.command.command != (static_cast(flags::data_offset) + static_cast(buffer_cmd))) + { + throw std::runtime_error("Unsupported configuration."); + } + + break; + } + default: { + throw std::runtime_error("Unrecognised sound format '" + std::to_string(sound_format) + "' in resource: " + + std::to_string(m_id) + ", " + m_name); + } + } + + sound_header header; + header.sample_ptr = reader.read_long(); + header.length = reader.read_long(); + header.sample_rate_fixed = reader.read_long(); + header.loop_start = reader.read_long(); + header.loop_end = reader.read_long(); + header.encode = reader.read_byte(); + header.base_frequency = reader.read_byte(); + + switch (header.encode) { + case header::standard: { + m_descriptor.format_id = format_type::sound_format_8_bit_offset; + m_descriptor.channels = 1; + m_descriptor.packet_count = header.length; + break; + } + case header::extended: { + extended_sound_header ext; + ext.frame_count = reader.read_long(); + ext.aiff_sample_rate_exp = reader.read_signed_short(); + ext.aiff_sample_rate_man = reader.read_quad(); + ext.marker_chunk = reader.read_long(); + ext.instrument_chunks = reader.read_long(); + ext.aes_recording = reader.read_long(); + ext.sample_size = reader.read_short(); + reader.move(14); + + m_descriptor.format_id = ext.sample_size == 8 ? format_type::sound_format_8_bit_offset + : format_type::sound_format_16_bit_be; + m_descriptor.channels = header.length; + m_descriptor.packet_count = ext.frame_count; + break; + } + case header::compressed: { + compressed_sound_header cmp; + cmp.frame_count = reader.read_long(); + cmp.aiff_sample_rate_exp = reader.read_signed_short(); + cmp.aiff_sample_rate_man = reader.read_quad(); + cmp.marker_chunk = reader.read_long(); + cmp.format = reader.read_long(); + cmp.future_use = reader.read_long(); + cmp.state_vars = reader.read_long(); + cmp.left_over_samples = reader.read_long(); + cmp.compression_id = reader.read_short(); + cmp.packet_size = reader.read_short(); + cmp.synth_id = reader.read_short(); + cmp.sample_size = reader.read_short(); + + if (cmp.compression_id == compression::three_to_one) { + m_descriptor.format_id = 'MAC3'; + } + else if (cmp.compression_id == compression::six_to_one) { + m_descriptor.format_id = 'MAC6'; + } + else { + m_descriptor.format_id = cmp.format; + } + + m_descriptor.channels = header.length; + m_descriptor.packet_count = cmp.frame_count; + break; + } + default: { + throw std::runtime_error("Invalid header in sound resource."); + } + } + + m_descriptor.sample_rate = static_cast(static_cast(header.sample_rate_fixed) * 1.0 / static_cast(1 << 16)); + + if (m_descriptor.format_id == format_type::sound_format_8_bit_offset || m_descriptor.format_id == format_type::sound_format_16_bit_be) { + if (m_descriptor.format_id == format_type::sound_format_8_bit_offset) { + m_descriptor.bit_width = 8; + } + else { + m_descriptor.bit_width = 16; + m_descriptor.format_flags = 0x6; // kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsBigEndian + } + + m_descriptor.format_id = 'lpcm'; + m_descriptor.bytes_per_frame = (m_descriptor.bit_width >> 3) * m_descriptor.channels; + m_descriptor.frames_per_packet = 1; + m_descriptor.bytes_per_packet = m_descriptor.bytes_per_frame * m_descriptor.frames_per_packet; + + auto sample_count = reader.size() - reader.position(); + m_samples = reader.read_data(sample_count); + } + else if (m_descriptor.format_id == format_type::sound_format_ima4) { + // TODO: Do not hard code this, but work out the conversions... + m_descriptor.format_flags = 0; + m_descriptor.bytes_per_packet = 34; + m_descriptor.frames_per_packet = 64; + m_descriptor.bytes_per_frame = 0; + m_descriptor.channels = 1; + m_descriptor.bit_width = 0; + + codec::ima4::sound ima4(m_descriptor, reader); + m_samples = ima4.samples(); + m_descriptor = ima4.descriptor(); + } + else { + throw std::runtime_error("Unrecognised sound format."); + } +} + +// MARK: - Accessors + +auto graphite::sound_manager::sound::samples() const -> const data::block& +{ + return m_samples; +} + +auto graphite::sound_manager::sound::codec_descriptor() const -> const codec::descriptor& +{ + return m_descriptor; +} + +auto graphite::sound_manager::sound::sample_rate() const -> std::uint32_t +{ + return m_descriptor.sample_rate; +} + +auto graphite::sound_manager::sound::channels() const -> std::uint16_t +{ + return m_descriptor.channels; +} + +auto graphite::sound_manager::sound::bit_width() const -> std::uint8_t +{ + return m_descriptor.bit_width; +} + +auto graphite::sound_manager::sound::bytes_per_frame() const -> std::uint32_t +{ + return m_descriptor.bytes_per_frame; +} + +auto graphite::sound_manager::sound::frames_per_packet() const -> std::uint32_t +{ + return m_descriptor.frames_per_packet; +} + +auto graphite::sound_manager::sound::bytes_per_packet() const -> std::uint32_t +{ + return m_descriptor.bytes_per_packet; +} + +auto graphite::sound_manager::sound::packet_count() const -> std::uint32_t +{ + return m_descriptor.packet_count; +} + +auto graphite::sound_manager::sound::format_id() const -> std::uint32_t +{ + return m_descriptor.format_id; +} + +auto graphite::sound_manager::sound::format_flags() const -> std::uint32_t +{ + return m_descriptor.format_flags; +} diff --git a/libGraphite/sound/sound.hpp b/libGraphite/sound/sound.hpp new file mode 100644 index 0000000..439709c --- /dev/null +++ b/libGraphite/sound/sound.hpp @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include "libGraphite/data/data.hpp" +#include "libGraphite/data/writer.hpp" +#include "libGraphite/data/reader.hpp" +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/sound/codec/descriptor.hpp" + +namespace graphite::sound_manager +{ + struct sound + { + public: + static auto type_code() -> std::string { return "snd "; } + + public: + explicit sound(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + + [[nodiscard]] auto samples() const -> const data::block&; + [[nodiscard]] auto codec_descriptor() const -> const codec::descriptor&; + + [[nodiscard]] auto sample_rate() const -> std::uint32_t; + [[nodiscard]] auto channels() const -> std::uint16_t; + [[nodiscard]] auto bit_width() const -> std::uint8_t; + [[nodiscard]] auto bytes_per_frame() const -> std::uint32_t; + [[nodiscard]] auto frames_per_packet() const -> std::uint32_t; + [[nodiscard]] auto bytes_per_packet() const -> std::uint32_t; + [[nodiscard]] auto packet_count() const -> std::uint32_t; + [[nodiscard]] auto format_id() const -> std::uint32_t; + [[nodiscard]] auto format_flags() const -> std::uint32_t; + + private: + rsrc::resource::identifier m_id {}; + std::string m_name; + codec::descriptor m_descriptor; + data::block m_samples; + + auto decode(data::reader& reader) -> void; + }; +} + diff --git a/libGraphite/toolbox/string.cpp b/libGraphite/toolbox/string.cpp new file mode 100644 index 0000000..f2af010 --- /dev/null +++ b/libGraphite/toolbox/string.cpp @@ -0,0 +1,39 @@ +// +// Created by Tom Hancocks on 24/03/2020. +// + +#include "libGraphite/toolbox/string.hpp" +#include "libGraphite/data/reader.hpp" + +// MARK: - Constructor + +graphite::toolbox::string::string(const data::block& data, rsrc::resource::identifier id, const std::string& name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +// MARK: - Accessor + +auto graphite::toolbox::string::value() const -> const std::string& +{ + return m_str; +} + +auto graphite::toolbox::string::data() const -> const data::block& +{ + return m_data; +} + +// MARK: - Decoder + +auto graphite::toolbox::string::decode(data::reader &reader) -> void +{ + m_str = reader.read_pstr(); + + auto length = reader.size() - reader.position(); + if (length > 0) { + m_data = reader.read_data(length); + } +} \ No newline at end of file diff --git a/libGraphite/toolbox/string.hpp b/libGraphite/toolbox/string.hpp new file mode 100644 index 0000000..d975551 --- /dev/null +++ b/libGraphite/toolbox/string.hpp @@ -0,0 +1,35 @@ +// +// Created by Tom Hancocks on 24/03/2020. +// + +#pragma once + +#include +#include "libGraphite/data/reader.hpp" +#include "libGraphite/rsrc/resource.hpp" + +namespace graphite::toolbox +{ + + struct string + { + public: + static auto type_code() -> std::string { return "STR "; } + + public: + string() = default; + explicit string(const data::block &data, rsrc::resource::identifier id = 0, const std::string& name = ""); + + [[nodiscard]] auto value() const -> const std::string&; + [[nodiscard]] auto data() const -> const data::block&; + + private: + rsrc::resource::identifier m_id {}; + std::string m_name; + std::string m_str; + data::block m_data; + + auto decode(data::reader& reader) -> void; + }; + +} diff --git a/libGraphite/toolbox/string_list.cpp b/libGraphite/toolbox/string_list.cpp new file mode 100644 index 0000000..2398a85 --- /dev/null +++ b/libGraphite/toolbox/string_list.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/toolbox/string_list.hpp" +#include "libGraphite/data/reader.hpp" + +// MARK: - Construction + +graphite::toolbox::string_list::string_list(const data::block &data, rsrc::resource::identifier id, const std::string& name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +// MARK: - Decoder + +auto graphite::toolbox::string_list::decode(data::reader &reader) -> void +{ + auto count = static_cast(reader.read_signed_short()); + m_strings = { count, "" }; + + for (std::int32_t i = 0; i < count; ++i) { + m_strings[i] = std::move(reader.read_pstr()); + } +} + +// MARK: - Access + +auto graphite::toolbox::string_list::string_count() const -> std::size_t +{ + return m_strings.size(); +} + +auto graphite::toolbox::string_list::at(std::uint32_t idx) const -> std::string +{ + return m_strings.at(idx); +} + +// MARK: - Iterator + +auto graphite::toolbox::string_list::begin() noexcept -> iterator +{ + return m_strings.begin(); +} + +auto graphite::toolbox::string_list::end() noexcept -> iterator +{ + return m_strings.end(); +} \ No newline at end of file diff --git a/libGraphite/rsrc/rez.hpp b/libGraphite/toolbox/string_list.hpp similarity index 52% rename from libGraphite/rsrc/rez.hpp rename to libGraphite/toolbox/string_list.hpp index 926dd78..f52e332 100644 --- a/libGraphite/rsrc/rez.hpp +++ b/libGraphite/toolbox/string_list.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tom Hancocks +// Copyright (c) 2022 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,38 +18,37 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#pragma once + #include #include -#include -#include "libGraphite/rsrc/file.hpp" #include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" +#include "libGraphite/rsrc/resource.hpp" -#if !defined(GRAPHITE_RSRC_REZ) -#define GRAPHITE_RSRC_REZ +namespace graphite::toolbox +{ + struct string_list + { + public: + static auto type_code() -> std::string { return "STR#"; } -namespace graphite::rsrc::rez { + using iterator = std::vector::iterator; - const std::string map_name = "resource.map"; - const uint32_t rez_signature = 'BRGR'; - const uint32_t rez_version = 1; - const uint32_t resource_offset_length = 12; - const uint32_t map_header_length = 8; - const uint32_t type_info_length = 12; - const uint32_t resource_info_length = 266; + public: + string_list() = default; + explicit string_list(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); - /** - * Parse the specified/provided data object that represents a resource file - * into a list of resource types. - */ - auto parse(const std::shared_ptr& reader) -> std::vector>; + [[nodiscard]] auto string_count() const -> std::size_t; + [[nodiscard]] auto at(std::uint32_t idx) const -> std::string; - /** - * Build a data object that represents a resource file from the provided list - * of resource types. - */ - auto write(const std::string& path, const std::vector>& types) -> void; + auto begin() noexcept -> iterator; + auto end() noexcept -> iterator; -} + private: + rsrc::resource::identifier m_id { 0 }; + std::string m_name; + std::vector m_strings; -#endif + auto decode(data::reader& reader) -> void; + }; +} diff --git a/libGraphite/util/concepts.hpp b/libGraphite/util/concepts.hpp new file mode 100644 index 0000000..c84183f --- /dev/null +++ b/libGraphite/util/concepts.hpp @@ -0,0 +1,48 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/data/data.hpp" + +namespace graphite +{ + template + concept convertible_to = std::is_convertible_v && requires { + static_cast(std::declval()); + }; + + template + concept constructible_from = std::destructible && std::is_constructible_v; + + template + concept move_constructible = constructible_from && convertible_to; + + template + concept resource_type = requires(const T& resource) { + requires constructible_from; + requires move_constructible; + { T::type_code() } -> std::same_as; + }; +} \ No newline at end of file diff --git a/libGraphite/util/hashing.cpp b/libGraphite/util/hashing.cpp new file mode 100644 index 0000000..68a76cd --- /dev/null +++ b/libGraphite/util/hashing.cpp @@ -0,0 +1,140 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include "libGraphite/util/hashing.hpp" + +// MARK: - Constants + +struct uint64_unaligned { uint64_t v; } __attribute__((packed)); +struct uint32_unaligned { uint32_t v; } __attribute__((packed)); + +static uint64_t xxhash64_seed = 0; +static uint64_t xxhash64_p1 = 11400714785074694791ULL; +static uint64_t xxhash64_p2 = 14029467366897019727ULL; +static uint64_t xxhash64_p3 = 1609587929392839161ULL; +static uint64_t xxhash64_p4 = 9650029242287828579ULL; +static uint64_t xxhash64_p5 = 2870177450012600261ULL; + +#define ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define ROTL64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#define UNALGINED64(p) (((struct uint64_unaligned *)(p))->v) +#define UNALGINED32(p) (((struct uint32_unaligned *)(p))->v) + +// MARK: - XXHash64 + +auto graphite::hashing::xxh64(const void *src, std::size_t length) -> hashing::value +{ + uint64_t h64 { 0 }; + auto ptr = const_cast(reinterpret_cast(src)); + auto end = ptr + length; + + if (length >= 32) { + uint8_t *limit = end - 32; + uint64_t v2 = xxhash64_seed + xxhash64_p2; + uint64_t v1 = v2 + xxhash64_p1; + uint64_t v3 = xxhash64_seed; + uint64_t v4 = xxhash64_seed - xxhash64_p1; + + do { + v1 += UNALGINED64(ptr) * xxhash64_p2; + ptr += 8; + v1 = ROTL64(v1, 31); + v1 *= xxhash64_p1; + + v2 += UNALGINED64(ptr) * xxhash64_p2; + ptr += 8; + v2 = ROTL64(v2, 31); + v2 *= xxhash64_p1; + + v3 += UNALGINED64(ptr) * xxhash64_p2; + ptr += 8; + v3 = ROTL64(v3, 31); + v3 *= xxhash64_p1; + + v4 += UNALGINED64(ptr) * xxhash64_p2; + ptr += 8; + v4 = ROTL64(v4, 31); + v4 *= xxhash64_p1; + } + while (ptr <= limit); + + h64 = ROTL64(v1, 1) + ROTL64(v2, 7) + ROTL64(v3, 12) + ROTL64(v4, 18); + + v1 *= xxhash64_p2; + v1 = ROTL64(v1, 31); + v1 *= xxhash64_p1; + h64 ^= v1; + h64 = h64 * xxhash64_p1 + xxhash64_p4; + + v2 *= xxhash64_p2; + v2 = ROTL64(v2, 31); + v2 *= xxhash64_p1; + h64 ^= v2; + h64 = h64 * xxhash64_p1 + xxhash64_p4; + + v3 *= xxhash64_p2; + v3 = ROTL64(v3, 31); + v3 *= xxhash64_p1; + h64 ^= v3; + h64 = h64 * xxhash64_p1 + xxhash64_p4; + + v4 *= xxhash64_p2; + v4 = ROTL64(v4, 31); + v4 *= xxhash64_p1; + h64 ^= v4; + h64 = h64 * xxhash64_p1 + xxhash64_p4; + } + else { + h64 = xxhash64_seed + xxhash64_p5; + } + + h64 += length; + + while (ptr+8 <= end) { + uint64_t k1 = UNALGINED64(ptr); + k1 *= xxhash64_p2; + k1 = ROTL64(k1, 31); + k1 *= xxhash64_p1; + h64 ^= k1; + h64 = ROTL64(h64, 27) * xxhash64_p1 + xxhash64_p4; + ptr += 8; + } + + if (ptr+4 <= end) { + h64 ^= (uint64_t)(UNALGINED32(ptr)) * xxhash64_p1; + ptr += 4; + h64 = ROTL64(h64, 23) * xxhash64_p2 + xxhash64_p3; + } + + while (ptr < end) { + h64 ^= *ptr * xxhash64_p5; + h64 = ROTL64(h64, 11) * xxhash64_p1; + ++ptr; + } + + h64 ^= h64 >> 33; + h64 *= xxhash64_p2; + h64 ^= h64 >> 29; + h64 *= xxhash64_p3; + h64 ^= h64 >> 32; + + return h64; +} \ No newline at end of file diff --git a/libGraphite/util/hashing.hpp b/libGraphite/util/hashing.hpp new file mode 100644 index 0000000..6ffa256 --- /dev/null +++ b/libGraphite/util/hashing.hpp @@ -0,0 +1,31 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace graphite::hashing +{ + typedef std::uint64_t value; + + auto xxh64(const void *ptr, std::size_t length) -> hashing::value; +} + From 35b32f6a624933acb442d47692b0b291950a1f2d Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 18 Jun 2022 22:47:43 +0100 Subject: [PATCH 002/113] Remove old QuickDraw implementation. --- libGraphite/quickdraw_old/cicn.cpp | 262 -------- libGraphite/quickdraw_old/cicn.hpp | 46 -- libGraphite/quickdraw_old/clut.cpp | 101 --- libGraphite/quickdraw_old/clut.hpp | 50 -- libGraphite/quickdraw_old/geometry.cpp | 475 -------------- libGraphite/quickdraw_old/geometry.hpp | 203 ------ libGraphite/quickdraw_old/internal/color.cpp | 100 --- libGraphite/quickdraw_old/internal/color.hpp | 57 -- .../quickdraw_old/internal/packbits.cpp | 88 --- .../quickdraw_old/internal/packbits.hpp | 23 - .../quickdraw_old/internal/surface.cpp | 87 --- .../quickdraw_old/internal/surface.hpp | 98 --- libGraphite/quickdraw_old/pict.cpp | 619 ------------------ libGraphite/quickdraw_old/pict.hpp | 89 --- libGraphite/quickdraw_old/pixmap.cpp | 255 -------- libGraphite/quickdraw_old/pixmap.hpp | 87 --- libGraphite/quickdraw_old/ppat.cpp | 150 ----- libGraphite/quickdraw_old/ppat.hpp | 42 -- libGraphite/quickdraw_old/rle.cpp | 371 ----------- libGraphite/quickdraw_old/rle.hpp | 63 -- 20 files changed, 3266 deletions(-) delete mode 100644 libGraphite/quickdraw_old/cicn.cpp delete mode 100644 libGraphite/quickdraw_old/cicn.hpp delete mode 100644 libGraphite/quickdraw_old/clut.cpp delete mode 100644 libGraphite/quickdraw_old/clut.hpp delete mode 100644 libGraphite/quickdraw_old/geometry.cpp delete mode 100644 libGraphite/quickdraw_old/geometry.hpp delete mode 100644 libGraphite/quickdraw_old/internal/color.cpp delete mode 100644 libGraphite/quickdraw_old/internal/color.hpp delete mode 100644 libGraphite/quickdraw_old/internal/packbits.cpp delete mode 100644 libGraphite/quickdraw_old/internal/packbits.hpp delete mode 100644 libGraphite/quickdraw_old/internal/surface.cpp delete mode 100644 libGraphite/quickdraw_old/internal/surface.hpp delete mode 100644 libGraphite/quickdraw_old/pict.cpp delete mode 100644 libGraphite/quickdraw_old/pict.hpp delete mode 100644 libGraphite/quickdraw_old/pixmap.cpp delete mode 100644 libGraphite/quickdraw_old/pixmap.hpp delete mode 100644 libGraphite/quickdraw_old/ppat.cpp delete mode 100644 libGraphite/quickdraw_old/ppat.hpp delete mode 100644 libGraphite/quickdraw_old/rle.cpp delete mode 100644 libGraphite/quickdraw_old/rle.hpp diff --git a/libGraphite/quickdraw_old/cicn.cpp b/libGraphite/quickdraw_old/cicn.cpp deleted file mode 100644 index 214e965..0000000 --- a/libGraphite/quickdraw_old/cicn.cpp +++ /dev/null @@ -1,262 +0,0 @@ -// -// Created by Tom Hancocks on 25/03/2020. -// - -#include "libGraphite/quickdraw/cicn.hpp" -#include "libGraphite/rsrc/manager.hpp" -#include -#include - -// MARK: - Constructor - -graphite::qd::cicn::cicn(std::shared_ptr data, int64_t id, std::string name) - : m_id(id), m_name(std::move(name)) -{ - data::reader reader(std::move(data)); - parse(reader); -} - -graphite::qd::cicn::cicn(std::shared_ptr surface) - : m_surface(std::move(surface)) -{ - -} - -auto graphite::qd::cicn::load_resource(int64_t id) -> std::shared_ptr -{ - if (auto res = graphite::rsrc::manager::shared_manager().find("cicn", id).lock()) { - return std::make_shared(res->data(), id, res->name()); - } - return nullptr; -} - - -// MARK: - Accessors - -auto graphite::qd::cicn::surface() const -> std::weak_ptr -{ - return m_surface; -} - -// MARK: - Parser - -auto graphite::qd::cicn::parse(graphite::data::reader& reader) -> void -{ - m_pixmap = graphite::qd::pixmap(reader.read_data(qd::pixmap::length)); - m_mask_base_addr = reader.read_long(); - m_mask_row_bytes = reader.read_short(); - m_mask_bounds = qd::rect::read(reader); - m_bmap_base_addr = reader.read_long(); - m_bmap_row_bytes = reader.read_short(); - m_bmap_bounds = qd::rect::read(reader); - - reader.move(4); - - auto mask_data_size = m_mask_row_bytes * m_mask_bounds.height(); - auto bmap_data_size = m_bmap_row_bytes * m_bmap_bounds.height(); - auto pmap_data_size = m_pixmap.row_bytes() * m_pixmap.bounds().height(); - - auto mask_data = reader.read_data(mask_data_size); - auto bmap_data = reader.read_data(bmap_data_size); - m_clut = qd::clut(reader); - auto pmap_data = reader.read_data(pmap_data_size); - - // Now that all information has been extracted from the resource, proceed and attempt to render it. - m_surface = std::make_shared(m_pixmap.bounds().width(), m_pixmap.bounds().height()); - - if (m_pixmap.cmp_size() == 1 && m_pixmap.cmp_count() == 1) { - - for (auto y = 0; y < m_pixmap.bounds().height(); ++y) { - auto y_offset = (y * m_pixmap.row_bytes()); - auto mask_y_offset = (y * m_mask_row_bytes); - - for (auto x = 0; x < m_pixmap.bounds().width(); ++x) { - auto byte_offset = 7 - (x % 8); - - auto byte = pmap_data->at(y_offset + (x / 8)); - auto mask = mask_data->at(mask_y_offset + (x / 8)); - auto v = (byte >> byte_offset) & 0x1; - - if ((mask >> byte_offset) & 0x1) { - m_surface->set(x, y, m_clut.get(v)); - } - } - } - - } - else if ((m_pixmap.cmp_size() == 1 && m_pixmap.cmp_count() == 2) || (m_pixmap.cmp_size() == 2 && m_pixmap.cmp_count() == 1)) { - - for (auto y = 0; y < m_pixmap.bounds().height(); ++y) { - auto y_offset = (y * m_pixmap.row_bytes()); - auto mask_y_offset = (y * m_mask_row_bytes); - - for (auto x = 0; x < m_pixmap.bounds().width(); ++x) { - auto byte_offset = (3 - (x % 4)) << 1; - auto mask_offset = (7 - (x % 8)); - - auto byte = pmap_data->at(y_offset + (x / 4)); - auto mask = mask_data->at(mask_y_offset + (x / 8)); - auto v = (byte >> byte_offset) & 0x3; - - if ((mask >> mask_offset) & 0x1) { - m_surface->set(x, y, m_clut.get(v)); - } - } - } - - } - else if ((m_pixmap.cmp_size() == 1 && m_pixmap.cmp_count() == 4) || (m_pixmap.cmp_size() == 4 && m_pixmap.cmp_count() == 1)) { - - for (auto y = 0; y < m_pixmap.bounds().height(); ++y) { - auto y_offset = (y * m_pixmap.row_bytes()); - auto mask_y_offset = (y * m_mask_row_bytes); - - for (auto x = 0; x < m_pixmap.bounds().width(); ++x) { - auto byte_offset = (1 - (x % 2)) << 2; - auto mask_offset = (7 - (x % 8)); - - auto byte = pmap_data->at(y_offset + (x / 2)); - auto mask = mask_data->at(mask_y_offset + (x / 8)); - auto v = (byte >> byte_offset) & 0xF; - - if ((mask >> mask_offset) & 0x1) { - m_surface->set(x, y, m_clut.get(v)); - } - } - } - - } - else if ((m_pixmap.cmp_size() == 1 && m_pixmap.cmp_count() == 8) || (m_pixmap.cmp_size() == 8 && m_pixmap.cmp_count() == 1)) { - - for (auto y = 0; y < m_pixmap.bounds().height(); ++y) { - auto y_offset = (y * m_pixmap.row_bytes()); - auto mask_y_offset = (y * m_mask_row_bytes); - - for (auto x = 0; x < m_pixmap.bounds().width(); ++x) { - auto mask_offset = (7 - (x % 8)); - - auto byte = static_cast(pmap_data->at(y_offset + x)); - auto mask = mask_data->at(mask_y_offset + (x / 8)); - - if ((mask >> mask_offset) & 0x1) { - m_surface->set(x, y, m_clut.get(byte)); - } - } - } - - } - else { - throw std::runtime_error("Currently unsupported cicn configuration: cmp_size=" + - std::to_string(m_pixmap.cmp_size()) + - ", cmp_count=" + std::to_string(m_pixmap.cmp_count())); - } -} - -// MARK: - Encoder - -auto graphite::qd::cicn::data() -> std::shared_ptr -{ - auto data = std::make_shared(); - auto writer = graphite::data::writer(data); - auto width = m_surface->size().width(); - auto height = m_surface->size().height(); - - // TODO: This is a brute force method of bringing down the color depth/number of colors required, - // for a cicn image. It doesn't optimise for image quality at all, and should be replaced at somepoint. - std::vector color_values; - std::vector mask_values; - uint8_t pass = 0; - do { - if (pass++ > 0) { - for (auto y = 0; y < height; ++y) { - for (auto x = 0; x < width; ++x) { - auto color = m_surface->at(x, y); - m_surface->set(x, y, qd::color( - color.red_component() & ~(1 << pass), - color.green_component() & ~(1 << pass), - color.blue_component() & ~(1 << pass), - color.alpha_component() - )); - } - } - } - - // Rebuild the Color Table for the surface. To do this we want to create an empty table, and populate it. - m_clut = qd::clut(); - color_values.clear(); - mask_values.clear(); - for (auto y = 0; y < height; ++y) { - for (auto x = 0; x < width; ++x) { - auto color = m_surface->at(x, y); - mask_values.emplace_back((color.alpha_component() & 0x80) != 0); - color_values.emplace_back(m_clut.set(color)); - } - } - } while(m_clut.size() > 256); - - - // Determine what component configuration we need. - m_pixmap = qd::pixmap(); - m_pixmap.set_bounds(qd::rect(point::zero(), m_surface->size())); - graphite::data::writer mask_data(std::make_shared()); - graphite::data::writer bmap_data(std::make_shared()); - std::shared_ptr pmap_data; - m_mask_row_bytes = m_bmap_row_bytes = (width - 1) / 8 + 1; - - bmap_data.write_byte(0, m_bmap_row_bytes * height); - - // Construct the mask data for the image. - for (auto y = 0; y < height; ++y) { - uint8_t scratch = 0; - for (auto x = 0; x < width; ++x) { - // We need to write the scratch byte every 8th bit that is visited, and clear it. - auto bit_offset = x % 8; - if (bit_offset == 0 && x != 0) { - mask_data.write_byte(scratch); - scratch = 0; - } - auto n = y * width + x; - uint8_t value = mask_values[n] ? 1 : 0; - value <<= (7 - bit_offset); - scratch |= value; - } - mask_data.write_byte(scratch); - } - - if (m_clut.size() > 256) { - throw std::runtime_error("Implementation does not currently handle more than 256 colors in a CICN"); - } - else if (m_clut.size() > 16) { - pmap_data = m_pixmap.build_pixel_data(color_values, 8); - } - else if (m_clut.size() > 4) { - pmap_data = m_pixmap.build_pixel_data(color_values, 4); - } - else if (m_clut.size() > 2) { - pmap_data = m_pixmap.build_pixel_data(color_values, 2); - } - else { - pmap_data = m_pixmap.build_pixel_data(color_values, 1); - } - - // Calculate some offsets - m_mask_base_addr = 4; - m_bmap_base_addr = m_mask_base_addr + mask_data.size(); - - // Write out the image data for the cicn. - m_pixmap.write(writer); - writer.write_long(0); - writer.write_short(m_mask_row_bytes); - m_pixmap.bounds().write(writer); - writer.write_long(0); - writer.write_short(m_bmap_row_bytes); - m_pixmap.bounds().write(writer); - writer.write_long(0); - - writer.write_data(mask_data.data()); - writer.write_data(bmap_data.data()); - m_clut.write(writer); - writer.write_data(pmap_data); - - return data; -} diff --git a/libGraphite/quickdraw_old/cicn.hpp b/libGraphite/quickdraw_old/cicn.hpp deleted file mode 100644 index 52ef5bc..0000000 --- a/libGraphite/quickdraw_old/cicn.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Created by Tom Hancocks on 25/03/2020. -// - -#if !defined(GRAPHITE_CICN_HPP) -#define GRAPHITE_CICN_HPP - -#include -#include "libGraphite/quickdraw/internal/surface.hpp" -#include "libGraphite/quickdraw/geometry.hpp" -#include "libGraphite/quickdraw/pixmap.hpp" -#include "libGraphite/quickdraw/clut.hpp" - -namespace graphite::qd { - - class cicn - { - private: - int64_t m_id{}; - std::string m_name; - qd::pixmap m_pixmap; - uint32_t m_mask_base_addr{}; - uint16_t m_mask_row_bytes{}; - qd::rect m_mask_bounds; - uint32_t m_bmap_base_addr{}; - uint16_t m_bmap_row_bytes{}; - qd::rect m_bmap_bounds; - uint32_t m_icon_data{}; - std::shared_ptr m_surface; - qd::clut m_clut; - - auto parse(data::reader& reader) -> void; - - public: - explicit cicn(std::shared_ptr data, int64_t id = 0, std::string name = ""); - explicit cicn(std::shared_ptr surface); - - static auto load_resource(int64_t id) -> std::shared_ptr; - - [[nodiscard]] auto surface() const -> std::weak_ptr; - auto data() -> std::shared_ptr; - }; - -} - -#endif //GRAPHITE_CICN_HPP diff --git a/libGraphite/quickdraw_old/clut.cpp b/libGraphite/quickdraw_old/clut.cpp deleted file mode 100644 index 72e5297..0000000 --- a/libGraphite/quickdraw_old/clut.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// -// Created by Tom Hancocks on 25/03/2020. -// - -#include -#include -#include "libGraphite/quickdraw/clut.hpp" -#include "libGraphite/rsrc/manager.hpp" - -// MARK: - Constructors - - -graphite::qd::clut::clut(std::shared_ptr data, int64_t id, std::string name) - : m_id(id), m_name(std::move(name)) -{ - data::reader reader(std::move(data)); - parse(reader); -} - -graphite::qd::clut::clut(graphite::data::reader& reader) - : m_id(std::numeric_limits::max()), m_name("Embedded `clut` resource") -{ - parse(reader); -} - -auto graphite::qd::clut::load_resource(int64_t id) -> std::shared_ptr -{ - if (auto res = graphite::rsrc::manager::shared_manager().find("clut", id).lock()) { - return std::make_shared(res->data(), id, res->name()); - } - return nullptr; -} - -// MARK: - Accessors - -auto graphite::qd::clut::size() const -> int -{ - return m_size; -} - -auto graphite::qd::clut::at(int index) const -> graphite::qd::color -{ - return m_entries.at(index); -} - -auto graphite::qd::clut::get(int value) const -> graphite::qd::color -{ - return m_entries.at(value); -} - -auto graphite::qd::clut::set(const qd::color& color) -> uint16_t -{ - uint16_t value = 0; - for (auto entry : m_entries) { - if (std::get<1>(entry) == color) { - return std::get<0>(entry); - } - if (std::get<0>(entry) == value) { - ++value; - } - } - m_entries.emplace(value, color); - m_size = m_entries.size(); - return value; -} - -// MARK: - Parser - -auto graphite::qd::clut::parse(graphite::data::reader& reader) -> void -{ - m_seed = reader.read_long(); - m_flags = static_cast(reader.read_short()); - m_size = reader.read_short() + 1; - - for (auto i = 0; i < m_size; ++i) { - auto value = reader.read_short(); - auto r = static_cast((reader.read_short() / 65535.0) * 255); - auto g = static_cast((reader.read_short() / 65535.0) * 255); - auto b = static_cast((reader.read_short() / 65535.0) * 255); - int index = m_flags == device ? i : value; - m_entries.emplace(index, qd::color(r, g, b)); - } -} - -// MARK: - Writer - -auto graphite::qd::clut::write(graphite::data::writer& writer) -> void -{ - writer.write_long(m_seed); - writer.write_short(static_cast(m_flags)); - writer.write_short(m_size - 1); - - for (auto entry : m_entries) { - auto value = std::get<0>(entry); - auto color = std::get<1>(entry); - writer.write_short(value); - writer.write_short(static_cast((color.red_component() / 255.0) * 65535.0)); - writer.write_short(static_cast((color.green_component() / 255.0) * 65535.0)); - writer.write_short(static_cast((color.blue_component() / 255.0) * 65535.0)); - } -} diff --git a/libGraphite/quickdraw_old/clut.hpp b/libGraphite/quickdraw_old/clut.hpp deleted file mode 100644 index 3a35441..0000000 --- a/libGraphite/quickdraw_old/clut.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Created by Tom Hancocks on 25/03/2020. -// - -#if !defined(GRAPHITE_CLUT_HPP) -#define GRAPHITE_CLUT_HPP - -#include -#include -#include "libGraphite/quickdraw/internal/color.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" - -namespace graphite::qd { - - struct clut - { - public: - enum flags : uint16_t { pixmap = 0x0000, device = 0x8000 }; - - private: - int64_t m_id { 0 }; - std::string m_name; - - uint32_t m_seed { 0 }; - enum flags m_flags { pixmap }; - uint16_t m_size { 0 }; - std::map m_entries; - - auto parse(data::reader& reader) -> void; - - public: - clut() = default; - explicit clut(std::shared_ptr data, int64_t id = 0, std::string name = ""); - explicit clut(data::reader& reader); - - static auto load_resource(int64_t id) -> std::shared_ptr; - - [[nodiscard]] auto size() const -> int; - - [[nodiscard]] auto at(int index) const -> qd::color; - [[nodiscard]] auto get(int value) const -> qd::color; - auto set(const qd::color& color) -> uint16_t; - - auto write(graphite::data::writer& writer) -> void; - }; - -} - -#endif //GRAPHITE_CLUT_HPP diff --git a/libGraphite/quickdraw_old/geometry.cpp b/libGraphite/quickdraw_old/geometry.cpp deleted file mode 100644 index e2eea42..0000000 --- a/libGraphite/quickdraw_old/geometry.cpp +++ /dev/null @@ -1,475 +0,0 @@ -// -// Created by tomhancocks on 18/04/2020. -// - -#include "libGraphite/quickdraw/geometry.hpp" - -// MARK: - Point - -graphite::qd::point::point(int16_t x, int16_t y) - : m_x(x), m_y(y) -{ - -} - -auto graphite::qd::point::zero() -> qd::point -{ - return { 0, 0 }; -} - -auto graphite::qd::point::x() const -> int16_t -{ - return m_x; -} - -auto graphite::qd::point::y() const -> int16_t -{ - return m_y; -} - -auto graphite::qd::point::set_x(const int16_t& x) -> void -{ - m_x = x; -} - -auto graphite::qd::point::set_y(const int16_t& y) -> void -{ - m_y = y; -} - -auto graphite::qd::point::read(graphite::data::reader& reader, enum coding_type type) -> qd::point -{ - switch (type) { - case coding_type::qd: { - auto y = reader.read_signed_short(); - auto x = reader.read_signed_short(); - return qd::point(x, y); - } - case coding_type::pict: { - auto x = reader.read_signed_short(); - auto y = reader.read_signed_short(); - return qd::point(x, y); - } - default: { - return qd::point(0, 0); - } - } -} - -auto graphite::qd::point::write(graphite::data::writer& writer, enum coding_type type) const -> void -{ - switch (type) { - case coding_type::qd: { - writer.write_signed_short(m_y); - writer.write_signed_short(m_x); - break; - } - case coding_type::pict: { - writer.write_signed_short(m_x); - writer.write_signed_short(m_y); - break; - } - } -} - -// MARK: - Fixed Point - -graphite::qd::fixed_point::fixed_point(double x, double y) - : m_x(x), m_y(y) -{ - -}; - -auto graphite::qd::fixed_point::zero() -> qd::fixed_point -{ - return { 0, 0 }; -}; - -auto graphite::qd::fixed_point::x() const -> double -{ - return m_x; -}; - -auto graphite::qd::fixed_point::y() const -> double -{ - return m_y; -}; - -auto graphite::qd::fixed_point::set_x(const double& x) -> void -{ - m_x = x; -}; - -auto graphite::qd::fixed_point::set_y(const double& y) -> void -{ - m_y = y; -}; - -auto graphite::qd::fixed_point::read(graphite::data::reader& reader, enum coding_type type) -> qd::fixed_point -{ - switch (type) { - case coding_type::qd: { - auto y = static_cast(reader.read_signed_long() / static_cast(1 << 16)); - auto x = static_cast(reader.read_signed_long() / static_cast(1 << 16)); - return qd::fixed_point(x, y); - } - default: { - return qd::fixed_point(0, 0); - } - } -} - -auto graphite::qd::fixed_point::write(graphite::data::writer& writer, enum coding_type type) const -> void -{ - switch (type) { - case coding_type::qd: { - writer.write_signed_long(static_cast(m_y * (1 << 16))); - writer.write_signed_long(static_cast(m_x * (1 << 16))); - break; - } - } -} - -// MARK: - Size - -graphite::qd::size::size(int16_t width, int16_t height) - : m_width(width), m_height(height) -{ - -}; - -auto graphite::qd::size::zero() -> qd::size -{ - return size(); -}; - -auto graphite::qd::size::width() const -> int16_t -{ - return m_width; -}; - -auto graphite::qd::size::height() const -> int16_t -{ - return m_height; -}; - -auto graphite::qd::size::set_width(const int16_t& width) -> void -{ - m_width = width; -}; - -auto graphite::qd::size::set_height(const int16_t& height) -> void -{ - m_height = height; -}; - -auto graphite::qd::size::read(graphite::data::reader& reader, enum coding_type type) -> qd::size -{ - switch (type) { - case coding_type::qd: { - auto height = reader.read_signed_short(); - auto width = reader.read_signed_short(); - return qd::size(width, height); - } - case coding_type::pict: { - auto width = reader.read_signed_short(); - auto height = reader.read_signed_short(); - return qd::size(width, height); - } - default: { - return qd::size(0, 0); - } - } -} - -auto graphite::qd::size::write(graphite::data::writer& writer, enum coding_type type) const -> void -{ - switch (type) { - case coding_type::qd: { - writer.write_signed_short(m_height); - writer.write_signed_short(m_width); - break; - } - case coding_type::pict: { - writer.write_signed_short(m_width); - writer.write_signed_short(m_height); - break; - } - } -} - -// MARK: - Fixed Size - -graphite::qd::fixed_size::fixed_size(double width, double height) - : m_width(width), m_height(height) -{ - -} - -auto graphite::qd::fixed_size::zero() -> qd::fixed_size -{ - return { 0, 0 }; -} - -auto graphite::qd::fixed_size::width() const -> double -{ - return m_width; -} - -auto graphite::qd::fixed_size::height() const -> double -{ - return m_height; -} - -auto graphite::qd::fixed_size::set_width(const double& width) -> void -{ - m_width = width; -} - -auto graphite::qd::fixed_size::set_height(const double& height) -> void -{ - m_height = height; -} - -auto graphite::qd::fixed_size::read(graphite::data::reader& reader, enum coding_type type) -> qd::fixed_size -{ - switch (type) { - case coding_type::qd: { - auto height = static_cast(reader.read_signed_long() / static_cast(1 << 16)); - auto width = static_cast(reader.read_signed_long() / static_cast(1 << 16)); - return qd::fixed_size(width, height); - } - default: { - return qd::fixed_size(0, 0); - } - } -} - -auto graphite::qd::fixed_size::write(graphite::data::writer& writer, enum coding_type type) const -> void -{ - switch (type) { - case coding_type::qd: { - writer.write_signed_long(static_cast(m_height * (1 << 16))); - writer.write_signed_long(static_cast(m_width * (1 << 16))); - break; - } - } -} - -// MARK: - Rect - -graphite::qd::rect::rect(const point& origin, const qd::size& sz) - : m_origin(origin), m_size(sz) -{ - -} - -graphite::qd::rect::rect(int16_t x, int16_t y, int16_t width, int16_t height) - : m_origin(x, y), m_size(width, height) -{ - -} - -auto graphite::qd::rect::zero() -> qd::rect -{ - return { 0, 0, 0, 0 }; -} - -auto graphite::qd::rect::x() const -> int16_t -{ - return m_origin.x(); -} - -auto graphite::qd::rect::y() const -> int16_t -{ - return m_origin.y(); -} - -auto graphite::qd::rect::width() const -> int16_t -{ - return m_size.width(); -} - -auto graphite::qd::rect::height() const -> int16_t -{ - return m_size.height(); -} - -auto graphite::qd::rect::origin() const -> qd::point -{ - return m_origin; -} - -auto graphite::qd::rect::size() const -> qd::size -{ - return m_size; -} - -auto graphite::qd::rect::set_x(const int16_t& x) -> void -{ - m_origin.set_x(x); -} - -auto graphite::qd::rect::set_y(const int16_t& y) -> void -{ - m_origin.set_y(y); -} - -auto graphite::qd::rect::set_width(const int16_t& width) -> void -{ - m_size.set_width(width); -} - -auto graphite::qd::rect::set_height(const int16_t& height) -> void -{ - m_size.set_height(height); -} - -auto graphite::qd::rect::set_origin(const qd::point& origin) -> void -{ - m_origin = origin; -} - -auto graphite::qd::rect::set_size(const struct qd::size& size) -> void -{ - m_size = size; -} - -auto graphite::qd::rect::read(graphite::data::reader& reader, enum coding_type type) -> qd::rect -{ - switch (type) { - case coding_type::qd: { - auto origin = qd::point::read(reader, point::qd); - auto opposite = qd::point::read(reader, point::qd); - return qd::rect(origin, qd::size(opposite.x() - origin.x(), opposite.y() - origin.y())); - } - case coding_type::pict: { - auto origin = point::read(reader, point::pict); - auto sz = size::read(reader, size::pict); - return qd::rect(origin, sz); - } - default: { - return qd::rect({0, 0}, {0, 0}); - } - } -} - -auto graphite::qd::rect::write(graphite::data::writer& writer, enum coding_type type) -> void -{ - switch (type) { - case coding_type::qd: { - m_origin.write(writer, point::qd); - m_size.write(writer, size::qd); - break; - } - case coding_type::pict: { - m_origin.write(writer, point::pict); - m_size.write(writer, size::pict); - break; - } - } -} - -// MARK: - Fixed Rect - -graphite::qd::fixed_rect::fixed_rect(const qd::fixed_point& origin, const qd::fixed_size& size) - : m_origin(origin), m_size(size) -{ - -} - -graphite::qd::fixed_rect::fixed_rect(double x, double y, double width, double height) - : m_origin(x, y), m_size(width, height) -{ - -} - -auto graphite::qd::fixed_rect::zero() -> qd::fixed_rect -{ - return { 0, 0, 0, 0 }; -} - -auto graphite::qd::fixed_rect::x() const -> double -{ - return m_origin.x(); -} - -auto graphite::qd::fixed_rect::y() const -> double -{ - return m_origin.y(); -} - -auto graphite::qd::fixed_rect::width() const -> double -{ - return m_size.width(); -} - -auto graphite::qd::fixed_rect::height() const -> double -{ - return m_size.height(); -} - -auto graphite::qd::fixed_rect::origin() const -> qd::fixed_point -{ - return m_origin; -} - -auto graphite::qd::fixed_rect::size() const -> qd::fixed_size -{ - return m_size; -} - -auto graphite::qd::fixed_rect::set_x(const double& x) -> void -{ - m_origin.set_x(x); -} - -auto graphite::qd::fixed_rect::set_y(const double& y) -> void -{ - m_origin.set_y(y); -} - -auto graphite::qd::fixed_rect::set_width(const double& width) -> void -{ - m_size.set_width(width); -} - -auto graphite::qd::fixed_rect::set_height(const double& height) -> void -{ - m_size.set_height(height); -} - -auto graphite::qd::fixed_rect::set_origin(const qd::fixed_point& origin) -> void -{ - m_origin = origin; -} - -auto graphite::qd::fixed_rect::set_size(const qd::fixed_size& size) -> void -{ - m_size = size; -} - -auto graphite::qd::fixed_rect::read(graphite::data::reader& reader, enum coding_type type) -> qd::fixed_rect -{ - switch (type) { - case coding_type::qd: { - auto origin = fixed_point::read(reader, fixed_point::qd); - auto opposite = fixed_point::read(reader, fixed_point::qd); - return qd::fixed_rect(origin, fixed_size(origin.x() + opposite.x(), origin.y() + opposite.y())); - } - default: { - return qd::fixed_rect({0, 0}, {0, 0}); - } - } -} - -auto graphite::qd::fixed_rect::write(graphite::data::writer& writer, enum coding_type type) -> void -{ - switch (type) { - case coding_type::qd: { - m_origin.write(writer, fixed_point::qd); - m_size.write(writer, fixed_size::qd); - break; - } - } -} diff --git a/libGraphite/quickdraw_old/geometry.hpp b/libGraphite/quickdraw_old/geometry.hpp deleted file mode 100644 index 56d434e..0000000 --- a/libGraphite/quickdraw_old/geometry.hpp +++ /dev/null @@ -1,203 +0,0 @@ -// -// Created by Tom Hancocks on 19/03/2020. -// - -#if !defined(GRAPHITE_GEOMETRY_HPP) -#define GRAPHITE_GEOMETRY_HPP - -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" - -namespace graphite::qd { - - // MARK: - Point - - struct point - { - public: - enum coding_type { qd, pict }; - - private: - int16_t m_x { 0 }; - int16_t m_y { 0 }; - - public: - point() = default; - point(int16_t x, int16_t y); - point(const qd::point& p) = default; - - static auto zero() -> qd::point; - - [[nodiscard]] auto x() const -> int16_t; - [[nodiscard]] auto y() const -> int16_t; - - auto set_x(const int16_t& x) -> void; - auto set_y(const int16_t& y) -> void; - - static auto read(graphite::data::reader& reader, enum coding_type type = qd) -> qd::point; - auto write(graphite::data::writer& writer, coding_type type = qd) const -> void; - - }; - - // MARK: - Fixed Point - - struct fixed_point - { - public: - enum coding_type { qd }; - - private: - double m_x { 0 }; - double m_y { 0 }; - - public: - fixed_point() = default; - fixed_point(double x, double y); - fixed_point(const fixed_point& p) = default; - - static auto zero() -> fixed_point; - - [[nodiscard]] auto x() const -> double; - [[nodiscard]] auto y() const -> double; - - auto set_x(const double& x) -> void; - auto set_y(const double& y) -> void; - - static auto read(graphite::data::reader& reader, enum coding_type type = qd) -> fixed_point; - auto write(graphite::data::writer& writer, enum coding_type type = qd) const -> void; - - }; - - // MARK: - Size - - struct size - { - public: - enum coding_type { qd, pict }; - - private: - int16_t m_width { 0 }; - int16_t m_height { 0 }; - - public: - size() = default; - size(int16_t width, int16_t height); - size(const size& s) = default; - - static auto zero() -> size; - - [[nodiscard]] auto width() const -> int16_t; - [[nodiscard]] auto height() const -> int16_t; - - auto set_width(const int16_t& width) -> void; - auto set_height(const int16_t& height) -> void; - - static auto read(graphite::data::reader& reader, enum coding_type type = qd) -> size; - auto write(graphite::data::writer& writer, enum coding_type type = qd) const -> void; - }; - - // MARK: - Fixed Size - - struct fixed_size - { - public: - enum coding_type { qd }; - - private: - double m_width { 0 }; - double m_height { 0 }; - - public: - fixed_size() = default; - fixed_size(double width, double height); - fixed_size(const fixed_size& s) = default; - - static auto zero() -> fixed_size; - - [[nodiscard]] auto width() const -> double; - [[nodiscard]] auto height() const -> double; - - auto set_width(const double& width) -> void; - auto set_height(const double& height) -> void; - - static auto read(graphite::data::reader& reader, enum coding_type type = qd) -> fixed_size; - auto write(graphite::data::writer& writer, enum coding_type type = qd) const -> void; - }; - - // MARK: - Rect - - struct rect - { - public: - enum coding_type { qd, pict }; - - private: - qd::point m_origin { point::zero() }; - qd::size m_size { size::zero() }; - - public: - rect() = default; - rect(const qd::point& origin, const qd::size& size); - rect(int16_t x, int16_t y, int16_t width, int16_t height); - rect(const qd::rect& r) = default; - - static auto zero() -> qd::rect; - - [[nodiscard]] auto x() const -> int16_t; - [[nodiscard]] auto y() const -> int16_t; - [[nodiscard]] auto width() const -> int16_t; - [[nodiscard]] auto height() const -> int16_t; - [[nodiscard]] auto origin() const -> qd::point; - [[nodiscard]] auto size() const -> qd::size; - - auto set_x(const int16_t& x) -> void; - auto set_y(const int16_t& y) -> void; - auto set_width(const int16_t& width) -> void; - auto set_height(const int16_t& height) -> void; - auto set_origin(const qd::point& origin) -> void; - auto set_size(const struct qd::size& size) -> void; - - static auto read(graphite::data::reader& reader, enum coding_type type = qd) -> qd::rect; - auto write(graphite::data::writer& writer, enum coding_type type = qd) -> void; - }; - - // MARK: - Fixed Rect - - struct fixed_rect - { - public: - enum coding_type { qd }; - - private: - qd::fixed_point m_origin { fixed_point::zero() }; - qd::fixed_size m_size { fixed_size::zero() }; - - public: - fixed_rect() = default; - fixed_rect(const qd::fixed_point& origin, const qd::fixed_size& size); - fixed_rect(double x, double y, double width, double height); - fixed_rect(const qd::fixed_rect& r) = default; - - static auto zero() -> qd::fixed_rect; - - [[nodiscard]] auto x() const -> double; - [[nodiscard]] auto y() const -> double; - [[nodiscard]] auto width() const -> double; - [[nodiscard]] auto height() const -> double; - [[nodiscard]] auto origin() const -> qd::fixed_point; - [[nodiscard]] auto size() const -> qd::fixed_size; - - auto set_x(const double& x) -> void; - auto set_y(const double& y) -> void; - auto set_width(const double& width) -> void; - auto set_height(const double& height) -> void; - auto set_origin(const qd::fixed_point& origin) -> void; - auto set_size(const qd::fixed_size& size) -> void; - - static auto read(graphite::data::reader& reader, enum coding_type type = qd) -> qd::fixed_rect; - auto write(graphite::data::writer& writer, enum coding_type type = qd) -> void; - }; - -} - -#endif //GRAPHITE_GEOMETRY_HPP diff --git a/libGraphite/quickdraw_old/internal/color.cpp b/libGraphite/quickdraw_old/internal/color.cpp deleted file mode 100644 index e74d5e0..0000000 --- a/libGraphite/quickdraw_old/internal/color.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#include "libGraphite/quickdraw/internal/color.hpp" - -// MARK: - Constructor - -graphite::qd::color::color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) - : m_red(red), m_blue(blue), m_green(green), m_alpha(alpha) -{ - -} - -// MARK: - Accessors - -auto graphite::qd::color::red_component() const -> uint8_t -{ - return m_red; -} - -auto graphite::qd::color::green_component() const -> uint8_t -{ - return m_green; -} - -auto graphite::qd::color::blue_component() const -> uint8_t -{ - return m_blue; -} - -auto graphite::qd::color::alpha_component() const -> uint8_t -{ - return m_alpha; -} - - -// MARK: - Quick Colors - -auto graphite::qd::color::black() -> graphite::qd::color -{ - return graphite::qd::color(0, 0, 0); -} - -auto graphite::qd::color::white() -> graphite::qd::color -{ - return graphite::qd::color(255, 255, 255); -} - -auto graphite::qd::color::red() -> graphite::qd::color -{ - return graphite::qd::color(255, 0, 0); -} - -auto graphite::qd::color::green() -> graphite::qd::color -{ - return graphite::qd::color(0, 255, 0); -} - -auto graphite::qd::color::blue() -> graphite::qd::color -{ - return graphite::qd::color(0, 0, 255); -} - -auto graphite::qd::color::purple() -> graphite::qd::color -{ - return graphite::qd::color(150, 0, 255); -} - -auto graphite::qd::color::orange() -> graphite::qd::color -{ - return graphite::qd::color(255, 150, 0); -} - -auto graphite::qd::color::yellow() -> graphite::qd::color -{ - return graphite::qd::color(255, 255, 0); -} - -auto graphite::qd::color::lightGrey() -> graphite::qd::color -{ - return graphite::qd::color(200, 200, 200); -} - -auto graphite::qd::color::darkGrey() -> graphite::qd::color -{ - return graphite::qd::color(100, 100, 100); -} - -auto graphite::qd::color::clear() -> graphite::qd::color -{ - return graphite::qd::color(0, 0, 0, 0); -} - -// MARK: - Operators - -auto graphite::qd::color::operator==(const graphite::qd::color &rhs) const -> bool -{ - return (m_red == rhs.m_red) && (m_green == rhs.m_green) && (m_blue == rhs.m_blue) && (m_alpha == rhs.m_alpha); -} diff --git a/libGraphite/quickdraw_old/internal/color.hpp b/libGraphite/quickdraw_old/internal/color.hpp deleted file mode 100644 index 78e88e8..0000000 --- a/libGraphite/quickdraw_old/internal/color.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#ifndef GRAPHITE_COLOR_HPP -#define GRAPHITE_COLOR_HPP - -#include - -namespace graphite::qd { - - /** - * A structure representing a 4-component color, as used by the internal QuickDraw surface. - */ - struct color - { - private: - uint8_t m_red; - uint8_t m_green; - uint8_t m_blue; - uint8_t m_alpha; - - public: - - /** - * Construct a new color using the specified color component values. - * @param red The red component of the color - * @param green The green component of the color - * @param blue The blue component of the color - * @param alpha The alpha component of the color - */ - color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255); - - [[nodiscard]] auto red_component() const -> uint8_t; - [[nodiscard]] auto green_component() const -> uint8_t; - [[nodiscard]] auto blue_component() const -> uint8_t; - [[nodiscard]] auto alpha_component() const -> uint8_t; - - static auto black() -> color; - static auto white() -> color; - static auto red() -> color; - static auto green() -> color; - static auto blue() -> color; - static auto purple() -> color; - static auto orange() -> color; - static auto yellow() -> color; - static auto lightGrey() -> color; - static auto darkGrey() -> color; - static auto clear() -> color; - - auto operator== (const color& rhs) const -> bool; - }; - -} - - -#endif //GRAPHITE_COLOR_HPP diff --git a/libGraphite/quickdraw_old/internal/packbits.cpp b/libGraphite/quickdraw_old/internal/packbits.cpp deleted file mode 100644 index 0e7cfb4..0000000 --- a/libGraphite/quickdraw_old/internal/packbits.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#include -#include "libGraphite/quickdraw/internal/packbits.hpp" -#include - -auto graphite::qd::packbits::decode(std::vector &out_data, const std::vector& pack_data, std::size_t value_size) -> std::size_t -{ - std::size_t pos = 0; - - while (pos < pack_data.size()) { - auto count = pack_data[pos++]; - if (count >= 0 && count < 128) { - uint16_t run = (1 + count) * value_size; - if ((pos + run) > pack_data.size()) { - throw std::runtime_error("Unable to decode packbits."); - } - out_data.insert(out_data.end(), std::make_move_iterator(pack_data.begin() + pos), std::make_move_iterator(pack_data.begin() + pos + run)); - pos += run; - } - else if (count >= 128) { - uint8_t run = 256 - count + 1; - for (uint8_t i = 0; i < run; ++i) { - for (uint8_t j = 0; j < value_size; ++j) { - out_data.push_back(pack_data[pos + j]); - } - } - pos += value_size; - } - else { - // No-op - } - } - - return out_data.size(); -} - -auto graphite::qd::packbits::encode(const std::vector& scanline_bytes) -> std::vector -{ - std::vector result; - std::vector buffer(128); - - int offset = 0; - const unsigned long max = scanline_bytes.size() - 1; - const unsigned long max_minus_1 = max - 1; - - while (offset <= max) { - // Compressed run - int run = 1; - uint8_t replicate = scanline_bytes[offset]; - while (run < 127 && offset < max && scanline_bytes[offset] == scanline_bytes[offset + 1]) { - offset++; - run++; - } - - if (run > 1) { - offset++; - result.emplace_back(static_cast(-(run - 1))); - result.emplace_back(replicate); - } - - // Literal run - run = 0; - while ((run < 128 && ((offset < max && scanline_bytes[offset] != scanline_bytes[offset + 1]) - || (offset < max_minus_1 && scanline_bytes[offset] != scanline_bytes[offset + 2])))) { - buffer[run++] = scanline_bytes[offset++]; - } - - if (offset == max && run > 0 && run < 128) { - buffer[run++] = scanline_bytes[offset++]; - } - - if (run > 0) { - result.emplace_back(run - 1); - result.insert(result.end(), buffer.begin(), buffer.begin() + run); - buffer = std::vector(128); - } - - if (offset == max && (run <= 0 || run >= 128)) { - result.emplace_back(0); - result.emplace_back(scanline_bytes[offset++]); - } - } - - return result; -} diff --git a/libGraphite/quickdraw_old/internal/packbits.hpp b/libGraphite/quickdraw_old/internal/packbits.hpp deleted file mode 100644 index f2d5e3c..0000000 --- a/libGraphite/quickdraw_old/internal/packbits.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#if !defined(GRAPHITE_PACKBITS_HPP) -#define GRAPHITE_PACKBITS_HPP - -#include -#include -#include - -namespace graphite::qd { - - struct packbits - { - public: - static auto decode(std::vector &out_data, const std::vector& pack_data, std::size_t value_size) -> std::size_t; - static auto encode(const std::vector& scanline_bytes) -> std::vector; - }; - -} - -#endif //GRAPHITE_PACKBITS_HPP diff --git a/libGraphite/quickdraw_old/internal/surface.cpp b/libGraphite/quickdraw_old/internal/surface.cpp deleted file mode 100644 index 78b1db4..0000000 --- a/libGraphite/quickdraw_old/internal/surface.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#include "libGraphite/quickdraw/internal/surface.hpp" - -// MARK: - Constructor - -graphite::qd::surface::surface(int width, int height) - : m_width(width), m_height(height), m_data(width * height, graphite::qd::color::clear()) -{ -} - -graphite::qd::surface::surface(int width, int height, std::vector rgb) -: m_width(width), m_height(height), m_data(std::move(rgb)) -{ -} - -// MARK: - Surface Access - -auto graphite::qd::surface::raw() const -> std::vector -{ - auto out = std::vector(); - for (const auto& i : m_data) { - uint32_t color = (i.alpha_component() << 24) - | i.red_component() - | (i.green_component() << 8UL) - | (i.blue_component() << 16UL); - out.push_back(color); - } - return out; -} - -auto graphite::qd::surface::size() const -> graphite::qd::size -{ - return graphite::qd::size(m_width, m_height); -} - -auto graphite::qd::surface::at(int x, int y) const -> graphite::qd::color -{ - return m_data[(y * m_width) + x]; -} - -auto graphite::qd::surface::set(int x, int y, graphite::qd::color color) -> void -{ - if (x >= m_width || y >= m_height) { - throw std::runtime_error("Attempted to set pixel beyond bounds of surface."); - } - m_data[(y * m_width) + x] = color; -} - -auto graphite::qd::surface::set(int offset, graphite::qd::color color) -> void -{ - if (offset >= m_data.size()) { - throw std::runtime_error("Attempted to set pixel beyond bounds of surface."); - } - m_data[offset] = color; -} - -// MARK: - Drawing Operations - -auto graphite::qd::surface::draw_line(int x0, int y0, int x1, int y1, graphite::qd::color color) -> void -{ - int delta_x = abs(x1 - x0); - int delta_y = abs(y1 - y0); - int sx = (x0 < x1) ? 1 : -1; - int sy = (y0 < y1) ? 1 : -1; - int err = delta_x - delta_y; - - for (;;) { - if (x0 >= 0 && y0 >= 0 && x0 < m_width && y0 < m_height) { - set(x0, y0, color); - } - if (x0 == x1 & y0 == y1) { - break; - } - int e2 = 2 * err; - if (e2 > -delta_y) { - err -= delta_y; - x0 += sx; - } - if (e2 < delta_x) { - err += delta_x; - y0 += sy; - } - } -} diff --git a/libGraphite/quickdraw_old/internal/surface.hpp b/libGraphite/quickdraw_old/internal/surface.hpp deleted file mode 100644 index eac09cf..0000000 --- a/libGraphite/quickdraw_old/internal/surface.hpp +++ /dev/null @@ -1,98 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#if !defined(GRAPHITE_QD_SURFACE) -#define GRAPHITE_QD_SURFACE - -#include -#include -#include -#include "libGraphite/quickdraw/internal/color.hpp" - -namespace graphite::qd -{ - - /** - * The `graphite::qd::surface` class is an internal component of Graphite's QuickDraw implementation - * and the component that provides image drawing functionality. This component should not be interacted - * with directly, and should always go through the "QuickDraw" methods. - */ - class surface - { - private: - int m_width; - int m_height; - std::vector m_data; - - public: - - /** - * Construct a new surface with the specified dimensions. - * @param width The width of the surface in pixels. - * @param height The height of the surface in pixels. - */ - surface(int width, int height); - - /** - * Construct a new surface with the specified dimensions and rgb data. - * @param width The width of the surface in pixels. - * @param height The height of the surface in pixels. - * @param rgb The rgb data of the surface. - */ - surface(int width, int height, std::vector rgb); - - /** - * Export the raw surface data. - */ - [[nodiscard]] auto raw() const -> std::vector; - - /** - * Returns the size of the surface - */ - [[nodiscard]] auto size() const -> qd::size; - - /** - * Returns the color at the specified coordinate within the surface. - * @param x The x position in the surface - * @param y The y position in the surface - * @return The color - * - * @note This method of getting colors is _slow_. Use only for single point lookup. - */ - [[nodiscard]] auto at(int x, int y) const -> graphite::qd::color; - - /** - * Set the color at the specified coordinate within the surface. - * @param x The x position in the surface - * @param y The y position in the surface - * @param color The color - * - * @note This method of setting colors is _slow_. Use only for single point setting. - */ - auto set(int x, int y, graphite::qd::color color) -> void; - - /** - * Set the color at the specified coordinate within the surface. - * @param offset The absolute offset in the surface data - * @param color The color - * - * @note This method of setting colors is _slow_. Use only for single point setting. - */ - auto set(int offset, graphite::qd::color color) -> void; - - /** - * Draw a line from point x0,y0 to x1,y1 using the color specified. - * @param x0 - * @param y0 - * @param x1 - * @param y1 - * @param color - */ - auto draw_line(int x0, int y0, int x1, int y1, graphite::qd::color color) -> void; - - }; - -} - -#endif //GRAPHITE_SURFACE_H diff --git a/libGraphite/quickdraw_old/pict.cpp b/libGraphite/quickdraw_old/pict.cpp deleted file mode 100644 index ea558e7..0000000 --- a/libGraphite/quickdraw_old/pict.cpp +++ /dev/null @@ -1,619 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#include -#include -#include "libGraphite/quickdraw/pict.hpp" -#include "libGraphite/quickdraw/internal/packbits.hpp" -#include "libGraphite/quickdraw/clut.hpp" - -// MARK: - Constants - -#define kPICT_V1_MAGIC 0x1101 -#define kPICT_V2_MAGIC 0x001102ff - -// MARK: - Constructors - -graphite::qd::pict::pict(std::shared_ptr data, int64_t id, std::string name) - : m_surface(nullptr), m_frame(0, 0, 100, 100), m_id(id), m_name(std::move(name)) -{ - // Setup a reader for the PICT data, and then parse it. - data::reader pict_reader(std::move(data)); - parse(pict_reader); -} - -graphite::qd::pict::pict(std::shared_ptr surface) - : m_surface(std::move(surface)), m_frame(qd::point::zero(), m_surface->size()), m_id(0), m_name("Picture") -{ - -} - -auto graphite::qd::pict::load_resource(int64_t id) -> std::shared_ptr -{ - if (auto pict_res = graphite::rsrc::manager::shared_manager().find("PICT", id).lock()) { - return std::make_shared(pict_res->data(), id, pict_res->name()); - } - return nullptr; -} - -auto graphite::qd::pict::from_surface(std::shared_ptr surface) -> std::shared_ptr -{ - return std::make_shared(surface); -} - -// MARK: - Accessors - -auto graphite::qd::pict::image_surface() const -> std::weak_ptr -{ - return m_surface; -} - -// MARK: - Helper Functions - -static inline auto read_bytes(graphite::data::reader& pict_reader, std::size_t size) -> std::vector -{ - auto out = std::vector(size); - auto in = pict_reader.read_bytes(size); - for (auto i = 0; i < in.size(); ++i) { - out[i] = in[i]; - } - return out; -} - -// MARK: - Parsing / Reading - -auto graphite::qd::pict::read_region(graphite::data::reader& pict_reader) const -> graphite::qd::rect -{ - auto size = pict_reader.read_short(); - auto rect = graphite::qd::rect::read(pict_reader, qd::rect::qd); - - rect.set_x(rect.x() / m_x_ratio); - rect.set_y(rect.y() / m_y_ratio); - rect.set_width(rect.width() / m_x_ratio); - rect.set_height(rect.height() / m_y_ratio); - - pict_reader.move(size - 10); - - return rect; -} - -auto graphite::qd::pict::read_long_comment(graphite::data::reader& pict_reader) -> void -{ - pict_reader.move(2); - auto length = pict_reader.read_short(); - pict_reader.move(length); -} - -auto graphite::qd::pict::read_indirect_bits_rect(graphite::data::reader& pict_reader, bool packed, bool region) -> void -{ - qd::pixmap pm; - qd::clut color_table; - // Determine if we're dealing a PixMap or an old style BitMap - bool is_pixmap = pict_reader.read_short(0, data::reader::peek) & 0x8000; - if (is_pixmap) { - // The pixmap base address is omitted here, step back when reading - pm = qd::pixmap(pict_reader.read_data(qd::pixmap::length, -sizeof(uint32_t))); - // Color Table - color_table = qd::clut(pict_reader); - } - else { - // Old style bitmap - pm.set_pack_type(1); - pm.set_cmp_count(1); - pm.set_cmp_size(1); - pm.set_row_bytes(pict_reader.read_short()); - pm.set_bounds(qd::rect::read(pict_reader, qd::rect::qd)); - // Monochrome color table - color_table.set(qd::color(255, 255, 255)); - color_table.set(qd::color(0, 0, 0)); - } - - // Read the source and destination bounds - auto source_rect = qd::rect::read(pict_reader, qd::rect::qd); - auto destination_rect = qd::rect::read(pict_reader, qd::rect::qd); - - auto transfer_mode = pict_reader.read_short(); - - if (region) { - read_region(pict_reader); - } - - // Setup pixel buffer for raw values - std::vector raw; - auto row_bytes = pm.row_bytes(); - auto width = pm.bounds().width(); - auto height = pm.bounds().height(); - - if (packed) { - uint16_t packed_bytes_count = 0; - for (auto scanline = 0; scanline < height; ++scanline) { - if (row_bytes > 250) { - packed_bytes_count = pict_reader.read_short(); - } - else { - packed_bytes_count = pict_reader.read_byte(); - } - - auto packed_data = read_bytes(pict_reader, packed_bytes_count); - qd::packbits::decode(raw, packed_data, sizeof(uint8_t)); - } - } - else { - raw = read_bytes(pict_reader, row_bytes * height); - } - - destination_rect.set_x(destination_rect.x() - m_frame.origin().x()); - destination_rect.set_y(destination_rect.y() - m_frame.origin().y()); - pm.build_surface(m_surface, raw, color_table, destination_rect); - m_size += width * height; -} - -auto graphite::qd::pict::read_direct_bits_rect(graphite::data::reader &pict_reader, bool region) -> void -{ - graphite::qd::pixmap pm = graphite::qd::pixmap(pict_reader.read_data(qd::pixmap::length)); - auto pack_type = pm.pack_type(); - auto cmp_count = pm.cmp_count(); - auto color_model = static_cast(pm.pixel_format()); - auto row_bytes = pm.row_bytes(); - auto bounds = pm.bounds(); - - // Read the source and destination bounds - auto source_rect = qd::rect::read(pict_reader, qd::rect::qd); - auto destination_rect = qd::rect::read(pict_reader, qd::rect::qd); - - auto transfer_mode = pict_reader.read_short(); - - if (region) { - read_region(pict_reader); - } - - // Verify the type of PixMap. We can only accept certain types for the time being, until - // support for decoding/rendering other types is added. - std::vector raw; - switch (pack_type) { - case 1: - case 2: - case 3: { - raw.reserve(row_bytes); - break; - } - case 4: { - raw.reserve(cmp_count * row_bytes / 4); - break; - } - default: { - throw std::runtime_error("Unsupported pack type " + std::to_string(pack_type) + " encountered in PICT: " + std::to_string(m_id) + ", " + m_name); - } - } - - // Allocate a private memory buffer before going to the surface. - std::vector px_short_buffer; - std::vector px_long_buffer; - uint32_t px_buffer_offset = 0; - uint16_t packed_bytes_count = 0; - uint32_t height = source_rect.height(); - uint32_t width = source_rect.width(); - uint32_t bounds_width = bounds.width(); - uint32_t source_length = width * height; - - if (pack_type == 3) { - px_short_buffer = std::vector(source_length); - } - else { - px_long_buffer = std::vector(source_length); - } - - auto packing_enabled = ((pack_type == 3 ? 2 : 1) + (row_bytes > 250 ? 2 : 1)) <= bounds_width; - - for (uint32_t scanline = 0; scanline < height; ++scanline) { - raw.clear(); - - if (pack_type > 2 && packing_enabled) { - if (row_bytes > 250) { - packed_bytes_count = pict_reader.read_short(); - } - else { - packed_bytes_count = pict_reader.read_byte(); - } - - // Create a temporary buffer to read the packed data into, on the stack. - auto packed_data = read_bytes(pict_reader, packed_bytes_count); - qd::packbits::decode(raw, packed_data, pack_type == 3 ? sizeof(uint16_t) : sizeof(uint8_t)); - } - else { - raw = read_bytes(pict_reader, row_bytes); - } - - if (pack_type == 3) { - for (uint32_t x = 0; x < width; ++x) { - px_short_buffer[px_buffer_offset + x] = (0xFF & raw[2 * x + 1]) | ((0xFF & raw[2 * x]) << 8); - } - } - else { - if (cmp_count == 3) { - // RGB Formatted Data - for (uint32_t x = 0; x < width; x++) { - px_long_buffer[px_buffer_offset + x] = - 0xFF000000 - | ((raw[x] & 0xFF) << 16) - | ((raw[bounds_width + x] & 0xFF) << 8) - | (raw[2 * bounds_width + x] & 0xFF); - } - } - else if (cmp_count == 4) { - // ARGB Formatted Data - for (uint32_t x = 0; x < width; x++) { - px_long_buffer[px_buffer_offset + x] = - ((raw[x] & 0xFF) << 24) - | ((raw[bounds_width + x] & 0xFF) << 16) - | ((raw[2 * bounds_width + x] & 0xFF) << 8) - | (raw[3 * bounds_width + x] & 0xFF); - } - } - } - - px_buffer_offset += width; - } - - if (pack_type == 3) { - for (auto v : px_short_buffer) { - graphite::qd::color color(static_cast(((v & 0x7c00) >> 10) * 0xFF / 0x1F), - static_cast(((v & 0x03e0) >> 5) * 0xFF / 0x1F), - static_cast((v & 0x001f) * 0xFF / 0x1F)); - m_surface->set(m_size++, color); - } - } - else { - for (auto v : px_long_buffer) { - graphite::qd::color color(static_cast((v & 0xFF0000) >> 16), - static_cast((v & 0xFF00) >> 8), - static_cast(v & 0xFF), - static_cast((v & 0xFF000000) >> 24)); - m_surface->set(m_size++, color); - } - } -} - -auto graphite::qd::pict::read_compressed_quicktime(graphite::data::reader &pict_reader) -> void -{ - auto length = pict_reader.read_long(); - pict_reader.move(38); - auto matte_size = pict_reader.read_long(); - auto matte_rect = qd::rect::read(pict_reader, qd::rect::qd); - pict_reader.move(2); - auto source_rect = qd::rect::read(pict_reader, qd::rect::qd); - pict_reader.move(4); - auto mask_size = pict_reader.read_long(); - - if (matte_size > 0) { - read_image_description(pict_reader); - } - - if (mask_size > 0) { - pict_reader.move(mask_size); - } - - read_image_description(pict_reader); -} - -auto graphite::qd::pict::read_uncompressed_quicktime(graphite::data::reader &pict_reader) -> void -{ - auto length = pict_reader.read_long(); - pict_reader.move(38); - auto matte_size = pict_reader.read_long(); - auto matte_rect = qd::rect::read(pict_reader, qd::rect::qd); - - if (matte_size > 0) { - read_image_description(pict_reader); - } -} - -auto graphite::qd::pict::read_image_description(graphite::data::reader &pict_reader) -> void -{ - auto length = pict_reader.read_long(); - if (length != 86) { - throw std::runtime_error("Invalid QuickTime image description in PICT: " + std::to_string(m_id) + ", " + m_name); - } - auto compressor = pict_reader.read_long(); - pict_reader.move(24); - auto width = pict_reader.read_short(); - auto height = pict_reader.read_short(); - pict_reader.move(8); - auto data_size = pict_reader.read_long(); - pict_reader.move(34); - auto depth = pict_reader.read_short(); - if (depth > 32) { - depth -= 32; // grayscale - } - auto clut = pict_reader.read_signed_short(); - - if (compressor == 'rle ') { - // rle is often garbage or redundant, skip over it and hope we find other image data later. - pict_reader.move(data_size); - return; - } - - switch (compressor) { - default: - std::string comp; - comp.push_back(compressor >> 24); - comp.push_back(compressor >> 16); - comp.push_back(compressor >> 8); - comp.push_back(compressor); - throw std::runtime_error("Unsupported QuickTime compressor '" + comp + "' at offset " + std::to_string(pict_reader.position()) - + " in PICT: " + std::to_string(m_id) + ", " + m_name); - } -} - -auto graphite::qd::pict::parse(graphite::data::reader& pict_reader) -> void -{ - pict_reader.move(2); - - m_frame = qd::rect::read(pict_reader, qd::rect::qd); - bool v1 = false; - - // Check which version of PICT we're dealing with - if (pict_reader.read_short(0, data::reader::peek) == kPICT_V1_MAGIC) { - pict_reader.move(2); - v1 = true; - } else { - if (pict_reader.read_long() != kPICT_V2_MAGIC) { - throw std::runtime_error("Invalid PICT resource. Incorrect header: " + std::to_string(m_id) + ", " + m_name); - } - - // The very first thing we should find is an extended header opcode. Read this - // outside of the main opcode loop as it should only appear once. - if (static_cast(pict_reader.read_short()) != opcode::ext_header) { - throw std::runtime_error("Expected to find PICT Extended Header."); - } - - if ((pict_reader.read_long() >> 16) != 0xFFFE) { - // Standard header variant - auto rect = qd::fixed_rect::read(pict_reader); - m_x_ratio = m_frame.width() / rect.width(); - m_y_ratio = m_frame.height() / rect.height(); - } - else { - // Extended header variant - pict_reader.move(sizeof(uint32_t) * 2); - auto rect = qd::rect::read(pict_reader, qd::rect::qd); - m_x_ratio = static_cast(m_frame.width()) / rect.width(); - m_y_ratio = static_cast(m_frame.height()) / rect.height(); - // This isn't strictly correct but it allows us to decode some images which - // would otherwise fail due to mismatched frame sizes. QuickDraw would normally - // scale such images down to fit the frame but here we just expand the frame. - m_frame.set_size(rect.size()); - } - - if (m_x_ratio <= 0 || m_y_ratio <= 0) { - throw std::runtime_error("Invalid PICT resource. Content aspect ratio is not valid: " + std::to_string(m_id) + ", " + m_name); - } - - pict_reader.move(4); - } - - // Begin parsing PICT opcodes. - qd::rect clip_rect(0, 0, 0, 0); - - m_size = 0; - m_surface = std::make_shared(m_frame.width(), m_frame.height()); - bool has_bits = false; - - opcode op; - while (!pict_reader.eof()) { - if (v1) { - op = static_cast(pict_reader.read_byte()); - } else { - // Make sure we are correctly aligned. - pict_reader.move(pict_reader.position() % sizeof(uint16_t)); - op = static_cast(pict_reader.read_short()); - } - - if (op == opcode::eof) { - break; - } - - switch (op) { - case opcode::clip_region: { - clip_rect = read_region(pict_reader); - break; - } - case opcode::origin: { - auto origin = graphite::qd::point::read(pict_reader, qd::point::pict); - m_frame.set_origin(origin); - break; - } - case opcode::bits_rect: { - read_indirect_bits_rect(pict_reader, false, false); - has_bits = true; - break; - } - case opcode::bits_region: { - read_indirect_bits_rect(pict_reader, false, true); - has_bits = true; - break; - } - case opcode::pack_bits_rect: { - read_indirect_bits_rect(pict_reader, true, false); - has_bits = true; - break; - } - case opcode::pack_bits_region: { - read_indirect_bits_rect(pict_reader, true, true); - has_bits = true; - break; - } - case opcode::direct_bits_rect: { - read_direct_bits_rect(pict_reader, false); - has_bits = true; - break; - } - case opcode::direct_bits_region: { - read_direct_bits_rect(pict_reader, true); - has_bits = true; - break; - } - case opcode::long_comment: { - read_long_comment(pict_reader); - break; - } - case opcode::short_comment: { - pict_reader.move(2); - break; - } - case opcode::rgb_fg_color: - case opcode::rgb_bg_color: - case opcode::hilite_color: - case opcode::op_color: { - pict_reader.move(6); - break; - } - case opcode::frame_region: - case opcode::paint_region: - case opcode::erase_region: - case opcode::invert_region: - case opcode::fill_region: { - read_region(pict_reader); - break; - } - case opcode::nop: - case opcode::eof: - case opcode::ext_header: - case opcode::hilite_mode: - case opcode::def_hilite: { - break; - } - case opcode::compressed_quicktime: { - read_compressed_quicktime(pict_reader); - // Compressed quicktime data is often followed by drawing routines telling you that you need - // quicktime to decode the image. We should skip these and just return after a successful decode. - return; - } - case opcode::uncompressed_quicktime: { - read_uncompressed_quicktime(pict_reader); - break; - } - default: { - throw std::runtime_error("Encountered an incompatible PICT: " + std::to_string(m_id) + ", " + m_name); - } - } - } - - // This is a safety check for QuickTime rle which is skipped over. If no other image data was found, throw an error. - if (!has_bits) { - throw std::runtime_error("Encountered an incompatible PICT: " + std::to_string(m_id) + ", " + m_name); - } -} - -// MARK: - Encoder / Writing - -auto graphite::qd::pict::encode(graphite::data::writer& pict_encoder) -> void -{ - encode_header(pict_encoder); - encode_def_hilite(pict_encoder); - encode_clip_region(pict_encoder); - encode_direct_bits_rect(pict_encoder); - - // Make sure we're word aligned and put out the end of picture opcode. - auto align_adjust = pict_encoder.position() % sizeof(uint16_t); - for (auto n = 0; n < align_adjust; ++n) { - pict_encoder.write_byte(0); - } - pict_encoder.write_short(static_cast(opcode::eof)); -} - -auto graphite::qd::pict::encode_header(graphite::data::writer& pict_encoder) -> void -{ - // Write the size as zero. This seems to be fine. - pict_encoder.write_short(0); - - // Set the image frame. - m_frame.write(pict_encoder, rect::qd); - - // We're only dealing with PICT version 2 currently. - pict_encoder.write_long(kPICT_V2_MAGIC); - pict_encoder.write_short(static_cast(opcode::ext_header)); - pict_encoder.write_long(0xFFFE0000); - - // Image resolution (72dpi) - pict_encoder.write_short(72); - pict_encoder.write_short(0); - pict_encoder.write_short(72); - pict_encoder.write_short(0); - - // Optimal source frame. (identical to the image frame) - m_frame.write(pict_encoder, rect::qd); - - // Reserved - pict_encoder.write_long(0); - - // HEADER ENDS HERE -} - -auto graphite::qd::pict::encode_def_hilite(graphite::data::writer& pict_encoder) -> void -{ - pict_encoder.write_short(static_cast(opcode::def_hilite)); -} - -auto graphite::qd::pict::encode_clip_region(graphite::data::writer& pict_encoder) -> void -{ - pict_encoder.write_short(static_cast(opcode::clip_region)); - pict_encoder.write_short(10); - m_frame.write(pict_encoder, rect::qd); -} - -auto graphite::qd::pict::encode_direct_bits_rect(graphite::data::writer& pict_encoder) -> void -{ - pict_encoder.write_short(static_cast(opcode::direct_bits_rect)); - - qd::pixmap pm(m_frame); - pm.write(pict_encoder); - - // Source and destination frames - identical to the image frame. - m_frame.write(pict_encoder, rect::qd); - m_frame.write(pict_encoder, rect::qd); - - // Specify the transfer mode. - pict_encoder.write_short(0); // Source Copy - - // Prepare to write out the actual image data. - std::vector scanline_bytes(m_frame.width() * pm.cmp_count()); - for (auto scanline = 0; scanline < m_frame.height(); ++scanline) { - - if (pm.cmp_count() == 3) { - for (auto x = 0; x < m_frame.width(); ++x) { - auto pixel = m_surface->at(x, scanline); - scanline_bytes[x] = pixel.red_component(); - scanline_bytes[x + m_frame.width()] = pixel.green_component(); - scanline_bytes[x + m_frame.width() * 2] = pixel.blue_component(); - } - } - else if (pm.cmp_count() == 4) { - for (auto x = 0; x < m_frame.width(); ++x) { - auto pixel = m_surface->at(x, scanline); - scanline_bytes[x] = pixel.alpha_component(); - scanline_bytes[x + m_frame.width()] = pixel.red_component(); - scanline_bytes[x + m_frame.width() * 2] = pixel.green_component(); - scanline_bytes[x + m_frame.width() * 3] = pixel.blue_component(); - } - } - - auto packed = packbits::encode(scanline_bytes); - if (pm.row_bytes() > 250) { - pict_encoder.write_short(packed.size()); - } - else { - pict_encoder.write_byte(packed.size()); - } - pict_encoder.write_bytes(packed); - } -} - -auto graphite::qd::pict::data() -> std::shared_ptr -{ - auto data = std::make_shared(); - graphite::data::writer writer(data); - encode(writer); - return data; -} diff --git a/libGraphite/quickdraw_old/pict.hpp b/libGraphite/quickdraw_old/pict.hpp deleted file mode 100644 index c7465fa..0000000 --- a/libGraphite/quickdraw_old/pict.hpp +++ /dev/null @@ -1,89 +0,0 @@ -// -// Created by Tom Hancocks on 20/02/2020. -// - -#if !defined(GRAPHITE_PICT_HPP) -#define GRAPHITE_PICT_HPP - -#include -#include "libGraphite/quickdraw/internal/surface.hpp" -#include "libGraphite/quickdraw/pixmap.hpp" -#include "libGraphite/data/reader.hpp" - -namespace graphite::qd { - - /** - * The `graphite::qd::pict` class represents a QuickDraw Picture. - */ - class pict - { - public: - enum opcode - { - nop = 0x0000, - clip_region = 0x0001, - origin = 0x000c, - bits_rect = 0x0090, - bits_region = 0x0091, - pack_bits_rect = 0x0098, - pack_bits_region = 0x0099, - direct_bits_rect = 0x009a, - direct_bits_region = 0x009b, - eof = 0x00ff, - rgb_fg_color = 0x001a, - rgb_bg_color = 0x001b, - hilite_mode = 0x001c, - hilite_color = 0x001d, - def_hilite = 0x001e, - op_color = 0x001f, - frame_region = 0x0080, - paint_region = 0x0081, - erase_region = 0x0082, - invert_region = 0x0083, - fill_region = 0x0084, - short_comment = 0x00a0, - long_comment = 0x00a1, - ext_header = 0x0c00, - compressed_quicktime = 0x8200, - uncompressed_quicktime = 0x8201, - }; - - private: - int64_t m_id {}; - std::string m_name; - std::shared_ptr m_surface; - graphite::qd::rect m_frame; - double m_x_ratio {}; - double m_y_ratio {}; - std::size_t m_size; - - auto parse(graphite::data::reader& pict_reader) -> void; - auto read_region(graphite::data::reader& pict_reader) const -> graphite::qd::rect; - auto read_long_comment(graphite::data::reader& pict_reader) -> void; - auto read_direct_bits_rect(graphite::data::reader& pict_reader, bool region) -> void; - auto read_indirect_bits_rect(graphite::data::reader& pict_reader, bool packed, bool region) -> void; - auto read_compressed_quicktime(graphite::data::reader & pict_reader) -> void; - auto read_uncompressed_quicktime(graphite::data::reader & pict_reader) -> void; - auto read_image_description(graphite::data::reader & pict_reader) -> void; - - auto encode(graphite::data::writer& pict_encoder) -> void; - auto encode_header(graphite::data::writer& pict_encoder) -> void; - auto encode_def_hilite(graphite::data::writer& pict_encoder) -> void; - auto encode_clip_region(graphite::data::writer& pict_encoder) -> void; - auto encode_direct_bits_rect(graphite::data::writer& pict_encoder) -> void; - - public: - explicit pict(std::shared_ptr data, int64_t id = 0, std::string name = ""); - explicit pict(std::shared_ptr surface); - - static auto load_resource(int64_t id) -> std::shared_ptr; - static auto from_surface(std::shared_ptr surface) -> std::shared_ptr; - - [[nodiscard]] auto image_surface() const -> std::weak_ptr; - - auto data() -> std::shared_ptr; - }; - -} - -#endif //GRAPHITE_PICT_HPP diff --git a/libGraphite/quickdraw_old/pixmap.cpp b/libGraphite/quickdraw_old/pixmap.cpp deleted file mode 100644 index d71ed5f..0000000 --- a/libGraphite/quickdraw_old/pixmap.cpp +++ /dev/null @@ -1,255 +0,0 @@ -// -// Created by Tom Hancocks on 19/03/2020. -// - -#include "libGraphite/quickdraw/pixmap.hpp" -#include "libGraphite/quickdraw/clut.hpp" -#include "libGraphite/quickdraw/internal/surface.hpp" -#include "libGraphite/data/reader.hpp" - -// MARK: - Constructors - -graphite::qd::pixmap::pixmap() - : m_bounds(0, 0, 100, 100) -{ - -} - -graphite::qd::pixmap::pixmap(qd::rect frame) - : m_base_address(0x000000ff), - m_row_bytes(frame.width() * 4), - m_bounds(frame), - m_pm_version(0), - m_pack_type(4), - m_pack_size(0), - m_h_res(0.001098632812), - m_v_res(0.001098632812), - m_pixel_type(16), - m_pixel_size(32), - m_cmp_count(3), - m_cmp_size(8), - m_pixel_format(unknown), - m_pm_table(0), - m_pm_extension(0) -{ -} - -graphite::qd::pixmap::pixmap(std::shared_ptr px_data) - : m_bounds(0, 0, 0, 0) -{ - // Setup a new data reader for the pixmap - data::reader px_reader(std::move(px_data)); - - // Read each of the member fields for the pixmap. - m_base_address = px_reader.read_long(); - m_row_bytes = static_cast(static_cast(px_reader.read_signed_short()) & 0x7FFFU); - m_bounds = graphite::qd::rect::read(px_reader, qd::rect::qd); - m_pm_version = px_reader.read_signed_short(); - m_pack_type = px_reader.read_signed_short(); - m_pack_size = px_reader.read_signed_long(); - m_h_res = static_cast(px_reader.read_signed_long() / static_cast(1U << 16UL)); - m_v_res = static_cast(px_reader.read_signed_long() / static_cast(1U << 16UL)); - m_pixel_type = px_reader.read_signed_short(); - m_pixel_size = px_reader.read_signed_short(); - m_cmp_count = px_reader.read_signed_short(); - m_cmp_size = px_reader.read_signed_short(); - m_pixel_format = static_cast(px_reader.read_long()); - m_pm_table = px_reader.read_long(); - m_pm_extension = px_reader.read_long(); -} - -// MARK: - Accessors - -auto graphite::qd::pixmap::bounds() const -> graphite::qd::rect -{ - return m_bounds; -} - -auto graphite::qd::pixmap::set_bounds(const graphite::qd::rect& rect) -> void -{ - m_bounds = rect; -} - -auto graphite::qd::pixmap::row_bytes() const -> int16_t -{ - return m_row_bytes; -} - -auto graphite::qd::pixmap::set_row_bytes(const int16_t& row_bytes) -> void -{ - m_row_bytes = row_bytes; -} - -auto graphite::qd::pixmap::pack_type() const -> int16_t -{ - return m_pack_type; -} - -auto graphite::qd::pixmap::set_pack_type(const int16_t& pack_type) -> void -{ - m_pack_type = pack_type; -} - -auto graphite::qd::pixmap::pack_size() const -> int16_t -{ - return m_pack_size; -} - -auto graphite::qd::pixmap::set_pack_size(const int16_t& pack_size) -> void -{ - m_pack_size = pack_size; -} - -auto graphite::qd::pixmap::pixel_type() const -> int16_t -{ - return m_pixel_type; -} - -auto graphite::qd::pixmap::set_pixel_type(const int16_t& pixel_type) -> void -{ - m_pixel_type = pixel_type; -} - -auto graphite::qd::pixmap::pixel_size() const -> int16_t -{ - return m_pixel_size; -} - -auto graphite::qd::pixmap::set_pixel_size(const int16_t& pixel_size) -> void -{ - m_pixel_size = pixel_size; -} - -auto graphite::qd::pixmap::cmp_count() const -> int16_t -{ - return m_cmp_count; -} - -auto graphite::qd::pixmap::set_cmp_count(const int16_t& cmp_count) -> void -{ - m_cmp_count = cmp_count; -} - -auto graphite::qd::pixmap::cmp_size() const -> int16_t -{ - return m_cmp_size; -} - -auto graphite::qd::pixmap::set_cmp_size(const int16_t& cmp_size) -> void -{ - m_cmp_size = cmp_size; -} - -auto graphite::qd::pixmap::pixel_format() const -> enum graphite::qd::pixel_format -{ - return m_pixel_format; -} - -auto graphite::qd::pixmap::pm_table() const -> uint32_t -{ - return m_pm_table; -} - -auto graphite::qd::pixmap::set_pm_table(const uint32_t& pm_table) -> void -{ - m_pm_table = pm_table; -} - -// MARK: - - -auto graphite::qd::pixmap::build_surface( - std::shared_ptr surface, - const std::vector& pixel_data, - const qd::clut& clut, - qd::rect destination) -> void -{ - if (pixel_data.size() < destination.height() * m_row_bytes) { - throw std::runtime_error("Insufficent data to build surface from pixmap."); - } - auto pixel_size = m_cmp_size * m_cmp_count; - - if (pixel_size == 8) { - for (auto y = 0; y < destination.height(); ++y) { - auto y_offset = (y * m_row_bytes); - for (auto x = 0; x < destination.width(); ++x) { - auto byte = pixel_data[y_offset + x]; - surface->set(destination.x() + x, destination.y() + y, clut.get(byte)); - } - } - } - else { - auto mod = 8 / pixel_size; - auto mask = (1 << pixel_size) - 1; - auto diff = 8 - pixel_size; - - for (auto y = 0; y < destination.height(); ++y) { - auto y_offset = (y * m_row_bytes); - for (auto x = 0; x < destination.width(); ++x) { - auto byte = pixel_data[y_offset + (x / mod)]; - auto byte_offset = diff - ((x % mod) * pixel_size); - auto v = (byte >> byte_offset) & mask; - surface->set(destination.x() + x, destination.y() + y, clut.get(v)); - } - } - } -} - -// MARK: - - -auto graphite::qd::pixmap::build_pixel_data(const std::vector& color_values, uint16_t pixel_size) -> std::shared_ptr -{ - graphite::data::writer pmap_data(std::make_shared()); - m_pixel_size = m_cmp_size = pixel_size; - m_cmp_count = 1; - - if (pixel_size == 8) { - m_row_bytes = m_bounds.width(); - for (auto color_value : color_values) { - pmap_data.write_byte(static_cast(color_value & 0xFF)); - } - } - else { - auto width = m_bounds.width(); - auto mod = 8 / pixel_size; - m_row_bytes = (width - 1) / mod + 1; - auto mask = (1 << pixel_size) - 1; - auto diff = 8 - pixel_size; - - for (auto y = 0; y < m_bounds.height(); ++y) { - uint8_t scratch = 0; - for (auto x = 0; x < width; ++x) { - auto bit_offset = x % mod; - if (bit_offset == 0 && x != 0) { - pmap_data.write_byte(scratch); - scratch = 0; - } - auto n = y * width + x; - auto value = static_cast(color_values[n] & mask); - value <<= (diff - (bit_offset * pixel_size)); - scratch |= value; - } - pmap_data.write_byte(scratch); - } - } - - return pmap_data.data(); -} - -auto graphite::qd::pixmap::write(graphite::data::writer& writer) -> void -{ - writer.write_long(m_base_address); - writer.write_short(0x8000 | m_row_bytes); - m_bounds.write(writer, rect::qd); - writer.write_signed_short(m_pm_version); - writer.write_signed_short(m_pack_type); - writer.write_signed_long(m_pack_size); - writer.write_signed_long(static_cast(m_h_res * (1 << 16))); - writer.write_signed_long(static_cast(m_v_res * (1 << 16))); - writer.write_signed_short(m_pixel_type); - writer.write_signed_short(m_pixel_size); - writer.write_signed_short(m_cmp_count); - writer.write_signed_short(m_cmp_size); - writer.write_signed_long(static_cast(m_pixel_format)); - writer.write_long(m_pm_table); - writer.write_signed_long(m_pm_extension); -} diff --git a/libGraphite/quickdraw_old/pixmap.hpp b/libGraphite/quickdraw_old/pixmap.hpp deleted file mode 100644 index ee921c7..0000000 --- a/libGraphite/quickdraw_old/pixmap.hpp +++ /dev/null @@ -1,87 +0,0 @@ -// -// Created by Tom Hancocks on 19/03/2020. -// - -#if !defined(GRAPHITE_PIXMAP_HPP) -#define GRAPHITE_PIXMAP_HPP - -#include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/quickdraw/clut.hpp" -#include "libGraphite/quickdraw/geometry.hpp" -#include "libGraphite/quickdraw/internal/surface.hpp" -#include "libGraphite/data/data.hpp" - -namespace graphite::qd { - - enum pixel_format - { - unknown = 0, - monochrome = 0x01, // 1 bit indexed - indexed_2 = 0x02, // 2 bit indexed - indexed_4 = 0x04, // 4 bit indexed - indexed_8 = 0x08, // 8 bit indexed - b16_rgb555 = 0x10, // 16 bit, RGB 555 (Mac) - true_color = 0x18, // 24 bit RGB - true_color_alpha = 0x20, // 32 bit ARGB - }; - - class pixmap - { - private: - uint32_t m_base_address { 0 }; - int16_t m_row_bytes { 0 }; - graphite::qd::rect m_bounds { rect::zero() }; - int16_t m_pm_version { 0 }; - int16_t m_pack_type { 0 }; - int32_t m_pack_size { 0 }; - double m_h_res { 72 }; - double m_v_res { 72 }; - int16_t m_pixel_type { 0 }; - int16_t m_pixel_size { 0 }; - int16_t m_cmp_count { 0 }; - int16_t m_cmp_size { 0 }; - enum pixel_format m_pixel_format { unknown }; - uint32_t m_pm_table { 0 }; - uint32_t m_pm_extension { 0 }; - public: - static constexpr int length { 50 }; - - pixmap(); - explicit pixmap(qd::rect frame); - explicit pixmap(std::shared_ptr data); - - [[nodiscard]] auto bounds() const -> graphite::qd::rect; - [[nodiscard]] auto row_bytes() const -> int16_t; - [[nodiscard]] auto pack_type() const -> int16_t; - [[nodiscard]] auto pack_size() const -> int16_t; - [[nodiscard]] auto pixel_type() const -> int16_t; - [[nodiscard]] auto pixel_size() const -> int16_t; - [[nodiscard]] auto cmp_count() const -> int16_t; - [[nodiscard]] auto cmp_size() const -> int16_t; - [[nodiscard]] auto pixel_format() const -> enum graphite::qd::pixel_format; - [[nodiscard]] auto pm_table() const -> uint32_t; - - auto set_bounds(const graphite::qd::rect& rect) -> void; - auto set_row_bytes(const int16_t& row_bytes) -> void; - auto set_pack_type(const int16_t& pack_type) -> void; - auto set_pack_size(const int16_t& pack_size) -> void; - auto set_pixel_type(const int16_t& pixel_type) -> void; - auto set_pixel_size(const int16_t& pixel_size) -> void; - auto set_cmp_count(const int16_t& cmp_count) -> void; - auto set_cmp_size(const int16_t& cmp_size) -> void; - auto set_pm_table(const uint32_t& pm_table) -> void; - - auto build_surface( - std::shared_ptr surface, - const std::vector& pixel_data, - const qd::clut& clut, - qd::rect destination - ) -> void; - auto build_pixel_data(const std::vector& color_values, uint16_t pixel_size) -> std::shared_ptr; - auto write(graphite::data::writer& writer) -> void; - }; - -} - -#endif //GRAPHITE_PIXMAP_HPP diff --git a/libGraphite/quickdraw_old/ppat.cpp b/libGraphite/quickdraw_old/ppat.cpp deleted file mode 100644 index 976fb8b..0000000 --- a/libGraphite/quickdraw_old/ppat.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// -// Created by Tom Hancocks on 17/07/2020. -// - -#include "libGraphite/quickdraw/ppat.hpp" -#include "libGraphite/rsrc/manager.hpp" -#include -#include - -// MARK: - Constructor - -graphite::qd::ppat::ppat(std::shared_ptr data, int64_t id, std::string name) - : m_id(id), m_name(std::move(name)) -{ - data::reader reader(std::move(data)); - parse(reader); -} - -graphite::qd::ppat::ppat(std::shared_ptr surface) - : m_surface(std::move(surface)) -{ - -} - -auto graphite::qd::ppat::load_resource(int64_t id) -> std::shared_ptr -{ - if (auto res = graphite::rsrc::manager::shared_manager().find("ppat", id).lock()) { - return std::make_shared(res->data(), id, res->name()); - } - return nullptr; -} - - -// MARK: - Accessors - -auto graphite::qd::ppat::surface() const -> std::weak_ptr -{ - return m_surface; -} - -// MARK: - Parser - -auto graphite::qd::ppat::parse(graphite::data::reader& reader) -> void -{ - m_pat_type = reader.read_short(); - if (m_pat_type != 1) { - throw std::runtime_error("Currently unsupported ppat configuration: pat_type=" + - std::to_string(m_pat_type)); - } - - m_pmap_base_addr = reader.read_long(); - m_pat_base_addr = reader.read_long(); - - reader.set_position(m_pmap_base_addr); - m_pixmap = graphite::qd::pixmap(reader.read_data(qd::pixmap::length)); - - reader.set_position(m_pat_base_addr); - auto pmap_data_size = m_pixmap.row_bytes() * m_pixmap.bounds().height(); - auto pmap_data = reader.read_bytes(pmap_data_size); - - reader.set_position(m_pixmap.pm_table()); - m_clut = qd::clut(reader); - - // Now that all information has been extracted from the resource, proceed and attempt to render it. - m_surface = std::make_shared(m_pixmap.bounds().width(), m_pixmap.bounds().height()); - - m_pixmap.build_surface(m_surface, std::vector(pmap_data.begin(), pmap_data.end()), m_clut, m_pixmap.bounds()); -} - -// MARK: - Encoder - -auto graphite::qd::ppat::data() -> std::shared_ptr -{ - auto data = std::make_shared(); - auto writer = graphite::data::writer(data); - auto width = m_surface->size().width(); - auto height = m_surface->size().height(); - - // TODO: This is a brute force method of bringing down the color depth/number of colors required, - // for a ppat image. It doesn't optimise for image quality at all, and should be replaced at somepoint. - std::vector color_values; - uint8_t pass = 0; - do { - if (pass++ > 0) { - for (auto y = 0; y < height; ++y) { - for (auto x = 0; x < width; ++x) { - auto color = m_surface->at(x, y); - m_surface->set(x, y, qd::color( - color.red_component() & ~(1 << pass), - color.green_component() & ~(1 << pass), - color.blue_component() & ~(1 << pass), - color.alpha_component() - )); - } - } - } - - // Rebuild the Color Table for the surface. To do this we want to create an empty table, and populate it. - m_clut = qd::clut(); - color_values.clear(); - for (auto y = 0; y < height; ++y) { - for (auto x = 0; x < width; ++x) { - auto color = m_surface->at(x, y); - color_values.emplace_back(m_clut.set(color)); - } - } - } while(m_clut.size() > 256); - - - // Determine what component configuration we need. - m_pixmap = qd::pixmap(); - m_pixmap.set_bounds(qd::rect(point::zero(), m_surface->size())); - std::shared_ptr pmap_data; - - if (m_clut.size() > 256) { - throw std::runtime_error("Implementation does not currently handle more than 256 colors in a PPAT"); - } - else if (m_clut.size() > 16) { - pmap_data = m_pixmap.build_pixel_data(color_values, 8); - } - else if (m_clut.size() > 4) { - pmap_data = m_pixmap.build_pixel_data(color_values, 4); - } - else if (m_clut.size() > 2) { - pmap_data = m_pixmap.build_pixel_data(color_values, 2); - } - else { - pmap_data = m_pixmap.build_pixel_data(color_values, 1); - } - - // Calculate some offsets - m_pat_type = 1; - m_pmap_base_addr = 28; - m_pat_base_addr = m_pmap_base_addr + 50; - m_pixmap.set_pm_table(m_pat_base_addr + pmap_data->size()); - - // Write out the image data for the ppat. - writer.write_short(m_pat_type); - writer.write_long(m_pmap_base_addr); - writer.write_long(m_pat_base_addr); - writer.write_long(0); - writer.write_short(0); - writer.write_long(0); - writer.write_quad(0); - m_pixmap.write(writer); - writer.write_data(pmap_data); - m_clut.write(writer); - - return data; -} diff --git a/libGraphite/quickdraw_old/ppat.hpp b/libGraphite/quickdraw_old/ppat.hpp deleted file mode 100644 index c187bcb..0000000 --- a/libGraphite/quickdraw_old/ppat.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// Created by Tom Hancocks on 17/07/2020. -// - -#if !defined(GRAPHITE_PPAT_HPP) -#define GRAPHITE_PPAT_HPP - -#include -#include "libGraphite/quickdraw/internal/surface.hpp" -#include "libGraphite/quickdraw/geometry.hpp" -#include "libGraphite/quickdraw/pixmap.hpp" -#include "libGraphite/quickdraw/clut.hpp" - -namespace graphite::qd { - - class ppat - { - private: - int64_t m_id {}; - std::string m_name; - uint16_t m_pat_type {}; - uint32_t m_pmap_base_addr {}; - uint32_t m_pat_base_addr {}; - qd::pixmap m_pixmap; - std::shared_ptr m_surface; - qd::clut m_clut; - - auto parse(data::reader& reader) -> void; - - public: - explicit ppat(std::shared_ptr data, int64_t id = 0, std::string name = ""); - explicit ppat(std::shared_ptr surface); - - static auto load_resource(int64_t id) -> std::shared_ptr; - - [[nodiscard]] auto surface() const -> std::weak_ptr; - auto data() -> std::shared_ptr; - }; - -} - -#endif //GRAPHITE_PPAT_HPP diff --git a/libGraphite/quickdraw_old/rle.cpp b/libGraphite/quickdraw_old/rle.cpp deleted file mode 100644 index 63ece27..0000000 --- a/libGraphite/quickdraw_old/rle.cpp +++ /dev/null @@ -1,371 +0,0 @@ -// -// Created by Tom Hancocks on 24/03/2020. -// - -#include -#include -#include -#include "libGraphite/quickdraw/rle.hpp" -#include "libGraphite/rsrc/manager.hpp" - -static const auto rle_grid_width = 6; - -// MARK: - Constructor - -graphite::qd::rle::rle(std::shared_ptr data, int64_t id, std::string name) - : m_id(id), m_name(std::move(name)) -{ - auto reader = data::reader(std::move(data)); - parse(reader); -} - -graphite::qd::rle::rle(qd::size frame_size, uint16_t frame_count) - : m_id(0), m_name("RLE"), m_frame_size(frame_size), m_frame_count(frame_count), m_bpp(16), m_palette_id(0) -{ - // Determine what the grid will be. We need to round up to the next whole number and have blank tiles - // if the frame count is not divisible by the grid width constant. - auto grid_width = std::min(rle_grid_width, static_cast(m_frame_count)); - m_grid_size = qd::size(static_cast(grid_width), - static_cast(std::ceil(m_frame_count / static_cast(grid_width)))); - - // Create the surface - m_surface = std::make_shared(m_grid_size.width() * m_frame_size.width(), - m_grid_size.height() * m_frame_size.height()); -} - -auto graphite::qd::rle::load_resource(int64_t id) -> std::shared_ptr -{ - if (auto rle_res = graphite::rsrc::manager::shared_manager().find("rlëD", id).lock()) { - return std::make_shared(rle_res->data()); - } - return nullptr; -} - -// MARK: - Accessors - -auto graphite::qd::rle::surface() const -> std::weak_ptr -{ - return m_surface; -} - -auto graphite::qd::rle::frames() const -> std::vector -{ - return m_frames; -} - -auto graphite::qd::rle::frame_count() const -> int -{ - return static_cast(m_frame_count); -} - -auto graphite::qd::rle::frame_rect(int frame) const -> graphite::qd::rect -{ - return qd::rect((frame % rle_grid_width) * m_frame_size.width(), (frame / rle_grid_width) * m_frame_size.height(), - m_frame_size.width(), m_frame_size.height()); -} - -auto graphite::qd::rle::frame_surface(int frame) const -> std::shared_ptr -{ - auto surface = std::make_shared(m_frame_size.width(), m_frame_size.height()); - auto src_rect = frame_rect(frame); - - // Extract the frame area of the origin surface - for (auto x = 0; x < src_rect.width(); x++) { - for (auto y = 0; y < src_rect.height(); y++) { - surface->set(x, y, m_surface->at(x + src_rect.x(), y + src_rect.y())); - } - } - - return surface; -} - -auto graphite::qd::rle::write_frame(int frame, const std::shared_ptr& surface) -> void -{ - auto dst_rect = frame_rect(frame); - auto src_size = surface->size(); - - if (src_size.width() != m_frame_size.width() || src_size.height() != m_frame_size.height()) { - throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width()) + "x" + std::to_string(src_size.height()) + - ", expected " + std::to_string(m_frame_size.width()) + "x" + std::to_string(m_frame_size.height())); - } - - // Copy from the source surface into the destination frame - for (auto x = 0; x < dst_rect.width(); x++) { - for (auto y = 0; y < dst_rect.height(); y++) { - m_surface->set(x + dst_rect.x(), y + dst_rect.y(), surface->at(x, y)); - } - } -} - -// MARK: - Parsing - -auto graphite::qd::rle::parse(data::reader &reader) -> void -{ - // Read the header of the RLE information. This will tell us what we need to do in order to - // actually decode the frames. - m_frame_size = qd::size::read(reader, qd::size::pict); - m_bpp = reader.read_short(); - m_palette_id = reader.read_short(); - m_frame_count = reader.read_short(); - reader.move(6); - - // Ensure that the RLE has a BPP of 16. This is the only format that we support currently. - if (m_bpp != 16) { - throw std::runtime_error("Incorrect color depth for rlëD resource: " + std::to_string(m_id) + ", " + m_name); - } - - // Determine what the grid will be. We need to round up to the next whole number and have blank tiles - // if the frame count is not divisible by the grid width constant. - auto grid_width = std::min(rle_grid_width, static_cast(m_frame_count)); - m_grid_size = qd::size(static_cast(grid_width), - static_cast(std::ceil(m_frame_count / static_cast(grid_width)))); - - // Create the surface in which all frames will be drawn to, and other working variables required to parse and decode - // the RLE data correctly. - m_surface = std::make_shared(m_grid_size.width() * m_frame_size.width(), - m_grid_size.height() * m_frame_size.height()); - - rle::opcode opcode = eof; - uint64_t position = 0; - uint32_t row_start = 0; - int32_t current_line = -1; - uint64_t current_offset = 0; - int32_t count = 0; - uint16_t pixel = 0; - int32_t current_frame = 0; - uint32_t pixel_run = 0; - - while (!reader.eof()) { - if ((row_start != 0) && ((position - row_start) & 0x03)) { - position += 4 - ((position - row_start) & 0x03); - reader.move(4 - (count & 0x03)); - } - - count = reader.read_long(); - opcode = static_cast(count >> 24); - count &= 0x00FFFFFF; - - switch (opcode) { - case rle::opcode::eof: { - // Check that we're not erroneously encountering an EOF. - if (current_line != static_cast(m_frame_size.height() - 1)) { - throw std::runtime_error("Incorrect number of scanlines in rlëD resource: " + std::to_string(m_id) + ", " + m_name); - } - - // Have we finished decoding the last frame in the data? - if (++current_frame >= m_frame_count) { - goto COMPLETED_LAST_FRAME; - } - - // Prepare for the next frame. - current_line = -1; - break; - } - - case rle::opcode::line_start: { - current_offset = surface_offset(current_frame, ++current_line); - row_start = static_cast(reader.position()); - break; - } - - case rle::opcode::pixel_data: { - for (auto i = 0; i < count; i += 2) { - pixel = reader.read_short(); - write_pixel(pixel, 0xff, current_offset); - ++current_offset; - } - - if (count & 0x03) { - reader.move(4 - (count & 0x03)); - } - - break; - } - - case rle::opcode::pixel_run: { - pixel_run = reader.read_long(); - for (auto i = 0; i < count; i += 4) { - write_pixel_variant1(pixel_run, 0xff, current_offset); - ++current_offset; - - if (i + 2 < count) { - write_pixel_variant2(pixel_run, 0xff, current_offset); - ++current_offset; - } - } - break; - } - - case rle::opcode::transparent_run: { - current_offset += count >> 1; - break; - } - } - } - - COMPLETED_LAST_FRAME: - // Finished decoding rlëD data. - return; -} - -auto graphite::qd::rle::surface_offset(int32_t frame, int32_t line) const -> uint64_t -{ - qd::point fo(frame % rle_grid_width, frame / rle_grid_width); - qd::point p(fo.x() * m_frame_size.width(), (fo.y() * m_frame_size.height()) + line); - return static_cast(p.y() * m_surface->size().width() + p.x()); -} - -auto graphite::qd::rle::write_pixel(uint16_t pixel, uint8_t mask, uint64_t offset) -> void -{ - auto r = static_cast((pixel & 0x7C00) >> 7); - auto g = static_cast((pixel & 0x03E0) >> 2); - auto b = static_cast((pixel & 0x001F) << 3); - m_surface->set(static_cast(offset), qd::color(r, g, b)); -} - -auto graphite::qd::rle::write_pixel_variant1(uint32_t pixel, uint8_t mask, uint64_t offset) -> void -{ - auto r = static_cast((pixel & 0x7C000000) >> 23); - auto g = static_cast((pixel & 0x03E00000) >> 18); - auto b = static_cast((pixel & 0x001F0000) << 13); - m_surface->set(static_cast(offset), qd::color(r, g, b)); -} - -auto graphite::qd::rle::write_pixel_variant2(uint32_t pixel, uint8_t mask, uint64_t offset) -> void -{ - auto r = static_cast((pixel & 0x00007C00) >> 7); - auto g = static_cast((pixel & 0x000003E0) >> 2); - auto b = static_cast((pixel & 0x0000001F) << 3); - m_surface->set(static_cast(offset), qd::color(r, g, b)); -} - -// MARK: - Encoder / Writing - -auto graphite::qd::rle::encode(graphite::data::writer& writer) -> void -{ - // Write out the header - m_frame_size.write(writer, qd::size::pict); - writer.write_short(m_bpp); - writer.write_short(m_palette_id); - writer.write_short(m_frame_count); - - // Reserved fields - writer.write_short(0); - writer.write_short(0); - writer.write_short(0); - - const auto advance = 2; // we only support 16 bits per pixel - - // Write out the RLE frames - for (auto f = 0; f < m_frame_count; f++) { - auto frame = frame_rect(f); - - for (auto y = 0; y < frame.height(); y++) { - auto line_start_pos = writer.position(); - writer.write_long(0); // line start opcode placeholder -- we'll write it later - - opcode run_state = line_start; - auto run_start_pos = line_start_pos + 4; - auto run_count = 0; - - for (auto x = 0; x < frame.width(); x++) { - qd::color pixel = m_surface->at(frame.x() + x, frame.y() + y); - - if (pixel.alpha_component() == 0) { - if (run_state == line_start) { - // Start of a transparent run - run_start_pos = writer.position(); - writer.write_long(0); // opcode placeholder - run_state = transparent_run; - run_count = advance; - } - else if (run_state == transparent_run) { - // Continue transparent run - run_count += advance; - } - else { - // End of pixel run, start of transparent run - auto run_end_pos = writer.position(); - writer.set_position(run_start_pos); - writer.write_long((pixel_data << 24) | (run_count & 0x00FFFFFF)); - writer.set_position(run_end_pos); - - // Pad to nearest 4-byte boundary - if (run_count & 3) { - writer.move(4 - (run_count & 3)); - } - - // Start transparent run - run_start_pos = writer.position(); - writer.write_long(0); // opcode placeholder - run_state = transparent_run; - run_count = advance; - } - } - else { - if (run_state == line_start) { - // Start of a pixel run - run_start_pos = writer.position(); - writer.write_long(0); // opcode placeholder - run_state = pixel_data; - run_count = advance; - } - else if (run_state == transparent_run) { - // End of transparent run, start of pixel run - writer.move(-4); - writer.write_long((transparent_run << 24) | (run_count & 0x00FFFFFF)); - - // Start pixel run - run_start_pos = writer.position(); - writer.write_long(0); // opcode placeholder - run_state = pixel_data; - run_count = advance; - } - else { - // Continue pixel run - run_count += advance; - } - - // Write the pixel - writer.write_short(pixel.blue_component() >> 3 | - (pixel.green_component() >> 3) << 5 | - (pixel.red_component() >> 3) << 10); - } - } - - // Terminate the current opcode - if (run_state == pixel_data) { - auto run_end_pos = writer.position(); - writer.set_position(run_start_pos); - writer.write_long((pixel_data << 24) | (run_count & 0x00FFFFFF)); - writer.set_position(run_end_pos); - - // Pad to nearest 4-byte boundary - if ((run_end_pos - line_start_pos) & 3) { - writer.move(4 - ((run_end_pos - line_start_pos) & 3)); - } - } - else if (run_state == transparent_run) { - // Erase the transparent run opcode placeholder -- remaining data is assumed transparent - writer.set_position(run_start_pos); - } - - // Write out the opcode and size at the start of the line - auto line_end_pos = writer.position(); - writer.set_position(line_start_pos); - writer.write_long((line_start << 24) | ((line_end_pos - line_start_pos - 4) & 0x00FFFFFF)); - writer.set_position(line_end_pos); - } - - // Mark end-of-frame - writer.write_long(eof << 24); - } -} - -auto graphite::qd::rle::data() -> std::shared_ptr -{ - auto data = std::make_shared(); - graphite::data::writer writer(data); - encode(writer); - return data; -} diff --git a/libGraphite/quickdraw_old/rle.hpp b/libGraphite/quickdraw_old/rle.hpp deleted file mode 100644 index 75e150c..0000000 --- a/libGraphite/quickdraw_old/rle.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// -// Created by Tom Hancocks on 24/03/2020. -// - -#if !defined(GRAPHITE_RLE_HPP) -#define GRAPHITE_RLE_HPP - -#include -#include "libGraphite/quickdraw/internal/surface.hpp" -#include "libGraphite/quickdraw/geometry.hpp" - -namespace graphite::qd { - - class rle - { - private: - enum opcode : uint8_t - { - eof = 0x00, - line_start = 0x01, - pixel_data = 0x02, - transparent_run = 0x03, - pixel_run = 0x04, - }; - - int64_t m_id {}; - std::string m_name; - std::vector m_frames; - std::shared_ptr m_surface; - qd::size m_frame_size; - qd::size m_grid_size; - uint16_t m_frame_count {}; - uint16_t m_bpp {}; - uint16_t m_palette_id {}; - - auto parse(data::reader &reader) -> void; - [[nodiscard]] auto surface_offset(int32_t frame, int32_t line) const -> uint64_t; - auto write_pixel(uint16_t pixel, uint8_t mask, uint64_t offset) -> void; - auto write_pixel_variant1(uint32_t pixel, uint8_t mask, uint64_t offset) -> void; - auto write_pixel_variant2(uint32_t pixel, uint8_t mask, uint64_t offset) -> void; - - auto encode(graphite::data::writer& writer) -> void; - - public: - explicit rle(std::shared_ptr data, int64_t id = 0, std::string name = ""); - rle(qd::size frame_size, uint16_t frame_count); - - static auto load_resource(int64_t id) -> std::shared_ptr; - - [[nodiscard]] auto surface() const -> std::weak_ptr; - [[nodiscard]] auto frames() const -> std::vector; - - [[nodiscard]] auto frame_count() const -> int; - [[nodiscard]] auto frame_rect(int frame) const -> qd::rect; - [[nodiscard]] auto frame_surface(int frame) const -> std::shared_ptr; - auto write_frame(int frame, const std::shared_ptr& surface) -> void; - - auto data() -> std::shared_ptr; - }; - -} - -#endif //GRAPHITE_RLE_HPP From aefd31fee656b4e7fe2c17a6f7494dafd03b1532 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Tue, 21 Jun 2022 20:11:32 +0100 Subject: [PATCH 003/113] Fix compilation of libGraphite.a --- libGraphite/compression/packbits.cpp | 8 +++++--- libGraphite/data/data.cpp | 8 +++++--- libGraphite/data/data.hpp | 6 +++--- libGraphite/data/writer.hpp | 2 +- libGraphite/quickdraw/format/clut.cpp | 8 ++++++-- libGraphite/quickdraw/support/surface.cpp | 10 ++++++++++ libGraphite/quickdraw/support/surface.hpp | 4 ++-- libGraphite/quickdraw/type/color.cpp | 4 ++-- libGraphite/quickdraw/type/point.hpp | 2 ++ libGraphite/quickdraw/type/rect.hpp | 2 +- libGraphite/rsrc/classic/parser.cpp | 4 ++-- libGraphite/rsrc/resource.cpp | 3 +-- libGraphite/rsrc/result.cpp | 2 +- libGraphite/rsrc/rez/parser.cpp | 6 +++--- 14 files changed, 44 insertions(+), 25 deletions(-) diff --git a/libGraphite/compression/packbits.cpp b/libGraphite/compression/packbits.cpp index 990cc9c..b05c398 100644 --- a/libGraphite/compression/packbits.cpp +++ b/libGraphite/compression/packbits.cpp @@ -35,10 +35,11 @@ auto graphite::compression::packbits::decompress(const data::block &compressed, auto count = reader.read_byte(); if (count >= 0 && count < 128) { std::uint16_t run = (1 + count) * value_size; - if ((pos + run) > reader.size()) { + if ((reader.position() + run) > reader.size()) { throw std::runtime_error("Unable to decode packbits"); } - writer.write_data(std::move(reader.read_data(run))); + auto data = std::move(reader.read_data(run)); + writer.write_data(&data); } else if (count >= 128) { std::uint8_t run = 256 - count + 1; @@ -97,8 +98,9 @@ auto graphite::compression::packbits::compress(const data::block &uncompressed) } if (run > 0) { + auto sliced = std::move(buffer.slice(0, run)); writer.write_byte(run - 1); - writer.write_data(buffer.slice(0, run)); + writer.write_data(&sliced); buffer.clear(); } diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 1bff4d5..b11fc6f 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -167,7 +167,7 @@ graphite::data::block::block(const block &data) copy_from(data); } -graphite::data::block::block(block &&data) +graphite::data::block::block(block &&data) noexcept : m_raw_size(data.m_raw_size), m_data_size(data.m_data_size), m_raw(data.m_raw), @@ -203,6 +203,8 @@ auto graphite::data::block::operator=(const block &data) -> struct block & m_raw = malloc(m_raw_size); m_data = simd_align(m_raw); copy_from(data); + + return *this; } auto graphite::data::block::operator=(block &&data) noexcept -> struct block & @@ -335,7 +337,7 @@ auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::positi auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::position start) -> void { - union simd_value v; + union simd_value v { 0 }; for (auto n = 0; n < simd_fields; ++n) { v.fields[n] = value; } @@ -346,5 +348,5 @@ auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::positi auto graphite::data::block::slice(block::position pos, std::size_t size, bool copy) const -> block { - return std::move(data(*this, pos, size, copy)); + return std::move(block(*this, pos, size, copy)); } diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index 1874aed..f18338c 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -58,11 +58,11 @@ namespace graphite::data block() = default; explicit block(std::size_t capacity, enum byte_order order = byte_order::msb); explicit block(const std::string& path, enum byte_order order = byte_order::msb); - block(const block& source, bool copy = true); + block(const block& source); + block(const block& source, bool copy); block(const block& source, block::position pos, std::size_t count, bool copy = true); - block(const block& data); - block(block&& data); + block(block&& data) noexcept; auto operator=(const block& data) -> struct block&; auto operator=(block&& data) noexcept -> struct block&; diff --git a/libGraphite/data/writer.hpp b/libGraphite/data/writer.hpp index 7d6a72e..485cd06 100644 --- a/libGraphite/data/writer.hpp +++ b/libGraphite/data/writer.hpp @@ -36,7 +36,7 @@ namespace graphite::data ~writer(); - [[nodiscard]] inline auto data() const -> const class data * { return m_data; }; + [[nodiscard]] inline auto data() const -> const class data * { return reinterpret_cast(m_data); }; [[nodiscard]] inline auto owns_data() const -> bool { return m_owns_data; } [[nodiscard]] inline auto position() const -> block::position { return m_position; } diff --git a/libGraphite/quickdraw/format/clut.cpp b/libGraphite/quickdraw/format/clut.cpp index 9e28653..714ef4b 100644 --- a/libGraphite/quickdraw/format/clut.cpp +++ b/libGraphite/quickdraw/format/clut.cpp @@ -46,8 +46,12 @@ auto graphite::quickdraw::clut::size() const -> size_type auto graphite::quickdraw::clut::at(index_type index) const -> union color { - const auto& it = m_entries.find(index); - return (it != m_entries.end()) ? it->second : colors::black(); + for (const auto& entry : m_entries) { + if (entry.first == index) { + return entry.second; + } + } + return colors::black(); } auto graphite::quickdraw::clut::set(union color color) -> index_type diff --git a/libGraphite/quickdraw/support/surface.cpp b/libGraphite/quickdraw/support/surface.cpp index 8653825..992efe3 100644 --- a/libGraphite/quickdraw/support/surface.cpp +++ b/libGraphite/quickdraw/support/surface.cpp @@ -50,6 +50,16 @@ graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, u m_data.set(color.value); } +graphite::quickdraw::surface::surface(const surface &surface) +{ + +} + +graphite::quickdraw::surface::surface(surface &&surface) noexcept +{ + +} + // MARK: - Accessors auto graphite::quickdraw::surface::raw() const -> const data::block& diff --git a/libGraphite/quickdraw/support/surface.hpp b/libGraphite/quickdraw/support/surface.hpp index 87f1e94..6274c92 100644 --- a/libGraphite/quickdraw/support/surface.hpp +++ b/libGraphite/quickdraw/support/surface.hpp @@ -35,8 +35,8 @@ namespace graphite::quickdraw surface(std::int16_t width, std::int16_t height); surface(const size& size, union color color); surface(std::int16_t width, std::int16_t height, union color color); - surface(const surface& surface) = default; - surface(surface&& surface) noexcept = default; + surface(const surface& surface); + surface(surface&& surface) noexcept; auto operator=(const surface&) -> surface& = default; auto operator=(surface&&) -> surface& = default; diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index 7c8aa4b..cb3564a 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -27,8 +27,8 @@ auto graphite::quickdraw::rgb(color_component r, color_component g, color_compon return { .components = { .red = r, .green = g, .blue = b, .alpha = a - }; - } + } + }; } // MARK: - Pre-defined Colors diff --git a/libGraphite/quickdraw/type/point.hpp b/libGraphite/quickdraw/type/point.hpp index 2830bd2..ded0041 100644 --- a/libGraphite/quickdraw/type/point.hpp +++ b/libGraphite/quickdraw/type/point.hpp @@ -24,6 +24,8 @@ #include #include "libGraphite/data/encoding.hpp" #include "libGraphite/quickdraw/type/coding_type.hpp" +#include "libGraphite/data/reader.hpp" +#include "libGraphite/data/writer.hpp" namespace graphite::quickdraw { diff --git a/libGraphite/quickdraw/type/rect.hpp b/libGraphite/quickdraw/type/rect.hpp index 3dc22a1..43f3c9f 100644 --- a/libGraphite/quickdraw/type/rect.hpp +++ b/libGraphite/quickdraw/type/rect.hpp @@ -75,7 +75,7 @@ namespace graphite::quickdraw auto operator/(U v) const -> rect { return { origin / static_cast(v), size / static_cast(v) }; } template::value>> - auto cast() const -> rect { return { origin.cast(), size.cast() }; } + auto cast() const -> rect { return { origin.template cast(), size.template cast() }; } }; } \ No newline at end of file diff --git a/libGraphite/rsrc/classic/parser.cpp b/libGraphite/rsrc/classic/parser.cpp index b28aa48..faabd40 100644 --- a/libGraphite/rsrc/classic/parser.cpp +++ b/libGraphite/rsrc/classic/parser.cpp @@ -127,11 +127,11 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> // 6. Create a data slice for the resources data. reader.set_position(data_offset + resource_data_offset); auto data_size = reader.read_long(); - auto slice = reader.read_data(data_size); + auto slice = std::move(reader.read_data(data_size)); reader.restore_position(); // 7. Construct a new resource instance and add it to the type. - struct resource resource { &type, id, name, slice }; + struct resource resource { &type, id, name, std::move(slice) }; type.add_resource(std::move(resource)); } diff --git a/libGraphite/rsrc/resource.cpp b/libGraphite/rsrc/resource.cpp index 5cbd04d..edd2e33 100644 --- a/libGraphite/rsrc/resource.cpp +++ b/libGraphite/rsrc/resource.cpp @@ -22,7 +22,6 @@ #include "libGraphite/rsrc/type.hpp" #include "libGraphite/util/hashing.hpp" - // MARK: - Construction graphite::rsrc::resource::resource(resource::identifier id, const std::string &name) @@ -39,7 +38,7 @@ graphite::rsrc::resource::resource(const resource &resource) : m_type(resource.m_type), m_id(resource.m_id), m_name(resource.m_name), - m_data(fast_data::data(resource.m_data, true)) + m_data(data::block(resource.m_data, true)) { } diff --git a/libGraphite/rsrc/result.cpp b/libGraphite/rsrc/result.cpp index 0911610..2b83f91 100644 --- a/libGraphite/rsrc/result.cpp +++ b/libGraphite/rsrc/result.cpp @@ -113,7 +113,7 @@ auto graphite::rsrc::resource_result::resource(const std::string &type_code, res return m_resources.at(resource_result::sort_key(type_code, id)); } -auto graphite::rsrc::resource_result::filter(const std::functionbool>& fn) const -> :resource_result +auto graphite::rsrc::resource_result::filter(const std::functionbool>& fn) const -> resource_result { resource_result result; diff --git a/libGraphite/rsrc/rez/parser.cpp b/libGraphite/rsrc/rez/parser.cpp index f85a0bb..0a9b58c 100644 --- a/libGraphite/rsrc/rez/parser.cpp +++ b/libGraphite/rsrc/rez/parser.cpp @@ -118,14 +118,14 @@ auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> boo reader.set_position(next_offset); // 7. Construct a new resource instance and add it to the type. - struct resource resource { &type, id, name, slice }; - type.add_resource(std::move(resource)); + struct resource resource { &type, id, name, std::move(slice) }; + type.add_resource(resource); } reader.restore_position(); types.emplace_back(std::move(type)); } - file.add_types(std::move(types)); + file.add_types(types); return true; } From 5f306ebbac5038535e989fbb1d90010e09f6b870 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Tue, 21 Jun 2022 20:38:37 +0100 Subject: [PATCH 004/113] Remove ASan flag in CMake. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 816630a..11a630b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ file(GLOB_RECURSE graphite_test_sources libGraphite/new_rsrc/*.cpp libGraphite/util/*.cpp ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") add_executable(GraphiteTest ${graphite_test_sources}) #target_link_libraries(GraphiteTest Graphite) From 1bf0f00f704f03f5b8c68274e216a2427f4d4879 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 22 Jun 2022 09:48:42 +0100 Subject: [PATCH 005/113] Introduce a new constructor the data::block class. --- libGraphite/data/data.cpp | 16 ++++++++++++++++ libGraphite/data/data.hpp | 1 + 2 files changed, 17 insertions(+) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index b11fc6f..a9a72fa 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -118,6 +118,22 @@ graphite::data::block::block(const std::string &path, enum byte_order order) file.close(); } +graphite::data::block::block(const std::vector& bytes, enum byte_order order) + : m_byte_order(order), + m_allocation_owner(nullptr) +{ + m_data_size = bytes.size(); + m_raw_size = simd_expand_capacity(m_data_size); + m_raw = malloc(m_raw_size); + m_data = simd_align(m_raw); + + // TODO: This is slow, and should be speeded up in the future. + auto ptr = static_cast(m_data); + for (const auto& byte : bytes) { + *ptr++ = byte; + } +} + graphite::data::block::block(const block &source, bool copy) : m_raw_size(source.m_raw_size), m_data_size(source.m_data_size), diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index f18338c..8ccdd41 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -58,6 +58,7 @@ namespace graphite::data block() = default; explicit block(std::size_t capacity, enum byte_order order = byte_order::msb); explicit block(const std::string& path, enum byte_order order = byte_order::msb); + block(const std::vector& bytes, enum byte_order order = byte_order::msb); block(const block& source); block(const block& source, bool copy); block(const block& source, block::position pos, std::size_t count, bool copy = true); From 4aaf70b601e0f3599d5cb8656fa2ec0a2873318c Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 22 Jun 2022 10:33:11 +0100 Subject: [PATCH 006/113] Initialize QuickDraw image types from a surface. --- libGraphite/quickdraw/format/cicn.cpp | 5 +++++ libGraphite/quickdraw/format/cicn.hpp | 1 + libGraphite/quickdraw/format/ppat.cpp | 5 +++++ libGraphite/quickdraw/format/ppat.hpp | 1 + 4 files changed, 12 insertions(+) diff --git a/libGraphite/quickdraw/format/cicn.cpp b/libGraphite/quickdraw/format/cicn.cpp index 33be7c5..bc48e55 100644 --- a/libGraphite/quickdraw/format/cicn.cpp +++ b/libGraphite/quickdraw/format/cicn.cpp @@ -39,6 +39,11 @@ graphite::quickdraw::cicn::cicn(data::reader &reader) decode(reader); } +graphite::quickdraw::cicn::cicn(quickdraw::surface& surface) + : m_surface(std::move(surface)) +{ +} + // MARK: - Accessors auto graphite::quickdraw::cicn::surface() const -> const quickdraw::surface& diff --git a/libGraphite/quickdraw/format/cicn.hpp b/libGraphite/quickdraw/format/cicn.hpp index cdce169..2e9e662 100644 --- a/libGraphite/quickdraw/format/cicn.hpp +++ b/libGraphite/quickdraw/format/cicn.hpp @@ -37,6 +37,7 @@ namespace graphite::quickdraw cicn() = default; explicit cicn(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); explicit cicn(data::reader& reader); + explicit cicn(quickdraw::surface& surface); [[nodiscard]] auto surface() const -> const surface&; diff --git a/libGraphite/quickdraw/format/ppat.cpp b/libGraphite/quickdraw/format/ppat.cpp index 76ee943..82a79d9 100644 --- a/libGraphite/quickdraw/format/ppat.cpp +++ b/libGraphite/quickdraw/format/ppat.cpp @@ -36,6 +36,11 @@ graphite::quickdraw::ppat::ppat(data::reader &reader) decode(reader); } +graphite::quickdraw::ppat::ppat(graphite::quickdraw::surface& surface) + : m_surface(surface) +{ +} + // MARK: - Accessors auto graphite::quickdraw::ppat::surface() const -> const struct surface & diff --git a/libGraphite/quickdraw/format/ppat.hpp b/libGraphite/quickdraw/format/ppat.hpp index 7d4886d..d13ab4c 100644 --- a/libGraphite/quickdraw/format/ppat.hpp +++ b/libGraphite/quickdraw/format/ppat.hpp @@ -37,6 +37,7 @@ namespace graphite::quickdraw ppat() = default; explicit ppat(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); explicit ppat(data::reader& reader); + explicit ppat(graphite::quickdraw::surface& surface); [[nodiscard]] auto surface() const -> const quickdraw::surface&; From 971f701a5b9f73bf05822c22c547f177b9bdfaca Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 22 Jun 2022 12:41:56 +0100 Subject: [PATCH 007/113] Add a new constructor to the sound resource. --- libGraphite/sound/sound.cpp | 30 ++++++++++++++++++++++++++++++ libGraphite/sound/sound.hpp | 2 ++ 2 files changed, 32 insertions(+) diff --git a/libGraphite/sound/sound.cpp b/libGraphite/sound/sound.cpp index 361ec82..1a12de0 100644 --- a/libGraphite/sound/sound.cpp +++ b/libGraphite/sound/sound.cpp @@ -211,6 +211,36 @@ graphite::sound_manager::sound::sound(const data::block &data, rsrc::resource::i decode(reader); } +graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) +{ + m_descriptor.sample_rate = sample_rate; + m_descriptor.bit_width = sample_bits; + + graphite::data::writer writer(&m_samples); + if (sample_bits == 8) { + for (auto& channel : sample_data) { + for (auto& frame : channel) { + writer.write_byte(static_cast(frame)); + } + } + } + else { + for (auto& channel : sample_data) { + for (auto& frame : channel) { + writer.write_short(static_cast(frame)); + } + } + } + +} + +graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const graphite::data::block& sample_data) +{ + m_descriptor.sample_rate = sample_rate; + m_descriptor.bit_width = sample_bits; + m_samples = sample_data; +} + // MARK: - Decoding auto graphite::sound_manager::sound::decode(data::reader &reader) -> void diff --git a/libGraphite/sound/sound.hpp b/libGraphite/sound/sound.hpp index 439709c..cb3520d 100644 --- a/libGraphite/sound/sound.hpp +++ b/libGraphite/sound/sound.hpp @@ -36,6 +36,8 @@ namespace graphite::sound_manager public: explicit sound(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const graphite::data::block& sample_data); + explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector>& sample_data); [[nodiscard]] auto samples() const -> const data::block&; [[nodiscard]] auto codec_descriptor() const -> const codec::descriptor&; From 376dee3bf4ad02f0e8f690abd7f890717a6bd8d7 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 22 Jun 2022 15:35:20 +0100 Subject: [PATCH 008/113] Add resource directly to file. --- libGraphite/rsrc/file.cpp | 27 +++++++++++++++++++++++++++ libGraphite/rsrc/file.hpp | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index c3e6e55..09cd859 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -92,6 +92,33 @@ auto graphite::rsrc::file::hash_value() const -> hash // MARK: - Type Management +auto graphite::rsrc::file::add_resource(const std::string &type_code, + rsrc::resource::identifier id, + const std::string &name, + const data::block &data, + const std::unordered_map &attributes) -> void +{ + struct resource resource(nullptr, id, name, data); + + auto type_hash = rsrc::type::hash_for_type_code(type_code); + auto it = m_types.find(type_hash); + if (it == m_types.end()) { + // The type doesn't exist, so we need to create it. + struct type type(type_code); + m_types.emplace(std::pair(type_hash, std::move(type))); + + struct type *type_ptr = &m_types.find(type_hash)->second; + resource.set_type(type_ptr); + + type.add_resource(std::move(resource)); + } + else { + // Found the type, add the resource to it. + resource.set_type(&it->second); + it->second.add_resource(std::move(resource)); + } +} + auto graphite::rsrc::file::add_type(const struct type &type) -> void { m_types.emplace(std::pair(type.hash_value(), std::move(type))); diff --git a/libGraphite/rsrc/file.hpp b/libGraphite/rsrc/file.hpp index afe91ef..024be7b 100644 --- a/libGraphite/rsrc/file.hpp +++ b/libGraphite/rsrc/file.hpp @@ -59,6 +59,12 @@ namespace graphite::rsrc [[nodiscard]] auto type(const std::string& code) const -> const struct type *; [[nodiscard]] auto type(type::hash hash) const -> const struct type *; + auto add_resource(const std::string& type_code, + rsrc::resource::identifier id, + const std::string& name, + const data::block& data, + const std::unordered_map& attributes = {}) -> void; + template [[nodiscard]] auto find(resource::identifier id) const -> const struct resource * { From 36d3e5cface5207f382649f10ed6594942094e53 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 23 Jun 2022 21:18:43 +0100 Subject: [PATCH 009/113] Convenience constructor for quickdraw::rect --- libGraphite/quickdraw/type/rect.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libGraphite/quickdraw/type/rect.hpp b/libGraphite/quickdraw/type/rect.hpp index 43f3c9f..7e27c37 100644 --- a/libGraphite/quickdraw/type/rect.hpp +++ b/libGraphite/quickdraw/type/rect.hpp @@ -39,6 +39,7 @@ namespace graphite::quickdraw rect() = default; explicit rect(T v) : origin(v), size(v) {} + rect(T x, T y, T width, T height) : origin(x, y), size(width, height) {} rect(struct point origin, struct quickdraw::size size) : origin(origin), size(size) {} rect(const rect&) = default; rect(rect&&) noexcept = default; From 490e1e9730c35f5b1d45609087d06a3325c8a7f2 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 24 Jun 2022 23:18:43 +0100 Subject: [PATCH 010/113] Fix issues found in and reported by ASan --- CMakeLists.txt | 2 +- libGraphite/data/data.hpp | 2 +- libGraphite/data/reader.cpp | 30 --------------------- libGraphite/data/reader.hpp | 39 +++++++++++++++++++++++++-- libGraphite/data/writer.cpp | 24 ----------------- libGraphite/data/writer.hpp | 39 ++++++++++++++++++++++----- libGraphite/quickdraw/format/cicn.cpp | 5 ++-- libGraphite/quickdraw/format/pict.cpp | 7 +++++ libGraphite/quickdraw/format/ppat.cpp | 5 ++-- libGraphite/quickdraw/format/rle.cpp | 29 +++++++++++++++++--- libGraphite/quickdraw/type/color.cpp | 18 +++++++++++++ libGraphite/quickdraw/type/color.hpp | 5 ++-- libGraphite/quickdraw/type/point.hpp | 22 +++++++-------- libGraphite/quickdraw/type/size.hpp | 12 ++++----- libGraphite/rsrc/file.cpp | 2 +- libGraphite/rsrc/resource.cpp | 31 ++++++++++++++++++++- libGraphite/rsrc/resource.hpp | 9 ++++--- libGraphite/rsrc/type.cpp | 28 ++++++++++--------- libGraphite/rsrc/type.hpp | 2 +- 19 files changed, 201 insertions(+), 110 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11a630b..3ba4d85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,5 +45,5 @@ file(GLOB_RECURSE graphite_test_sources ) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") add_executable(GraphiteTest ${graphite_test_sources}) -#target_link_libraries(GraphiteTest Graphite) +target_link_libraries(GraphiteTest Graphite) diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index 8ccdd41..68e6673 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -58,7 +58,7 @@ namespace graphite::data block() = default; explicit block(std::size_t capacity, enum byte_order order = byte_order::msb); explicit block(const std::string& path, enum byte_order order = byte_order::msb); - block(const std::vector& bytes, enum byte_order order = byte_order::msb); + explicit block(const std::vector& bytes, enum byte_order order = byte_order::msb); block(const block& source); block(const block& source, bool copy); block(const block& source, block::position pos, std::size_t count, bool copy = true); diff --git a/libGraphite/data/reader.cpp b/libGraphite/data/reader.cpp index 4cb9c84..b73f92a 100644 --- a/libGraphite/data/reader.cpp +++ b/libGraphite/data/reader.cpp @@ -82,36 +82,6 @@ auto graphite::data::reader::restore_position() -> void // MARK: - Read Operations -template::value>::type*> -auto graphite::data::reader::read_integer(block::position offset, mode mode, std::size_t size) -> T -{ - T v = 0; - if (size <= 0 || size > sizeof(T)) { - throw std::runtime_error("Invalid integer size specified in data reader."); - } - - for (block::position i = 0; i < size; ++i) { - auto b = m_data->template operator[](m_position + offset + i); - v |= static_cast(b) << (i << 3ULL); - } - - if (size > 1) { - v = swap(v, m_data->byte_order(), native_byte_order(), size); - } - - if (mode == mode::advance) { - move(offset + size); - } - - return v; -} - -template::value>::type*> -auto graphite::data::reader::read_enum(block::position offset, mode mode, std::size_t size) -> E -{ - return read_integer(offset, mode, size); -} - auto graphite::data::reader::read_byte(block::position offset, mode mode) -> uint8_t { return read_integer(offset, mode); diff --git a/libGraphite/data/reader.hpp b/libGraphite/data/reader.hpp index 493b6e3..f230bdd 100644 --- a/libGraphite/data/reader.hpp +++ b/libGraphite/data/reader.hpp @@ -136,10 +136,45 @@ namespace graphite::data } template::value>::type* = nullptr> - auto read_integer(block::position offset = 0, mode mode = mode::advance, std::size_t size = sizeof(T)) -> T; + auto read_integer(block::position offset = 0, mode mode = mode::advance, std::size_t size = sizeof(T)) -> T + { + T v = 0; + if (size <= 0 || size > sizeof(T)) { + throw std::runtime_error("Invalid integer size specified in data reader."); + } + + for (block::position i = 0; i < size; ++i) { + auto b = m_data->template operator[](m_position + offset + i); + v |= static_cast(b) << (i << 3ULL); + } + + if (size > 1) { + v = swap(v, m_data->byte_order(), native_byte_order(), size); + } + + if (mode == mode::advance) { + move(offset + size); + } + + return v; + } template::value>::type* = nullptr> - auto read_enum(block::position offset = 0, mode mode = mode::advance, std::size_t size = sizeof(E)) -> E; + auto read_enum(block::position offset = 0, mode mode = mode::advance, std::size_t size = sizeof(E)) -> E + { + if (sizeof(E) == sizeof(std::uint8_t)) { + return static_cast(read_byte(offset, mode)); + } + else if (sizeof(E) == sizeof(std::uint16_t)) { + return static_cast(read_short(offset, mode)); + } + else if (sizeof(E) == sizeof(std::uint32_t)) { + return static_cast(read_long(offset, mode)); + } + else if (sizeof(E) == sizeof(std::uint64_t)) { + return static_cast(read_quad(offset, mode)); + } + } private: bool m_owns_data { false }; diff --git a/libGraphite/data/writer.cpp b/libGraphite/data/writer.cpp index d8427a2..19d50bc 100644 --- a/libGraphite/data/writer.cpp +++ b/libGraphite/data/writer.cpp @@ -94,30 +94,6 @@ auto graphite::data::writer::move(block::position delta) -> void // MARK: - Write Operations -template::value>::type*> -auto graphite::data::writer::write_integer(T value, std::size_t count, std::size_t size) -> void -{ - auto swapped = swap(value, native_byte_order(), m_data->byte_order()); - - ensure_required_space(position(), size * count); - auto ptr = m_data->template get(position()); - - for (auto n = 0; n < count; ++n) { - for (auto i = 0; i < size; ++i) { - auto b = i << 3ULL; - *ptr++ = (swapped >> b) & 0xFF; - move(); - } - } -} - -template::value>::type*> -auto graphite::data::writer::write_enum(E value, std::size_t count, std::size_t size) -> E -{ - return write_integer(value, count, size); -} - - auto graphite::data::writer::write_byte(uint8_t value, std::size_t count) -> void { write_integer(value, count); diff --git a/libGraphite/data/writer.hpp b/libGraphite/data/writer.hpp index 485cd06..5a418b9 100644 --- a/libGraphite/data/writer.hpp +++ b/libGraphite/data/writer.hpp @@ -36,7 +36,7 @@ namespace graphite::data ~writer(); - [[nodiscard]] inline auto data() const -> const class data * { return reinterpret_cast(m_data); }; + [[nodiscard]] inline auto data() const -> const class block * { return reinterpret_cast(m_data); }; [[nodiscard]] inline auto owns_data() const -> bool { return m_owns_data; } [[nodiscard]] inline auto position() const -> block::position { return m_position; } @@ -51,7 +51,7 @@ namespace graphite::data auto move(block::position delta = 1) -> void; template::value && std::is_signed::value>> - auto write_integer(T value, std::size_t count = 1) -> void { } + auto write_integer(T value, std::size_t count = 1) -> void {} template auto write_integer(std::int8_t value, std::size_t count = 1) -> void { write_signed_byte(value, count); } @@ -66,8 +66,7 @@ namespace graphite::data auto write_integer(std::int64_t value, std::size_t count = 1) -> void { write_signed_quad(value, count); } template::value>> - - auto write_integer(T value, std::size_t count = 1) -> void { } + auto write_integer(T value, std::size_t count = 1) -> void {} template auto write_integer(std::uint8_t value, std::size_t count = 1) -> void { write_byte(value, count); } @@ -122,10 +121,38 @@ namespace graphite::data auto save(const std::string& path, std::size_t size = 0) const -> void; template::value>::type* = nullptr> - auto write_integer(T value, std::size_t count = 1, std::size_t size = sizeof(T)) -> void; + auto write_integer(T value, std::size_t count = 1, std::size_t size = sizeof(T)) -> void + { + auto swapped = swap(value, native_byte_order(), m_data->byte_order()); + + ensure_required_space(position(), size * count); + auto ptr = m_data->template get(position()); + + for (auto n = 0; n < count; ++n) { + for (auto i = 0; i < size; ++i) { + auto b = i << 3ULL; + *ptr++ = (swapped >> b) & 0xFF; + move(); + } + } + } template::value>::type* = nullptr> - auto write_enum(E value, std::size_t count = 1, std::size_t size = sizeof(E)) -> E; + auto write_enum(E value, std::size_t count = 1, std::size_t size = sizeof(E)) -> void + { + if (sizeof(E) == sizeof(std::uint8_t)) { + write_byte(static_cast(value), count); + } + else if (sizeof(E) == sizeof(std::uint16_t)) { + write_short(static_cast(value), count); + } + else if (sizeof(E) == sizeof(std::uint32_t)) { + write_long(static_cast(value), count); + } + else if (sizeof(E) == sizeof(std::uint64_t)) { + write_quad(static_cast(value), count); + } + } private: bool m_owns_data { false }; diff --git a/libGraphite/quickdraw/format/cicn.cpp b/libGraphite/quickdraw/format/cicn.cpp index bc48e55..5afd135 100644 --- a/libGraphite/quickdraw/format/cicn.cpp +++ b/libGraphite/quickdraw/format/cicn.cpp @@ -53,10 +53,9 @@ auto graphite::quickdraw::cicn::surface() const -> const quickdraw::surface& auto graphite::quickdraw::cicn::data() -> data::block { - data::block data; - data::writer writer(&data); + data::writer writer; encode(writer); - return std::move(data); + return std::move(*const_cast(writer.data())); } // MARK: - Coding diff --git a/libGraphite/quickdraw/format/pict.cpp b/libGraphite/quickdraw/format/pict.cpp index 4042f3e..47444aa 100644 --- a/libGraphite/quickdraw/format/pict.cpp +++ b/libGraphite/quickdraw/format/pict.cpp @@ -57,6 +57,13 @@ auto graphite::quickdraw::pict::surface() const -> const quickdraw::surface & return m_surface; } +auto graphite::quickdraw::pict::data() -> data::block +{ + data::writer writer; + encode(writer); + return std::move(*const_cast(writer.data())); +} + // MARK: - Decoding auto graphite::quickdraw::pict::decode(data::reader &reader) -> void diff --git a/libGraphite/quickdraw/format/ppat.cpp b/libGraphite/quickdraw/format/ppat.cpp index 82a79d9..32198ea 100644 --- a/libGraphite/quickdraw/format/ppat.cpp +++ b/libGraphite/quickdraw/format/ppat.cpp @@ -50,10 +50,9 @@ auto graphite::quickdraw::ppat::surface() const -> const struct surface & auto graphite::quickdraw::ppat::data() -> data::block { - data::block data; - data::writer writer(&data); + data::writer writer; encode(writer); - return std::move(data); + return std::move(*const_cast(writer.data())); } // MARK: - Coding diff --git a/libGraphite/quickdraw/format/rle.cpp b/libGraphite/quickdraw/format/rle.cpp index 89d9be0..3eac7ab 100644 --- a/libGraphite/quickdraw/format/rle.cpp +++ b/libGraphite/quickdraw/format/rle.cpp @@ -74,10 +74,9 @@ auto graphite::quickdraw::rle::frame_count() const -> std::size_t auto graphite::quickdraw::rle::data() -> data::block { - data::block data; - data::writer writer(&data); + data::writer writer; encode(writer); - return std::move(data); + return std::move(*const_cast(writer.data())); } // MARK: - Operations @@ -126,6 +125,30 @@ auto graphite::quickdraw::rle::write_frame(std::uint32_t frame, const quickdraw: } } +auto graphite::quickdraw::rle::write_pixel(std::uint16_t pixel, std::uint8_t mask, std::uint64_t offset) -> void +{ + m_surface.set(offset, rgb(pixel)); +} + +auto graphite::quickdraw::rle::write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void +{ + switch (type) { + case pixel_type::type1: { + m_surface.set(offset, rgb(pixel >> 16)); + } + case pixel_type::type2: { + m_surface.set(offset, rgb(pixel & 0xFFFF)); + } + } +} + +auto graphite::quickdraw::rle::surface_offset(std::uint32_t frame, std::uint64_t offset) -> std::uint64_t +{ + quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); + quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + offset); + return static_cast(p.y * m_surface.size().width + p.x); +} + // MARK: - Decoding auto graphite::quickdraw::rle::decode(data::reader &reader) -> void diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index cb3564a..b2ffbcf 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -31,6 +31,24 @@ auto graphite::quickdraw::rgb(color_component r, color_component g, color_compon }; } +auto graphite::quickdraw::rgb(std::uint16_t rgb555) -> union color +{ + union color c = { + .components = { + .red = static_cast((rgb555 & 0x7c00) >> 7), + .green = static_cast((rgb555 & 0x03e0) >> 2), + .blue = static_cast((rgb555 & 0x001f) << 3), + .alpha = 255 + } + }; + + c.components.red |= c.components.red >> 5; + c.components.green |= c.components.green >> 5; + c.components.blue |= c.components.blue >> 5; + + return c; +} + // MARK: - Pre-defined Colors auto graphite::quickdraw::colors::white() -> union color diff --git a/libGraphite/quickdraw/type/color.hpp b/libGraphite/quickdraw/type/color.hpp index 040d366..2d8bef1 100644 --- a/libGraphite/quickdraw/type/color.hpp +++ b/libGraphite/quickdraw/type/color.hpp @@ -38,10 +38,11 @@ namespace graphite::quickdraw } components; }; - auto operator==(const union color& lhs, const union color& rhs) -> bool { return lhs.value == rhs.value; } - auto operator!=(const union color& lhs, const union color& rhs) -> bool { return lhs.value != rhs.value; } + static auto operator==(const union color& lhs, const union color& rhs) -> bool { return lhs.value == rhs.value; } + static auto operator!=(const union color& lhs, const union color& rhs) -> bool { return lhs.value != rhs.value; } [[nodiscard]] auto rgb(color_component r, color_component g, color_component b, color_component a = 255) -> union color; + [[nodiscard]] auto rgb(std::uint16_t rgb555) -> union color; namespace constants { diff --git a/libGraphite/quickdraw/type/point.hpp b/libGraphite/quickdraw/type/point.hpp index ded0041..8c9d529 100644 --- a/libGraphite/quickdraw/type/point.hpp +++ b/libGraphite/quickdraw/type/point.hpp @@ -106,20 +106,20 @@ namespace graphite::quickdraw auto cast() const -> point { return { static_cast(x), static_cast(y) }; } private: - auto read_component(data::reader& reader) -> T { return reader.read_integer(); } - auto write_component(T value, data::writer& writer) -> void { writer.write_integer(value); } + static auto read_component(data::reader& reader) -> T { return reader.read_integer(); } + static auto write_component(T value, data::writer& writer) -> void { writer.write_integer(value); } }; - template<> - auto point::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } +} - template<> - auto point::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } +template<> +inline auto graphite::quickdraw::point::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } - template<> - auto point::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } +template<> +inline auto graphite::quickdraw::point::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } - template<> - auto point::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } +template<> +inline auto graphite::quickdraw::point::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } -} \ No newline at end of file +template<> +inline auto graphite::quickdraw::point::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } \ No newline at end of file diff --git a/libGraphite/quickdraw/type/size.hpp b/libGraphite/quickdraw/type/size.hpp index 37e7d22..6c0718f 100644 --- a/libGraphite/quickdraw/type/size.hpp +++ b/libGraphite/quickdraw/type/size.hpp @@ -105,20 +105,20 @@ namespace graphite::quickdraw auto cast() const -> size { return { static_cast(width), static_cast(height) }; } private: - auto read_component(data::reader& reader) -> T { return reader.read_integer(); } - auto write_component(T value, data::writer& writer) -> void { writer.write_integer(value); } + static auto read_component(data::reader& reader) -> T { return reader.read_integer(); } + static auto write_component(T value, data::writer& writer) -> void { writer.write_integer(value); } }; template<> - auto size::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } + inline auto size::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } template<> - auto size::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } + inline auto size::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } template<> - auto size::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } + inline auto size::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } template<> - auto size::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } + inline auto size::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } } \ No newline at end of file diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 09cd859..3fb8d7d 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -110,7 +110,7 @@ auto graphite::rsrc::file::add_resource(const std::string &type_code, struct type *type_ptr = &m_types.find(type_hash)->second; resource.set_type(type_ptr); - type.add_resource(std::move(resource)); + type_ptr->add_resource(std::move(resource)); } else { // Found the type, add the resource to it. diff --git a/libGraphite/rsrc/resource.cpp b/libGraphite/rsrc/resource.cpp index edd2e33..25ac7d2 100644 --- a/libGraphite/rsrc/resource.cpp +++ b/libGraphite/rsrc/resource.cpp @@ -45,7 +45,7 @@ graphite::rsrc::resource::resource(const resource &resource) graphite::rsrc::resource::resource(resource &&resource) noexcept : m_type(resource.m_type), m_id(resource.m_id), - m_name(resource.m_name), + m_name(std::move(resource.m_name)), m_data(std::move(resource.m_data)) { resource.m_type = nullptr; @@ -57,6 +57,35 @@ graphite::rsrc::resource::~resource() { } +// MARK: - Operators + +auto graphite::rsrc::resource::operator=(const resource &resource) -> struct resource & +{ + if (this == const_cast(&resource)) { + return *this; + } + + m_id = resource.m_id; + m_type = resource.m_type; + m_name = resource.m_name; + m_data = resource.m_data; + m_data_offset = resource.m_data_offset; + + return *this; +} + +auto graphite::rsrc::resource::operator=(resource &&resource) noexcept -> struct resource & +{ + if (this != &resource) { + m_id = resource.m_id; + m_type = resource.m_type; + m_name = std::move(resource.m_name); + m_data = std::move(resource.m_data); + m_data_offset = resource.m_data_offset; + } + return *this; +} + // MARK: - Accessors auto graphite::rsrc::resource::id() const -> resource::identifier diff --git a/libGraphite/rsrc/resource.hpp b/libGraphite/rsrc/resource.hpp index bd7b945..8e3b660 100644 --- a/libGraphite/rsrc/resource.hpp +++ b/libGraphite/rsrc/resource.hpp @@ -38,13 +38,16 @@ namespace graphite::rsrc static constexpr resource::identifier default_resource_id { 128 }; public: - resource(resource::identifier id = default_resource_id, const std::string& name = ""); - resource(struct type *type, resource::identifier id = default_resource_id, const std::string& name = "", data::block data = {}); - explicit resource(const resource& resource); + explicit resource(resource::identifier id = default_resource_id, const std::string& name = ""); + explicit resource(struct type *type, resource::identifier id = default_resource_id, const std::string& name = "", data::block data = {}); + resource(const resource& resource); resource(resource&& resource) noexcept; ~resource(); + auto operator=(const resource& resource) -> struct resource&; + auto operator=(resource&& resource) noexcept -> struct resource&; + [[nodiscard]] auto id() const -> resource::identifier; [[nodiscard]] auto type() const -> struct type *; [[nodiscard]] auto name() const -> const std::string&; diff --git a/libGraphite/rsrc/type.cpp b/libGraphite/rsrc/type.cpp index a8c279f..f1f4901 100644 --- a/libGraphite/rsrc/type.cpp +++ b/libGraphite/rsrc/type.cpp @@ -98,16 +98,16 @@ auto graphite::rsrc::type::has_resource(const std::string &name) const -> bool return (m_resource_name_map.find(hash) != m_resource_name_map.end()); } -auto graphite::rsrc::type::add_resource(const resource &resource) -> void +auto graphite::rsrc::type::add_resource(resource resource) -> void { m_resources.emplace_back(std::move(resource)); - auto& ref = m_resources.back(); - auto id_hash = resource::hash(ref.id()); - auto name_hash = resource::hash(ref.name()); + auto ref = &m_resources.back(); + auto id_hash = resource::hash(ref->id()); + auto name_hash = resource::hash(ref->name()); - m_resource_id_map[id_hash] = &ref; - m_resource_name_map[name_hash] = &ref; + m_resource_id_map.emplace(std::pair(id_hash, ref)); + m_resource_name_map.emplace(std::pair(name_hash, ref)); } auto graphite::rsrc::type::remove_resource(resource::identifier id) -> void @@ -117,18 +117,22 @@ auto graphite::rsrc::type::remove_resource(resource::identifier id) -> void auto graphite::rsrc::type::resource_with_id(resource::identifier id) const -> resource * { - auto it = m_resource_id_map.find(hashing::xxh64(&id, sizeof(id))); - if (it != m_resource_id_map.end()) { - return it->second; + for (const auto& it : m_resources) { + if (it.id() == id) { + auto ptr = const_cast(&it); + return ptr; + } } return nullptr; } auto graphite::rsrc::type::resource_with_name(const std::string &name) const -> resource * { - auto it = m_resource_name_map.find(hashing::xxh64(name.c_str(), name.size())); - if (it != m_resource_id_map.end()) { - return it->second; + for (const auto& it : m_resources) { + if (it.name() == name) { + auto ptr = const_cast(&it); + return ptr; + } } return nullptr; } diff --git a/libGraphite/rsrc/type.hpp b/libGraphite/rsrc/type.hpp index bf7d41b..2597284 100644 --- a/libGraphite/rsrc/type.hpp +++ b/libGraphite/rsrc/type.hpp @@ -52,7 +52,7 @@ namespace graphite::rsrc [[nodiscard]] auto has_resource(resource::identifier id) const -> bool; [[nodiscard]] auto has_resource(const std::string& name) const -> bool; - auto add_resource(const resource& resource) -> void; + auto add_resource(resource resource) -> void; auto remove_resource(resource::identifier id) -> void; [[nodiscard]] auto resource_with_id(resource::identifier id) const -> resource *; From e5808505bfa0b57b7ab4af31bac3324d32eed2c0 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 26 Jun 2022 08:18:11 +0100 Subject: [PATCH 011/113] Ensure resource type attributes are correctly hooked up. --- libGraphite/rsrc/attribute.cpp | 11 +++++++++-- libGraphite/rsrc/attribute.hpp | 2 ++ libGraphite/rsrc/file.cpp | 31 ++++++++++++++++++++++++++++--- libGraphite/rsrc/file.hpp | 8 +++++--- libGraphite/rsrc/manager.cpp | 4 +--- libGraphite/rsrc/type.cpp | 27 +++++++++++++++++++++------ libGraphite/rsrc/type.hpp | 2 ++ 7 files changed, 68 insertions(+), 17 deletions(-) diff --git a/libGraphite/rsrc/attribute.cpp b/libGraphite/rsrc/attribute.cpp index a89d9fa..32e039f 100644 --- a/libGraphite/rsrc/attribute.cpp +++ b/libGraphite/rsrc/attribute.cpp @@ -38,7 +38,7 @@ graphite::rsrc::attribute::attribute(const std::string &name, T value) auto graphite::rsrc::attribute::hash_value() const -> hash { - return hashing::xxh64(m_name.c_str(), m_name.size()); + return hash_for_name(m_name); } auto graphite::rsrc::attribute::name() const -> const std::string& @@ -55,4 +55,11 @@ template::value>::type auto graphite::rsrc::attribute::value() const -> T { return std::to_integer(m_value); -} \ No newline at end of file +} + +// MARK: - Helpers + +auto graphite::rsrc::attribute::hash_for_name(const std::string& name) -> hash +{ + return hashing::xxh64(name.c_str(), name.size()); +} diff --git a/libGraphite/rsrc/attribute.hpp b/libGraphite/rsrc/attribute.hpp index 0780277..65f47e5 100644 --- a/libGraphite/rsrc/attribute.hpp +++ b/libGraphite/rsrc/attribute.hpp @@ -30,6 +30,8 @@ namespace graphite::rsrc public: typedef std::uint64_t hash; + static auto hash_for_name(const std::string& name) -> hash; + public: attribute(const std::string& name, const std::string& value); diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 3fb8d7d..de76323 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -134,21 +134,46 @@ auto graphite::rsrc::file::add_types(const std::vector &types) -> v } } -auto graphite::rsrc::file::type(const std::string &code) const -> const struct type * +auto graphite::rsrc::file::type(const std::string &code, const std::unordered_map& attributes) const -> const struct type * +{ + // Convert the unordered map to what is required. + std::unordered_map attributes_map; + for (const auto& it : attributes) { + rsrc::attribute attr(it.first, it.second); + attributes_map.emplace(std::pair(attr.hash_value(), std::move(attr))); + } + + auto it = m_types.find(type::hash_for_type_code(code, attributes_map)); + return (it == m_types.end()) ? nullptr : &it->second; +} + +auto graphite::rsrc::file::type(const std::string& code, const std::vector& attributes) const -> const struct type * +{ + std::unordered_map attributes_map; + for (const auto& it : attributes) { + attributes_map.emplace(std::pair(it.hash_value(), it)); + } + + auto it = m_types.find(type::hash_for_type_code(code, attributes_map)); + return (it == m_types.end()) ? nullptr : &it->second; +} + +auto graphite::rsrc::file::type(const std::string& code) const -> const struct type * { auto it = m_types.find(type::hash_for_type_code(code)); return (it == m_types.end()) ? nullptr : &it->second; } + auto graphite::rsrc::file::type(type::hash hash) const -> const struct type * { auto it = m_types.find(hash); return (it == m_types.end()) ? nullptr : &it->second; } -auto graphite::rsrc::file::find(const std::string &type_code, resource::identifier id) const -> const struct resource * +auto graphite::rsrc::file::find(const std::string &type_code, resource::identifier id, const std::unordered_map& attributes) const -> const struct resource * { - if (auto type = this->type(type_code)) { + if (auto type = this->type(type_code, attributes)) { return type->resource_with_id(id); } return nullptr; diff --git a/libGraphite/rsrc/file.hpp b/libGraphite/rsrc/file.hpp index 024be7b..f8912db 100644 --- a/libGraphite/rsrc/file.hpp +++ b/libGraphite/rsrc/file.hpp @@ -56,6 +56,8 @@ namespace graphite::rsrc auto add_type(const struct type &type) -> void; auto add_types(const std::vector& types) -> void; + [[nodiscard]] auto type(const std::string& code, const std::unordered_map& attributes) const -> const struct type *; + [[nodiscard]] auto type(const std::string& code, const std::vector& attributes) const -> const struct type *; [[nodiscard]] auto type(const std::string& code) const -> const struct type *; [[nodiscard]] auto type(type::hash hash) const -> const struct type *; @@ -66,12 +68,12 @@ namespace graphite::rsrc const std::unordered_map& attributes = {}) -> void; template - [[nodiscard]] auto find(resource::identifier id) const -> const struct resource * + [[nodiscard]] auto find(resource::identifier id, const std::unordered_map& attributes = {}) const -> const struct resource * { - return find(T::type_code(), id); + return find(T::type_code(), id, attributes); } - [[nodiscard]] auto find(const std::string& type_code, resource::identifier id) const -> const struct resource *; + [[nodiscard]] auto find(const std::string& type_code, resource::identifier id, const std::unordered_map& attributes = {}) const -> const struct resource *; template [[nodiscard]] auto load(resource::identifier id) const -> T diff --git a/libGraphite/rsrc/manager.cpp b/libGraphite/rsrc/manager.cpp index 3b15780..2767580 100644 --- a/libGraphite/rsrc/manager.cpp +++ b/libGraphite/rsrc/manager.cpp @@ -98,9 +98,7 @@ auto graphite::rsrc::manager::all_types(const std::string &type_code, const std: { std::vector types; for (const auto& it : m_files) { - auto type = it.second.type(type_code); - - // TODO: Attribute matching... + auto type = it.second.type(type_code, attributes); if (type) { types.emplace_back(const_cast(type)); diff --git a/libGraphite/rsrc/type.cpp b/libGraphite/rsrc/type.cpp index f1f4901..6a5bfdf 100644 --- a/libGraphite/rsrc/type.cpp +++ b/libGraphite/rsrc/type.cpp @@ -31,11 +31,29 @@ graphite::rsrc::type::type(const std::string &code) // MARK: - Accessors +auto graphite::rsrc::type::attribute_string(const std::unordered_map &attributes) -> std::string +{ + std::string descriptor; + for (const auto& attribute : attributes) { + descriptor += "<" + attribute.second.name() + ":" + attribute.second.string_value() + ">"; + } + return std::move(descriptor); +} + auto graphite::rsrc::type::hash_for_type_code(const std::string &code) -> hash { return hashing::xxh64(code.c_str(), code.size()); } +auto graphite::rsrc::type::hash_for_type_code(const std::string &code, const std::unordered_map &attributes) -> graphite::rsrc::type::hash +{ + std::string assembled_code { code }; + if (!attributes.empty()) { + assembled_code += ":" + attribute_string(attributes); + } + return hash_for_type_code(assembled_code); +} + auto graphite::rsrc::type::hash_value() const -> hash { std::string code { m_code }; @@ -62,11 +80,7 @@ auto graphite::rsrc::type::count() const -> std::size_t auto graphite::rsrc::type::attribute_descriptor_string() const -> std::string { - std::string descriptor; - for (const auto& attribute : m_attributes) { - descriptor += "<" + attribute.second.name() + ":" + attribute.second.string_value() + ">"; - } - return std::move(descriptor); + return std::move(attribute_string(m_attributes)); } // MARK: - Attribute Management @@ -160,4 +174,5 @@ auto graphite::rsrc::type::sync_resource_type_references() -> void for (auto& resource : *this) { resource.set_type(this); } -} \ No newline at end of file +} + diff --git a/libGraphite/rsrc/type.hpp b/libGraphite/rsrc/type.hpp index 2597284..bafa2fc 100644 --- a/libGraphite/rsrc/type.hpp +++ b/libGraphite/rsrc/type.hpp @@ -36,7 +36,9 @@ namespace graphite::rsrc public: explicit type(const std::string& code); + static auto attribute_string(const std::unordered_map& attributes) -> std::string; static auto hash_for_type_code(const std::string& code) -> hash; + static auto hash_for_type_code(const std::string& code, const std::unordered_map& attributes) -> hash; [[nodiscard]] auto hash_value() const -> hash; [[nodiscard]] auto code() const -> const std::string&; From b5aa193bc0a34a48ed162b3d1beae093ed57ef61 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 26 Jun 2022 21:03:23 +0100 Subject: [PATCH 012/113] Update to the Resource Manager in Graphite. --- libGraphite/data/reader.cpp | 7 ++-- libGraphite/rsrc/classic/parser.cpp | 12 +++---- libGraphite/rsrc/classic/writer.cpp | 18 +++++----- libGraphite/rsrc/extended/parser.cpp | 14 ++++---- libGraphite/rsrc/extended/writer.cpp | 16 ++++----- libGraphite/rsrc/file.cpp | 40 +++++++++------------ libGraphite/rsrc/file.hpp | 6 ++-- libGraphite/rsrc/manager.cpp | 32 +++++++++-------- libGraphite/rsrc/manager.hpp | 6 ++-- libGraphite/rsrc/result.cpp | 7 ++-- libGraphite/rsrc/rez/parser.cpp | 14 ++++---- libGraphite/rsrc/rez/writer.cpp | 8 ++--- libGraphite/rsrc/type.cpp | 54 ++++++++++++++++------------ libGraphite/rsrc/type.hpp | 13 +++---- 14 files changed, 125 insertions(+), 122 deletions(-) diff --git a/libGraphite/data/reader.cpp b/libGraphite/data/reader.cpp index b73f92a..48e4fb4 100644 --- a/libGraphite/data/reader.cpp +++ b/libGraphite/data/reader.cpp @@ -39,7 +39,7 @@ graphite::data::reader::reader(const class block *data, block::position pos, boo auto graphite::data::reader::file(const std::string &path, block::position pos) -> reader { auto data = new class block(path, byte_order::msb); - return std::move(reader(data, pos, true)); + return reader(data, pos, true); } // MARK: - Destruction @@ -55,10 +55,7 @@ graphite::data::reader::~reader() auto graphite::data::reader::set_position(block::position pos) -> void { - if (pos < 0 || pos > size()) { - throw std::runtime_error("Attempted to set position of data reader out of bounds."); - } - m_position = pos; + m_position = static_cast(std::max(static_cast(0), std::min(static_cast(pos), size() + 1))); } auto graphite::data::reader::move(block::position delta) -> void diff --git a/libGraphite/rsrc/classic/parser.cpp b/libGraphite/rsrc/classic/parser.cpp index faabd40..353e3d0 100644 --- a/libGraphite/rsrc/classic/parser.cpp +++ b/libGraphite/rsrc/classic/parser.cpp @@ -31,7 +31,7 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> bool { - std::vector types; + std::vector types; // 1. Resource Preamble auto data_offset = reader.read_long(); @@ -103,7 +103,7 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> auto count = reader.read_short() + 1; auto first_resource_offset = static_cast(reader.read_short()); - struct type type { code }; + auto type = new struct type(code); // 4. Parse the list of resources for the current resource type. reader.save_position(); @@ -131,15 +131,15 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> reader.restore_position(); // 7. Construct a new resource instance and add it to the type. - struct resource resource { &type, id, name, std::move(slice) }; - type.add_resource(std::move(resource)); + auto resource = new struct resource(type, id, name, std::move(slice)); + type->add_resource(resource); } reader.restore_position(); - types.emplace_back(std::move(type)); + types.emplace_back(type); } - file.add_types(std::move(types)); + file.add_types(types); return true; } diff --git a/libGraphite/rsrc/classic/writer.cpp b/libGraphite/rsrc/classic/writer.cpp index 577fe5d..872522e 100644 --- a/libGraphite/rsrc/classic/writer.cpp +++ b/libGraphite/rsrc/classic/writer.cpp @@ -84,9 +84,9 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) } for (auto& resource : *type) { - auto data = resource.data(); + auto data = resource->data(); auto size = data.size(); - resource.set_data_offset(writer.size() - data_offset); + resource->set_data_offset(writer.size() - data_offset); writer.write_long(static_cast(size)); writer.write_data(&data); } @@ -138,7 +138,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) uint16_t name_len = 0; for (const auto type : types) { for (const auto& resource : *type) { - auto id = resource.id(); + auto id = resource->id(); if (id < std::numeric_limits::min() || id > std::numeric_limits::max()) { return false; @@ -147,7 +147,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) // The name is actually stored in the name list, and the resource stores and offset to that name. // If no name is assigned to the resource then the offset is encoded as 0xFFFF - if (resource.name().empty()) { + if (resource->name().empty()) { writer.write_short(0xFFFF); } else { @@ -158,7 +158,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) writer.write_short(name_offset); // Convert the name to MacRoman so that we can get the length of it when encoded. - auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + auto mac_roman = encoding::mac_roman::from_utf8(resource->name()); name_len = mac_roman.size() + 1; if (name_len > 0x100) { name_len = 0x100; @@ -170,7 +170,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) // The data offset is a 3 byte (24-bit) value. This means the hi-byte needs discarding and then a swap // performing. - auto offset = static_cast(resource.data_offset()); + auto offset = static_cast(resource->data_offset()); if (offset > 0xFFFFFF) { return false; } @@ -185,15 +185,15 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) name_offset = 0; for (const auto type : types) { for (const auto& resource : *type) { - if (resource.name().empty()) { + if (resource->name().empty()) { continue; } - auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + auto mac_roman = encoding::mac_roman::from_utf8(resource->name()); if (mac_roman.size() >= 0x100) { mac_roman.resize(0xFF); } - name_offset += writer.write_pstr(resource.name()) + 1; + name_offset += writer.write_pstr(resource->name()) + 1; } } diff --git a/libGraphite/rsrc/extended/parser.cpp b/libGraphite/rsrc/extended/parser.cpp index 3681bd3..e6b4087 100644 --- a/libGraphite/rsrc/extended/parser.cpp +++ b/libGraphite/rsrc/extended/parser.cpp @@ -31,7 +31,7 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) -> bool { - std::vector types; + std::vector types; // 1. Resource Preamble if (reader.read_quad(0, data::reader::mode::peek) != 1) { @@ -108,7 +108,7 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - auto attribute_count = reader.read_quad(); auto attribute_offset = reader.read_quad(); - struct type type { code }; + auto type = new struct type(code); // 4. Extract the list of attributes before we create the type, as they are needed for actually building the // type. @@ -116,7 +116,7 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - if (attribute_count > 0) { reader.set_position(attribute_list_offset + attribute_offset); for (auto i = 0; i < attribute_count; ++i) { - type.add_attribute(reader.read_cstr(), reader.read_cstr()); + type->add_attribute(reader.read_cstr(), reader.read_cstr()); } } @@ -145,14 +145,14 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - reader.restore_position(); // 7. Construct a new resource instance and add it to the type. - struct resource resource { &type, id, name, std::move(slice) }; - type.add_resource(std::move(resource)); + auto resource = new struct resource(type, id, name, std::move(slice)); + type->add_resource(resource); } reader.restore_position(); - types.emplace_back(std::move(type)); + types.emplace_back(type); } - file.add_types(std::move(types)); + file.add_types(types); return true; } diff --git a/libGraphite/rsrc/extended/writer.cpp b/libGraphite/rsrc/extended/writer.cpp index b97b702..5220c33 100644 --- a/libGraphite/rsrc/extended/writer.cpp +++ b/libGraphite/rsrc/extended/writer.cpp @@ -81,9 +81,9 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path resource_count += type->count(); for (auto& resource : *type) { - auto data = resource.data(); + auto data = resource->data(); auto size = data.size(); - resource.set_data_offset(writer.size() - data_offset); + resource->set_data_offset(writer.size() - data_offset); writer.write_quad(size); writer.write_data(&data); } @@ -147,16 +147,16 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path uint64_t name_offset = 0; for (const auto type : types) { for (const auto& resource : *type) { - writer.write_signed_quad(resource.id()); + writer.write_signed_quad(resource->id()); // The name is actually stored in the name list, and the resource stores an offset to that name. // If no name is assigned to the resource then the offset is encoded as 0xFFFFFFFFFFFFFFFF. - if (resource.name().empty()) { + if (resource->name().empty()) { writer.write_quad(std::numeric_limits::max()); } else { // Convert the name to MacRoman so that we can get the length of it when encoded. - auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + auto mac_roman = encoding::mac_roman::from_utf8(resource->name()); auto len = mac_roman.size(); writer.write_quad(name_offset); @@ -164,7 +164,7 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path } writer.write_byte(0); - writer.write_quad(resource.data_offset()); + writer.write_quad(resource->data_offset()); writer.write_long(0); } } @@ -173,11 +173,11 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path name_offset = 0; for (const auto type : types) { for (const auto& resource : *type) { - if (resource.name().empty()) { + if (resource->name().empty()) { continue; } - auto mac_roman = encoding::mac_roman::from_utf8(resource.name()); + auto mac_roman = encoding::mac_roman::from_utf8(resource->name()); if (mac_roman.size() >= 0x100) { mac_roman.resize(0xFF); } diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index de76323..49a5490 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -74,7 +74,7 @@ auto graphite::rsrc::file::type_codes() const -> std::vector { std::vector types; for (const auto& type : m_types) { - types.emplace_back(type.second.code()); + types.emplace_back(type.second->code()); } return std::move(types); } @@ -98,39 +98,31 @@ auto graphite::rsrc::file::add_resource(const std::string &type_code, const data::block &data, const std::unordered_map &attributes) -> void { - struct resource resource(nullptr, id, name, data); + auto resource = new struct resource(nullptr, id, name, data); auto type_hash = rsrc::type::hash_for_type_code(type_code); auto it = m_types.find(type_hash); if (it == m_types.end()) { // The type doesn't exist, so we need to create it. - struct type type(type_code); - m_types.emplace(std::pair(type_hash, std::move(type))); - - struct type *type_ptr = &m_types.find(type_hash)->second; - resource.set_type(type_ptr); - - type_ptr->add_resource(std::move(resource)); + auto type = new struct type(type_code); + m_types.emplace(std::pair(type_hash, type)); + type->add_resource(resource); } else { // Found the type, add the resource to it. - resource.set_type(&it->second); - it->second.add_resource(std::move(resource)); + it->second->add_resource(resource); } } -auto graphite::rsrc::file::add_type(const struct type &type) -> void +auto graphite::rsrc::file::add_type(struct type *type) -> void { - m_types.emplace(std::pair(type.hash_value(), std::move(type))); + m_types.emplace(std::pair(type->hash_value(), type)); } -auto graphite::rsrc::file::add_types(const std::vector &types) -> void +auto graphite::rsrc::file::add_types(const std::vector &types) -> void { - for (const auto& type : types) { - m_types.emplace(std::pair(type.hash_value(), std::move(type))); - - // We need to resync all of the type references inside the resources for the type. - m_types.at(type.hash_value()).sync_resource_type_references(); + for (const auto type : types) { + m_types.emplace(std::pair(type->hash_value(), type)); } } @@ -144,7 +136,7 @@ auto graphite::rsrc::file::type(const std::string &code, const std::unordered_ma } auto it = m_types.find(type::hash_for_type_code(code, attributes_map)); - return (it == m_types.end()) ? nullptr : &it->second; + return (it == m_types.end()) ? nullptr : it->second; } auto graphite::rsrc::file::type(const std::string& code, const std::vector& attributes) const -> const struct type * @@ -155,25 +147,25 @@ auto graphite::rsrc::file::type(const std::string& code, const std::vectorsecond; + return (it == m_types.end()) ? nullptr : it->second; } auto graphite::rsrc::file::type(const std::string& code) const -> const struct type * { auto it = m_types.find(type::hash_for_type_code(code)); - return (it == m_types.end()) ? nullptr : &it->second; + return (it == m_types.end()) ? nullptr : it->second; } auto graphite::rsrc::file::type(type::hash hash) const -> const struct type * { auto it = m_types.find(hash); - return (it == m_types.end()) ? nullptr : &it->second; + return (it == m_types.end()) ? nullptr : it->second; } auto graphite::rsrc::file::find(const std::string &type_code, resource::identifier id, const std::unordered_map& attributes) const -> const struct resource * { - if (auto type = this->type(type_code, attributes)) { + if (auto type = const_cast(this->type(type_code, attributes))) { return type->resource_with_id(id); } return nullptr; diff --git a/libGraphite/rsrc/file.hpp b/libGraphite/rsrc/file.hpp index f8912db..7343c53 100644 --- a/libGraphite/rsrc/file.hpp +++ b/libGraphite/rsrc/file.hpp @@ -54,8 +54,8 @@ namespace graphite::rsrc [[nodiscard]] auto format() const -> enum format; [[nodiscard]] auto hash_value() const -> hash; - auto add_type(const struct type &type) -> void; - auto add_types(const std::vector& types) -> void; + auto add_type(struct type *type) -> void; + auto add_types(const std::vector& types) -> void; [[nodiscard]] auto type(const std::string& code, const std::unordered_map& attributes) const -> const struct type *; [[nodiscard]] auto type(const std::string& code, const std::vector& attributes) const -> const struct type *; [[nodiscard]] auto type(const std::string& code) const -> const struct type *; @@ -86,7 +86,7 @@ namespace graphite::rsrc private: std::string m_path; - std::unordered_map m_types; + std::unordered_map m_types; data::block *m_data { nullptr }; enum format m_format { format::classic }; }; diff --git a/libGraphite/rsrc/manager.cpp b/libGraphite/rsrc/manager.cpp index 2767580..0d3e59b 100644 --- a/libGraphite/rsrc/manager.cpp +++ b/libGraphite/rsrc/manager.cpp @@ -30,22 +30,25 @@ auto graphite::rsrc::manager::shared_manager() -> manager & // MARK: - File Management -auto graphite::rsrc::manager::import_file(class file file) -> class file * +auto graphite::rsrc::manager::import_file(class file *file) -> class file * { - auto hash = file.hash_value(); - m_files.emplace(std::pair(hash, std::move(file))); - return &m_files.at(hash); + m_files.emplace(std::pair(file->hash_value(), file)); + return file; } auto graphite::rsrc::manager::import_file(const std::string &path) -> class file * { - graphite::rsrc::file file(path); - return import_file(std::move(file)); + auto file = new graphite::rsrc::file(path); + return import_file(file); } auto graphite::rsrc::manager::unload_file(file::hash file) -> void { - m_files.erase(file); + auto it = m_files.find(file); + if (it != m_files.end()) { + delete it->second; + m_files.erase(file); + } } auto graphite::rsrc::manager::unload_file(class file *file) -> void @@ -64,7 +67,7 @@ auto graphite::rsrc::manager::file(file::hash file) -> class file * { auto it = m_files.find(file); if (it != m_files.end()) { - return &it->second; + return it->second; } return nullptr; } @@ -87,21 +90,20 @@ auto graphite::rsrc::manager::file_references() const -> std::vector files; for (const auto& it : m_files) { - files.emplace_back(const_cast(&it.second)); + files.emplace_back(it.second); } return std::move(files); } // MARK: - Searching -auto graphite::rsrc::manager::all_types(const std::string &type_code, const std::vector &attributes) const -> std::vector +auto graphite::rsrc::manager::all_types(const std::string &type_code, const std::vector &attributes) const -> std::vector { - std::vector types; + std::vector types; for (const auto& it : m_files) { - auto type = it.second.type(type_code, attributes); - + auto type = it.second->type(type_code, attributes); if (type) { - types.emplace_back(const_cast(type)); + types.emplace_back(type); } } return types; @@ -116,7 +118,7 @@ auto graphite::rsrc::manager::find(const std::string &type_code, const std::vect const auto& types = all_types(type_code, attributes); for (const auto type : types) { for (const auto& resource : *type) { - result.add(const_cast(&resource)); + result.add(resource); } } diff --git a/libGraphite/rsrc/manager.hpp b/libGraphite/rsrc/manager.hpp index 6a643ae..1881d60 100644 --- a/libGraphite/rsrc/manager.hpp +++ b/libGraphite/rsrc/manager.hpp @@ -41,7 +41,7 @@ namespace graphite::rsrc static auto shared_manager() -> manager&; - auto import_file(file file) -> class file *; + auto import_file(class file *file) -> class file *; auto import_file(const std::string& path) -> class file *; auto unload_file(class file *file) -> void; @@ -76,7 +76,7 @@ namespace graphite::rsrc return find(T::type_code(), name_prefix, attributes); } - [[nodiscard]] auto all_types(const std::string& type_code, const std::vector& attributes = {}) const -> std::vector; + [[nodiscard]] auto all_types(const std::string& type_code, const std::vector& attributes = {}) const -> std::vector; template [[nodiscard]] auto all_types(const std::vector& attributes = {}) const -> std::vector @@ -94,7 +94,7 @@ namespace graphite::rsrc }; private: - std::unordered_map m_files; + std::unordered_map m_files; manager() = default; }; diff --git a/libGraphite/rsrc/result.cpp b/libGraphite/rsrc/result.cpp index 2b83f91..6be4500 100644 --- a/libGraphite/rsrc/result.cpp +++ b/libGraphite/rsrc/result.cpp @@ -95,7 +95,8 @@ auto graphite::rsrc::resource_result::end() -> iterator auto graphite::rsrc::resource_result::at(std::uint64_t idx) const -> struct resource * { - return m_resources.at(m_sorted_keys.at(idx)); + auto it = m_resources.find(m_sorted_keys.at(idx)); + return (it != m_resources.end()) ? it->second : nullptr; } auto graphite::rsrc::resource_result::id(resource::identifier id) const -> struct resource * @@ -110,7 +111,9 @@ auto graphite::rsrc::resource_result::id(resource::identifier id) const -> struc auto graphite::rsrc::resource_result::resource(const std::string &type_code, resource::identifier id) const -> struct resource * { - return m_resources.at(resource_result::sort_key(type_code, id)); + auto key = resource_result::sort_key(type_code, id); + auto it = m_resources.find(key); + return (it != m_resources.end()) ? it->second : nullptr; } auto graphite::rsrc::resource_result::filter(const std::functionbool>& fn) const -> resource_result diff --git a/libGraphite/rsrc/rez/parser.cpp b/libGraphite/rsrc/rez/parser.cpp index 0a9b58c..e9132a7 100644 --- a/libGraphite/rsrc/rez/parser.cpp +++ b/libGraphite/rsrc/rez/parser.cpp @@ -44,7 +44,7 @@ namespace graphite::rsrc::format::rez::constants auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> bool { - std::vector types; + std::vector types; // 1. Read the preamble if (reader.read_long() != constants::signature) { @@ -94,17 +94,17 @@ auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> boo // 5. Read the resource types. for (auto type_idx = 0; type_idx < type_count; ++type_idx) { auto code = reader.read_cstr(4); - auto type_offset = static_cast(reader.read_long()); + auto type_offset = static_cast(reader.read_long()); auto count = reader.read_long(); - struct type type { code }; + auto type = new struct type(code); reader.save_position(); reader.set_position(map_offset + type_offset); // 6. Read the resource info. for (auto res_idx = 0; res_idx < count; ++res_idx) { auto index = reader.read_long(); - if (code != reader.read_cstr()) { + if (code != reader.read_cstr(4)) { reader.set_position(0); return false; } @@ -118,12 +118,12 @@ auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> boo reader.set_position(next_offset); // 7. Construct a new resource instance and add it to the type. - struct resource resource { &type, id, name, std::move(slice) }; - type.add_resource(resource); + auto resource = new struct resource(type, id, name, std::move(slice)); + type->add_resource(resource); } reader.restore_position(); - types.emplace_back(std::move(type)); + types.emplace_back(type); } file.add_types(types); diff --git a/libGraphite/rsrc/rez/writer.cpp b/libGraphite/rsrc/rez/writer.cpp index e440a9f..9bdf87d 100644 --- a/libGraphite/rsrc/rez/writer.cpp +++ b/libGraphite/rsrc/rez/writer.cpp @@ -88,7 +88,7 @@ auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> for (const auto& resource : *type) { // Get the data for the resource and determine its size. - auto size = resource.data().size(); + auto size = resource->data().size(); writer.write_long(resource_offset); writer.write_long(static_cast(size)); writer.write_long(0); @@ -112,7 +112,7 @@ auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> for (const auto type_hash : file.types()) { auto type = const_cast(file.type(type_hash)); for (const auto& resource : *type) { - writer.write_data(&resource.data()); + writer.write_data(&resource->data()); } } @@ -135,8 +135,8 @@ auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> for (const auto& resource : *type) { writer.write_long(index++); writer.write_cstr(type->code(), 4); - writer.write_signed_short(static_cast(resource.id())); - writer.write_cstr(resource.name(), 256); + writer.write_signed_short(static_cast(resource->id())); + writer.write_cstr(resource->name(), 256); } } diff --git a/libGraphite/rsrc/type.cpp b/libGraphite/rsrc/type.cpp index 6a5bfdf..5a1074c 100644 --- a/libGraphite/rsrc/type.cpp +++ b/libGraphite/rsrc/type.cpp @@ -29,6 +29,13 @@ graphite::rsrc::type::type(const std::string &code) { } +graphite::rsrc::type::~type() +{ + for (auto it : m_resources) { + delete it; + } +} + // MARK: - Accessors auto graphite::rsrc::type::attribute_string(const std::unordered_map &attributes) -> std::string @@ -112,16 +119,16 @@ auto graphite::rsrc::type::has_resource(const std::string &name) const -> bool return (m_resource_name_map.find(hash) != m_resource_name_map.end()); } -auto graphite::rsrc::type::add_resource(resource resource) -> void +auto graphite::rsrc::type::add_resource(resource *resource) -> void { - m_resources.emplace_back(std::move(resource)); + m_resources.emplace_back(resource); + resource->set_type(this); - auto ref = &m_resources.back(); - auto id_hash = resource::hash(ref->id()); - auto name_hash = resource::hash(ref->name()); + auto id_hash = resource::hash(resource->id()); + auto name_hash = resource::hash(resource->name()); - m_resource_id_map.emplace(std::pair(id_hash, ref)); - m_resource_name_map.emplace(std::pair(name_hash, ref)); + m_resource_id_map.emplace(std::pair(id_hash, resource)); + m_resource_name_map.emplace(std::pair(name_hash, resource)); } auto graphite::rsrc::type::remove_resource(resource::identifier id) -> void @@ -132,9 +139,8 @@ auto graphite::rsrc::type::remove_resource(resource::identifier id) -> void auto graphite::rsrc::type::resource_with_id(resource::identifier id) const -> resource * { for (const auto& it : m_resources) { - if (it.id() == id) { - auto ptr = const_cast(&it); - return ptr; + if (it->id() == id) { + return it; } } return nullptr; @@ -143,36 +149,38 @@ auto graphite::rsrc::type::resource_with_id(resource::identifier id) const -> re auto graphite::rsrc::type::resource_with_name(const std::string &name) const -> resource * { for (const auto& it : m_resources) { - if (it.name() == name) { - auto ptr = const_cast(&it); - return ptr; + if (it->name() == name) { + return it; } } return nullptr; } -auto graphite::rsrc::type::begin() -> std::vector::iterator +auto graphite::rsrc::type::begin() -> std::vector::iterator { return m_resources.begin(); } -auto graphite::rsrc::type::end() -> std::vector::iterator +auto graphite::rsrc::type::end() -> std::vector::iterator { return m_resources.end(); } -auto graphite::rsrc::type::at(int64_t idx) -> resource * +auto graphite::rsrc::type::begin() const -> std::vector::const_iterator { - if (idx < 0 || idx >= m_resources.size()) { - return nullptr; - } - return &m_resources.at(idx); + return m_resources.cbegin(); } -auto graphite::rsrc::type::sync_resource_type_references() -> void +auto graphite::rsrc::type::end() const -> std::vector::const_iterator { - for (auto& resource : *this) { - resource.set_type(this); + return m_resources.end(); +} + +auto graphite::rsrc::type::at(int64_t idx) -> resource * +{ + if (idx < 0 || idx >= m_resources.size()) { + return nullptr; } + return m_resources.at(idx); } diff --git a/libGraphite/rsrc/type.hpp b/libGraphite/rsrc/type.hpp index bafa2fc..a42f6d2 100644 --- a/libGraphite/rsrc/type.hpp +++ b/libGraphite/rsrc/type.hpp @@ -35,6 +35,7 @@ namespace graphite::rsrc public: explicit type(const std::string& code); + ~type(); static auto attribute_string(const std::unordered_map& attributes) -> std::string; static auto hash_for_type_code(const std::string& code) -> hash; @@ -54,21 +55,21 @@ namespace graphite::rsrc [[nodiscard]] auto has_resource(resource::identifier id) const -> bool; [[nodiscard]] auto has_resource(const std::string& name) const -> bool; - auto add_resource(resource resource) -> void; + auto add_resource(resource *resource) -> void; auto remove_resource(resource::identifier id) -> void; [[nodiscard]] auto resource_with_id(resource::identifier id) const -> resource *; [[nodiscard]] auto resource_with_name(const std::string& name) const -> resource *; - auto begin() -> std::vector::iterator; - auto end() -> std::vector::iterator; + auto begin() -> std::vector::iterator; + auto end() -> std::vector::iterator; + [[nodiscard]] auto begin() const -> std::vector::const_iterator; + [[nodiscard]] auto end() const-> std::vector::const_iterator; auto at(int64_t idx) -> resource *; - auto sync_resource_type_references() -> void; - private: std::string m_code; - std::vector m_resources; + std::vector m_resources; std::unordered_map m_resource_id_map {}; std::unordered_map m_resource_name_map {}; std::unordered_map m_attributes {}; From 39f8d871dd96c75b50fa63204f597fa4798878cf Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 27 Jun 2022 10:07:35 +0100 Subject: [PATCH 013/113] Start re-introducing some of the QuickTime image codecs. --- libGraphite/compression/packbits.cpp | 12 +- libGraphite/quickdraw/format/cicn.cpp | 18 +-- libGraphite/quickdraw/format/cicn.hpp | 12 +- libGraphite/quickdraw/format/pict.cpp | 41 +++++- libGraphite/quickdraw/format/pict.hpp | 35 ++++- libGraphite/quickdraw/format/ppat.cpp | 2 +- libGraphite/quickdraw/format/ppat.hpp | 2 +- libGraphite/quickdraw/format/rle.cpp | 2 +- libGraphite/quickdraw/format/rle.hpp | 2 +- libGraphite/quicktime/animation.cpp | 138 ++++++++++++++++++ libGraphite/quicktime/animation.hpp | 32 ++++ libGraphite/quicktime/image_description.cpp | 153 ++++++++++++++++++++ libGraphite/quicktime/image_description.hpp | 71 +++++++++ libGraphite/quicktime/planar.cpp | 106 ++++++++++++++ libGraphite/quicktime/planar.hpp | 30 ++++ libGraphite/quicktime/raw.cpp | 62 ++++++++ libGraphite/quicktime/raw.hpp | 30 ++++ libGraphite/sys/types.hpp | 57 ++++++++ 18 files changed, 761 insertions(+), 44 deletions(-) create mode 100644 libGraphite/quicktime/animation.cpp create mode 100644 libGraphite/quicktime/animation.hpp create mode 100644 libGraphite/quicktime/image_description.cpp create mode 100644 libGraphite/quicktime/image_description.hpp create mode 100644 libGraphite/quicktime/planar.cpp create mode 100644 libGraphite/quicktime/planar.hpp create mode 100644 libGraphite/quicktime/raw.cpp create mode 100644 libGraphite/quicktime/raw.hpp create mode 100644 libGraphite/sys/types.hpp diff --git a/libGraphite/compression/packbits.cpp b/libGraphite/compression/packbits.cpp index b05c398..aa1a4fc 100644 --- a/libGraphite/compression/packbits.cpp +++ b/libGraphite/compression/packbits.cpp @@ -27,9 +27,8 @@ auto graphite::compression::packbits::decompress(const data::block &compressed, std::size_t value_size) -> data::block { - data::block decompressed_data; data::reader reader(&compressed); - data::writer writer(&decompressed_data); + data::writer writer; while (!reader.eof()) { auto count = reader.read_byte(); @@ -41,7 +40,12 @@ auto graphite::compression::packbits::decompress(const data::block &compressed, auto data = std::move(reader.read_data(run)); writer.write_data(&data); } - else if (count >= 128) { + else if (value_size == 1) { + // Run of single bytes (fast) + std::uint8_t run = 256 - count + 1; + writer.write_byte(reader.read_byte(), run); + } + else if (count > 128) { std::uint8_t run = 256 - count + 1; for (std::uint8_t i = 0; i < run; ++i) { for (std::uint8_t j = 0; j < value_size; ++j) { @@ -55,7 +59,7 @@ auto graphite::compression::packbits::decompress(const data::block &compressed, } } - return std::move(decompressed_data); + return std::move(*const_cast(writer.data())); } // MARK: - Compression diff --git a/libGraphite/quickdraw/format/cicn.cpp b/libGraphite/quickdraw/format/cicn.cpp index 5afd135..7706583 100644 --- a/libGraphite/quickdraw/format/cicn.cpp +++ b/libGraphite/quickdraw/format/cicn.cpp @@ -46,7 +46,7 @@ graphite::quickdraw::cicn::cicn(quickdraw::surface& surface) // MARK: - Accessors -auto graphite::quickdraw::cicn::surface() const -> const quickdraw::surface& +auto graphite::quickdraw::cicn::surface() -> quickdraw::surface& { return m_surface; } @@ -122,21 +122,7 @@ auto graphite::quickdraw::cicn::encode(data::writer &writer) -> void m_pixmap = pixmap(rect({ 0, 0 }, { width, height })); data::block pmap_data; - if (m_clut.size() > 256) { - throw std::runtime_error("Implementation does not currently handle more than 256 colors in a CICN"); - } - else if (m_clut.size() > 16) { - pmap_data = m_pixmap.build_pixel_data(color_values, 8); - } - else if (m_clut.size() > 4) { - pmap_data = m_pixmap.build_pixel_data(color_values, 4); - } - else if (m_clut.size() > 2) { - pmap_data = m_pixmap.build_pixel_data(color_values, 2); - } - else { - pmap_data = m_pixmap.build_pixel_data(color_values, 1); - } + pmap_data = m_pixmap.build_pixel_data(color_values, m_clut.size()); // Calculate some offsets m_mask_base_address = 4; diff --git a/libGraphite/quickdraw/format/cicn.hpp b/libGraphite/quickdraw/format/cicn.hpp index 2e9e662..b8e934b 100644 --- a/libGraphite/quickdraw/format/cicn.hpp +++ b/libGraphite/quickdraw/format/cicn.hpp @@ -39,20 +39,20 @@ namespace graphite::quickdraw explicit cicn(data::reader& reader); explicit cicn(quickdraw::surface& surface); - [[nodiscard]] auto surface() const -> const surface&; + auto surface() -> surface&; auto encode(data::writer& writer) -> void; auto data() -> data::block; private: - rsrc::resource::identifier m_id; + rsrc::resource::identifier m_id { INT64_MIN }; std::string m_name; quickdraw::pixmap m_pixmap; - std::uint32_t m_mask_base_address; - std::uint16_t m_mask_row_bytes; + std::uint32_t m_mask_base_address { 0 }; + std::uint16_t m_mask_row_bytes { 0 }; rect m_mask_bounds; - std::uint32_t m_bmap_base_address; - std::uint16_t m_bmap_row_bytes; + std::uint32_t m_bmap_base_address { 0 }; + std::uint16_t m_bmap_row_bytes { 0 }; rect m_bmap_bounds; quickdraw::surface m_surface; quickdraw::clut m_clut; diff --git a/libGraphite/quickdraw/format/pict.cpp b/libGraphite/quickdraw/format/pict.cpp index 47444aa..46b2f32 100644 --- a/libGraphite/quickdraw/format/pict.cpp +++ b/libGraphite/quickdraw/format/pict.cpp @@ -22,6 +22,7 @@ #include "libGraphite/quickdraw/support/pixmap.hpp" #include "libGraphite/quickdraw/format/clut.hpp" #include "libGraphite/compression/packbits.hpp" +#include "libGraphite/quicktime/image_description.hpp" // MARK: - Constants @@ -52,7 +53,7 @@ graphite::quickdraw::pict::pict(quickdraw::surface &surface) // MARK: - Accessors -auto graphite::quickdraw::pict::surface() const -> const quickdraw::surface & +auto graphite::quickdraw::pict::surface() -> quickdraw::surface & { return m_surface; } @@ -176,6 +177,17 @@ auto graphite::quickdraw::pict::decode(data::reader &reader) -> void read_short_comment(reader); break; } + case opcode::short_line_from: + case opcode::pen_mode: { + reader.move(2); + break; + } + case opcode::line_from: + case opcode::pen_size: { + reader.move(4); + break; + } + case opcode::short_line: case opcode::rgb_fg_color: case opcode::rgb_bg_color: case opcode::hilite_color: @@ -183,6 +195,22 @@ auto graphite::quickdraw::pict::decode(data::reader &reader) -> void reader.move(6); break; } + case opcode::pen_pattern: + case opcode::fill_pattern: + case opcode::line: + case opcode::frame_rect: + case opcode::paint_rect: + case opcode::erase_rect: + case opcode::invert_rect: + case opcode::fill_rect: + case opcode::frame_same_rect: + case opcode::paint_same_rect: + case opcode::erase_same_rect: + case opcode::invert_same_rect: + case opcode::fill_same_rect: { + reader.move(8); + break; + } case opcode::frame_region: case opcode::paint_region: case opcode::erase_region: @@ -360,8 +388,7 @@ auto graphite::quickdraw::pict::read_direct_bits_rect(data::reader &reader, bool } // Allocate a private memory buffer before going to the surface. - data::block pixel_buffer_data; - data::writer pixel_buffer(&pixel_buffer_data); + data::writer pixel_buffer; std::uint32_t width = source_rect.size.width; std::uint32_t height = source_rect.size.height; std::uint32_t bounds_width = bounds.size.width; @@ -420,7 +447,7 @@ auto graphite::quickdraw::pict::read_direct_bits_rect(data::reader &reader, bool } } - data::reader pixel_buffer_reader(&pixel_buffer_data); + data::reader pixel_buffer_reader(pixel_buffer.data()); if (pack_type == 3) { while (!pixel_buffer_reader.eof()) { auto value = pixel_buffer_reader.read_short(); @@ -460,14 +487,16 @@ auto graphite::quickdraw::pict::read_compressed_quicktime(data::reader &reader) auto mask_size = reader.read_long(); if (matte_size > 0) { - read_image_description(reader); + auto matte = quicktime::image_description(reader); } if (mask_size > 0) { reader.move(mask_size); } - read_image_description(reader); + auto image_description = quicktime::image_description(reader); + m_surface = image_description.surface(); + m_format = static_cast(image_description.compressor()); } auto graphite::quickdraw::pict::read_uncompressed_quicktime(data::reader &reader) -> void diff --git a/libGraphite/quickdraw/format/pict.hpp b/libGraphite/quickdraw/format/pict.hpp index bf4312f..1432db3 100644 --- a/libGraphite/quickdraw/format/pict.hpp +++ b/libGraphite/quickdraw/format/pict.hpp @@ -40,26 +40,43 @@ namespace graphite::quickdraw auto encode(data::writer& writer) -> void; auto data() -> data::block; - [[nodiscard]] auto surface() const -> const quickdraw::surface&; + auto surface() -> quickdraw::surface&; private: enum class opcode : std::uint16_t { nop = 0x0000, clip_region = 0x0001, + pen_size = 0x0007, + pen_mode = 0x0008, + pen_pattern = 0x0009, + fill_pattern = 0x000a, origin = 0x000c, - bits_rect = 0x0090, - bits_region = 0x0091, - pack_bits_rect = 0x0098, - pack_bits_region = 0x0099, - direct_bits_rect = 0x009a, - direct_bits_region = 0x009b, - eof = 0x00ff, rgb_fg_color = 0x001a, rgb_bg_color = 0x001b, hilite_mode = 0x001c, hilite_color = 0x001d, def_hilite = 0x001e, op_color = 0x001f, + line = 0x0020, + line_from = 0x0021, + short_line = 0x0022, + short_line_from = 0x0023, + frame_rect = 0x0030, + paint_rect = 0x0031, + erase_rect = 0x0032, + invert_rect = 0x0033, + fill_rect = 0x0034, + frame_same_rect = 0x0038, + paint_same_rect = 0x0039, + erase_same_rect = 0x003a, + invert_same_rect = 0x003b, + fill_same_rect = 0x003c, + bits_rect = 0x0090, + bits_region = 0x0091, + pack_bits_rect = 0x0098, + pack_bits_region = 0x0099, + direct_bits_rect = 0x009a, + direct_bits_region = 0x009b, frame_region = 0x0080, paint_region = 0x0081, erase_region = 0x0082, @@ -67,6 +84,7 @@ namespace graphite::quickdraw fill_region = 0x0084, short_comment = 0x00a0, long_comment = 0x00a1, + eof = 0x00ff, ext_header = 0x0c00, compressed_quicktime = 0x8200, uncompressed_quicktime = 0x8201, @@ -79,6 +97,7 @@ namespace graphite::quickdraw rect m_frame; point m_dpi; std::size_t m_size; + std::uint32_t m_format { 0 }; auto decode(data::reader& reader) -> void; auto read_region(data::reader& reader) const -> rect; diff --git a/libGraphite/quickdraw/format/ppat.cpp b/libGraphite/quickdraw/format/ppat.cpp index 32198ea..ae760f7 100644 --- a/libGraphite/quickdraw/format/ppat.cpp +++ b/libGraphite/quickdraw/format/ppat.cpp @@ -43,7 +43,7 @@ graphite::quickdraw::ppat::ppat(graphite::quickdraw::surface& surface) // MARK: - Accessors -auto graphite::quickdraw::ppat::surface() const -> const struct surface & +auto graphite::quickdraw::ppat::surface() -> struct surface & { return m_surface; } diff --git a/libGraphite/quickdraw/format/ppat.hpp b/libGraphite/quickdraw/format/ppat.hpp index d13ab4c..ff574ef 100644 --- a/libGraphite/quickdraw/format/ppat.hpp +++ b/libGraphite/quickdraw/format/ppat.hpp @@ -39,7 +39,7 @@ namespace graphite::quickdraw explicit ppat(data::reader& reader); explicit ppat(graphite::quickdraw::surface& surface); - [[nodiscard]] auto surface() const -> const quickdraw::surface&; + auto surface() -> quickdraw::surface&; auto encode(data::writer& writer) -> void; auto data() -> data::block; diff --git a/libGraphite/quickdraw/format/rle.cpp b/libGraphite/quickdraw/format/rle.cpp index 3eac7ab..8bfaa2b 100644 --- a/libGraphite/quickdraw/format/rle.cpp +++ b/libGraphite/quickdraw/format/rle.cpp @@ -57,7 +57,7 @@ graphite::quickdraw::rle::rle(const size &size, std::uint16_t fram // MARK: - Accessors -auto graphite::quickdraw::rle::surface() const -> const quickdraw::surface& +auto graphite::quickdraw::rle::surface() -> quickdraw::surface& { return m_surface; } diff --git a/libGraphite/quickdraw/format/rle.hpp b/libGraphite/quickdraw/format/rle.hpp index f46674a..f83bb8f 100644 --- a/libGraphite/quickdraw/format/rle.hpp +++ b/libGraphite/quickdraw/format/rle.hpp @@ -38,7 +38,7 @@ namespace graphite::quickdraw explicit rle(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); explicit rle(data::reader& reader); - [[nodiscard]] auto surface() const -> const quickdraw::surface&; + auto surface() -> quickdraw::surface&; [[nodiscard]] auto frames() const -> std::vector>; [[nodiscard]] auto frame_count() const -> std::size_t; diff --git a/libGraphite/quicktime/animation.cpp b/libGraphite/quicktime/animation.cpp new file mode 100644 index 0000000..d8decbf --- /dev/null +++ b/libGraphite/quicktime/animation.cpp @@ -0,0 +1,138 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quicktime/animation.hpp" + +auto graphite::quicktime::format::animation::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface +{ + auto depth = desc.depth(); + if (depth < 8) { + // Depths 1, 2, 4 currently unsupported + throw std::runtime_error("Unsupported rle bit depth: " + std::to_string(depth)); + } + auto clut = desc.clut(); + auto surface = quickdraw::surface(desc.width(), desc.height()); + auto chunk_size = reader.read_long(); + auto header = reader.read_short(); + auto y = 0; + if (header & 0x0008) { + y = reader.read_short(); + reader.move(6); + } + + std::int8_t skip; + std::int8_t code; + auto x = 0; + while ((skip = reader.read_byte())) { + x += skip-1; + while (true) { + code = reader.read_signed_byte(); + if (code == 0) { + // No op + break; + } + else if (code == -1) { + // Next line + x = 0; + y++; + break; + } + else if (code > 0) { + // Literal + switch (depth) { + case 8: { + auto raw = reader.read_data(4 * code); + for (auto i = 0; i < 4 * code; ++i) { + auto color = clut.at(raw.get(i)); + surface.set(x++, y, color); + } + break; + } + case 16: { + auto raw = reader.read_data(2 * code); + for (auto i = 0; i < code; ++i) { + auto color = quickdraw::rgb((raw.get(i * 2) << 8) | (raw.get(i * 2 + 1))); + surface.set(x++, y, color); + } + break; + } + case 24: { + auto raw = reader.read_data(3 * code); + for (auto i = 0; i < code; ++i) { + auto color = quickdraw::rgb(raw.get(i * 3), + raw.get(i * 3 + 1), + raw.get(i * 3 + 2)); + surface.set(x++, y, color); + } + break; + } + case 32: { + auto raw = reader.read_data(4 * code); + for (auto i = 0; i < code; ++i) { + auto color = quickdraw::rgb(raw.get(i * 4 + 1), + raw.get(i * 4 + 2), + raw.get(i * 4 + 3), + raw.get(i * 4)); + surface.set(x++, y, color); + } + break; + } + } + } + else { + // Run + switch (depth) { + case 8: { + auto raw = reader.read_data(4); + for (auto i = 0; i < 4 * -code; ++i) { + auto color = clut.at(raw.get(i % 4)); + surface.set(x++, y, color); + } + break; + } + case 16: { + auto color = quickdraw::rgb(reader.read_short()); + for (auto i = 0; i < -code; ++i) { + surface.set(x++, y, color); + } + break; + } + case 24: { + auto color = quickdraw::rgb(reader.read_byte(), reader.read_byte(), reader.read_byte()); + for (auto i = 0; i < -code; ++i) { + surface.set(x++, y, color); + } + break; + } + case 32: { + auto alpha = reader.read_byte(); + auto color = quickdraw::rgb(reader.read_byte(), reader.read_byte(), reader.read_byte(), alpha); + for (auto i = 0; i < -code; ++i) { + surface.set(x++, y, color); + } + break; + } + } + } + } + } + + return std::move(surface); +} diff --git a/libGraphite/quicktime/animation.hpp b/libGraphite/quicktime/animation.hpp new file mode 100644 index 0000000..f3e5230 --- /dev/null +++ b/libGraphite/quicktime/animation.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/data/reader.hpp" +#include "libGraphite/quicktime/image_description.hpp" +#include "libGraphite/quickdraw/support/surface.hpp" + +namespace graphite::quicktime::format::animation +{ + auto decode(const quicktime::image_description& desc, data::reader& reader) -> quickdraw::surface; +} + + diff --git a/libGraphite/quicktime/image_description.cpp b/libGraphite/quicktime/image_description.cpp new file mode 100644 index 0000000..f3137c7 --- /dev/null +++ b/libGraphite/quicktime/image_description.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quicktime/image_description.hpp" +#include "libGraphite/quickdraw/format/pict.hpp" +#include "libGraphite/rsrc/manager.hpp" +#include "libGraphite/quicktime/raw.hpp" +#include "libGraphite/quicktime/animation.hpp" +#include "libGraphite/quicktime/planar.hpp" + +// MARK: - Construction + +graphite::quicktime::image_description::image_description(data::reader &reader) +{ + // http://mirror.informatimago.com/next/developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.17.htm + auto start = reader.position(); + m_length = reader.read_signed_long(); + if (m_length < 86) { + throw std::runtime_error("Invalid QuickTime image description."); + } + + m_compressor = reader.read_enum(); + reader.move(8); + m_version = reader.read_long(); + reader.move(12); + m_width = reader.read_signed_short(); + m_height = reader.read_signed_short(); + reader.move(8); + m_data_size = reader.read_signed_long(); + reader.move(34); + m_depth = reader.read_signed_short(); + if (m_depth > 32) { + m_depth -= 32; // grayscale + } + auto clut = reader.read_signed_short(); + if (clut == 0) { + m_clut = reader.read(); + } else if (clut > 0) { + if (auto resource = rsrc::manager::shared_manager().find(clut)) { + m_clut = quickdraw::clut(resource->data()); + } + else { + throw std::runtime_error("Color table not found: clut " + std::to_string(clut)); + } + } + + // Record the number remaining bytes of the image description before the data start + m_data_offset = m_length - static_cast(reader.position() - start); + decode(reader); +} + +// MARK: - Accessors + +auto graphite::quicktime::image_description::length() const -> std::int32_t +{ + return m_length; +} + +auto graphite::quicktime::image_description::compressor() const -> enum compression_type +{ + return m_compressor; +} + +auto graphite::quicktime::image_description::version() const -> std::uint32_t +{ + return m_version; +} + +auto graphite::quicktime::image_description::width() const -> std::int16_t +{ + return m_width; +} + +auto graphite::quicktime::image_description::height() const -> std::int16_t +{ + return m_height; +} + +auto graphite::quicktime::image_description::data_size() const -> std::int32_t +{ + return m_data_size; +} + +auto graphite::quicktime::image_description::depth() const -> std::int16_t +{ + return m_depth; +} + +auto graphite::quicktime::image_description::data_offset() const -> std::int32_t +{ + return m_data_offset; +} + +auto graphite::quicktime::image_description::clut() const -> const quickdraw::clut& +{ + return m_clut; +} + +auto graphite::quicktime::image_description::surface() const -> const quickdraw::surface& +{ + return m_surface; +} + +// MARK: - Decoding + +auto graphite::quicktime::image_description::decode(data::reader &reader) -> void +{ + switch (m_compressor) { + case compression_type::rle: { + m_surface = std::move(format::animation::decode(*this, reader)); + break; + } + case compression_type::planar: { + m_surface = std::move(format::planar::decode(*this, reader)); + break; + } + case compression_type::raw: { + m_surface = std::move(format::raw::decode(*this, reader)); + break; + } + case compression_type::quickdraw: { + auto pict = reader.read(m_data_size); + m_surface = pict.surface(); + break; + } + default: { + std::string compressor_name; + compressor_name.push_back(m_compressor >> 24); + compressor_name.push_back(m_compressor >> 16); + compressor_name.push_back(m_compressor >> 8); + compressor_name.push_back(m_compressor); + + throw std::runtime_error("Unsupported QuickTime compressor '" + compressor_name + "' at offset " + std::to_string(reader.position())); + } + } +} \ No newline at end of file diff --git a/libGraphite/quicktime/image_description.hpp b/libGraphite/quicktime/image_description.hpp new file mode 100644 index 0000000..0331274 --- /dev/null +++ b/libGraphite/quicktime/image_description.hpp @@ -0,0 +1,71 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/format/clut.hpp" + +namespace graphite::quicktime +{ + struct image_description + { + public: + enum compression_type : std::uint32_t + { + unknown = 0, + rle = 'rle ', + planar = '8BPS', + raw = 'raw ', + quickdraw = 'qdrw', + }; + + public: + image_description() = default; + explicit image_description(data::reader& reader); + + [[nodiscard]] auto length() const -> std::int32_t; + [[nodiscard]] auto compressor() const -> enum compression_type; + [[nodiscard]] auto version() const -> std::uint32_t; + [[nodiscard]] auto width() const -> std::int16_t; + [[nodiscard]] auto height() const -> std::int16_t; + [[nodiscard]] auto data_size() const -> std::int32_t; + [[nodiscard]] auto depth() const -> std::int16_t; + [[nodiscard]] auto data_offset() const -> std::int32_t; + [[nodiscard]] auto clut() const -> const quickdraw::clut&; + [[nodiscard]] auto surface() const -> const quickdraw::surface&; + + private: + std::int32_t m_length { 0 }; + enum compression_type m_compressor { unknown }; + std::uint32_t m_version { 0 }; + std::int16_t m_width { 0 }; + std::int16_t m_height { 0 }; + std::int32_t m_data_size { 0 }; + std::int16_t m_depth { 0 }; + std::int32_t m_data_offset { 0 }; + quickdraw::clut m_clut; + quickdraw::surface m_surface; + + auto decode(data::reader& reader) -> void; + }; +} + + diff --git a/libGraphite/quicktime/planar.cpp b/libGraphite/quicktime/planar.cpp new file mode 100644 index 0000000..5e051bb --- /dev/null +++ b/libGraphite/quicktime/planar.cpp @@ -0,0 +1,106 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quicktime/planar.hpp" +#include "libGraphite/compression/packbits.hpp" + +// MARK: - Decoding + +auto graphite::quicktime::format::planar::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface +{ + auto depth = desc.depth(); + if (depth != 1 && depth != 8 && depth != 24 && depth != 32) { + throw std::runtime_error("Unsupported planar bit depth: " + std::to_string(depth)); + } + + // Parse the remaining atoms to determine the channel count + auto channel_count = 1; + auto remaining = desc.data_offset(); + while (remaining >= 10) { + auto size = reader.read_long(); + auto type = reader.read_long(); + auto value = reader.read_short(); + remaining -= 10; + if (type == 'chct') { + channel_count = value; + } + } + if (remaining > 0) { + reader.move(remaining); + } + + auto width = desc.width(); + auto height = desc.height(); + auto data_size = desc.data_size(); + auto row_bytes = (width * depth + 7) / 8; // +7 to ensure result is rounded up + auto surface = quickdraw::surface(width, height); + + data::block raw; + if (desc.version() == 0) { + raw = reader.read_data(row_bytes * height); + } else { + // Packbits - all counts are stored first + std::vector pack_counts(height * channel_count); + for (auto i=0; i < pack_counts.size(); ++i) { + pack_counts[i] = reader.read_short(); + } + for (auto count : pack_counts) { + raw = reader.read_compressed_data(count); + } + } + + if (depth == 1) { + // Monochrome + for (auto y = 0; y < height; ++y) { + for (auto offset = 0; offset < row_bytes; ++offset) { + auto byte = raw.get(y * row_bytes + offset); + for (auto i = 0; i < 8; ++i) { + auto v = byte & (1 << (7 - i)); + surface.set(offset * 8 + i, y, v ? quickdraw::colors::black() : quickdraw::colors::white()); + } + } + } + } + else if (depth == 8) { + // 8-bit indexed + auto clut = desc.clut(); + for (auto y = 0; y < height; ++y) { + for (auto x = 0; x < width; ++x) { + surface.set(x, y, clut.at(raw.get(y * width + x))); + } + } + } + else if (depth == 24 || depth == 32) { + // Planar RGB + auto plane_size = width * height; + for (auto y=0; y < height; ++y) { + for (auto x=0; x < width; ++x) { + auto color = quickdraw::rgb( + raw.get(y * width + x), + raw.get(y * width + x + plane_size), + raw.get(y * width + x + plane_size * 2) + ); + surface.set(x, y, color); + } + } + } + + return std::move(surface); +} \ No newline at end of file diff --git a/libGraphite/quicktime/planar.hpp b/libGraphite/quicktime/planar.hpp new file mode 100644 index 0000000..9af75a3 --- /dev/null +++ b/libGraphite/quicktime/planar.hpp @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/data/reader.hpp" +#include "libGraphite/quicktime/image_description.hpp" +#include "libGraphite/quickdraw/support/surface.hpp" + +namespace graphite::quicktime::format::planar +{ + auto decode(const quicktime::image_description& desc, data::reader& reader) -> quickdraw::surface; +} diff --git a/libGraphite/quicktime/raw.cpp b/libGraphite/quicktime/raw.cpp new file mode 100644 index 0000000..fe1a152 --- /dev/null +++ b/libGraphite/quicktime/raw.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/quicktime/raw.hpp" + +// MARK: - Decoding + +auto graphite::quicktime::format::raw::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface +{ + auto depth = desc.depth(); + if (depth > 8) { + throw std::runtime_error("Unsupported raw bit depth: " + std::to_string(depth)); + } + auto width = desc.width(); + auto height = desc.height(); + auto clut = desc.clut(); + auto surface = quickdraw::surface(width, height); + + if (depth == 8) { + for (auto y = 0; y < height; ++y) { + for (auto x = 0; x < width; ++x) { + surface.set(x, y, clut.at(reader.read_byte())); + } + } + } + else { + auto pixels_per_byte = 8 / depth; + auto mask = (1 << depth) - 1; + auto row_bytes = desc.data_size() / height; + + for (auto y = 0; y < height; ++y) { + auto x = 0; + auto raw = reader.read_bytes(row_bytes); + for (auto byte : raw) { + for (auto i = 1; i <= pixels_per_byte; ++i) { + auto byte_offset = 8 - (i * depth); + auto v = (byte >> byte_offset) & mask; + surface.set(x++, y, clut.at(v)); + } + } + } + } + + return std::move(surface); +} \ No newline at end of file diff --git a/libGraphite/quicktime/raw.hpp b/libGraphite/quicktime/raw.hpp new file mode 100644 index 0000000..4359c15 --- /dev/null +++ b/libGraphite/quicktime/raw.hpp @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/data/reader.hpp" +#include "libGraphite/quicktime/image_description.hpp" +#include "libGraphite/quickdraw/support/surface.hpp" + +namespace graphite::quicktime::format::raw +{ + auto decode(const quicktime::image_description& desc, data::reader& reader) -> quickdraw::surface; +} \ No newline at end of file diff --git a/libGraphite/sys/types.hpp b/libGraphite/sys/types.hpp new file mode 100644 index 0000000..d194d61 --- /dev/null +++ b/libGraphite/sys/types.hpp @@ -0,0 +1,57 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// MARK: - Helper Macros + +#if defined(GRAPHITE_USE_CAMEL_CASE) +# define GRAPHITE_SYMBOL(_snake, _camel, _posix) _camel +#else +# define GRAPHITE_SYMBOL(_snake, _camel, _posix) _snake +#endif + +// MARK: - Classic Macintosh Integer types + +namespace graphite +{ + typedef signed char GRAPHITE_SYMBOL(sint8, SInt8, int8_t); + typedef unsigned char GRAPHITE_SYMBOL(uint8, UInt8, uint8_t); + typedef signed short GRAPHITE_SYMBOL(sint16, SInt16, int16_t); + typedef unsigned short GRAPHITE_SYMBOL(uint16, UInt16, uint16_t); + typedef signed long GRAPHITE_SYMBOL(sint32, SInt32, int32_t); + typedef unsigned long GRAPHITE_SYMBOL(uint32, UInt32, uint32_t); + typedef signed long long GRAPHITE_SYMBOL(sint64, SInt64, int64_t); + typedef unsigned long long GRAPHITE_SYMBOL(uint64, UInt64, uint64_t); +} + +// MARK: - ResEdit Integer Types + +namespace graphite +{ + typedef signed char DBYT; + typedef unsigned char HBYT; + typedef signed short DWRD; + typedef unsigned short HWRD; + typedef signed long DLNG; + typedef unsigned long HLNG; + typedef signed long long DQWD; + typedef unsigned long long HQWD; +} \ No newline at end of file From 13ffd986e839f72af8a166aa7555394686adb567 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 27 Jun 2022 21:54:07 +0100 Subject: [PATCH 014/113] Fix some sizing issues in PICT decoding. --- libGraphite/compression/packbits.cpp | 118 ------------- libGraphite/compression/packbits.hpp | 106 +++++++++--- libGraphite/data/data.cpp | 8 +- libGraphite/quickdraw/format/pict.cpp | 179 ++++++++------------ libGraphite/quickdraw/support/pixmap.cpp | 10 +- libGraphite/quickdraw/support/pixmap.hpp | 17 +- libGraphite/quickdraw/support/surface.cpp | 10 +- libGraphite/quickdraw/support/surface.hpp | 1 + libGraphite/quickdraw/type/pixel_format.hpp | 2 +- libGraphite/quicktime/planar.cpp | 2 +- 10 files changed, 191 insertions(+), 262 deletions(-) delete mode 100644 libGraphite/compression/packbits.cpp diff --git a/libGraphite/compression/packbits.cpp b/libGraphite/compression/packbits.cpp deleted file mode 100644 index aa1a4fc..0000000 --- a/libGraphite/compression/packbits.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include "libGraphite/compression/packbits.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" - -// MARK: - Decompression - -auto graphite::compression::packbits::decompress(const data::block &compressed, std::size_t value_size) -> data::block -{ - data::reader reader(&compressed); - data::writer writer; - - while (!reader.eof()) { - auto count = reader.read_byte(); - if (count >= 0 && count < 128) { - std::uint16_t run = (1 + count) * value_size; - if ((reader.position() + run) > reader.size()) { - throw std::runtime_error("Unable to decode packbits"); - } - auto data = std::move(reader.read_data(run)); - writer.write_data(&data); - } - else if (value_size == 1) { - // Run of single bytes (fast) - std::uint8_t run = 256 - count + 1; - writer.write_byte(reader.read_byte(), run); - } - else if (count > 128) { - std::uint8_t run = 256 - count + 1; - for (std::uint8_t i = 0; i < run; ++i) { - for (std::uint8_t j = 0; j < value_size; ++j) { - writer.write_byte(reader.read_byte(j, data::reader::mode::peek)); - } - } - reader.move(value_size); - } - else { - // No Operation - } - } - - return std::move(*const_cast(writer.data())); -} - -// MARK: - Compression - -auto graphite::compression::packbits::compress(const data::block &uncompressed) -> data::block -{ - data::block result; - data::block buffer(128); - data::writer writer(&result); - - auto offset = 0; - const auto max = uncompressed.size() - 1; - const auto max_minus_1 = max - 1; - - while (offset <= max) { - // Compressed run - auto run = 1; - auto replicate = uncompressed.get(offset); - while (run < 127 && offset < max && uncompressed.get(offset) == uncompressed.get(offset + 1)) { - ++offset; - ++run; - } - - if (run > 1) { - ++offset; - writer.write_byte(static_cast(-(run - 1))); - writer.write_byte(replicate); - } - - // Literal run - run = 0; - while (run < 128 && ((offset < max && uncompressed.get(offset) != uncompressed.get(offset + 1)) - || (offset < max_minus_1 && uncompressed.get(offset) != uncompressed.get(offset + 2)))) - { - buffer.set(uncompressed.get(offset++), 1, run++); - } - - if (offset == max && run > 0 && run < 128) { - buffer.set(uncompressed.get(offset++), 1, run++); - } - - if (run > 0) { - auto sliced = std::move(buffer.slice(0, run)); - writer.write_byte(run - 1); - writer.write_data(&sliced); - buffer.clear(); - } - - if (offset == max && (run <= 0 || run >= 128)) { - writer.write_byte(0); - writer.write_byte(uncompressed.get(offset++)); - } - } - - return std::move(result); -} \ No newline at end of file diff --git a/libGraphite/compression/packbits.hpp b/libGraphite/compression/packbits.hpp index ef77b09..b8f6614 100644 --- a/libGraphite/compression/packbits.hpp +++ b/libGraphite/compression/packbits.hpp @@ -22,38 +22,102 @@ #include #include "libGraphite/data/data.hpp" +#include "libGraphite/data/writer.hpp" +#include "libGraphite/data/reader.hpp" namespace graphite::compression { + template struct packbits - { - static auto decompress(const data::block& compressed, std::size_t value_size) -> data::block; - static auto compress(const data::block& uncompressed) -> data::block; - }; - - struct packbits8 { static auto decompress(const data::block& compressed) -> data::block { - return std::move(packbits::decompress(compressed, 1)); - } + std::size_t value_size = Bits >> 3; + data::reader reader(&compressed); + data::writer writer; - static auto compress(const data::block& uncompressed) -> data::block - { - return std::move(packbits::compress(uncompressed)); - } - }; + while (!reader.eof()) { + auto count = reader.read_byte(); + if (count < 128) { + std::uint16_t run = (1 + count) * value_size; + if ((reader.position() + run) > reader.size()) { + throw std::runtime_error("Unable to decode packbits"); + } + auto data = std::move(reader.read_data(run)); + writer.write_data(&data); + } + else if (count == 128) { + // No Operation + } + else if (value_size == 1) { + // Run of single bytes (fast) + std::uint8_t run = 256 - count + 1; + writer.write_byte(reader.read_byte(), run); + } + else { + std::uint8_t run = 256 - count + 1; + for (std::uint8_t i = 0; i < run; ++i) { + for (std::uint8_t j = 0; j < value_size; ++j) { + writer.write_byte(reader.read_byte(j, data::reader::mode::peek)); + } + } + reader.move(value_size); + } + } - struct packbits16 - { - static auto decompress(const data::block& compressed) -> data::block - { - return std::move(packbits::decompress(compressed, 2)); + return std::move(*const_cast(writer.data())); } - static auto compress(const data::block& uncompressed) -> data::block - { - return std::move(packbits::compress(uncompressed)); + static auto compress(const data::block& uncompressed) -> data::block { + data::block result; + data::block buffer(128); + data::writer writer(&result); + + auto offset = 0; + const auto max = uncompressed.size() - 1; + const auto max_minus_1 = max - 1; + + while (offset <= max) { + // Compressed run + auto run = 1; + auto replicate = uncompressed.get(offset); + while (run < 127 && offset < max && uncompressed.get(offset) == uncompressed.get(offset + 1)) { + ++offset; + ++run; + } + + if (run > 1) { + ++offset; + writer.write_byte(static_cast(-(run - 1))); + writer.write_byte(replicate); + } + + // Literal run + run = 0; + while (run < 128 && ((offset < max && uncompressed.get(offset) != uncompressed.get(offset + 1)) + || (offset < max_minus_1 && uncompressed.get(offset) != uncompressed.get(offset + 2)))) + { + buffer.set(uncompressed.get(offset++), 1, run++); + } + + if (offset == max && run > 0 && run < 128) { + buffer.set(uncompressed.get(offset++), 1, run++); + } + + if (run > 0) { + auto sliced = std::move(buffer.slice(0, run)); + writer.write_byte(run - 1); + writer.write_data(&sliced); + buffer.clear(); + } + + if (offset == max && (run <= 0 || run >= 128)) { + writer.write_byte(0); + writer.write_byte(uncompressed.get(offset++)); + } + } + + return std::move(result); } }; } \ No newline at end of file diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index a9a72fa..68ad587 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -290,8 +290,9 @@ auto graphite::data::block::copy_from(const block &source) const -> void std::size_t len = std::min(source.size(), size()); std::size_t n = 0; + auto simd_fields_len = simd_fields * simd_field_size; while (n < len) { - if ((reinterpret_cast(source_ptr) & simd_alignment_width) || (len - n) < simd_fields) { + if ((reinterpret_cast(source_ptr) & simd_alignment_width) || (len - n) < simd_fields_len) { *dest_ptr = *source_ptr; ++dest_ptr; ++source_ptr; @@ -314,8 +315,9 @@ static inline auto inline_set(graphite::data::block *dst, union simd_value v, st auto ptr = dst->get(start); std::size_t n = 0; + auto simd_fields_len = simd_fields * simd_field_size; while (n < len) { - if ((reinterpret_cast(ptr) & simd_alignment_width) || (len - n) < simd_fields) { + if ((reinterpret_cast(ptr) & simd_alignment_width) || (len - n) < simd_fields_len) { *ptr = v.fields[n & (simd_fields - 1)]; ++ptr; n += simd_field_size; @@ -364,5 +366,5 @@ auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::positi auto graphite::data::block::slice(block::position pos, std::size_t size, bool copy) const -> block { - return std::move(block(*this, pos, size, copy)); + return std::move(block(*this, m_start_position + pos, size, copy)); } diff --git a/libGraphite/quickdraw/format/pict.cpp b/libGraphite/quickdraw/format/pict.cpp index 46b2f32..0c814ec 100644 --- a/libGraphite/quickdraw/format/pict.cpp +++ b/libGraphite/quickdraw/format/pict.cpp @@ -121,7 +121,6 @@ auto graphite::quickdraw::pict::decode(data::reader &reader) -> void quickdraw::rect clipping_rect; m_size = 0; m_surface = quickdraw::surface(m_frame.size); - auto has_bits = false; while (!reader.eof()) { if (v1) { @@ -241,11 +240,6 @@ auto graphite::quickdraw::pict::decode(data::reader &reader) -> void } } } - - // This is a safety check for QuickTime RLE which is skipped over. If no other image data was found, throw an error. - if (!has_bits) { - throw std::runtime_error("Encountered an incompatible PICT: " + std::to_string(m_id) + ", " + m_name); - } } // MARK: - Encoding @@ -307,7 +301,7 @@ auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bo } else { // Old style Bitmap - pm.set_pack_type(1); + pm.set_pack_type(pixmap::argb); pm.set_component_count(1); pm.set_component_size(1); pm.set_row_bytes(reader.read_short()); @@ -336,7 +330,7 @@ auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bo if (packed) { data::writer raw(&raw_data); for (std::int16_t scanline = 0; scanline < height; ++scanline) { - auto data = reader.read_compressed_data(row_bytes > 250 ? reader.read_short() : reader.read_byte()); + auto data = reader.read_compressed_data>(row_bytes > 250 ? reader.read_short() : reader.read_byte()); raw.write_data(&data); } } @@ -353,123 +347,98 @@ auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bo auto graphite::quickdraw::pict::read_direct_bits_rect(data::reader &reader, bool region) -> void { auto pm = reader.read(); - auto pack_type = pm.pack_type(); - auto component_count = pm.component_count(); - auto color_model = pm.pixel_format(); - auto row_bytes = pm.row_bytes(); - auto bounds = pm.bounds(); + m_format = pm.pixel_size() == 16 ? 16 : pm.component_size() * pm.component_count(); // Read the source and destination bounds auto source_rect = reader.read>(); - auto destinationm_rect = reader.read>(); + auto destination_rect = reader.read>(); + auto transfer_mode = reader.read_short(); if (region) { read_region(reader); } - // Verify the type of PixMap. We can only accept certain types for the time being, until support for decoding - // other types is added. - data::block raw_data; - switch (pack_type) { - case 1: - case 2: - case 3: { - raw_data = data::block(row_bytes); - break; - } - case 4: { - raw_data = data::block(component_count * row_bytes / 4); - break; - } - default: { - throw std::runtime_error("Unsupported pack type " + std::to_string(pack_type) + " encountered in PICT: " - + std::to_string(m_id) + ", " + m_name); - } - } + auto pack_type = pm.pack_type(); + auto component_count = pm.component_count(); + auto color_model = pm.pixel_format(); + auto row_bytes = pm.row_bytes(); + auto bounds = pm.bounds(); - // Allocate a private memory buffer before going to the surface. - data::writer pixel_buffer; - std::uint32_t width = source_rect.size.width; - std::uint32_t height = source_rect.size.height; - std::uint32_t bounds_width = bounds.size.width; - std::uint32_t source_length = width * height; - if (pack_type == 3) { - pixel_buffer.write_short(0, source_length); + // Calculate the bounds of the pixels we need to copy to the surface, clipping to fit if necessary + auto copy_x = destination_rect.origin.x - m_frame.origin.x; + auto copy_y = destination_rect.origin.y - m_frame.origin.y; + auto copy_w = std::min(destination_rect.size.width, static_cast(m_frame.size.width - copy_x)); + auto copy_h = std::min(destination_rect.size.height, static_cast(m_frame.size.height - copy_y)); + + // When row bytes < 8, data is never packed. Raw format will instead match the pixel size, either 16-bit words or + // 32-bit argb. + auto packed = row_bytes >= 8 && pack_type >= pixmap::packbits_word; + if (row_bytes < 8 && pack_type != pixmap::packbits_word) { + pack_type = pixmap::argb; } - else { - pixel_buffer.write_long(0, source_length); + else if (pack_type == pixmap::none || pack_type == pixmap::rgb) { + // Row bytes is always width * 4, but alpha is omitted here so make sure we only read width * 3. + row_bytes = bounds.size.width * 3; } - auto packing_enabled = ((pack_type == 3 ? 2 : 1) + (row_bytes > 250 ? 2 : 1)) <= bounds_width; - - for (std::uint32_t scanline = 0; scanline < height; ++scanline) { - if (pack_type > 2 && packing_enabled) { - if (pack_type == 3) { - raw_data = std::move(reader.read_compressed_data(row_bytes > 250 ? reader.read_short() : reader.read_byte())); + data::block raw_data; + for (auto y = 0; y < copy_h; ++y) { + if (packed) { + auto pack_bytes_count = row_bytes > 250 ? reader.read_short() : reader.read_byte(); + if (pack_type == pixmap::packbits_word) { + raw_data = std::move(reader.read_compressed_data>(pack_bytes_count)); } else { - raw_data = std::move(reader.read_compressed_data(row_bytes > 250 ? reader.read_short() : reader.read_byte())); + raw_data = std::move(reader.read_compressed_data>(pack_bytes_count)); } } else { raw_data = std::move(reader.read_data(row_bytes)); } - if (pack_type == 3) { - for (std::uint32_t x = 0; x < width; ++x) { - pixel_buffer.write_short( - (0xFF& raw_data.get(2 * x + 1)) | ((0xFF & raw_data.get(2 * x)) << 8) - ); - } - } - else if (component_count == 3) { - // RGB Formatted Data - for (std::uint32_t x = 0; x < width; ++x) { - pixel_buffer.write_long( - 0xFF000000 - | ((raw_data.get(x) & 0xFF) << 16) - | ((raw_data.get(bounds_width + x) & 0xFF) << 8) - | (raw_data.get(2 * bounds_width + x) & 0xFF) - ); - } - } - else if (component_count == 4) { - // ARGB Formatted Data - for (std::uint32_t x = 0; x < width; ++x) { - pixel_buffer.write_long( - ((raw_data.get(x) & 0xFF) << 24) - | ((raw_data.get(bounds_width + x) & 0xFF) << 16) - | ((raw_data.get(2 * bounds_width + x) & 0xFF) << 8) - | (raw_data.get(3 * bounds_width + x) & 0xFF) - ); - } - } - } - - data::reader pixel_buffer_reader(pixel_buffer.data()); - if (pack_type == 3) { - while (!pixel_buffer_reader.eof()) { - auto value = pixel_buffer_reader.read_short(); - auto color = rgb( - static_cast(((value & 0x7c00) >> 10) * 0xFF / 0x1F), - static_cast(((value & 0x03e0) >> 5) * 0xFF / 0x1F), - static_cast((value & 0x001f) * 0xFF / 0x1F) - ); - m_surface.set(m_size++, color); - } - } - else { - while (!pixel_buffer_reader.eof()) { - while (!pixel_buffer_reader.eof()) { - auto value = pixel_buffer_reader.read_short(); - auto color = rgb( - static_cast((value & 0xFF0000) >> 16), - static_cast((value & 0xFF00) >> 8), - static_cast(value & 0xFF), - static_cast((value & 0xFF000000) >> 24) - ); - m_surface.set(m_size++, color); + for (auto x = 0; x < copy_w; ++x) { + switch (pack_type) { + case pixmap::none: + case pixmap::rgb: { + m_surface.set(x + copy_x, y + copy_y, rgb( + raw_data.get(3 * x), + raw_data.get(3 * x + 1), + raw_data.get(3 * x + 2) + )); + break; + } + case pixmap::argb: { + m_surface.set(x + copy_x, y + copy_y, rgb( + raw_data.get(4 * x + 1), + raw_data.get(4 * x + 2), + raw_data.get(4 * x + 3) + )); + break; + } + case pixmap::packbits_word: { + m_surface.set(x + copy_x, y + copy_y, rgb( + (raw_data.get(2 * x) << 8) | (raw_data.get(2 * x + 1)) + )); + break; + } + case pixmap::packbits_component: { + if (component_count == 3) { + m_surface.set(x + copy_x, y + copy_y, rgb( + raw_data.get(x), + raw_data.get(bounds.size.width + x), + raw_data.get(2 * bounds.size.width + x) + )); + } + else if (component_count == 4) { + m_surface.set(x + copy_x, y + copy_y, rgb( + raw_data.get(bounds.size.width + x), + raw_data.get(2 * bounds.size.width + x), + raw_data.get(3 * bounds.size.width + x) + )); + } + break; + } } } } @@ -644,7 +613,7 @@ auto graphite::quickdraw::pict::write_direct_bits_rect(data::writer &writer) -> } } - auto packed = std::move(compression::packbits8::compress(scanline_data)); + auto packed = std::move(compression::packbits<8>::compress(scanline_data)); if (pm.row_bytes() > 250) { writer.write_short(packed.size()); } diff --git a/libGraphite/quickdraw/support/pixmap.cpp b/libGraphite/quickdraw/support/pixmap.cpp index 97af90b..c8fd62a 100644 --- a/libGraphite/quickdraw/support/pixmap.cpp +++ b/libGraphite/quickdraw/support/pixmap.cpp @@ -51,7 +51,7 @@ auto graphite::quickdraw::pixmap::row_bytes() const -> std::int16_t return m_row_bytes; } -auto graphite::quickdraw::pixmap::pack_type() const -> std::int16_t +auto graphite::quickdraw::pixmap::pack_type() const -> enum pack_type { return m_pack_type; } @@ -101,7 +101,7 @@ auto graphite::quickdraw::pixmap::set_row_bytes(std::int16_t row_bytes) -> void m_row_bytes = row_bytes; } -auto graphite::quickdraw::pixmap::set_pack_type(std::int16_t pack_type) -> void +auto graphite::quickdraw::pixmap::set_pack_type(enum pack_type pack_type) -> void { m_pack_type = pack_type; } @@ -169,12 +169,12 @@ auto graphite::quickdraw::pixmap::draw_configuration::aspect::expected_data_size auto graphite::quickdraw::pixmap::decode(data::reader &reader) -> void { m_base_address = reader.read_long(); - m_row_bytes = static_cast(static_cast(reader.read_signed_short()) & 0x7FFF); + m_row_bytes = static_cast(reader.read_short() & 0x7FFF); m_bounds = reader.read>(); m_pm_version = reader.read_signed_short(); - m_pack_type = reader.read_signed_short(); + m_pack_type = reader.read_enum(); m_pack_size = reader.read_signed_long(); - m_dpi = reader.read>(); + m_dpi = size::read(reader, coding_type::macintosh); m_pixel_type = reader.read_signed_short(); m_pixel_size = reader.read_signed_short(); m_component_count = reader.read_signed_short(); diff --git a/libGraphite/quickdraw/support/pixmap.hpp b/libGraphite/quickdraw/support/pixmap.hpp index f3ecc8a..6279b01 100644 --- a/libGraphite/quickdraw/support/pixmap.hpp +++ b/libGraphite/quickdraw/support/pixmap.hpp @@ -54,6 +54,15 @@ namespace graphite::quickdraw struct clut *color_table { nullptr }; }; + enum pack_type : std::uint16_t + { + none = 0, + argb = 1, + rgb = 2, + packbits_word = 3, + packbits_component = 4 + }; + public: static constexpr std::size_t length = 50; @@ -70,7 +79,7 @@ namespace graphite::quickdraw [[nodiscard]] auto bounds() const -> rect; [[nodiscard]] auto row_bytes() const -> std::int16_t; - [[nodiscard]] auto pack_type() const -> std::int16_t; + [[nodiscard]] auto pack_type() const -> enum pack_type; [[nodiscard]] auto pack_size() const -> std::int16_t; [[nodiscard]] auto pixel_type() const -> std::int16_t; [[nodiscard]] auto pixel_size() const -> std::int16_t; @@ -83,7 +92,7 @@ namespace graphite::quickdraw auto set_bounds(const rect& rect) -> void; auto set_row_bytes(std::int16_t row_bytes) -> void; - auto set_pack_type(std::int16_t pack_type) -> void; + auto set_pack_type(enum pack_type pack_type) -> void; auto set_pack_size(std::int16_t pack_size) -> void; auto set_pixel_type(std::int16_t pixel_type) -> void; auto set_pixel_size(std::int16_t pixel_size) -> void; @@ -97,8 +106,6 @@ namespace graphite::quickdraw auto build_surface(surface& surface, const data::block& pixel_data, const clut& clut, const rect& destination) -> void; auto build_pixel_data(const data::block& color_data, std::uint16_t pixel_size) -> data::block; - - auto encode(data::writer& writer) -> void; private: @@ -107,7 +114,7 @@ namespace graphite::quickdraw std::int16_t m_row_bytes { 0 }; rect m_bounds; std::int16_t m_pm_version { 0 }; - std::int16_t m_pack_type { 4 }; + enum pack_type m_pack_type { none }; std::int32_t m_pack_size { 0 }; quickdraw::size m_dpi { 0.001098632812 }; std::int16_t m_pixel_type { 16 }; diff --git a/libGraphite/quickdraw/support/surface.cpp b/libGraphite/quickdraw/support/surface.cpp index 992efe3..ea4a6ee 100644 --- a/libGraphite/quickdraw/support/surface.cpp +++ b/libGraphite/quickdraw/support/surface.cpp @@ -24,6 +24,7 @@ graphite::quickdraw::surface::surface(const quickdraw::size &size) : m_size(size), + m_row_bytes(size.width * constants::color_width), m_data(size.width * size.height * constants::color_width) { @@ -31,6 +32,7 @@ graphite::quickdraw::surface::surface(const quickdraw::size &size) graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) : m_size(width, height), + m_row_bytes(width * constants::color_width), m_data(width * height * constants::color_width) { @@ -38,6 +40,7 @@ graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) graphite::quickdraw::surface::surface(const quickdraw::size& size, union color color) : m_size(size), + m_row_bytes(size.width * constants::color_width), m_data(size.width * size.height * constants::color_width) { m_data.set(color.value); @@ -45,6 +48,7 @@ graphite::quickdraw::surface::surface(const quickdraw::size& size, graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, union color color) : m_size(width, height), + m_row_bytes(width * constants::color_width), m_data(width * height * constants::color_width) { m_data.set(color.value); @@ -81,7 +85,7 @@ auto graphite::quickdraw::surface::at(const point &p) const -> uni auto graphite::quickdraw::surface::at(std::int16_t x, std::int16_t y) const -> union color { - return at(y * m_size.width + x); + return at((y * m_row_bytes) + (x * constants::color_width)); } auto graphite::quickdraw::surface::at(std::uint32_t offset) const -> union color @@ -96,10 +100,10 @@ auto graphite::quickdraw::surface::set(const point& p, union color auto graphite::quickdraw::surface::set(std::int16_t x, std::int16_t y, union color color) -> void { - set(y * m_size.width + x, color); + set((y * m_row_bytes) + (x * constants::color_width), color); } auto graphite::quickdraw::surface::set(std::uint32_t offset, union color color) -> void { - m_data.set(color.value, 4, offset); + m_data.set(color.value, constants::color_width, offset); } \ No newline at end of file diff --git a/libGraphite/quickdraw/support/surface.hpp b/libGraphite/quickdraw/support/surface.hpp index 6274c92..5a69c99 100644 --- a/libGraphite/quickdraw/support/surface.hpp +++ b/libGraphite/quickdraw/support/surface.hpp @@ -53,6 +53,7 @@ namespace graphite::quickdraw auto set(std::uint32_t offset, union color color) -> void; private: + std::uint32_t m_row_bytes; quickdraw::size m_size; data::block m_data; }; diff --git a/libGraphite/quickdraw/type/pixel_format.hpp b/libGraphite/quickdraw/type/pixel_format.hpp index 83a185c..c872a3e 100644 --- a/libGraphite/quickdraw/type/pixel_format.hpp +++ b/libGraphite/quickdraw/type/pixel_format.hpp @@ -24,7 +24,7 @@ namespace graphite::quickdraw { - enum pixel_format : std::uint8_t + enum pixel_format : std::uint32_t { unknown = 0x00, monochrome = 0x01, diff --git a/libGraphite/quicktime/planar.cpp b/libGraphite/quicktime/planar.cpp index 5e051bb..f29deb0 100644 --- a/libGraphite/quicktime/planar.cpp +++ b/libGraphite/quicktime/planar.cpp @@ -62,7 +62,7 @@ auto graphite::quicktime::format::planar::decode(const quicktime::image_descript pack_counts[i] = reader.read_short(); } for (auto count : pack_counts) { - raw = reader.read_compressed_data(count); + raw = reader.read_compressed_data>(count); } } From 72ca64a812502847df7e8b0fe2f849c54bd262be Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 29 Jun 2022 08:02:23 +0100 Subject: [PATCH 015/113] More tweaks to functionality. --- libGraphite/quickdraw/format/cicn.cpp | 4 ++ libGraphite/quickdraw/format/pict.cpp | 5 ++- libGraphite/quickdraw/format/rle.cpp | 9 +++-- libGraphite/quickdraw/format/rle.hpp | 2 +- libGraphite/quickdraw/support/surface.cpp | 47 ++++++++++++++++------- libGraphite/quickdraw/support/surface.hpp | 6 ++- libGraphite/rsrc/manager.cpp | 22 +++++++---- libGraphite/rsrc/manager.hpp | 4 +- 8 files changed, 69 insertions(+), 30 deletions(-) diff --git a/libGraphite/quickdraw/format/cicn.cpp b/libGraphite/quickdraw/format/cicn.cpp index 7706583..e670374 100644 --- a/libGraphite/quickdraw/format/cicn.cpp +++ b/libGraphite/quickdraw/format/cicn.cpp @@ -162,6 +162,10 @@ auto graphite::quickdraw::cicn::decode(data::reader &reader) -> void cfg.color_table = &(m_clut = reader.read()); auto pmap_data = reader.read_data(cfg.pixmap.expected_data_size()); + cfg.mask.data = &mask_data; + cfg.bitmap.data = &bmap_data; + cfg.pixmap.data = &pmap_data; + m_surface = quickdraw::surface(cfg.pixmap.bounds.size); if (m_pixmap.total_component_width() == 1) { diff --git a/libGraphite/quickdraw/format/pict.cpp b/libGraphite/quickdraw/format/pict.cpp index 0c814ec..0471498 100644 --- a/libGraphite/quickdraw/format/pict.cpp +++ b/libGraphite/quickdraw/format/pict.cpp @@ -312,6 +312,8 @@ auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bo color_table.set(colors::black()); } + m_format = pm.pixel_size(); + // Read the source and destination bounds auto source_rect = reader.read>(); auto destination_rect = reader.read>(); @@ -328,11 +330,12 @@ auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bo auto height = pm.bounds().size.height; if (packed) { - data::writer raw(&raw_data); + data::writer raw; for (std::int16_t scanline = 0; scanline < height; ++scanline) { auto data = reader.read_compressed_data>(row_bytes > 250 ? reader.read_short() : reader.read_byte()); raw.write_data(&data); } + raw_data = std::move(*raw.data()); } else { raw_data = reader.read_data(row_bytes * height); diff --git a/libGraphite/quickdraw/format/rle.cpp b/libGraphite/quickdraw/format/rle.cpp index 8bfaa2b..39f60e3 100644 --- a/libGraphite/quickdraw/format/rle.cpp +++ b/libGraphite/quickdraw/format/rle.cpp @@ -142,10 +142,10 @@ auto graphite::quickdraw::rle::write_pixel(std::uint32_t pixel, std::uint8_t mas } } -auto graphite::quickdraw::rle::surface_offset(std::uint32_t frame, std::uint64_t offset) -> std::uint64_t +auto graphite::quickdraw::rle::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t { quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); - quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + offset); + quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); return static_cast(p.y * m_surface.size().width + p.x); } @@ -173,7 +173,8 @@ auto graphite::quickdraw::rle::decode(data::reader &reader) -> void // Create the surface in which all frame will be draw to, and other working variables required to parse and decode // the RLE data correctly. - m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, colors::clear()); + m_surface.clear(); rle::opcode opcode = opcode::eof; std::uint64_t position = 0; std::uint32_t row_start = 0; @@ -376,4 +377,4 @@ auto graphite::quickdraw::rle::encode(data::writer &writer) -> void writer.write_enum(opcode::eof); writer.write_triple(0); } -} \ No newline at end of file +} diff --git a/libGraphite/quickdraw/format/rle.hpp b/libGraphite/quickdraw/format/rle.hpp index f83bb8f..64e2447 100644 --- a/libGraphite/quickdraw/format/rle.hpp +++ b/libGraphite/quickdraw/format/rle.hpp @@ -73,7 +73,7 @@ namespace graphite::quickdraw auto decode(data::reader& reader) -> void; - [[nodiscard]] auto surface_offset(std::uint32_t frame, std::uint64_t offset) -> std::uint64_t; + [[nodiscard]] auto surface_offset(std::int32_t frame, std::int32_t offset) -> std::uint64_t; auto write_pixel(std::uint16_t pixel, std::uint8_t mask, std::uint64_t offset) -> void; auto write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void; }; diff --git a/libGraphite/quickdraw/support/surface.cpp b/libGraphite/quickdraw/support/surface.cpp index ea4a6ee..5da798d 100644 --- a/libGraphite/quickdraw/support/surface.cpp +++ b/libGraphite/quickdraw/support/surface.cpp @@ -25,50 +25,62 @@ graphite::quickdraw::surface::surface(const quickdraw::size &size) : m_size(size), m_row_bytes(size.width * constants::color_width), - m_data(size.width * size.height * constants::color_width) + m_data(new data::block(size.width * size.height * constants::color_width)) { - + m_data->set(static_cast(0)); } graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) : m_size(width, height), m_row_bytes(width * constants::color_width), - m_data(width * height * constants::color_width) + m_data(new data::block(width * height * constants::color_width)) { - + m_data->set(static_cast(0)); } graphite::quickdraw::surface::surface(const quickdraw::size& size, union color color) : m_size(size), m_row_bytes(size.width * constants::color_width), - m_data(size.width * size.height * constants::color_width) + m_data(new data::block(size.width * size.height * constants::color_width)) { - m_data.set(color.value); + m_data->set(color.value); } graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, union color color) : m_size(width, height), m_row_bytes(width * constants::color_width), - m_data(width * height * constants::color_width) + m_data(new data::block(width * height * constants::color_width)) { - m_data.set(color.value); + m_data->set(color.value); } graphite::quickdraw::surface::surface(const surface &surface) + : m_size(surface.m_size), + m_row_bytes(surface.m_row_bytes), + m_data(new data::block(*surface.m_data)) { - } graphite::quickdraw::surface::surface(surface &&surface) noexcept + : m_size(surface.m_size), + m_row_bytes(surface.m_row_bytes), + m_data(surface.m_data) { + surface.m_data = nullptr; +} + +// MARK: - Destruction +graphite::quickdraw::surface::~surface() +{ + delete m_data; } // MARK: - Accessors auto graphite::quickdraw::surface::raw() const -> const data::block& { - return m_data; + return *m_data; } auto graphite::quickdraw::surface::size() const -> struct quickdraw::size @@ -85,12 +97,12 @@ auto graphite::quickdraw::surface::at(const point &p) const -> uni auto graphite::quickdraw::surface::at(std::int16_t x, std::int16_t y) const -> union color { - return at((y * m_row_bytes) + (x * constants::color_width)); + return at((y * m_size.width) + x); } auto graphite::quickdraw::surface::at(std::uint32_t offset) const -> union color { - return m_data.get()[offset]; + return m_data->get()[offset * constants::color_width]; } auto graphite::quickdraw::surface::set(const point& p, union color color) -> void @@ -100,10 +112,17 @@ auto graphite::quickdraw::surface::set(const point& p, union color auto graphite::quickdraw::surface::set(std::int16_t x, std::int16_t y, union color color) -> void { - set((y * m_row_bytes) + (x * constants::color_width), color); + set((y * m_size.width) + x, color); } auto graphite::quickdraw::surface::set(std::uint32_t offset, union color color) -> void { - m_data.set(color.value, constants::color_width, offset); + m_data->set(color.value, constants::color_width, offset * constants::color_width); +} + +// MARK: - Operations + +auto graphite::quickdraw::surface::clear() -> void +{ + m_data->set(colors::clear().value); } \ No newline at end of file diff --git a/libGraphite/quickdraw/support/surface.hpp b/libGraphite/quickdraw/support/surface.hpp index 5a69c99..b8fb94b 100644 --- a/libGraphite/quickdraw/support/surface.hpp +++ b/libGraphite/quickdraw/support/surface.hpp @@ -38,6 +38,8 @@ namespace graphite::quickdraw surface(const surface& surface); surface(surface&& surface) noexcept; + ~surface(); + auto operator=(const surface&) -> surface& = default; auto operator=(surface&&) -> surface& = default; @@ -52,9 +54,11 @@ namespace graphite::quickdraw auto set(std::int16_t x, std::int16_t y, union color color) -> void; auto set(std::uint32_t offset, union color color) -> void; + auto clear() -> void; + private: std::uint32_t m_row_bytes; quickdraw::size m_size; - data::block m_data; + data::block *m_data; }; } diff --git a/libGraphite/rsrc/manager.cpp b/libGraphite/rsrc/manager.cpp index 0d3e59b..a1a5898 100644 --- a/libGraphite/rsrc/manager.cpp +++ b/libGraphite/rsrc/manager.cpp @@ -33,6 +33,7 @@ auto graphite::rsrc::manager::shared_manager() -> manager & auto graphite::rsrc::manager::import_file(class file *file) -> class file * { m_files.emplace(std::pair(file->hash_value(), file)); + m_file_load_order.insert(m_file_load_order.begin(), file->hash_value()); return file; } @@ -72,25 +73,30 @@ auto graphite::rsrc::manager::file(file::hash file) -> class file * return nullptr; } +auto graphite::rsrc::manager::file(file::hash file) const -> class file * +{ + auto it = m_files.find(file); + if (it != m_files.end()) { + return it->second; + } + return nullptr; +} + auto graphite::rsrc::manager::file(const std::string &path) -> class file * { return file(file::hash_for_path(path)); } -auto graphite::rsrc::manager::files() const -> std::vector +auto graphite::rsrc::manager::files() const -> const std::vector& { - std::vector files; - for (const auto& it : m_files) { - files.emplace_back(it.first); - } - return std::move(files); + return m_file_load_order; } auto graphite::rsrc::manager::file_references() const -> std::vector { std::vector files; - for (const auto& it : m_files) { - files.emplace_back(it.second); + for (auto hash : this->files()) { + files.emplace_back(this->file(hash)); } return std::move(files); } diff --git a/libGraphite/rsrc/manager.hpp b/libGraphite/rsrc/manager.hpp index 1881d60..1bc1ab0 100644 --- a/libGraphite/rsrc/manager.hpp +++ b/libGraphite/rsrc/manager.hpp @@ -49,9 +49,10 @@ namespace graphite::rsrc auto unload_file(const std::string& path) -> void; auto file(file::hash file) -> class file *; + auto file(file::hash file) const -> class file *; auto file(const std::string& path) -> class file *; - [[nodiscard]] auto files() const -> std::vector; + [[nodiscard]] auto files() const -> const std::vector&; [[nodiscard]] auto file_references() const -> std::vector; [[nodiscard]] auto find(const std::string& type_code, const std::vector& attributes = {}) const -> resource_result; @@ -94,6 +95,7 @@ namespace graphite::rsrc }; private: + std::vector m_file_load_order; std::unordered_map m_files; manager() = default; From 184d55a3089fd48376bfaadddbf5b2db2eaa94e7 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 29 Jun 2022 08:22:13 +0100 Subject: [PATCH 016/113] Bug fixes and improvements to the QuickDraw surface --- libGraphite/quickdraw/support/surface.cpp | 29 +++++++++++++++++++++++ libGraphite/quickdraw/support/surface.hpp | 6 ++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/libGraphite/quickdraw/support/surface.cpp b/libGraphite/quickdraw/support/surface.cpp index 5da798d..cd46bcf 100644 --- a/libGraphite/quickdraw/support/surface.cpp +++ b/libGraphite/quickdraw/support/surface.cpp @@ -76,6 +76,35 @@ graphite::quickdraw::surface::~surface() delete m_data; } +// MARK: - Operators + +auto graphite::quickdraw::surface::operator=(const surface& surface) -> class surface& +{ + if (this == const_cast(&surface)) { + return *this; + } + + m_data = new data::block(*surface.m_data); + m_size = surface.m_size; + m_row_bytes = surface.m_row_bytes; + + return *this; +} + +auto graphite::quickdraw::surface::operator=(class surface&& surface) -> class surface& +{ + if (this != &surface) { + delete m_data; + + m_data = surface.m_data; + m_size = surface.m_size; + m_row_bytes = surface.m_row_bytes; + + surface.m_data = nullptr; + } + return *this; +} + // MARK: - Accessors auto graphite::quickdraw::surface::raw() const -> const data::block& diff --git a/libGraphite/quickdraw/support/surface.hpp b/libGraphite/quickdraw/support/surface.hpp index b8fb94b..710dc35 100644 --- a/libGraphite/quickdraw/support/surface.hpp +++ b/libGraphite/quickdraw/support/surface.hpp @@ -40,8 +40,8 @@ namespace graphite::quickdraw ~surface(); - auto operator=(const surface&) -> surface& = default; - auto operator=(surface&&) -> surface& = default; + auto operator=(const surface&) -> surface&; + auto operator=(surface&&) -> surface&; [[nodiscard]] auto raw() const -> const data::block&; [[nodiscard]] auto size() const -> struct size; @@ -59,6 +59,6 @@ namespace graphite::quickdraw private: std::uint32_t m_row_bytes; quickdraw::size m_size; - data::block *m_data; + data::block *m_data { nullptr }; }; } From 3b449043ccb72c8d69b6db477509b1f6487a110e Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 29 Jun 2022 11:34:22 +0100 Subject: [PATCH 017/113] Further fixes to memory allocations. --- GraphiteTest/main.cpp | 2 +- libGraphite/data/data.cpp | 4 +- libGraphite/quickdraw/format/rle.cpp | 2 +- libGraphite/quickdraw/support/surface.cpp | 10 ++-- libGraphite/rsrc/file.cpp | 67 ++++++++++++++++++++++- libGraphite/rsrc/file.hpp | 7 +++ libGraphite/rsrc/type.cpp | 57 +++++++++++++++++++ libGraphite/rsrc/type.hpp | 6 ++ 8 files changed, 145 insertions(+), 10 deletions(-) diff --git a/GraphiteTest/main.cpp b/GraphiteTest/main.cpp index 729db0d..4a1b848 100644 --- a/GraphiteTest/main.cpp +++ b/GraphiteTest/main.cpp @@ -20,10 +20,10 @@ #include #include "libGraphite/rsrc/manager.hpp" +#include "libGraphite/data/data.hpp" int main(int argc, char const *argv[]) { - auto file = graphite::rsrc::manager::shared_manager().import_file("/Applications/EV Nova.app/Contents/Resources/Nova Files/Nova Data 1.ndat"); return 0; } diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 68ad587..4d03f89 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -174,7 +174,7 @@ graphite::data::block::block(const block &data) m_data_size(data.m_data_size), m_allocation_owner(nullptr), m_start_position(data.m_start_position), - m_users(data.m_users), + m_users(0), m_count(data.m_count), m_byte_order(data.m_byte_order) { @@ -212,7 +212,7 @@ auto graphite::data::block::operator=(const block &data) -> struct block & m_data_size = data.m_data_size; m_allocation_owner = nullptr; m_start_position = data.m_start_position; - m_users = data.m_users; + m_users = 0; m_count = data.m_count; m_byte_order = data.m_byte_order; diff --git a/libGraphite/quickdraw/format/rle.cpp b/libGraphite/quickdraw/format/rle.cpp index 39f60e3..6b19b2e 100644 --- a/libGraphite/quickdraw/format/rle.cpp +++ b/libGraphite/quickdraw/format/rle.cpp @@ -174,7 +174,7 @@ auto graphite::quickdraw::rle::decode(data::reader &reader) -> void // Create the surface in which all frame will be draw to, and other working variables required to parse and decode // the RLE data correctly. m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, colors::clear()); - m_surface.clear(); + rle::opcode opcode = opcode::eof; std::uint64_t position = 0; std::uint32_t row_start = 0; diff --git a/libGraphite/quickdraw/support/surface.cpp b/libGraphite/quickdraw/support/surface.cpp index cd46bcf..b7ee7d7 100644 --- a/libGraphite/quickdraw/support/surface.cpp +++ b/libGraphite/quickdraw/support/surface.cpp @@ -27,7 +27,7 @@ graphite::quickdraw::surface::surface(const quickdraw::size &size) m_row_bytes(size.width * constants::color_width), m_data(new data::block(size.width * size.height * constants::color_width)) { - m_data->set(static_cast(0)); + m_data->set(static_cast(0), m_data->size()); } graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) @@ -35,7 +35,7 @@ graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) m_row_bytes(width * constants::color_width), m_data(new data::block(width * height * constants::color_width)) { - m_data->set(static_cast(0)); + m_data->set(static_cast(0), m_data->size()); } graphite::quickdraw::surface::surface(const quickdraw::size& size, union color color) @@ -43,7 +43,7 @@ graphite::quickdraw::surface::surface(const quickdraw::size& size, m_row_bytes(size.width * constants::color_width), m_data(new data::block(size.width * size.height * constants::color_width)) { - m_data->set(color.value); + m_data->set(color.value, m_data->size()); } graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, union color color) @@ -51,7 +51,7 @@ graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, u m_row_bytes(width * constants::color_width), m_data(new data::block(width * height * constants::color_width)) { - m_data->set(color.value); + m_data->set(color.value, m_data->size()); } graphite::quickdraw::surface::surface(const surface &surface) @@ -153,5 +153,5 @@ auto graphite::quickdraw::surface::set(std::uint32_t offset, union color color) auto graphite::quickdraw::surface::clear() -> void { - m_data->set(colors::clear().value); + m_data->set(colors::clear().value, m_data->size()); } \ No newline at end of file diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 49a5490..ab8eba6 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -36,6 +36,71 @@ graphite::rsrc::file::file(const std::string &path) read(path); } +graphite::rsrc::file::file(const file &file) + : m_format(file.m_format), + m_path(file.m_path), + m_data(new data::block(*file.m_data)) +{ + // Copy the types. + for (const auto& it : file.m_types) { + m_types.emplace(std::pair(it.first, new struct type(*it.second))); + } +} + +graphite::rsrc::file::file(file &&file) noexcept + : m_format(file.m_format), + m_path(std::move(file.m_path)), + m_data(file.m_data), + m_types(std::move(file.m_types)) +{ + file.m_data = nullptr; + file.m_types = {}; +} + +// MARK: - Destruction + +graphite::rsrc::file::~file() +{ + for (auto& it : m_types) { + delete it.second; + } + delete m_data; +} + +// MARK: - Operators + +auto graphite::rsrc::file::operator=(const file &file) -> class file & +{ + if (this == const_cast(&file)) { + return *this; + } + + m_path = file.m_path; + m_format = file.m_format; + m_data = new data::block(*file.m_data); + + // Copy the types. + for (const auto& it : file.m_types) { + m_types.emplace(std::pair(it.first, new struct type(*it.second))); + } + + return *this; +} + +auto graphite::rsrc::file::operator=(file &&file) noexcept -> class file & +{ + if (this != &file) { + m_path = std::move(file.m_path); + m_format = file.m_format; + m_data = file.m_data; + m_types = std::move(file.m_types); + + file.m_data = nullptr; + file.m_types = {}; + } + return *this; +} + // MARK: - Hashing auto graphite::rsrc::file::hash_for_path(const std::string &path) -> hash @@ -177,7 +242,7 @@ auto graphite::rsrc::file::read(const std::string &path) -> void { m_path = path; m_data = new graphite::data::block(m_path); - graphite::data::reader reader { m_data }; + graphite::data::reader reader(m_data); if (rsrc::format::extended::parse(reader, *this)) { m_format = format::extended; diff --git a/libGraphite/rsrc/file.hpp b/libGraphite/rsrc/file.hpp index 7343c53..4a88d67 100644 --- a/libGraphite/rsrc/file.hpp +++ b/libGraphite/rsrc/file.hpp @@ -38,6 +38,13 @@ namespace graphite::rsrc public: file() = default; explicit file(const std::string& path); + file(const file& file); + file(file&& file) noexcept; + + ~file(); + + auto operator=(const file& file) -> class file&; + auto operator=(file&& file) noexcept -> class file&; static auto hash_for_path(const std::string& path) -> hash; diff --git a/libGraphite/rsrc/type.cpp b/libGraphite/rsrc/type.cpp index 5a1074c..ef2b6d5 100644 --- a/libGraphite/rsrc/type.cpp +++ b/libGraphite/rsrc/type.cpp @@ -29,6 +29,29 @@ graphite::rsrc::type::type(const std::string &code) { } +graphite::rsrc::type::type(const type &type) + : m_code(type.m_code), + m_attributes(type.m_attributes) +{ + for (const auto& resource : type.m_resources) { + add_resource(new rsrc::resource(*resource)); + } +} + +graphite::rsrc::type::type(type &&type) noexcept + : m_code(std::move(type.m_code)), + m_resources(std::move(type.m_resources)), + m_resource_id_map(std::move(type.m_resource_id_map)), + m_resource_name_map(std::move(type.m_resource_name_map)), + m_attributes(std::move(type.m_attributes)) +{ + type.m_resources = {}; + type.m_resource_id_map = {}; + type.m_resource_name_map = {}; +} + +// MARK: - Destruction + graphite::rsrc::type::~type() { for (auto it : m_resources) { @@ -36,6 +59,40 @@ graphite::rsrc::type::~type() } } +// MARK: - Operators + +auto graphite::rsrc::type::operator=(const type &type) -> struct type& +{ + if (this == const_cast(&type)) { + return *this; + } + + m_code = type.m_code; + m_attributes = type.m_attributes; + + for (const auto& resource : type.m_resources) { + add_resource(new rsrc::resource(*resource)); + } + + return *this; +} + +auto graphite::rsrc::type::operator=(type &&type) noexcept -> struct type& +{ + if (this != &type) { + m_code = std::move(type.m_code); + m_resources = std::move(type.m_resources); + m_resource_id_map = std::move(type.m_resource_id_map); + m_resource_name_map = std::move(type.m_resource_name_map); + m_attributes = std::move(type.m_attributes); + + type.m_resources = {}; + type.m_resource_id_map = {}; + type.m_resource_name_map = {}; + } + return *this; +} + // MARK: - Accessors auto graphite::rsrc::type::attribute_string(const std::unordered_map &attributes) -> std::string diff --git a/libGraphite/rsrc/type.hpp b/libGraphite/rsrc/type.hpp index a42f6d2..9ab30b5 100644 --- a/libGraphite/rsrc/type.hpp +++ b/libGraphite/rsrc/type.hpp @@ -35,8 +35,14 @@ namespace graphite::rsrc public: explicit type(const std::string& code); + type(const type& type); + type(type&& type) noexcept; + ~type(); + auto operator=(const type& type) -> struct type&; + auto operator=(type&& type) noexcept -> struct type&; + static auto attribute_string(const std::unordered_map& attributes) -> std::string; static auto hash_for_type_code(const std::string& code) -> hash; static auto hash_for_type_code(const std::string& code, const std::unordered_map& attributes) -> hash; From 7904877738876894973b80849c43fa25985aece6 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 29 Jun 2022 21:44:45 +0100 Subject: [PATCH 018/113] Fix to data::writer space expansion. --- libGraphite/data/writer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libGraphite/data/writer.cpp b/libGraphite/data/writer.cpp index 19d50bc..c6d707a 100644 --- a/libGraphite/data/writer.cpp +++ b/libGraphite/data/writer.cpp @@ -70,11 +70,11 @@ auto graphite::data::writer::expand_storage(std::size_t amount) -> void auto graphite::data::writer::ensure_required_space(block::position position, std::size_t amount) -> void { auto remaining = static_cast(this->size()) - position; - auto delta = amount; + auto delta = 0; if (amount > remaining) { - delta -= remaining; + delta = amount - remaining; + expand_storage(delta); } - expand_storage(delta); } // MARK: - Position Management From b4a2b7f50efb41e4b2f6192403b0799870136aa8 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 6 Jul 2022 08:36:23 +0100 Subject: [PATCH 019/113] Various fixes to decoding and resource finding --- libGraphite/data/reader.cpp | 4 ++-- .../quickdraw/support/drawing/monochrome.cpp | 4 ++-- libGraphite/rsrc/file.cpp | 22 ++++++++++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/libGraphite/data/reader.cpp b/libGraphite/data/reader.cpp index 48e4fb4..43bc0cc 100644 --- a/libGraphite/data/reader.cpp +++ b/libGraphite/data/reader.cpp @@ -134,11 +134,11 @@ auto graphite::data::reader::read_pstr(block::position offset, mode mode) -> std switch (mode) { case mode::advance: { auto length = read_byte(offset, mode); - return read_cstr(length, 0, mode); + return length == 0 ? "" : read_cstr(length, 0, mode); } case mode::peek: { auto length = read_byte(offset, mode); - return read_cstr(length, offset + 1, mode); + return length == 0 ? "" : read_cstr(length, offset + 1, mode); } default: { return ""; diff --git a/libGraphite/quickdraw/support/drawing/monochrome.cpp b/libGraphite/quickdraw/support/drawing/monochrome.cpp index 66319bf..09c4e29 100644 --- a/libGraphite/quickdraw/support/drawing/monochrome.cpp +++ b/libGraphite/quickdraw/support/drawing/monochrome.cpp @@ -35,7 +35,7 @@ auto graphite::quickdraw::drawing::monochrome::pixmap::draw(const quickdraw::pix for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { auto y_offset = y * cfg.pixmap.row_bytes; for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { - auto byte_offset = y - (x % CHAR_BIT); + auto byte_offset = 7 - (x % CHAR_BIT); auto byte = cfg.pixmap.data->get(y_offset + (x / CHAR_BIT)); auto value = (byte >> byte_offset) & 0x1; surface.set(x, y, cfg.color_table->at(value)); @@ -49,7 +49,7 @@ auto graphite::quickdraw::drawing::monochrome::pixmap::draw_masked(const quickdr auto y_offset = y * cfg.pixmap.row_bytes; auto mask_y_offset = y * cfg.mask.row_bytes; for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { - auto byte_offset = y - (x % CHAR_BIT); + auto byte_offset = 7 - (x % CHAR_BIT); auto byte = cfg.pixmap.data->get(y_offset + (x / CHAR_BIT)); auto mask = cfg.mask.data->get(mask_y_offset + (x / CHAR_BIT)); auto value = (byte >> byte_offset) & 0x1; diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index ab8eba6..62d4a26 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -206,13 +206,29 @@ auto graphite::rsrc::file::type(const std::string &code, const std::unordered_ma auto graphite::rsrc::file::type(const std::string& code, const std::vector& attributes) const -> const struct type * { + bool universal_namespace = false; std::unordered_map attributes_map; for (const auto& it : attributes) { - attributes_map.emplace(std::pair(it.hash_value(), it)); + if (it.name() == "namespace" && it.string_value() == "*") { + universal_namespace = true; + } + else { + attributes_map.emplace(std::pair(it.hash_value(), it)); + } } - auto it = m_types.find(type::hash_for_type_code(code, attributes_map)); - return (it == m_types.end()) ? nullptr : it->second; + if (universal_namespace) { + // TODO: Merge types together so that we can browse all namespaces. + for (const auto& it : m_types) { + if (it.second->code() == code) { + return it.second; + } + } + } + else { + auto it = m_types.find(type::hash_for_type_code(code, attributes_map)); + return (it == m_types.end()) ? nullptr : it->second; + } } auto graphite::rsrc::file::type(const std::string& code) const -> const struct type * From 8bf5a4fe719030b11b6cc27943dc3f84b129e15b Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 7 Jul 2022 15:56:41 +0100 Subject: [PATCH 020/113] Addition to data::block ownership model. --- libGraphite/data/data.cpp | 42 +++++++++++++++++++++++++++++++-------- libGraphite/data/data.hpp | 2 ++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 4d03f89..4e1ee14 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -92,13 +92,15 @@ graphite::data::block::block(std::size_t capacity, enum byte_order order) m_raw(malloc(m_raw_size)), m_data(simd_align(m_raw)), m_allocation_owner(nullptr), - m_byte_order(order) + m_byte_order(order), + m_has_ownership(true) { } graphite::data::block::block(const std::string &path, enum byte_order order) : m_byte_order(order), - m_allocation_owner(nullptr) + m_allocation_owner(nullptr), + m_has_ownership(true) { std::ifstream file { path, std::ios::binary }; if (!file.is_open() || file.fail()) { @@ -120,7 +122,8 @@ graphite::data::block::block(const std::string &path, enum byte_order order) graphite::data::block::block(const std::vector& bytes, enum byte_order order) : m_byte_order(order), - m_allocation_owner(nullptr) + m_allocation_owner(nullptr), + m_has_ownership(true) { m_data_size = bytes.size(); m_raw_size = simd_expand_capacity(m_data_size); @@ -140,7 +143,8 @@ graphite::data::block::block(const block &source, bool copy) m_start_position(source.m_start_position), m_count(source.m_count), m_byte_order(source.m_byte_order), - m_allocation_owner(copy ? nullptr : &source) + m_allocation_owner(copy ? nullptr : &source), + m_has_ownership(copy) { clone_from(source); } @@ -156,6 +160,7 @@ graphite::data::block::block(const block &source, block::position pos, std::size m_data_size = source.m_data_size; m_start_position = pos; m_count = amount; + m_has_ownership = false; const_cast(m_allocation_owner)->m_users++; } @@ -166,9 +171,23 @@ graphite::data::block::block(const block &source, block::position pos, std::size m_data = simd_align(m_raw); m_start_position = 0; m_count = 0; + m_has_ownership = true; } } +graphite::data::block::block(const void *data, std::size_t count, bool take_ownership, enum byte_order order) + : m_allocation_owner(nullptr), + m_has_ownership(take_ownership), + m_raw(const_cast(data)), + m_data(const_cast(data)), + m_raw_size(count), + m_data_size(count), + m_start_position(0), + m_count(count), + m_byte_order(order) +{ +} + graphite::data::block::block(const block &data) : m_raw_size(data.m_raw_size), m_data_size(data.m_data_size), @@ -176,7 +195,8 @@ graphite::data::block::block(const block &data) m_start_position(data.m_start_position), m_users(0), m_count(data.m_count), - m_byte_order(data.m_byte_order) + m_byte_order(data.m_byte_order), + m_has_ownership(data.m_has_ownership) { m_raw = malloc(m_raw_size); m_data = simd_align(m_raw); @@ -192,7 +212,8 @@ graphite::data::block::block(block &&data) noexcept m_start_position(data.m_start_position), m_users(data.m_users), m_count(data.m_count), - m_byte_order(data.m_byte_order) + m_byte_order(data.m_byte_order), + m_has_ownership(data.m_has_ownership) { data.m_raw = nullptr; data.m_data = nullptr; @@ -215,6 +236,7 @@ auto graphite::data::block::operator=(const block &data) -> struct block & m_users = 0; m_count = data.m_count; m_byte_order = data.m_byte_order; + m_has_ownership = true; m_raw = malloc(m_raw_size); m_data = simd_align(m_raw); @@ -230,7 +252,7 @@ auto graphite::data::block::operator=(block &&data) noexcept -> struct block & if (m_allocation_owner) { const_cast(m_allocation_owner)->m_users--; } - else if (!m_allocation_owner) { + else if (!m_allocation_owner || m_has_ownership) { assert(m_users == 0); free(m_raw); } @@ -245,10 +267,12 @@ auto graphite::data::block::operator=(block &&data) noexcept -> struct block & m_users = data.m_users; m_count = data.m_count; m_byte_order = data.m_byte_order; + m_has_ownership = data.m_has_ownership; data.m_allocation_owner = nullptr; data.m_raw = nullptr; data.m_data = nullptr; + data.m_has_ownership = false; } return *this; @@ -261,7 +285,7 @@ graphite::data::block::~block() if (m_allocation_owner) { const_cast(m_allocation_owner)->m_users--; } - else if (!m_allocation_owner) { + else if (!m_allocation_owner || m_has_ownership) { assert(m_users == 0); free(m_raw); } @@ -274,11 +298,13 @@ auto graphite::data::block::clone_from(const graphite::data::block &source) -> v if (m_allocation_owner) { m_raw = source.m_raw; m_data = source.m_data; + m_has_ownership = false; const_cast(m_allocation_owner)->m_users++; } else { m_raw = malloc(m_raw_size); m_data = simd_align(m_raw); + m_has_ownership = true; copy_from(source); } } diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index 68e6673..87bf7ec 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -59,6 +59,7 @@ namespace graphite::data explicit block(std::size_t capacity, enum byte_order order = byte_order::msb); explicit block(const std::string& path, enum byte_order order = byte_order::msb); explicit block(const std::vector& bytes, enum byte_order order = byte_order::msb); + block(const void *data, std::size_t count, bool take_ownership = true, enum byte_order order = byte_order::msb); block(const block& source); block(const block& source, bool copy); block(const block& source, block::position pos, std::size_t count, bool copy = true); @@ -108,6 +109,7 @@ namespace graphite::data void *m_raw { nullptr }; void *m_data { nullptr }; + bool m_has_ownership { false }; const block *m_allocation_owner { nullptr }; std::uint32_t m_users { 0 }; From 21da95d61a5ebe9b2dba7ff02bde6b2b6fd3054d Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 7 Jul 2022 19:42:20 +0100 Subject: [PATCH 021/113] Adjustments to data::block ownership model --- libGraphite/data/data.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 4e1ee14..43741e0 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -252,7 +252,7 @@ auto graphite::data::block::operator=(block &&data) noexcept -> struct block & if (m_allocation_owner) { const_cast(m_allocation_owner)->m_users--; } - else if (!m_allocation_owner || m_has_ownership) { + else if ((!m_allocation_owner && m_has_ownership) || m_has_ownership) { assert(m_users == 0); free(m_raw); } @@ -285,7 +285,7 @@ graphite::data::block::~block() if (m_allocation_owner) { const_cast(m_allocation_owner)->m_users--; } - else if (!m_allocation_owner || m_has_ownership) { + else if ((!m_allocation_owner && m_has_ownership) || m_has_ownership) { assert(m_users == 0); free(m_raw); } From eb2812450d491d09076e4f92cb9eaf8c3b27d54a Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 7 Jul 2022 22:35:52 +0100 Subject: [PATCH 022/113] Fix a warning in rsrc::file. --- libGraphite/rsrc/file.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 62d4a26..916993f 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -229,6 +229,8 @@ auto graphite::rsrc::file::type(const std::string& code, const std::vectorsecond; } + + return nullptr; } auto graphite::rsrc::file::type(const std::string& code) const -> const struct type * From c2f08fd2a153fab7a5831dee7297a10d474dbe98 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 09:17:37 +0100 Subject: [PATCH 023/113] Fix compile issues, stop compiling with macOS 10.15 and add macOS 12 --- .github/workflows/build.yml | 2 +- libGraphite/data/data.cpp | 1 + libGraphite/data/writer.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a5f1a89..a80c009 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: name: Build on macOS strategy: matrix: - os: [ macos-10.15, macos-11 ] + os: [ macos-11, macos-12 ] runs-on: ${{ matrix.os }} steps: - name: Checkout diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 43741e0..219aa0c 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "libGraphite/data/data.hpp" // MARK: - SIMD Support diff --git a/libGraphite/data/writer.cpp b/libGraphite/data/writer.cpp index c6d707a..bb22dec 100644 --- a/libGraphite/data/writer.cpp +++ b/libGraphite/data/writer.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "libGraphite/data/writer.hpp" #include "libGraphite/encoding/macroman/macroman.hpp" From 46cfe71d50f9b9c5dd0b5570f826bab25a5ed30d Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 09:53:29 +0100 Subject: [PATCH 024/113] Fix CHAR_BIT missing symbol on Linux and Windows. --- libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp | 3 --- libGraphite/quickdraw/support/drawing/depth_4bpp.cpp | 3 --- libGraphite/quickdraw/support/drawing/monochrome.cpp | 1 + libGraphite/quickdraw/support/drawing/true_color.cpp | 6 +++--- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp b/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp index a7eba88..f97446b 100644 --- a/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp +++ b/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp @@ -18,12 +18,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - #include "libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp" #include "libGraphite/data/data.hpp" -static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); - // MARK: - Drawing auto graphite::quickdraw::drawing::depth_2bpp::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void diff --git a/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp b/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp index 9954561..cd4564a 100644 --- a/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp +++ b/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp @@ -18,12 +18,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - #include "libGraphite/quickdraw/support/drawing/depth_4bpp.hpp" #include "libGraphite/data/data.hpp" -static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); - // MARK: - Drawing auto graphite::quickdraw::drawing::depth_4bpp::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void diff --git a/libGraphite/quickdraw/support/drawing/monochrome.cpp b/libGraphite/quickdraw/support/drawing/monochrome.cpp index 09c4e29..d57a896 100644 --- a/libGraphite/quickdraw/support/drawing/monochrome.cpp +++ b/libGraphite/quickdraw/support/drawing/monochrome.cpp @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include #include "libGraphite/quickdraw/support/drawing/monochrome.hpp" #include "libGraphite/data/data.hpp" diff --git a/libGraphite/quickdraw/support/drawing/true_color.cpp b/libGraphite/quickdraw/support/drawing/true_color.cpp index 9ac75f1..aa7350c 100644 --- a/libGraphite/quickdraw/support/drawing/true_color.cpp +++ b/libGraphite/quickdraw/support/drawing/true_color.cpp @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - +#include #include "libGraphite/quickdraw/support/drawing/true_color.hpp" #include "libGraphite/data/data.hpp" @@ -50,10 +50,10 @@ auto graphite::quickdraw::drawing::true_color::pixmap::draw_masked(const quickdr auto mask_y_offset = y * cfg.mask.row_bytes; for (std::int16_t x = 0; x < cfg.pixmap.bounds.size.width; ++x) { - auto mask_offset = (7 - (x % 8)); + auto mask_offset = (7 - (x % CHAR_BIT)); auto byte = cfg.pixmap.data->get(y_offset + x); - auto mask = cfg.mask.data->get(mask_y_offset + (x / 8)); + auto mask = cfg.mask.data->get(mask_y_offset + (x / CHAR_BIT)); if ((mask >> mask_offset) & 0x1) { surface.set(x, y, cfg.color_table->at(byte)); From fa6abef28b2b779ca8c064a9a9cb09ee744eae28 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 09:56:06 +0100 Subject: [PATCH 025/113] Another CHAR_BIT fix. --- libGraphite/quickdraw/support/drawing/monochrome.cpp | 6 +++++- libGraphite/quickdraw/support/drawing/true_color.cpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libGraphite/quickdraw/support/drawing/monochrome.cpp b/libGraphite/quickdraw/support/drawing/monochrome.cpp index d57a896..442d1e4 100644 --- a/libGraphite/quickdraw/support/drawing/monochrome.cpp +++ b/libGraphite/quickdraw/support/drawing/monochrome.cpp @@ -22,7 +22,11 @@ #include "libGraphite/quickdraw/support/drawing/monochrome.hpp" #include "libGraphite/data/data.hpp" -static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); +#if defined(CHAR_BIT) + static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); +#else +# define CHAR_BIT 8 +#endif // MARK: - Drawing diff --git a/libGraphite/quickdraw/support/drawing/true_color.cpp b/libGraphite/quickdraw/support/drawing/true_color.cpp index aa7350c..411161a 100644 --- a/libGraphite/quickdraw/support/drawing/true_color.cpp +++ b/libGraphite/quickdraw/support/drawing/true_color.cpp @@ -22,7 +22,11 @@ #include "libGraphite/quickdraw/support/drawing/true_color.hpp" #include "libGraphite/data/data.hpp" -static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); +#if defined(CHAR_BIT) + static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); +#else +# define CHAR_BIT 8 +#endif // MARK: - Drawing From d31118c3021a1e4b3421d35e59fd653c326a1098 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 09:57:51 +0100 Subject: [PATCH 026/113] Missing std::function on Linux/Windows --- libGraphite/rsrc/result.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libGraphite/rsrc/result.hpp b/libGraphite/rsrc/result.hpp index 54b17da..1b6daa9 100644 --- a/libGraphite/rsrc/result.hpp +++ b/libGraphite/rsrc/result.hpp @@ -20,9 +20,10 @@ #pragma once -#include #include #include +#include +#include #include "libGraphite/rsrc/resource.hpp" namespace graphite::rsrc @@ -68,7 +69,7 @@ namespace graphite::rsrc resource_result *m_ptr { nullptr }; std::uint64_t m_index { 0 }; - auto get() const -> pointer + [[nodiscard]] auto get() const -> pointer { if (m_index == std::numeric_limits::max()) { return nullptr; From c8df2f406ad4635dbe56c4ae83a1a626173a2204 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 10:02:37 +0100 Subject: [PATCH 027/113] More fixes for Linux and Windows. --- libGraphite/rsrc/attribute.cpp | 12 ------------ libGraphite/rsrc/attribute.hpp | 9 ++++++--- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/libGraphite/rsrc/attribute.cpp b/libGraphite/rsrc/attribute.cpp index 32e039f..01ac965 100644 --- a/libGraphite/rsrc/attribute.cpp +++ b/libGraphite/rsrc/attribute.cpp @@ -28,12 +28,6 @@ graphite::rsrc::attribute::attribute(const std::string &name, const std::string { } -template::value>::type*> -graphite::rsrc::attribute::attribute(const std::string &name, T value) - : m_name(name), m_value(std::to_string(value)) -{ -} - // MARK: - Accessors auto graphite::rsrc::attribute::hash_value() const -> hash @@ -51,12 +45,6 @@ auto graphite::rsrc::attribute::string_value() const -> const std::string& return m_value; } -template::value>::type*> -auto graphite::rsrc::attribute::value() const -> T -{ - return std::to_integer(m_value); -} - // MARK: - Helpers auto graphite::rsrc::attribute::hash_for_name(const std::string& name) -> hash diff --git a/libGraphite/rsrc/attribute.hpp b/libGraphite/rsrc/attribute.hpp index 65f47e5..d75cad9 100644 --- a/libGraphite/rsrc/attribute.hpp +++ b/libGraphite/rsrc/attribute.hpp @@ -36,14 +36,17 @@ namespace graphite::rsrc attribute(const std::string& name, const std::string& value); template::value>::type* = nullptr> - attribute(const std::string& name, T value); + attribute(const std::string& name, T value) : m_name(name), m_value(std::to_string(value)) {} [[nodiscard]] auto hash_value() const -> hash; [[nodiscard]] auto name() const -> const std::string&; [[nodiscard]] auto string_value() const -> const std::string&; - template::value>::type* = nullptr> - [[nodiscard]] auto value() const -> T; + template::value>::type* = nullptr> + [[nodiscard]] auto value() const -> T + { + return std::to_integer(m_value); + } private: std::string m_name; From 15f9e3deea0e590f60e3911e803e37df855eee29 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 10:10:37 +0100 Subject: [PATCH 028/113] Another small fix. --- libGraphite/rsrc/attribute.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libGraphite/rsrc/attribute.hpp b/libGraphite/rsrc/attribute.hpp index d75cad9..a625cc9 100644 --- a/libGraphite/rsrc/attribute.hpp +++ b/libGraphite/rsrc/attribute.hpp @@ -45,7 +45,7 @@ namespace graphite::rsrc template::value>::type* = nullptr> [[nodiscard]] auto value() const -> T { - return std::to_integer(m_value); + return std::to_integer(std::stoi(m_value)); } private: From 07f2ea070051fcaa47befe1025451415cf97ef51 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 10:11:54 +0100 Subject: [PATCH 029/113] Redo previous fix --- libGraphite/rsrc/attribute.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libGraphite/rsrc/attribute.hpp b/libGraphite/rsrc/attribute.hpp index a625cc9..cd553d8 100644 --- a/libGraphite/rsrc/attribute.hpp +++ b/libGraphite/rsrc/attribute.hpp @@ -45,7 +45,7 @@ namespace graphite::rsrc template::value>::type* = nullptr> [[nodiscard]] auto value() const -> T { - return std::to_integer(std::stoi(m_value)); + return std::stoi(m_value); } private: From bdeb942fc747831a54fcfb7ef62c18e813da1da4 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 10:18:19 +0100 Subject: [PATCH 030/113] Fix for Windows --- libGraphite/rsrc/result.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libGraphite/rsrc/result.cpp b/libGraphite/rsrc/result.cpp index 6be4500..0546ba1 100644 --- a/libGraphite/rsrc/result.cpp +++ b/libGraphite/rsrc/result.cpp @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include #include "libGraphite/rsrc/result.hpp" #include "libGraphite/rsrc/resource.hpp" #include "libGraphite/util/hashing.hpp" From 578ec3d7b9be0db634bc7d5096900a22db3d35ae Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 10:23:51 +0100 Subject: [PATCH 031/113] Another Windows Fix --- libGraphite/rsrc/result.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libGraphite/rsrc/result.hpp b/libGraphite/rsrc/result.hpp index 1b6daa9..044b6cf 100644 --- a/libGraphite/rsrc/result.hpp +++ b/libGraphite/rsrc/result.hpp @@ -20,6 +20,7 @@ #pragma once +#include #include #include #include From 8fc603f15b82c6269365030d123d780a75ee1a1c Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 10:28:40 +0100 Subject: [PATCH 032/113] Fix to the IMA4 decoder --- libGraphite/sound/codec/ima4.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libGraphite/sound/codec/ima4.cpp b/libGraphite/sound/codec/ima4.cpp index 4c931f3..8eddee6 100644 --- a/libGraphite/sound/codec/ima4.cpp +++ b/libGraphite/sound/codec/ima4.cpp @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include #include "libGraphite/sound/codec/ima4.hpp" #include "libGraphite/data/writer.hpp" From ccb34a2694a1b0a25307d308637bad5e0d7c45b2 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 15:04:09 +0100 Subject: [PATCH 033/113] Move the RLE resource into a SpriteWorld specific namespace. --- .../{quickdraw/format => spriteworld}/rle.cpp | 54 +++++++++---------- .../{quickdraw/format => spriteworld}/rle.hpp | 16 +++--- 2 files changed, 36 insertions(+), 34 deletions(-) rename libGraphite/{quickdraw/format => spriteworld}/rle.cpp (85%) rename libGraphite/{quickdraw/format => spriteworld}/rle.hpp (86%) diff --git a/libGraphite/quickdraw/format/rle.cpp b/libGraphite/spriteworld/rle.cpp similarity index 85% rename from libGraphite/quickdraw/format/rle.cpp rename to libGraphite/spriteworld/rle.cpp index 6b19b2e..64e3436 100644 --- a/libGraphite/quickdraw/format/rle.cpp +++ b/libGraphite/spriteworld/rle.cpp @@ -18,12 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/format/rle.hpp" +#include "libGraphite/spriteworld/rle.hpp" #include // MARK: - Constants -namespace graphite::quickdraw::constants +namespace graphite::spriteworld::constants { static constexpr std::uint16_t rle_grid_width = 6; static constexpr std::size_t advance = 2; @@ -31,19 +31,19 @@ namespace graphite::quickdraw::constants // MARK: - Construction -graphite::quickdraw::rle::rle(const data::block &data, rsrc::resource::identifier id, const std::string &name) +graphite::spriteworld::rle::rle(const data::block &data, rsrc::resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::quickdraw::rle::rle(data::reader &reader) +graphite::spriteworld::rle::rle(data::reader &reader) { decode(reader); } -graphite::quickdraw::rle::rle(const size &size, std::uint16_t frame_count) +graphite::spriteworld::rle::rle(const quickdraw::size &size, std::uint16_t frame_count) : m_id(0), m_name("RLE"), m_frame_size(size), m_frame_count(frame_count), m_bpp(16), m_palette_id(0) { // Determine what the grid will be. We need to round up to the next whole number and have blank tiles @@ -57,22 +57,22 @@ graphite::quickdraw::rle::rle(const size &size, std::uint16_t fram // MARK: - Accessors -auto graphite::quickdraw::rle::surface() -> quickdraw::surface& +auto graphite::spriteworld::rle::surface() -> quickdraw::surface& { return m_surface; } -auto graphite::quickdraw::rle::frames() const -> std::vector> +auto graphite::spriteworld::rle::frames() const -> std::vector> { return m_frames; } -auto graphite::quickdraw::rle::frame_count() const -> std::size_t +auto graphite::spriteworld::rle::frame_count() const -> std::size_t { return m_frame_count; } -auto graphite::quickdraw::rle::data() -> data::block +auto graphite::spriteworld::rle::data() -> data::block { data::writer writer; encode(writer); @@ -81,10 +81,10 @@ auto graphite::quickdraw::rle::data() -> data::block // MARK: - Operations -auto graphite::quickdraw::rle::frame_rect(std::uint32_t frame) const -> rect +auto graphite::spriteworld::rle::frame_rect(std::uint32_t frame) const -> quickdraw::rect { return { - point( + quickdraw::point( static_cast(frame % constants::rle_grid_width) * m_frame_size.width, static_cast(frame / constants::rle_grid_width) * m_frame_size.height ), @@ -92,10 +92,10 @@ auto graphite::quickdraw::rle::frame_rect(std::uint32_t frame) const -> rect quickdraw::surface +auto graphite::spriteworld::rle::frame_surface(std::uint32_t frame) const -> quickdraw::surface { quickdraw::surface surface(m_frame_size); - rect src_rect(frame_rect(frame)); + quickdraw::rect src_rect(frame_rect(frame)); // Extract the frame area of the origin surface for (std::int16_t y = 0; y < src_rect.size.height; ++y) { @@ -107,10 +107,10 @@ auto graphite::quickdraw::rle::frame_surface(std::uint32_t frame) const -> quick return std::move(surface); } -auto graphite::quickdraw::rle::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +auto graphite::spriteworld::rle::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void { - rect dst_rect = frame_rect(frame); - size src_size = surface.size(); + quickdraw::rect dst_rect = frame_rect(frame); + quickdraw::size src_size = surface.size(); if (src_size.width != m_frame_size.width || src_size.height != m_frame_size.height) { throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width) + "x" + std::to_string(src_size.height) + @@ -125,24 +125,24 @@ auto graphite::quickdraw::rle::write_frame(std::uint32_t frame, const quickdraw: } } -auto graphite::quickdraw::rle::write_pixel(std::uint16_t pixel, std::uint8_t mask, std::uint64_t offset) -> void +auto graphite::spriteworld::rle::write_pixel(std::uint16_t pixel, std::uint8_t mask, std::uint64_t offset) -> void { - m_surface.set(offset, rgb(pixel)); + m_surface.set(offset, quickdraw::rgb(pixel)); } -auto graphite::quickdraw::rle::write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void +auto graphite::spriteworld::rle::write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void { switch (type) { case pixel_type::type1: { - m_surface.set(offset, rgb(pixel >> 16)); + m_surface.set(offset, quickdraw::rgb(pixel >> 16)); } case pixel_type::type2: { - m_surface.set(offset, rgb(pixel & 0xFFFF)); + m_surface.set(offset, quickdraw::rgb(pixel & 0xFFFF)); } } } -auto graphite::quickdraw::rle::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t +auto graphite::spriteworld::rle::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t { quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); @@ -151,11 +151,11 @@ auto graphite::quickdraw::rle::surface_offset(std::int32_t frame, std::int32_t l // MARK: - Decoding -auto graphite::quickdraw::rle::decode(data::reader &reader) -> void +auto graphite::spriteworld::rle::decode(data::reader &reader) -> void { // Read the header of the RLE information. This will tell us what we need to do in order to actually // decode the frames. - m_frame_size = size::read(reader, coding_type::macintosh); + m_frame_size = quickdraw::size::read(reader, quickdraw::coding_type::macintosh); m_bpp = reader.read_short(); m_palette_id = reader.read_short(); m_frame_count = reader.read_short(); @@ -173,7 +173,7 @@ auto graphite::quickdraw::rle::decode(data::reader &reader) -> void // Create the surface in which all frame will be draw to, and other working variables required to parse and decode // the RLE data correctly. - m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, colors::clear()); + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); rle::opcode opcode = opcode::eof; std::uint64_t position = 0; @@ -257,10 +257,10 @@ auto graphite::quickdraw::rle::decode(data::reader &reader) -> void // MARK: - Encoding -auto graphite::quickdraw::rle::encode(data::writer &writer) -> void +auto graphite::spriteworld::rle::encode(data::writer &writer) -> void { // Write out the header - m_frame_size.encode(writer, coding_type::macintosh); + m_frame_size.encode(writer, quickdraw::coding_type::macintosh); writer.write_short(m_bpp); writer.write_short(m_palette_id); writer.write_short(m_frame_count); diff --git a/libGraphite/quickdraw/format/rle.hpp b/libGraphite/spriteworld/rle.hpp similarity index 86% rename from libGraphite/quickdraw/format/rle.hpp rename to libGraphite/spriteworld/rle.hpp index 64e2447..0ededa5 100644 --- a/libGraphite/quickdraw/format/rle.hpp +++ b/libGraphite/spriteworld/rle.hpp @@ -25,7 +25,7 @@ #include "libGraphite/quickdraw/support/surface.hpp" #include "libGraphite/quickdraw/type/rect.hpp" -namespace graphite::quickdraw +namespace graphite::spriteworld { struct rle { @@ -34,15 +34,17 @@ namespace graphite::quickdraw public: rle() = default; - rle(const size& size, std::uint16_t frame_count); + rle(const quickdraw::size& size, std::uint16_t frame_count); explicit rle(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); explicit rle(data::reader& reader); + ~rle() = default; + auto surface() -> quickdraw::surface&; - [[nodiscard]] auto frames() const -> std::vector>; + [[nodiscard]] auto frames() const -> std::vector>; [[nodiscard]] auto frame_count() const -> std::size_t; - [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> rect; + [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> quickdraw::rect; [[nodiscard]] auto frame_surface(std::uint32_t idx) const -> quickdraw::surface; auto write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void; @@ -63,10 +65,10 @@ namespace graphite::quickdraw rsrc::resource::identifier m_id { 0 }; std::string m_name; - std::vector> m_frames; + std::vector> m_frames; quickdraw::surface m_surface; - size m_frame_size { 0 }; - size m_grid_size { 0 }; + quickdraw::size m_frame_size { 0 }; + quickdraw::size m_grid_size { 0 }; std::uint16_t m_frame_count { 0 }; std::uint16_t m_bpp { 0 }; std::uint16_t m_palette_id { 0 }; From ea0edf507ff82c6bf40d5f4d024a22647a2d6325 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 19:37:47 +0100 Subject: [PATCH 034/113] =?UTF-8?q?Begin=20introducing=20a=20custom=20"rl?= =?UTF-8?q?=C3=ABX"=20SpriteWorld=20resource=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/spriteworld/rle.cpp | 326 +++++++++++++++++++++++++++----- libGraphite/spriteworld/rle.hpp | 92 +++++++-- 2 files changed, 350 insertions(+), 68 deletions(-) diff --git a/libGraphite/spriteworld/rle.cpp b/libGraphite/spriteworld/rle.cpp index 64e3436..8db6291 100644 --- a/libGraphite/spriteworld/rle.cpp +++ b/libGraphite/spriteworld/rle.cpp @@ -31,57 +31,22 @@ namespace graphite::spriteworld::constants // MARK: - Construction -graphite::spriteworld::rle::rle(const data::block &data, rsrc::resource::identifier id, const std::string &name) - : m_id(id), m_name(name) -{ - data::reader reader(&data); - decode(reader); -} - -graphite::spriteworld::rle::rle(data::reader &reader) -{ - decode(reader); -} - -graphite::spriteworld::rle::rle(const quickdraw::size &size, std::uint16_t frame_count) - : m_id(0), m_name("RLE"), m_frame_size(size), m_frame_count(frame_count), m_bpp(16), m_palette_id(0) +template +auto graphite::spriteworld::rle::_create_surface() -> void { // Determine what the grid will be. We need to round up to the next whole number and have blank tiles // if the frame count is not divisible by the grid width constant. - auto grid_width = std::min(constants::rle_grid_width, frame_count); + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); // Create the surface m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); } -// MARK: - Accessors - -auto graphite::spriteworld::rle::surface() -> quickdraw::surface& -{ - return m_surface; -} - -auto graphite::spriteworld::rle::frames() const -> std::vector> -{ - return m_frames; -} - -auto graphite::spriteworld::rle::frame_count() const -> std::size_t -{ - return m_frame_count; -} - -auto graphite::spriteworld::rle::data() -> data::block -{ - data::writer writer; - encode(writer); - return std::move(*const_cast(writer.data())); -} - // MARK: - Operations -auto graphite::spriteworld::rle::frame_rect(std::uint32_t frame) const -> quickdraw::rect +template +auto graphite::spriteworld::rle::_frame_rect(std::uint32_t frame) const -> quickdraw::rect { return { quickdraw::point( @@ -92,7 +57,8 @@ auto graphite::spriteworld::rle::frame_rect(std::uint32_t frame) const -> quickd }; } -auto graphite::spriteworld::rle::frame_surface(std::uint32_t frame) const -> quickdraw::surface +template +auto graphite::spriteworld::rle::_frame_surface(std::uint32_t frame) const -> quickdraw::surface { quickdraw::surface surface(m_frame_size); quickdraw::rect src_rect(frame_rect(frame)); @@ -107,7 +73,8 @@ auto graphite::spriteworld::rle::frame_surface(std::uint32_t frame) const -> qui return std::move(surface); } -auto graphite::spriteworld::rle::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +template +auto graphite::spriteworld::rle::_write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void { quickdraw::rect dst_rect = frame_rect(frame); quickdraw::size src_size = surface.size(); @@ -125,16 +92,24 @@ auto graphite::spriteworld::rle::write_frame(std::uint32_t frame, const quickdra } } -auto graphite::spriteworld::rle::write_pixel(std::uint16_t pixel, std::uint8_t mask, std::uint64_t offset) -> void +template<> +auto graphite::spriteworld::rle<16>::_write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void +{ + m_surface.set(offset, quickdraw::rgb(static_cast(pixel & 0xFFFF))); +} + +template<> +auto graphite::spriteworld::rle<32>::_write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void { m_surface.set(offset, quickdraw::rgb(pixel)); } -auto graphite::spriteworld::rle::write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void +template<> +auto graphite::spriteworld::rle<16>::_write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void { switch (type) { case pixel_type::type1: { - m_surface.set(offset, quickdraw::rgb(pixel >> 16)); + m_surface.set(offset, quickdraw::rgb((pixel >> 16) & 0xFFFF)); } case pixel_type::type2: { m_surface.set(offset, quickdraw::rgb(pixel & 0xFFFF)); @@ -142,7 +117,21 @@ auto graphite::spriteworld::rle::write_pixel(std::uint32_t pixel, std::uint8_t m } } -auto graphite::spriteworld::rle::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t +template<> +auto graphite::spriteworld::rle<32>::_write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void +{ + switch (type) { + case pixel_type::type1: { + m_surface.set(offset, quickdraw::rgb(pixel >> 32)); + } + case pixel_type::type2: { + m_surface.set(offset, quickdraw::rgb(pixel & 0xFFFF'FFFF)); + } + } +} + +template +auto graphite::spriteworld::rle::_surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t { quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); @@ -151,7 +140,8 @@ auto graphite::spriteworld::rle::surface_offset(std::int32_t frame, std::int32_t // MARK: - Decoding -auto graphite::spriteworld::rle::decode(data::reader &reader) -> void +template<> +auto graphite::spriteworld::rle<16>::_decode(data::reader &reader) -> void { // Read the header of the RLE information. This will tell us what we need to do in order to actually // decode the frames. @@ -212,7 +202,7 @@ auto graphite::spriteworld::rle::decode(data::reader &reader) -> void } case opcode::line_start: { - current_offset = surface_offset(current_frame, ++current_line); + current_offset = _surface_offset(current_frame, ++current_line); row_start = reader.position(); break; } @@ -220,7 +210,7 @@ auto graphite::spriteworld::rle::decode(data::reader &reader) -> void case opcode::pixel_data: { for (auto i = 0; i < count; i += 2) { pixel = reader.read_short(); - write_pixel(pixel, 0xFF, current_offset); + _write_pixel(pixel, 0xFF, current_offset); ++current_offset; } @@ -234,10 +224,116 @@ auto graphite::spriteworld::rle::decode(data::reader &reader) -> void case opcode::pixel_run: { pixel_run = reader.read_long(); for (auto i = 0; i < count; i += 4) { - write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type1); + _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type1); ++current_offset; if (i + 2 < count) { - write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type2); + _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type2); + ++current_offset; + } + } + break; + } + + case opcode::transparent_run: { + current_offset += count >> 1; + break; + } + } + } + + COMPLETED_LAST_FRAME: + return; +} + + +template<> +auto graphite::spriteworld::rle<32>::_decode(data::reader &reader) -> void +{ + // Read the header of the RLE information. This will tell us what we need to do in order to actually + // decode the frames. + m_frame_size = quickdraw::size::read(reader, quickdraw::coding_type::macintosh); + m_bpp = reader.read_short(); + m_palette_id = reader.read_short(); + m_frame_count = reader.read_short(); + reader.move(6); + + // Ensure that the RLE has a BPP of 16. This is the only format that we support currently. + if (m_bpp != 32) { + throw std::runtime_error("Incorrect color depth for rlëX resource: " + std::to_string(m_id) + ", " + m_name); + } + + // Determine what the grid will be. We need to round up to the next whole and have blank tiles if the frame count + // is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface in which all frame will be draw to, and other working variables required to parse and decode + // the RLE data correctly. + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); + + rle::opcode opcode = opcode::eof; + std::uint64_t position = 0; + std::uint32_t row_start = 0; + std::int32_t current_line = -1; + std::uint64_t current_offset = 0; + std::int32_t count = 0; + std::uint32_t pixel = 0; + std::int32_t current_frame = 0; + std::uint32_t pixel_run = 0; + + while (!reader.eof()) { + if ((row_start != 0) && ((position - row_start) & 0x03)) { + position += 4 - ((position - row_start) & 0x03); + reader.move(4 - (count & 0x03)); + } + + opcode = reader.read_enum(); + count = reader.read_triple(); + + switch (opcode) { + case opcode::eof: { + // Check that we're not erroneously an EOF. + if (current_line != m_frame_size.height - 1) { + throw std::runtime_error("Incorrect number of scanlines in rlëX resource: " + std::to_string(m_id) + ", " + m_name); + } + + // Have we finished decoding the last frame in the data? + if (++current_frame >= m_frame_count) { + goto COMPLETED_LAST_FRAME; + } + + // Prepare for the next frame + current_line = -1; + break; + } + + case opcode::line_start: { + current_offset = _surface_offset(current_frame, ++current_line); + row_start = reader.position(); + break; + } + + case opcode::pixel_data: { + for (auto i = 0; i < count; i += 2) { + pixel = reader.read_long(); + _write_pixel(pixel, 0xFF, current_offset); + ++current_offset; + } + + if (count & 0x03) { + reader.move(4 - (count & 0x03)); + } + + break; + } + + case opcode::pixel_run: { + pixel_run = reader.read_quad(); + for (auto i = 0; i < count; i += 8) { + _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type1); + ++current_offset; + if (i + 4 < count) { + _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type2); ++current_offset; } } @@ -257,8 +353,134 @@ auto graphite::spriteworld::rle::decode(data::reader &reader) -> void // MARK: - Encoding -auto graphite::spriteworld::rle::encode(data::writer &writer) -> void +template<> +auto graphite::spriteworld::rle<16>::_encode(data::writer &writer) -> void +{ + // Write out the header + m_frame_size.encode(writer, quickdraw::coding_type::macintosh); + writer.write_short(m_bpp); + writer.write_short(m_palette_id); + writer.write_short(m_frame_count); + + // Reserved fields + writer.write_short(0, 3); + + // Write out the RLE frames + for (auto f = 0; f < m_frame_count; ++f) { + auto frame = frame_rect(f); + + for (std::int16_t y = 0; y < frame.size.height; ++y) { + auto line_start_pos = writer.position(); + writer.write_long(0); + + rle::opcode run_state = opcode::line_start; + auto run_start_pos = line_start_pos + 4; + auto run_count = 0; + + for (std::int16_t x = 0; x < frame.size.width; ++x) { + auto pixel = m_surface.at(frame.origin.x + x, frame.origin.y + y); + + if (pixel.components.alpha == 0) { + if (run_state == opcode::line_start) { + // Start of a transparent run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::transparent_run; + run_count = constants::advance; + } + else if (run_state == opcode::transparent_run) { + // Continue transparent run + run_count += constants::advance; + } + else { + // End of pixel run, start of transparent run. + auto run_end_pos = writer.position(); + writer.set_position(run_start_pos); + writer.write_enum(opcode::pixel_data); + writer.write_triple(run_count); + writer.set_position(run_end_pos); + + // Pad to nearest 4-byte boundary + if (run_count & 0x3) { + writer.move(4 - (run_count & 0x3)); + } + + // Start transparent run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::transparent_run; + run_count = constants::advance; + } + } + else { + if (run_state == opcode::line_start) { + // Start of pixel run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::pixel_data; + run_count = constants::advance; + } + else if (run_state == opcode::transparent_run) { + // End of transparent run, start of pixel run + writer.move(-4); + writer.write_enum(opcode::transparent_run); + writer.write_triple(run_count); + + // Start pixel run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::pixel_data; + run_count = constants::advance; + } + else { + // Continue pixel run + run_count += constants::advance; + } + + // Write the pixel + writer.write_short( + (pixel.components.blue >> 3) | + ((pixel.components.green >> 3) << 5) | + ((pixel.components.red >> 3) << 10) + ); + } + } + + // Terminate the current opcode + if (run_state == opcode::pixel_data) { + auto run_end_pos = writer.position(); + writer.set_position(run_start_pos); + writer.write_enum(opcode::pixel_data); + writer.write_triple(run_count); + + // Pad to the nearest 4-byte boundary + if ((run_end_pos - line_start_pos) & 0x3) { + writer.move(4 - ((run_end_pos - line_start_pos) & 0x3)); + } + } + else if (run_state == opcode::transparent_run) { + // Erase the transparent run opcode placeholder -- remaining data is assumed transparent + writer.set_position(run_start_pos); + } + + // Write out the opcode and the size at the start of the line + auto line_end_pos = writer.position(); + writer.set_position(line_start_pos); + writer.write_enum(opcode::line_start); + writer.write_triple(line_end_pos - line_start_pos - 4); + writer.set_position(line_end_pos); + } + + writer.write_enum(opcode::eof); + writer.write_triple(0); + } +} + +template<> +auto graphite::spriteworld::rle<32>::_encode(data::writer &writer) -> void { +#warning "This implementation is currently incorrect and needs to be fixed" + // Write out the header m_frame_size.encode(writer, quickdraw::coding_type::macintosh); writer.write_short(m_bpp); diff --git a/libGraphite/spriteworld/rle.hpp b/libGraphite/spriteworld/rle.hpp index 0ededa5..5c6cbb7 100644 --- a/libGraphite/spriteworld/rle.hpp +++ b/libGraphite/spriteworld/rle.hpp @@ -27,29 +27,78 @@ namespace graphite::spriteworld { + template struct rle { public: - static auto type_code() -> std::string { return "rlëD"; } + static_assert(Width == 16 || Width == 32); + + static auto type_code() -> std::string; public: rle() = default; - rle(const quickdraw::size& size, std::uint16_t frame_count); - explicit rle(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); - explicit rle(data::reader& reader); + + rle(const quickdraw::size& size, std::uint16_t frame_count) + : m_id(0), m_name("RLE"), m_frame_size(size), m_frame_count(frame_count), m_bpp(Width), m_palette_id(0) + { + _create_surface(); + } + + explicit rle(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = "") + : m_id(id), m_name(name) + { + data::reader reader(&data); + _decode(reader); + } + + explicit rle(data::reader& reader) + { + _decode(reader); + } ~rle() = default; - auto surface() -> quickdraw::surface&; - [[nodiscard]] auto frames() const -> std::vector>; + auto surface() -> quickdraw::surface& + { + return m_surface; + } + + [[nodiscard]] auto frames() const -> std::vector> + { + return {}; + } + + [[nodiscard]] auto frame_count() const -> std::size_t + { + return m_frame_count; + } + + [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> quickdraw::rect + { + return _frame_rect(idx); + } + + [[nodiscard]] auto frame_surface(std::uint32_t idx) const -> quickdraw::surface + { + return _frame_surface(idx); + } + + auto write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void + { + _write_frame(frame, surface); + } - [[nodiscard]] auto frame_count() const -> std::size_t; - [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> quickdraw::rect; - [[nodiscard]] auto frame_surface(std::uint32_t idx) const -> quickdraw::surface; - auto write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void; + auto encode(data::writer& writer) -> void + { + return _encode(writer); + } - auto encode(data::writer& writer) -> void; - auto data() -> data::block; + auto data() -> data::block + { + data::writer writer; + _encode(writer); + return std::move(*const_cast(writer.data())); + } private: enum class pixel_type { type1, type2 }; @@ -73,10 +122,21 @@ namespace graphite::spriteworld std::uint16_t m_bpp { 0 }; std::uint16_t m_palette_id { 0 }; - auto decode(data::reader& reader) -> void; + auto _create_surface() -> void; + + [[nodiscard]] auto _frame_rect(std::uint32_t idx) const -> quickdraw::rect; + [[nodiscard]] auto _frame_surface(std::uint32_t idx) const -> quickdraw::surface; + auto _write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void; - [[nodiscard]] auto surface_offset(std::int32_t frame, std::int32_t offset) -> std::uint64_t; - auto write_pixel(std::uint16_t pixel, std::uint8_t mask, std::uint64_t offset) -> void; - auto write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void; + auto _encode(data::writer& writer) -> void; + auto _decode(data::reader& reader) -> void; + + [[nodiscard]] auto _surface_offset(std::int32_t frame, std::int32_t offset) -> std::uint64_t; + + auto _write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void; + auto _write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void; }; + + template<> auto rle<16>::type_code() -> std::string { return "rlëD"; } + template<> auto rle<32>::type_code() -> std::string { return "rlëX"; } } From 0a617c2aab468f33e0059ab9719c2c870a3f70a4 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 8 Jul 2022 19:49:47 +0100 Subject: [PATCH 035/113] Fix a couple of issues in the RLE functionality when linking library --- libGraphite/spriteworld/rle.cpp | 44 ++++++++++++++++++++++++++++----- libGraphite/spriteworld/rle.hpp | 13 +++++++--- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/libGraphite/spriteworld/rle.cpp b/libGraphite/spriteworld/rle.cpp index 8db6291..279d0d9 100644 --- a/libGraphite/spriteworld/rle.cpp +++ b/libGraphite/spriteworld/rle.cpp @@ -31,8 +31,20 @@ namespace graphite::spriteworld::constants // MARK: - Construction -template -auto graphite::spriteworld::rle::_create_surface() -> void +template<> +auto graphite::spriteworld::rle<16>::_create_surface() -> void +{ + // Determine what the grid will be. We need to round up to the next whole number and have blank tiles + // if the frame count is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); +} + +template<> +auto graphite::spriteworld::rle<32>::_create_surface() -> void { // Determine what the grid will be. We need to round up to the next whole number and have blank tiles // if the frame count is not divisible by the grid width constant. @@ -73,8 +85,28 @@ auto graphite::spriteworld::rle::_frame_surface(std::uint32_t frame) cons return std::move(surface); } -template -auto graphite::spriteworld::rle::_write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +template<> +auto graphite::spriteworld::rle<16>::_write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +{ + quickdraw::rect dst_rect = frame_rect(frame); + quickdraw::size src_size = surface.size(); + + if (src_size.width != m_frame_size.width || src_size.height != m_frame_size.height) { + throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width) + "x" + std::to_string(src_size.height) + + ", expected " + std::to_string(m_frame_size.width) + "x" + std::to_string(m_frame_size.height)); + } + + // Copy from the source surface into the destination frame + for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { + for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { + m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); + } + } +} + + +template<> +auto graphite::spriteworld::rle<32>::_write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void { quickdraw::rect dst_rect = frame_rect(frame); quickdraw::size src_size = surface.size(); @@ -84,7 +116,7 @@ auto graphite::spriteworld::rle::_write_frame(std::uint32_t frame, const ", expected " + std::to_string(m_frame_size.width) + "x" + std::to_string(m_frame_size.height)); } - // Copy from the source surfac e into the destination frame + // Copy from the source surface into the destination frame for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); @@ -480,7 +512,7 @@ template<> auto graphite::spriteworld::rle<32>::_encode(data::writer &writer) -> void { #warning "This implementation is currently incorrect and needs to be fixed" - + // Write out the header m_frame_size.encode(writer, quickdraw::coding_type::macintosh); writer.write_short(m_bpp); diff --git a/libGraphite/spriteworld/rle.hpp b/libGraphite/spriteworld/rle.hpp index 5c6cbb7..b6926d8 100644 --- a/libGraphite/spriteworld/rle.hpp +++ b/libGraphite/spriteworld/rle.hpp @@ -33,7 +33,15 @@ namespace graphite::spriteworld public: static_assert(Width == 16 || Width == 32); - static auto type_code() -> std::string; + static auto type_code() -> std::string + { + if (Width == 16) { + return "rlëD"; + } + else if (Width == 32) { + return "rlëX"; + } + } public: rle() = default; @@ -136,7 +144,4 @@ namespace graphite::spriteworld auto _write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void; auto _write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void; }; - - template<> auto rle<16>::type_code() -> std::string { return "rlëD"; } - template<> auto rle<32>::type_code() -> std::string { return "rlëX"; } } From 72e73dc3ecc3b6b879d88e7f3664202d32419b88 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 13 Jul 2022 15:54:00 +0100 Subject: [PATCH 036/113] Fix a major memory leak in data::block --- libGraphite/data/data.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 219aa0c..6a58d69 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -199,9 +199,15 @@ graphite::data::block::block(const block &data) m_byte_order(data.m_byte_order), m_has_ownership(data.m_has_ownership) { - m_raw = malloc(m_raw_size); - m_data = simd_align(m_raw); - copy_from(data); + if (m_has_ownership) { + m_raw = malloc(m_raw_size); + m_data = simd_align(m_raw); + copy_from(data); + } + else { + m_raw = data.m_raw; + m_data = data.m_data; + } } graphite::data::block::block(block &&data) noexcept @@ -230,6 +236,15 @@ auto graphite::data::block::operator=(const block &data) -> struct block & return *this; } + // Clean up the current data... + if (m_allocation_owner) { + const_cast(m_allocation_owner)->m_users--; + } + else if ((!m_allocation_owner && m_has_ownership) || m_has_ownership) { + assert(m_users == 0); + free(m_raw); + } + m_raw_size = data.m_raw_size; m_data_size = data.m_data_size; m_allocation_owner = nullptr; From 50940fb9ce81ed96b434ef7d1d4dc00302b073bf Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 13 Jul 2022 15:54:24 +0100 Subject: [PATCH 037/113] Start introducing the DLOG and DITL types into graphite --- libGraphite/toolbox/dialog.cpp | 147 +++++++++++++++++++++++ libGraphite/toolbox/dialog.hpp | 76 ++++++++++++ libGraphite/toolbox/dialog_item_list.cpp | 86 +++++++++++++ libGraphite/toolbox/dialog_item_list.hpp | 79 ++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 libGraphite/toolbox/dialog.cpp create mode 100644 libGraphite/toolbox/dialog.hpp create mode 100644 libGraphite/toolbox/dialog_item_list.cpp create mode 100644 libGraphite/toolbox/dialog_item_list.hpp diff --git a/libGraphite/toolbox/dialog.cpp b/libGraphite/toolbox/dialog.cpp new file mode 100644 index 0000000..cbe1afb --- /dev/null +++ b/libGraphite/toolbox/dialog.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/toolbox/dialog.hpp" +#include "libGraphite/data/reader.hpp" + +// MARK: - Construction + +graphite::toolbox::dialog::dialog(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +// MARK: - Accessors + +auto graphite::toolbox::dialog::bounds() const -> quickdraw::rect +{ + return m_bounds; +} + +auto graphite::toolbox::dialog::proc_id() const -> std::int16_t +{ + return m_proc_id; +} + +auto graphite::toolbox::dialog::visible() const -> bool +{ + return m_visible; +} + +auto graphite::toolbox::dialog::go_away() const -> bool +{ + return m_go_away; +} + +auto graphite::toolbox::dialog::ref_con() const -> std::int32_t +{ + return m_ref_con; +} + +auto graphite::toolbox::dialog::interface_list() const -> rsrc::resource::identifier +{ + return m_ditl_id; +} + +auto graphite::toolbox::dialog::auto_position() const -> std::uint16_t +{ + return m_auto_position; +} + +auto graphite::toolbox::dialog::title() const -> std::string +{ + return m_title; +} + +auto graphite::toolbox::dialog::set_bounds(const quickdraw::rect& bounds) -> void +{ + m_bounds = bounds; +} + +auto graphite::toolbox::dialog::set_proc_id(std::int16_t id) -> void +{ + m_proc_id = id; +} + +auto graphite::toolbox::dialog::set_visible(bool visible) -> void +{ + m_visible = visible; +} + +auto graphite::toolbox::dialog::set_go_away(bool go_away) -> void +{ + m_go_away = go_away; +} + +auto graphite::toolbox::dialog::set_ref_con(std::int32_t ref_con) -> void +{ + m_ref_con = ref_con; +} + +auto graphite::toolbox::dialog::set_interface_list(rsrc::resource::identifier id) -> void +{ + m_ditl_id = id; +} + +auto graphite::toolbox::dialog::set_auto_position(std::uint16_t position) -> void +{ + m_auto_position = position; +} + +auto graphite::toolbox::dialog::set_title(const std::string& title) -> void +{ + m_title = title; +} + +// MARK: - Decoder + +auto graphite::toolbox::dialog::decode(data::reader &reader) -> void +{ + m_bounds = quickdraw::rect::read(reader, quickdraw::coding_type::macintosh); + + m_proc_id = reader.read_signed_short(); + m_visible = reader.read_short() != 0; + m_go_away = reader.read_short() != 0; + m_ref_con = reader.read_signed_long(); + m_ditl_id = reader.read_short(); + m_title = reader.read_pstr(); + + if (reader.position() % 2 != 0) { + reader.move(); + } + + m_auto_position = reader.read_short(); +} + +// MARK: - Encoder + +auto graphite::toolbox::dialog::encode(data::writer &writer) -> void +{ + +} + +auto graphite::toolbox::dialog::data() -> data::block +{ + data::writer writer; + encode(writer); + return std::move(*const_cast(writer.data())); +} \ No newline at end of file diff --git a/libGraphite/toolbox/dialog.hpp b/libGraphite/toolbox/dialog.hpp new file mode 100644 index 0000000..f026137 --- /dev/null +++ b/libGraphite/toolbox/dialog.hpp @@ -0,0 +1,76 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/data/reader.hpp" +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" + +namespace graphite::toolbox +{ + struct dialog + { + public: + static auto type_code() -> std::string { return "DLOG"; } + + public: + dialog() = default; + explicit dialog(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit dialog(data::reader& reader); + + [[nodiscard]] auto bounds() const -> quickdraw::rect; + [[nodiscard]] auto proc_id() const -> std::int16_t; + [[nodiscard]] auto visible() const -> bool; + [[nodiscard]] auto go_away() const -> bool; + [[nodiscard]] auto ref_con() const -> std::int32_t; + [[nodiscard]] auto interface_list() const -> rsrc::resource::identifier; + [[nodiscard]] auto auto_position() const -> std::uint16_t; + [[nodiscard]] auto title() const -> std::string; + + auto set_bounds(const quickdraw::rect& bounds) -> void; + auto set_proc_id(std::int16_t id) -> void; + auto set_visible(bool visible) -> void; + auto set_go_away(bool go_away) -> void; + auto set_ref_con(std::int32_t ref_con) -> void; + auto set_interface_list(rsrc::resource::identifier id) -> void; + auto set_auto_position(std::uint16_t position) -> void; + auto set_title(const std::string& title) -> void; + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + private: + rsrc::resource::identifier m_id { INT64_MIN }; + std::string m_name; + std::string m_title; + quickdraw::rect m_bounds; + std::int16_t m_proc_id { 0 }; + bool m_visible { true }; + bool m_go_away { true }; + std::int32_t m_ref_con { 0 }; + rsrc::resource::identifier m_ditl_id { 0 }; + std::uint16_t m_auto_position { 0 }; + + auto decode(data::reader& reader) -> void; + }; +} diff --git a/libGraphite/toolbox/dialog_item_list.cpp b/libGraphite/toolbox/dialog_item_list.cpp new file mode 100644 index 0000000..af1b37d --- /dev/null +++ b/libGraphite/toolbox/dialog_item_list.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/toolbox/dialog_item_list.hpp" +#include "libGraphite/data/reader.hpp" + +// MARK: - Construction + +graphite::toolbox::dialog_item_list::dialog_item_list(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::toolbox::dialog_item_list::dialog_item_list(data::reader &reader) +{ + decode(reader); +} + +// MARK: - Encoder + +auto graphite::toolbox::dialog_item_list::encode(data::writer &writer) -> void +{ + writer.write_short(m_items.size() - 1); + + for (const auto& item : m_items) { + writer.write_long(0); + + auto frame = item.frame; + frame.encode(writer, quickdraw::coding_type::macintosh); + + writer.write_enum(item.type); + writer.write_pstr(item.info); + + if (writer.position() % 2 == 1) { + writer.write_byte(0); + } + } +} + +auto graphite::toolbox::dialog_item_list::data() -> data::block +{ + data::writer writer; + encode(writer); + return std::move(*const_cast(writer.data())); +} + +// MARK: - Decoder + +auto graphite::toolbox::dialog_item_list::decode(data::reader &reader) -> void +{ + auto count = reader.read_short(); + + for (auto i = 0; i <= count; ++i) { + reader.move(4); + + struct item item; + item.frame = quickdraw::rect::read(reader, quickdraw::coding_type::macintosh); + item.type = static_cast(reader.read_byte()); + item.info = reader.read_pstr(); + + if (reader.position() % 2 == 1) { + reader.move(); + } + + m_items.emplace_back(std::move(item)); + } +} \ No newline at end of file diff --git a/libGraphite/toolbox/dialog_item_list.hpp b/libGraphite/toolbox/dialog_item_list.hpp new file mode 100644 index 0000000..58bc010 --- /dev/null +++ b/libGraphite/toolbox/dialog_item_list.hpp @@ -0,0 +1,79 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/data/reader.hpp" +#include "libGraphite/rsrc/resource.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" + +namespace graphite::toolbox +{ + struct dialog_item_list + { + public: + static auto type_code() -> std::string { return "DITL"; } + + enum class item_type : std::uint8_t + { + user_item = 0, + help_item = 1, + button = 4, + checkbox = 5, + radio = 6, + control = 7, + static_text = 8, + edit_text = 16, + icon = 32, + picture = 64, + disable = 128 + }; + + struct item + { + quickdraw::rect frame; + enum item_type type { item_type::user_item }; + std::string info; + }; + + public: + dialog_item_list() = default; + explicit dialog_item_list(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit dialog_item_list(data::reader& reader); + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + [[nodiscard]] auto item_count() const -> std::uint16_t { return m_items.size(); } + [[nodiscard]] auto at(std::uint16_t idx) const -> const item& { return m_items[idx]; } + + auto begin() -> std::vector::iterator { return m_items.begin(); } + auto end() -> std::vector::iterator { return m_items.end(); } + + private: + rsrc::resource::identifier m_id { INT64_MIN }; + std::string m_name; + std::vector m_items; + + auto decode(data::reader& reader) -> void; + }; +} From 9835c99e4b16e0765fc1387fd27944092358139f Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 16 Jul 2022 14:30:39 +0100 Subject: [PATCH 038/113] Fix a bug with attributes in resource types --- libGraphite/rsrc/file.cpp | 13 ++++++++++++- libGraphite/sound/sound.cpp | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 916993f..038b74e 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -165,11 +165,22 @@ auto graphite::rsrc::file::add_resource(const std::string &type_code, { auto resource = new struct resource(nullptr, id, name, data); - auto type_hash = rsrc::type::hash_for_type_code(type_code); + std::unordered_map type_attributes; + for (const auto& it : attributes) { + attribute attr(it.first, it.second); + type_attributes.emplace(std::pair(attr.hash_value(), std::move(attr))); + } + + auto type_hash = rsrc::type::hash_for_type_code(type_code, type_attributes); auto it = m_types.find(type_hash); if (it == m_types.end()) { // The type doesn't exist, so we need to create it. auto type = new struct type(type_code); + + for (const auto& attr : type_attributes) { + type->add_attribute(attr.second.name(), attr.second.string_value()); + } + m_types.emplace(std::pair(type_hash, type)); type->add_resource(resource); } diff --git a/libGraphite/sound/sound.cpp b/libGraphite/sound/sound.cpp index 1a12de0..491ad95 100644 --- a/libGraphite/sound/sound.cpp +++ b/libGraphite/sound/sound.cpp @@ -216,7 +216,7 @@ graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sa m_descriptor.sample_rate = sample_rate; m_descriptor.bit_width = sample_bits; - graphite::data::writer writer(&m_samples); + graphite::data::writer writer(data::byte_order::lsb); if (sample_bits == 8) { for (auto& channel : sample_data) { for (auto& frame : channel) { @@ -232,6 +232,7 @@ graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sa } } + m_samples = std::move(*const_cast(writer.data())); } graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const graphite::data::block& sample_data) From bed1c3bc56824ff9bdf1dcdd176a0e17088eaf52 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 17 Jul 2022 22:09:54 +0100 Subject: [PATCH 039/113] Start introducing a "font manager" for dealing with font related resources. --- libGraphite/font/fond.cpp | 161 +++++++++++++++++++++++++++++++++++ libGraphite/font/fond.hpp | 103 ++++++++++++++++++++++ libGraphite/font/manager.cpp | 63 ++++++++++++++ libGraphite/font/manager.hpp | 54 ++++++++++++ libGraphite/font/sfnt.cpp | 75 ++++++++++++++++ libGraphite/font/sfnt.hpp | 51 +++++++++++ 6 files changed, 507 insertions(+) create mode 100644 libGraphite/font/fond.cpp create mode 100644 libGraphite/font/fond.hpp create mode 100644 libGraphite/font/manager.cpp create mode 100644 libGraphite/font/manager.hpp create mode 100644 libGraphite/font/sfnt.cpp create mode 100644 libGraphite/font/sfnt.hpp diff --git a/libGraphite/font/fond.cpp b/libGraphite/font/fond.cpp new file mode 100644 index 0000000..8e3573c --- /dev/null +++ b/libGraphite/font/fond.cpp @@ -0,0 +1,161 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/font/fond.hpp" + +// MARK: - Construction + +graphite::fond::fond(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::fond::fond(data::reader &reader) +{ + decode(reader); +} + +// MARK: - Decoding + +auto graphite::fond::decode(data::reader &reader) -> void +{ + m_fixed = reader.read_short() & 0x8000 ? true : false; + m_family_id = reader.read_short(); + m_first = reader.read_short(); + m_last = reader.read_short(); + + m_ascent = reader.read_short(); + m_descent = static_cast(reader.read_short()); + m_leading = reader.read_short(); + m_widmax = reader.read_short(); + + m_widoff = reader.read_signed_long(); + m_kernoff = reader.read_signed_long(); + m_styleoff = reader.read_signed_long(); + + reader.move(sizeof(std::uint16_t) * 9); + reader.move(sizeof(std::uint32_t)); + reader.move(sizeof(std::uint16_t)); + + m_assoc_count = reader.read_short() + 1; + m_assoc = std::vector(m_assoc_count); + for (auto i = 0; i < m_assoc_count; ++i) { + m_assoc[i].size = reader.read_short(); + m_assoc[i].style = reader.read_short(); + m_assoc[i].id = reader.read_short(); + } + + if (m_widoff != 0) { + reader.set_position(m_widoff); + m_style_width_count = reader.read_short() + 1; + m_style_widths = std::vector(m_style_width_count); + for (auto i = 0; i < m_style_width_count; ++i) { + m_style_widths[i].style = reader.read_short(); + m_style_widths[i].width_tabs = std::vector((m_last - m_first + 3) * sizeof(std::uint16_t)); + for (auto j = m_first; j <= m_last + 2; ++j) { + m_style_widths[i].width_tabs[j] = reader.read_short(); + } + } + } + + if (m_kernoff != 0) { + reader.set_position(m_kernoff); + m_style_kern_count = reader.read_short() + 1; + m_style_kerns = std::vector(m_style_kern_count); + for (auto i = 0; i < m_style_kern_count; ++i) { + m_style_kerns[i].style = reader.read_short(); + m_style_kerns[i].kern_pairs = reader.read_short(); + m_style_kerns[i].kerns = std::vector(m_style_kerns[i].kern_pairs); + for (auto j = 0; j < m_style_kerns[i].kern_pairs; ++j) { + m_style_kerns[i].kerns[j].ch1 = reader.read_byte(); + m_style_kerns[i].kerns[j].ch2 = reader.read_byte(); + m_style_kerns[i].kerns[j].offset = reader.read_short(); + } + } + } + + if (m_styleoff != 0) { + reader.set_position(m_styleoff); + m_style_class = reader.read_short(); + m_glyph_encoding = reader.read_short(); + reader.move(sizeof(std::uint32_t)); + + std::uint8_t offsets[48] = { 0 }; + for (unsigned char& offset : offsets) { + offset = reader.read_byte(); + } + + std::uint16_t string_count = reader.read_short(); + char **strings = (char **)malloc(string_count * sizeof(char *)); + for (auto j = 0; j < string_count; ++j) { + std::uint8_t len = reader.read_byte(); + strings[j] = (char *)malloc(len + 2); + strings[j][0] = len; + strings[j][len + 1] = '\0'; + for (auto k = 0; k < len; ++k) { + strings[j][k + 1] = reader.read_byte(); + } + } + + for (auto j = 0; j < 48; ++j) { + auto k = j - 1; + for (; k >= 0; --k) { + if (offsets[j] == offsets[k]) { + break; + } + } + + if (k != -1 || offsets[j] == 0) { + continue; + } + + std::int32_t format = offsets[j] - 1; + std::uint8_t len = strings[0][0]; + if (format != 0 && format != -1) { + for (k =0; k < strings[format][0]; ++k) { + len += strings[strings[format][k + 1] - 1][0]; + } + } + + char *ptr_str = (char *)malloc(len + 1); + char *pt = ptr_str; + strlcpy(pt, strings[0] + 1, len + 1); + pt += strings[0][0]; + if (format != 0 && format != -1) { + for (k = 0; k < strings[format][0]; ++k) { + strlcpy(pt, strings[strings[format][k + 1] - 1] + 1, len + 1); + pt += strings[strings[format][k + 1] - 1][0]; + } + } + *pt = '\0'; + + m_ps_names[j] = std::string(ptr_str); + free(ptr_str); + } + + m_family = std::string(strdup(strings[0])); + for (auto j = 0; j < string_count; ++j) { + free(strings[j]); + } + free(strings); + } +} \ No newline at end of file diff --git a/libGraphite/font/fond.hpp b/libGraphite/font/fond.hpp new file mode 100644 index 0000000..17a5dd8 --- /dev/null +++ b/libGraphite/font/fond.hpp @@ -0,0 +1,103 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include "libGraphite/data/reader.hpp" +#include "libGraphite/rsrc/resource.hpp" + +namespace graphite +{ + struct fond + { + public: + static auto type_code() -> std::string { return "FOND"; } + + public: + fond() = default; + explicit fond(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); + explicit fond(data::reader& reader); + + private: + struct assoc + { + std::uint16_t size { 0 }; + std::uint16_t style { 0 }; + std::uint16_t id { 0 }; + }; + + struct style_widths + { + std::uint16_t style { 0 }; + std::vector width_tabs; + }; + + struct kern + { + std::uint8_t ch1 { 0 }; + std::uint8_t ch2 { 0 }; + std::uint16_t offset { 0 }; + }; + + struct style_kern + { + std::uint16_t style { 0 }; + std::uint16_t kern_pairs { 0 }; + std::vector kerns; + }; + + rsrc::resource::identifier m_id { INT64_MIN }; + std::string m_name; + bool m_fixed { false }; + std::uint16_t m_family_id { 0 }; + std::uint16_t m_first { 0 }; + std::uint16_t m_last { 0 }; + + std::uint16_t m_ascent { 0 }; + std::int16_t m_descent { 0 }; + std::uint16_t m_leading { 0 }; + std::uint16_t m_widmax { 0 }; + + std::int32_t m_widoff { 0 }; + std::int32_t m_kernoff { 0 }; + std::int32_t m_styleoff { 0 }; + + std::uint16_t m_assoc_count { 0 }; + std::vector m_assoc; + + std::uint16_t m_style_width_count { 0 }; + std::vector m_style_widths; + + std::uint16_t m_style_kern_count { 0 }; + std::vector m_style_kerns; + + std::uint16_t m_style_class { 0 }; + std::uint16_t m_glyph_encoding { 0 }; + + std::array m_ps_names; + std::string m_family; + + auto decode(data::reader& reader) -> void; + }; +} \ No newline at end of file diff --git a/libGraphite/font/manager.cpp b/libGraphite/font/manager.cpp new file mode 100644 index 0000000..e145032 --- /dev/null +++ b/libGraphite/font/manager.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/font/manager.hpp" +#include "libGraphite/rsrc/manager.hpp" +#include "libGraphite/font/sfnt.hpp" + +// MARK: - Singleton + +auto graphite::font_manager::shared_manager() -> graphite::font_manager & +{ + static font_manager instance; + return instance; +} + +// MARK: - Font Management + +auto graphite::font_manager::update_font_table() -> void +{ + auto sfnt_resources = rsrc::manager::shared_manager().find(); + for (const auto& res : sfnt_resources) { + auto font_name = res.name(); + auto it = m_fonts.find(font_name); + if (it != m_fonts.end()) { + // Already aware of font... ignore it. + continue; + } + + struct font_reference ref; + ref.name = font_name; + + struct sfnt sfnt(res.data()); + ref.ttf = sfnt.ttf_data(); + + m_fonts.emplace(std::pair(font_name, std::move(ref))); + } +} + +auto graphite::font_manager::font_named(const std::string &name) const -> const graphite::data::block * +{ + auto it = m_fonts.find(name); + if (it == m_fonts.end()) { + return nullptr; + } + return &it->second.ttf; +} diff --git a/libGraphite/font/manager.hpp b/libGraphite/font/manager.hpp new file mode 100644 index 0000000..c3eb054 --- /dev/null +++ b/libGraphite/font/manager.hpp @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/data/data.hpp" + +namespace graphite +{ + class font_manager + { + public: + struct font_reference + { + std::string name; + data::block ttf; + }; + + public: + font_manager(const font_manager&) = delete; + font_manager(font_manager&&) = delete; + auto operator=(const font_manager&) -> font_manager& = delete; + auto operator=(font_manager&&) -> font_manager& = delete; + + static auto shared_manager() -> font_manager&; + + auto update_font_table() -> void; + [[nodiscard]] auto font_named(const std::string& name) const -> const data::block *; + + private: + std::unordered_map m_fonts; + + font_manager() = default; + }; +} \ No newline at end of file diff --git a/libGraphite/font/sfnt.cpp b/libGraphite/font/sfnt.cpp new file mode 100644 index 0000000..8098c2a --- /dev/null +++ b/libGraphite/font/sfnt.cpp @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/font/sfnt.hpp" +#include "libGraphite/data/writer.hpp" + +// MARK: - Construction + +graphite::sfnt::sfnt(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::sfnt::sfnt(data::reader &reader) +{ + decode(reader); +} + +// MARK: - Decoding + +auto graphite::sfnt::decode(data::reader &reader) -> void +{ + auto ilen = reader.data()->size(); + auto rlen = ilen; + + if (rlen > 16 * 1024) { + ilen = 16 * 1024; + } + + auto max = std::min(static_cast(0x800), ilen); + data::writer ttf(data::byte_order::lsb); + + for (auto len = 0; len < rlen;) { + auto temp = ilen; + if (rlen - len < ilen) { + temp = rlen - len; + } + + auto buffer = reader.read_data(temp); + if (reader.eof()) { + break; + } + + ttf.write_data(&buffer); + len += temp; + } + + m_ttf = std::move(*const_cast(ttf.data())); +} + +// MARK: - Accessors + +auto graphite::sfnt::ttf_data() const -> const data::block& +{ + return m_ttf; +} \ No newline at end of file diff --git a/libGraphite/font/sfnt.hpp b/libGraphite/font/sfnt.hpp new file mode 100644 index 0000000..f56e20e --- /dev/null +++ b/libGraphite/font/sfnt.hpp @@ -0,0 +1,51 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include "libGraphite/data/reader.hpp" +#include "libGraphite/rsrc/resource.hpp" + +namespace graphite +{ + struct sfnt + { + public: + static auto type_code() -> std::string { return "sfnt"; } + + public: + sfnt() = default; + explicit sfnt(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); + explicit sfnt(data::reader& reader); + + [[nodiscard]] auto ttf_data() const -> const data::block&; + + private: + rsrc::resource::identifier m_id { INT64_MIN }; + std::string m_name; + data::block m_ttf; + + auto decode(data::reader& reader) -> void; + }; +} \ No newline at end of file From 41cbf4ceead13f4bcecfe04631a14778bc617043 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 18 Jul 2022 09:25:04 +0100 Subject: [PATCH 040/113] Some more font work --- libGraphite/font/sfnt.cpp | 30 ++---------------------------- libGraphite/rsrc/manager.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/libGraphite/font/sfnt.cpp b/libGraphite/font/sfnt.cpp index 8098c2a..a9c3fda 100644 --- a/libGraphite/font/sfnt.cpp +++ b/libGraphite/font/sfnt.cpp @@ -26,8 +26,7 @@ graphite::sfnt::sfnt(const data::block &data, rsrc::resource::identifier id, const std::string &name) : m_id(id), m_name(name) { - data::reader reader(&data); - decode(reader); + m_ttf = data; } graphite::sfnt::sfnt(data::reader &reader) @@ -39,32 +38,7 @@ graphite::sfnt::sfnt(data::reader &reader) auto graphite::sfnt::decode(data::reader &reader) -> void { - auto ilen = reader.data()->size(); - auto rlen = ilen; - - if (rlen > 16 * 1024) { - ilen = 16 * 1024; - } - - auto max = std::min(static_cast(0x800), ilen); - data::writer ttf(data::byte_order::lsb); - - for (auto len = 0; len < rlen;) { - auto temp = ilen; - if (rlen - len < ilen) { - temp = rlen - len; - } - - auto buffer = reader.read_data(temp); - if (reader.eof()) { - break; - } - - ttf.write_data(&buffer); - len += temp; - } - - m_ttf = std::move(*const_cast(ttf.data())); + m_ttf = std::move(*const_cast(reader.data())); } // MARK: - Accessors diff --git a/libGraphite/rsrc/manager.cpp b/libGraphite/rsrc/manager.cpp index a1a5898..a27a2e0 100644 --- a/libGraphite/rsrc/manager.cpp +++ b/libGraphite/rsrc/manager.cpp @@ -19,6 +19,8 @@ // SOFTWARE. #include "libGraphite/rsrc/manager.hpp" +#include "libGraphite/font/manager.hpp" +#include "libGraphite/font/sfnt.hpp" // MARK: - Singleton / Construction @@ -34,6 +36,11 @@ auto graphite::rsrc::manager::import_file(class file *file) -> class file * { m_files.emplace(std::pair(file->hash_value(), file)); m_file_load_order.insert(m_file_load_order.begin(), file->hash_value()); + + if (file->type(sfnt::type_code())) { + font_manager::shared_manager().update_font_table(); + } + return file; } From 001773f7f6e545c49a3a37752b81cd1d06035efb Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 18 Jul 2022 12:40:05 +0100 Subject: [PATCH 041/113] Continue working on the Font Manager for Graphite --- libGraphite/font/fond.cpp | 6 ++-- libGraphite/font/fond.hpp | 10 +++--- libGraphite/font/manager.cpp | 39 +++++++++++++++++++----- libGraphite/font/manager.hpp | 31 ++++++++++++------- libGraphite/font/nfnt.cpp | 54 +++++++++++++++++++++++++++++++++ libGraphite/font/nfnt.hpp | 59 ++++++++++++++++++++++++++++++++++++ libGraphite/font/sfnt.cpp | 8 ++--- libGraphite/font/sfnt.hpp | 10 +++--- libGraphite/rsrc/manager.cpp | 8 +++-- 9 files changed, 188 insertions(+), 37 deletions(-) create mode 100644 libGraphite/font/nfnt.cpp create mode 100644 libGraphite/font/nfnt.hpp diff --git a/libGraphite/font/fond.cpp b/libGraphite/font/fond.cpp index 8e3573c..b17b167 100644 --- a/libGraphite/font/fond.cpp +++ b/libGraphite/font/fond.cpp @@ -22,21 +22,21 @@ // MARK: - Construction -graphite::fond::fond(const data::block &data, rsrc::resource::identifier id, const std::string &name) +graphite::font::descriptor::descriptor(const data::block &data, rsrc::resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::fond::fond(data::reader &reader) +graphite::font::descriptor::descriptor(data::reader &reader) { decode(reader); } // MARK: - Decoding -auto graphite::fond::decode(data::reader &reader) -> void +auto graphite::font::descriptor::decode(data::reader &reader) -> void { m_fixed = reader.read_short() & 0x8000 ? true : false; m_family_id = reader.read_short(); diff --git a/libGraphite/font/fond.hpp b/libGraphite/font/fond.hpp index 17a5dd8..2f133c4 100644 --- a/libGraphite/font/fond.hpp +++ b/libGraphite/font/fond.hpp @@ -27,17 +27,17 @@ #include "libGraphite/data/reader.hpp" #include "libGraphite/rsrc/resource.hpp" -namespace graphite +namespace graphite::font { - struct fond + struct descriptor { public: static auto type_code() -> std::string { return "FOND"; } public: - fond() = default; - explicit fond(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); - explicit fond(data::reader& reader); + descriptor() = default; + explicit descriptor(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); + explicit descriptor(data::reader& reader); private: struct assoc diff --git a/libGraphite/font/manager.cpp b/libGraphite/font/manager.cpp index e145032..dd944f6 100644 --- a/libGraphite/font/manager.cpp +++ b/libGraphite/font/manager.cpp @@ -24,17 +24,17 @@ // MARK: - Singleton -auto graphite::font_manager::shared_manager() -> graphite::font_manager & +auto graphite::font::manager::shared_manager() -> graphite::font::manager & { - static font_manager instance; + static manager instance; return instance; } // MARK: - Font Management -auto graphite::font_manager::update_font_table() -> void +auto graphite::font::manager::update_font_table() -> void { - auto sfnt_resources = rsrc::manager::shared_manager().find(); + auto sfnt_resources = rsrc::manager::shared_manager().find(); for (const auto& res : sfnt_resources) { auto font_name = res.name(); auto it = m_fonts.find(font_name); @@ -43,17 +43,42 @@ auto graphite::font_manager::update_font_table() -> void continue; } - struct font_reference ref; + struct font ref; ref.name = font_name; - struct sfnt sfnt(res.data()); + struct outline_font sfnt(res.data()); ref.ttf = sfnt.ttf_data(); m_fonts.emplace(std::pair(font_name, std::move(ref))); } } -auto graphite::font_manager::font_named(const std::string &name) const -> const graphite::data::block * +auto graphite::font::manager::has_font_named(const std::string &name) const -> bool +{ + return m_fonts.find(name) != m_fonts.end(); +} + +auto graphite::font::manager::font_has_bitmap(const std::string &name) const -> bool +{ + if (!has_font_named(name)) { + return false; + } + + auto& font = m_fonts.find(name)->second; + return !font.m_bitmaps.empty(); +} + +auto graphite::font::manager::font_has_truetype(const std::string &name) const -> bool +{ + if (!has_font_named(name)) { + return false; + } + + auto& font = m_fonts.find(name)->second; + return font.ttf.size() > 0; +} + +auto graphite::font::manager::ttf_font_named(const std::string &name) const -> const data::block * { auto it = m_fonts.find(name); if (it == m_fonts.end()) { diff --git a/libGraphite/font/manager.hpp b/libGraphite/font/manager.hpp index c3eb054..1afe162 100644 --- a/libGraphite/font/manager.hpp +++ b/libGraphite/font/manager.hpp @@ -24,31 +24,40 @@ #include #include "libGraphite/data/data.hpp" -namespace graphite +#include "libGraphite/font/fond.hpp" +#include "libGraphite/font/nfnt.hpp" + +namespace graphite::font { - class font_manager + class manager { public: - struct font_reference + struct font { std::string name; + descriptor m_bitmap_descriptor; + std::unordered_map m_bitmaps; data::block ttf; }; public: - font_manager(const font_manager&) = delete; - font_manager(font_manager&&) = delete; - auto operator=(const font_manager&) -> font_manager& = delete; - auto operator=(font_manager&&) -> font_manager& = delete; + manager(const manager&) = delete; + manager(manager&&) = delete; + auto operator=(const manager&) -> manager& = delete; + auto operator=(manager&&) -> manager& = delete; - static auto shared_manager() -> font_manager&; + static auto shared_manager() -> manager&; auto update_font_table() -> void; - [[nodiscard]] auto font_named(const std::string& name) const -> const data::block *; + + [[nodiscard]] auto has_font_named(const std::string& name) const -> bool; + [[nodiscard]] auto font_has_bitmap(const std::string& name) const -> bool; + [[nodiscard]] auto font_has_truetype(const std::string& name) const -> bool; + [[nodiscard]] auto ttf_font_named(const std::string& name) const -> const data::block *; private: - std::unordered_map m_fonts; + std::unordered_map m_fonts; - font_manager() = default; + manager() = default; }; } \ No newline at end of file diff --git a/libGraphite/font/nfnt.cpp b/libGraphite/font/nfnt.cpp new file mode 100644 index 0000000..16c5b0e --- /dev/null +++ b/libGraphite/font/nfnt.cpp @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/font/nfnt.hpp" + +// MARK: - Construction + +graphite::font::bitmapped_font::bitmapped_font(const data::block &data, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +graphite::font::bitmapped_font::bitmapped_font(data::reader &reader) +{ + decode(reader); +} + +// MARK: - Decoding + +auto graphite::font::bitmapped_font::decode(data::reader &reader) -> void +{ + m_font_type = reader.read_signed_short(); + m_first_char_code = reader.read_signed_short(); + m_last_char_code = reader.read_signed_short(); + m_max_width = reader.read_signed_short(); + m_max_kerning = reader.read_signed_short(); + m_descent = reader.read_signed_short(); + m_font_rect_width = reader.read_signed_short(); + m_font_rect_height = reader.read_signed_short(); + m_width_table_offset = reader.read_signed_short(); + m_max_ascent = reader.read_signed_short(); + m_max_descent = reader.read_signed_short(); + m_leading = reader.read_signed_short(); + m_bit_image_row_width = reader.read_signed_short(); +} diff --git a/libGraphite/font/nfnt.hpp b/libGraphite/font/nfnt.hpp new file mode 100644 index 0000000..0618783 --- /dev/null +++ b/libGraphite/font/nfnt.hpp @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/data/data.hpp" +#include "libGraphite/data/reader.hpp" +#include "libGraphite/rsrc/resource.hpp" + +namespace graphite::font +{ + struct bitmapped_font + { + public: + static auto type_code() -> std::string { return "nfnt"; } + + public: + bitmapped_font() = default; + explicit bitmapped_font(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit bitmapped_font(data::reader& reader); + + private: + rsrc::resource::identifier m_id { INT64_MIN }; + std::string m_name; + + std::int16_t m_font_type { 0 }; + std::int16_t m_first_char_code { 0 }; + std::int16_t m_last_char_code { 0 }; + std::int16_t m_max_width { 0 }; + std::int16_t m_max_kerning { 0 }; + std::int16_t m_descent { 0 }; + std::int16_t m_font_rect_width { 0 }; + std::int16_t m_font_rect_height { 0 }; + std::int16_t m_width_table_offset { 0 }; + std::int16_t m_max_ascent { 0 }; + std::int16_t m_max_descent { 0 }; + std::int16_t m_leading { 0 }; + std::int16_t m_bit_image_row_width { 0 }; + + auto decode(data::reader& reader) -> void; + }; +} \ No newline at end of file diff --git a/libGraphite/font/sfnt.cpp b/libGraphite/font/sfnt.cpp index a9c3fda..7cb2832 100644 --- a/libGraphite/font/sfnt.cpp +++ b/libGraphite/font/sfnt.cpp @@ -23,27 +23,27 @@ // MARK: - Construction -graphite::sfnt::sfnt(const data::block &data, rsrc::resource::identifier id, const std::string &name) +graphite::font::outline_font::outline_font(const data::block &data, rsrc::resource::identifier id, const std::string &name) : m_id(id), m_name(name) { m_ttf = data; } -graphite::sfnt::sfnt(data::reader &reader) +graphite::font::outline_font::outline_font(data::reader &reader) { decode(reader); } // MARK: - Decoding -auto graphite::sfnt::decode(data::reader &reader) -> void +auto graphite::font::outline_font::decode(data::reader &reader) -> void { m_ttf = std::move(*const_cast(reader.data())); } // MARK: - Accessors -auto graphite::sfnt::ttf_data() const -> const data::block& +auto graphite::font::outline_font::ttf_data() const -> const data::block& { return m_ttf; } \ No newline at end of file diff --git a/libGraphite/font/sfnt.hpp b/libGraphite/font/sfnt.hpp index f56e20e..d7ee634 100644 --- a/libGraphite/font/sfnt.hpp +++ b/libGraphite/font/sfnt.hpp @@ -27,17 +27,17 @@ #include "libGraphite/data/reader.hpp" #include "libGraphite/rsrc/resource.hpp" -namespace graphite +namespace graphite::font { - struct sfnt + struct outline_font { public: static auto type_code() -> std::string { return "sfnt"; } public: - sfnt() = default; - explicit sfnt(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); - explicit sfnt(data::reader& reader); + outline_font() = default; + explicit outline_font(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); + explicit outline_font(data::reader& reader); [[nodiscard]] auto ttf_data() const -> const data::block&; diff --git a/libGraphite/rsrc/manager.cpp b/libGraphite/rsrc/manager.cpp index a27a2e0..d1fe46d 100644 --- a/libGraphite/rsrc/manager.cpp +++ b/libGraphite/rsrc/manager.cpp @@ -37,8 +37,12 @@ auto graphite::rsrc::manager::import_file(class file *file) -> class file * m_files.emplace(std::pair(file->hash_value(), file)); m_file_load_order.insert(m_file_load_order.begin(), file->hash_value()); - if (file->type(sfnt::type_code())) { - font_manager::shared_manager().update_font_table(); + if ( + file->type(font::outline_font::type_code()) || + file->type(font::descriptor::type_code()) || + file->type(font::bitmapped_font::type_code()) + ) { + font::manager::shared_manager().update_font_table(); } return file; From 2ac32595055cc32499a72a294274a470442a1f80 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 21 Jul 2022 15:10:17 +0100 Subject: [PATCH 042/113] Minor fixes in QuickDraw rect type and dialog_item_list. --- libGraphite/quickdraw/type/rect.hpp | 6 +++++- libGraphite/toolbox/dialog_item_list.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libGraphite/quickdraw/type/rect.hpp b/libGraphite/quickdraw/type/rect.hpp index 7e27c37..4e1402a 100644 --- a/libGraphite/quickdraw/type/rect.hpp +++ b/libGraphite/quickdraw/type/rect.hpp @@ -45,7 +45,11 @@ namespace graphite::quickdraw rect(rect&&) noexcept = default; explicit rect(data::reader& reader) : origin(reader), size(reader) {} - rect(data::reader& reader, coding_type type) : origin(reader, type), size(reader, type) {} + rect(data::reader& reader, coding_type type) : origin(reader, type), size(reader, type) + { + size.width -= origin.x; + size.height -= origin.y; + } static auto read(data::reader& reader, coding_type type) -> rect { return { reader, type }; } diff --git a/libGraphite/toolbox/dialog_item_list.cpp b/libGraphite/toolbox/dialog_item_list.cpp index af1b37d..cad901a 100644 --- a/libGraphite/toolbox/dialog_item_list.cpp +++ b/libGraphite/toolbox/dialog_item_list.cpp @@ -73,7 +73,7 @@ auto graphite::toolbox::dialog_item_list::decode(data::reader &reader) -> void reader.move(4); struct item item; - item.frame = quickdraw::rect::read(reader, quickdraw::coding_type::macintosh); + item.frame = quickdraw::rect::read(reader, quickdraw::coding_type::quickdraw); item.type = static_cast(reader.read_byte()); item.info = reader.read_pstr(); From 2132a7e9540ce436a64aa8d2704a677be6cfaf73 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 24 Jul 2022 08:48:26 +0100 Subject: [PATCH 043/113] Allow the data block of a resource to be altered after creation --- libGraphite/rsrc/file.cpp | 8 ++++++++ libGraphite/rsrc/file.hpp | 1 + libGraphite/rsrc/resource.cpp | 8 +++++++- libGraphite/rsrc/resource.hpp | 1 + libGraphite/toolbox/dialog.cpp | 7 ++++++- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 038b74e..f2339b2 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -265,6 +265,14 @@ auto graphite::rsrc::file::find(const std::string &type_code, resource::identifi return nullptr; } +auto graphite::rsrc::file::find(const std::string &type_code, resource::identifier id, const std::vector& attributes) const -> const struct resource * +{ + if (auto type = const_cast(this->type(type_code, attributes))) { + return type->resource_with_id(id); + } + return nullptr; +} + // MARK: - File Access auto graphite::rsrc::file::read(const std::string &path) -> void diff --git a/libGraphite/rsrc/file.hpp b/libGraphite/rsrc/file.hpp index 4a88d67..cfe807a 100644 --- a/libGraphite/rsrc/file.hpp +++ b/libGraphite/rsrc/file.hpp @@ -81,6 +81,7 @@ namespace graphite::rsrc } [[nodiscard]] auto find(const std::string& type_code, resource::identifier id, const std::unordered_map& attributes = {}) const -> const struct resource *; + [[nodiscard]] auto find(const std::string& type_code, resource::identifier id, const std::vector& attributes) const -> const struct resource *; template [[nodiscard]] auto load(resource::identifier id) const -> T diff --git a/libGraphite/rsrc/resource.cpp b/libGraphite/rsrc/resource.cpp index 25ac7d2..35a9bf7 100644 --- a/libGraphite/rsrc/resource.cpp +++ b/libGraphite/rsrc/resource.cpp @@ -133,6 +133,12 @@ auto graphite::rsrc::resource::set_type(struct type *type) -> void m_type = type; } +auto graphite::rsrc::resource::set_data(graphite::data::block &data) -> void +{ + m_data = data; + m_data_offset = 0; +} + // MARK: - Hashing auto graphite::rsrc::resource::hash(identifier id) -> identifier_hash @@ -155,4 +161,4 @@ auto graphite::rsrc::resource::set_data_offset(std::size_t offset) -> void auto graphite::rsrc::resource::data_offset() const -> std::size_t { return m_data_offset; -} \ No newline at end of file +} diff --git a/libGraphite/rsrc/resource.hpp b/libGraphite/rsrc/resource.hpp index 8e3b660..b2e939c 100644 --- a/libGraphite/rsrc/resource.hpp +++ b/libGraphite/rsrc/resource.hpp @@ -57,6 +57,7 @@ namespace graphite::rsrc auto set_id(resource::identifier id) -> void; auto set_name(const std::string& name) -> void; auto set_type(struct type *type) -> void; + auto set_data(data::block& data) -> void; static auto hash(identifier id) -> identifier_hash; static auto hash(const std::string& name) -> name_hash; diff --git a/libGraphite/toolbox/dialog.cpp b/libGraphite/toolbox/dialog.cpp index cbe1afb..7ba2da8 100644 --- a/libGraphite/toolbox/dialog.cpp +++ b/libGraphite/toolbox/dialog.cpp @@ -30,6 +30,11 @@ graphite::toolbox::dialog::dialog(const data::block &data, rsrc::resource::ident decode(reader); } +graphite::toolbox::dialog::dialog(graphite::data::reader &reader) +{ + decode(reader); +} + // MARK: - Accessors auto graphite::toolbox::dialog::bounds() const -> quickdraw::rect @@ -144,4 +149,4 @@ auto graphite::toolbox::dialog::data() -> data::block data::writer writer; encode(writer); return std::move(*const_cast(writer.data())); -} \ No newline at end of file +} From e4a9138f465d9573ea5a34d7bfdbdfdac1ad91fd Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 24 Jul 2022 09:34:33 +0100 Subject: [PATCH 044/113] Add header to fond.cpp --- libGraphite/font/fond.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libGraphite/font/fond.cpp b/libGraphite/font/fond.cpp index b17b167..297a265 100644 --- a/libGraphite/font/fond.cpp +++ b/libGraphite/font/fond.cpp @@ -19,6 +19,7 @@ // SOFTWARE. #include "libGraphite/font/fond.hpp" +#include // MARK: - Construction From 2e11b05397f0fe76be758e0552fa5b29c239a6e9 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 24 Jul 2022 09:38:21 +0100 Subject: [PATCH 045/113] Temporary alteration for Linux and Windows which do not have strlcpy --- libGraphite/font/fond.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libGraphite/font/fond.cpp b/libGraphite/font/fond.cpp index 297a265..76a1cd9 100644 --- a/libGraphite/font/fond.cpp +++ b/libGraphite/font/fond.cpp @@ -139,11 +139,11 @@ auto graphite::font::descriptor::decode(data::reader &reader) -> void char *ptr_str = (char *)malloc(len + 1); char *pt = ptr_str; - strlcpy(pt, strings[0] + 1, len + 1); + strncpy(pt, strings[0] + 1, len + 1); pt += strings[0][0]; if (format != 0 && format != -1) { for (k = 0; k < strings[format][0]; ++k) { - strlcpy(pt, strings[strings[format][k + 1] - 1] + 1, len + 1); + strncpy(pt, strings[strings[format][k + 1] - 1] + 1, len + 1); pt += strings[strings[format][k + 1] - 1][0]; } } From 666fb5f199bee1ff6c904aef0d119ea95ac49a31 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 24 Jul 2022 14:32:21 +0100 Subject: [PATCH 046/113] SpriteWorld updates --- libGraphite/quickdraw/type/color.cpp | 36 +- libGraphite/quickdraw/type/color.hpp | 11 + libGraphite/spriteworld/rle.cpp | 634 --------------------------- libGraphite/spriteworld/rle.hpp | 147 ------- libGraphite/spriteworld/rleD.cpp | 380 ++++++++++++++++ libGraphite/spriteworld/rleD.hpp | 83 ++++ libGraphite/spriteworld/rleX.cpp | 285 ++++++++++++ libGraphite/spriteworld/rleX.hpp | 84 ++++ 8 files changed, 878 insertions(+), 782 deletions(-) delete mode 100644 libGraphite/spriteworld/rle.cpp delete mode 100644 libGraphite/spriteworld/rle.hpp create mode 100644 libGraphite/spriteworld/rleD.cpp create mode 100644 libGraphite/spriteworld/rleD.hpp create mode 100644 libGraphite/spriteworld/rleX.cpp create mode 100644 libGraphite/spriteworld/rleX.hpp diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index b2ffbcf..366200b 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include #include "libGraphite/quickdraw/type/color.hpp" // MARK: - Construction @@ -64,4 +65,37 @@ auto graphite::quickdraw::colors::black() -> union color auto graphite::quickdraw::colors::clear() -> union color { return rgb(0, 0, 0, 0); -} \ No newline at end of file +} + +// MARK: - YCrCb Color + +auto graphite::quickdraw::ycrcb(const union color& rgb) -> struct ycrcb +{ + double r = rgb.components.red; + double g = rgb.components.green; + double b = rgb.components.blue; + + std::int32_t y = static_cast( 0.299 * r + 0.587 * g + 0.114 * b); + std::int32_t u = static_cast(-0.168736 * r - 0.331264 * g + 0.500 * b + 128); + std::int32_t v = static_cast( 0.500 * r - 0.418688 * g - 0.081312 * b + 128); + + std::uint8_t y_clamped = std::clamp(y, 0, 255); + std::uint8_t u_clamped = std::clamp(u, 0, 255); + std::uint8_t v_clamped = std::clamp(v, 0, 255); + + return (struct ycrcb) { + .y = y_clamped, + .cr = u_clamped, + .cb = v_clamped, + .alpha = rgb.components.alpha + }; +} + +auto graphite::quickdraw::rgb(const struct ycrcb& color) -> union color +{ + auto r = std::clamp(color.y + 1.4075 * (color.cb - 128), 0, 255); + auto g = std::clamp(color.y - (0.3455 * (color.cr - 128)) - (0.7169 * (color.cb - 128)), 0, 255); + auto b = std::clamp(color.y + 1.7790 * (color.cr - 128), 0, 255); + + return rgb(r, g, b, color.alpha); +} diff --git a/libGraphite/quickdraw/type/color.hpp b/libGraphite/quickdraw/type/color.hpp index 2d8bef1..c928af8 100644 --- a/libGraphite/quickdraw/type/color.hpp +++ b/libGraphite/quickdraw/type/color.hpp @@ -38,6 +38,14 @@ namespace graphite::quickdraw } components; }; + struct ycrcb + { + color_component y; + color_component cr; + color_component cb; + color_component alpha; + }; + static auto operator==(const union color& lhs, const union color& rhs) -> bool { return lhs.value == rhs.value; } static auto operator!=(const union color& lhs, const union color& rhs) -> bool { return lhs.value != rhs.value; } @@ -55,4 +63,7 @@ namespace graphite::quickdraw [[nodiscard]] auto white() -> union color; [[nodiscard]] auto clear() -> union color; } + + [[nodiscard]] auto ycrcb(const union color& rgb) -> struct ycrcb; + [[nodiscard]] auto rgb(const struct ycrcb& color) -> union color; } \ No newline at end of file diff --git a/libGraphite/spriteworld/rle.cpp b/libGraphite/spriteworld/rle.cpp deleted file mode 100644 index 279d0d9..0000000 --- a/libGraphite/spriteworld/rle.cpp +++ /dev/null @@ -1,634 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include "libGraphite/spriteworld/rle.hpp" -#include - -// MARK: - Constants - -namespace graphite::spriteworld::constants -{ - static constexpr std::uint16_t rle_grid_width = 6; - static constexpr std::size_t advance = 2; -} - -// MARK: - Construction - -template<> -auto graphite::spriteworld::rle<16>::_create_surface() -> void -{ - // Determine what the grid will be. We need to round up to the next whole number and have blank tiles - // if the frame count is not divisible by the grid width constant. - auto grid_width = std::min(constants::rle_grid_width, m_frame_count); - m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); - - // Create the surface - m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); -} - -template<> -auto graphite::spriteworld::rle<32>::_create_surface() -> void -{ - // Determine what the grid will be. We need to round up to the next whole number and have blank tiles - // if the frame count is not divisible by the grid width constant. - auto grid_width = std::min(constants::rle_grid_width, m_frame_count); - m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); - - // Create the surface - m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); -} - -// MARK: - Operations - -template -auto graphite::spriteworld::rle::_frame_rect(std::uint32_t frame) const -> quickdraw::rect -{ - return { - quickdraw::point( - static_cast(frame % constants::rle_grid_width) * m_frame_size.width, - static_cast(frame / constants::rle_grid_width) * m_frame_size.height - ), - m_frame_size - }; -} - -template -auto graphite::spriteworld::rle::_frame_surface(std::uint32_t frame) const -> quickdraw::surface -{ - quickdraw::surface surface(m_frame_size); - quickdraw::rect src_rect(frame_rect(frame)); - - // Extract the frame area of the origin surface - for (std::int16_t y = 0; y < src_rect.size.height; ++y) { - for (std::int16_t x = 0; x < src_rect.size.width; ++x) { - surface.set(x, y, m_surface.at(x + src_rect.origin.x, y + src_rect.origin.y)); - } - } - - return std::move(surface); -} - -template<> -auto graphite::spriteworld::rle<16>::_write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void -{ - quickdraw::rect dst_rect = frame_rect(frame); - quickdraw::size src_size = surface.size(); - - if (src_size.width != m_frame_size.width || src_size.height != m_frame_size.height) { - throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width) + "x" + std::to_string(src_size.height) + - ", expected " + std::to_string(m_frame_size.width) + "x" + std::to_string(m_frame_size.height)); - } - - // Copy from the source surface into the destination frame - for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { - for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { - m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); - } - } -} - - -template<> -auto graphite::spriteworld::rle<32>::_write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void -{ - quickdraw::rect dst_rect = frame_rect(frame); - quickdraw::size src_size = surface.size(); - - if (src_size.width != m_frame_size.width || src_size.height != m_frame_size.height) { - throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width) + "x" + std::to_string(src_size.height) + - ", expected " + std::to_string(m_frame_size.width) + "x" + std::to_string(m_frame_size.height)); - } - - // Copy from the source surface into the destination frame - for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { - for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { - m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); - } - } -} - -template<> -auto graphite::spriteworld::rle<16>::_write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void -{ - m_surface.set(offset, quickdraw::rgb(static_cast(pixel & 0xFFFF))); -} - -template<> -auto graphite::spriteworld::rle<32>::_write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void -{ - m_surface.set(offset, quickdraw::rgb(pixel)); -} - -template<> -auto graphite::spriteworld::rle<16>::_write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void -{ - switch (type) { - case pixel_type::type1: { - m_surface.set(offset, quickdraw::rgb((pixel >> 16) & 0xFFFF)); - } - case pixel_type::type2: { - m_surface.set(offset, quickdraw::rgb(pixel & 0xFFFF)); - } - } -} - -template<> -auto graphite::spriteworld::rle<32>::_write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void -{ - switch (type) { - case pixel_type::type1: { - m_surface.set(offset, quickdraw::rgb(pixel >> 32)); - } - case pixel_type::type2: { - m_surface.set(offset, quickdraw::rgb(pixel & 0xFFFF'FFFF)); - } - } -} - -template -auto graphite::spriteworld::rle::_surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t -{ - quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); - quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); - return static_cast(p.y * m_surface.size().width + p.x); -} - -// MARK: - Decoding - -template<> -auto graphite::spriteworld::rle<16>::_decode(data::reader &reader) -> void -{ - // Read the header of the RLE information. This will tell us what we need to do in order to actually - // decode the frames. - m_frame_size = quickdraw::size::read(reader, quickdraw::coding_type::macintosh); - m_bpp = reader.read_short(); - m_palette_id = reader.read_short(); - m_frame_count = reader.read_short(); - reader.move(6); - - // Ensure that the RLE has a BPP of 16. This is the only format that we support currently. - if (m_bpp != 16) { - throw std::runtime_error("Incorrect color depth for rlëD resource: " + std::to_string(m_id) + ", " + m_name); - } - - // Determine what the grid will be. We need to round up to the next whole and have blank tiles if the frame count - // is not divisible by the grid width constant. - auto grid_width = std::min(constants::rle_grid_width, m_frame_count); - m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); - - // Create the surface in which all frame will be draw to, and other working variables required to parse and decode - // the RLE data correctly. - m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); - - rle::opcode opcode = opcode::eof; - std::uint64_t position = 0; - std::uint32_t row_start = 0; - std::int32_t current_line = -1; - std::uint64_t current_offset = 0; - std::int32_t count = 0; - std::uint16_t pixel = 0; - std::int32_t current_frame = 0; - std::uint32_t pixel_run = 0; - - while (!reader.eof()) { - if ((row_start != 0) && ((position - row_start) & 0x03)) { - position += 4 - ((position - row_start) & 0x03); - reader.move(4 - (count & 0x03)); - } - - opcode = reader.read_enum(); - count = reader.read_triple(); - - switch (opcode) { - case opcode::eof: { - // Check that we're not erroneously an EOF. - if (current_line != m_frame_size.height - 1) { - throw std::runtime_error("Incorrect number of scanlines in rlëD resource: " + std::to_string(m_id) + ", " + m_name); - } - - // Have we finished decoding the last frame in the data? - if (++current_frame >= m_frame_count) { - goto COMPLETED_LAST_FRAME; - } - - // Prepare for the next frame - current_line = -1; - break; - } - - case opcode::line_start: { - current_offset = _surface_offset(current_frame, ++current_line); - row_start = reader.position(); - break; - } - - case opcode::pixel_data: { - for (auto i = 0; i < count; i += 2) { - pixel = reader.read_short(); - _write_pixel(pixel, 0xFF, current_offset); - ++current_offset; - } - - if (count & 0x03) { - reader.move(4 - (count & 0x03)); - } - - break; - } - - case opcode::pixel_run: { - pixel_run = reader.read_long(); - for (auto i = 0; i < count; i += 4) { - _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type1); - ++current_offset; - if (i + 2 < count) { - _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type2); - ++current_offset; - } - } - break; - } - - case opcode::transparent_run: { - current_offset += count >> 1; - break; - } - } - } - - COMPLETED_LAST_FRAME: - return; -} - - -template<> -auto graphite::spriteworld::rle<32>::_decode(data::reader &reader) -> void -{ - // Read the header of the RLE information. This will tell us what we need to do in order to actually - // decode the frames. - m_frame_size = quickdraw::size::read(reader, quickdraw::coding_type::macintosh); - m_bpp = reader.read_short(); - m_palette_id = reader.read_short(); - m_frame_count = reader.read_short(); - reader.move(6); - - // Ensure that the RLE has a BPP of 16. This is the only format that we support currently. - if (m_bpp != 32) { - throw std::runtime_error("Incorrect color depth for rlëX resource: " + std::to_string(m_id) + ", " + m_name); - } - - // Determine what the grid will be. We need to round up to the next whole and have blank tiles if the frame count - // is not divisible by the grid width constant. - auto grid_width = std::min(constants::rle_grid_width, m_frame_count); - m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); - - // Create the surface in which all frame will be draw to, and other working variables required to parse and decode - // the RLE data correctly. - m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); - - rle::opcode opcode = opcode::eof; - std::uint64_t position = 0; - std::uint32_t row_start = 0; - std::int32_t current_line = -1; - std::uint64_t current_offset = 0; - std::int32_t count = 0; - std::uint32_t pixel = 0; - std::int32_t current_frame = 0; - std::uint32_t pixel_run = 0; - - while (!reader.eof()) { - if ((row_start != 0) && ((position - row_start) & 0x03)) { - position += 4 - ((position - row_start) & 0x03); - reader.move(4 - (count & 0x03)); - } - - opcode = reader.read_enum(); - count = reader.read_triple(); - - switch (opcode) { - case opcode::eof: { - // Check that we're not erroneously an EOF. - if (current_line != m_frame_size.height - 1) { - throw std::runtime_error("Incorrect number of scanlines in rlëX resource: " + std::to_string(m_id) + ", " + m_name); - } - - // Have we finished decoding the last frame in the data? - if (++current_frame >= m_frame_count) { - goto COMPLETED_LAST_FRAME; - } - - // Prepare for the next frame - current_line = -1; - break; - } - - case opcode::line_start: { - current_offset = _surface_offset(current_frame, ++current_line); - row_start = reader.position(); - break; - } - - case opcode::pixel_data: { - for (auto i = 0; i < count; i += 2) { - pixel = reader.read_long(); - _write_pixel(pixel, 0xFF, current_offset); - ++current_offset; - } - - if (count & 0x03) { - reader.move(4 - (count & 0x03)); - } - - break; - } - - case opcode::pixel_run: { - pixel_run = reader.read_quad(); - for (auto i = 0; i < count; i += 8) { - _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type1); - ++current_offset; - if (i + 4 < count) { - _write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type2); - ++current_offset; - } - } - break; - } - - case opcode::transparent_run: { - current_offset += count >> 1; - break; - } - } - } - - COMPLETED_LAST_FRAME: - return; -} - -// MARK: - Encoding - -template<> -auto graphite::spriteworld::rle<16>::_encode(data::writer &writer) -> void -{ - // Write out the header - m_frame_size.encode(writer, quickdraw::coding_type::macintosh); - writer.write_short(m_bpp); - writer.write_short(m_palette_id); - writer.write_short(m_frame_count); - - // Reserved fields - writer.write_short(0, 3); - - // Write out the RLE frames - for (auto f = 0; f < m_frame_count; ++f) { - auto frame = frame_rect(f); - - for (std::int16_t y = 0; y < frame.size.height; ++y) { - auto line_start_pos = writer.position(); - writer.write_long(0); - - rle::opcode run_state = opcode::line_start; - auto run_start_pos = line_start_pos + 4; - auto run_count = 0; - - for (std::int16_t x = 0; x < frame.size.width; ++x) { - auto pixel = m_surface.at(frame.origin.x + x, frame.origin.y + y); - - if (pixel.components.alpha == 0) { - if (run_state == opcode::line_start) { - // Start of a transparent run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::transparent_run; - run_count = constants::advance; - } - else if (run_state == opcode::transparent_run) { - // Continue transparent run - run_count += constants::advance; - } - else { - // End of pixel run, start of transparent run. - auto run_end_pos = writer.position(); - writer.set_position(run_start_pos); - writer.write_enum(opcode::pixel_data); - writer.write_triple(run_count); - writer.set_position(run_end_pos); - - // Pad to nearest 4-byte boundary - if (run_count & 0x3) { - writer.move(4 - (run_count & 0x3)); - } - - // Start transparent run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::transparent_run; - run_count = constants::advance; - } - } - else { - if (run_state == opcode::line_start) { - // Start of pixel run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::pixel_data; - run_count = constants::advance; - } - else if (run_state == opcode::transparent_run) { - // End of transparent run, start of pixel run - writer.move(-4); - writer.write_enum(opcode::transparent_run); - writer.write_triple(run_count); - - // Start pixel run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::pixel_data; - run_count = constants::advance; - } - else { - // Continue pixel run - run_count += constants::advance; - } - - // Write the pixel - writer.write_short( - (pixel.components.blue >> 3) | - ((pixel.components.green >> 3) << 5) | - ((pixel.components.red >> 3) << 10) - ); - } - } - - // Terminate the current opcode - if (run_state == opcode::pixel_data) { - auto run_end_pos = writer.position(); - writer.set_position(run_start_pos); - writer.write_enum(opcode::pixel_data); - writer.write_triple(run_count); - - // Pad to the nearest 4-byte boundary - if ((run_end_pos - line_start_pos) & 0x3) { - writer.move(4 - ((run_end_pos - line_start_pos) & 0x3)); - } - } - else if (run_state == opcode::transparent_run) { - // Erase the transparent run opcode placeholder -- remaining data is assumed transparent - writer.set_position(run_start_pos); - } - - // Write out the opcode and the size at the start of the line - auto line_end_pos = writer.position(); - writer.set_position(line_start_pos); - writer.write_enum(opcode::line_start); - writer.write_triple(line_end_pos - line_start_pos - 4); - writer.set_position(line_end_pos); - } - - writer.write_enum(opcode::eof); - writer.write_triple(0); - } -} - -template<> -auto graphite::spriteworld::rle<32>::_encode(data::writer &writer) -> void -{ -#warning "This implementation is currently incorrect and needs to be fixed" - - // Write out the header - m_frame_size.encode(writer, quickdraw::coding_type::macintosh); - writer.write_short(m_bpp); - writer.write_short(m_palette_id); - writer.write_short(m_frame_count); - - // Reserved fields - writer.write_short(0, 3); - - // Write out the RLE frames - for (auto f = 0; f < m_frame_count; ++f) { - auto frame = frame_rect(f); - - for (std::int16_t y = 0; y < frame.size.height; ++y) { - auto line_start_pos = writer.position(); - writer.write_long(0); - - rle::opcode run_state = opcode::line_start; - auto run_start_pos = line_start_pos + 4; - auto run_count = 0; - - for (std::int16_t x = 0; x < frame.size.width; ++x) { - auto pixel = m_surface.at(frame.origin.x + x, frame.origin.y + y); - - if (pixel.components.alpha == 0) { - if (run_state == opcode::line_start) { - // Start of a transparent run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::transparent_run; - run_count = constants::advance; - } - else if (run_state == opcode::transparent_run) { - // Continue transparent run - run_count += constants::advance; - } - else { - // End of pixel run, start of transparent run. - auto run_end_pos = writer.position(); - writer.set_position(run_start_pos); - writer.write_enum(opcode::pixel_data); - writer.write_triple(run_count); - writer.set_position(run_end_pos); - - // Pad to nearest 4-byte boundary - if (run_count & 0x3) { - writer.move(4 - (run_count & 0x3)); - } - - // Start transparent run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::transparent_run; - run_count = constants::advance; - } - } - else { - if (run_state == opcode::line_start) { - // Start of pixel run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::pixel_data; - run_count = constants::advance; - } - else if (run_state == opcode::transparent_run) { - // End of transparent run, start of pixel run - writer.move(-4); - writer.write_enum(opcode::transparent_run); - writer.write_triple(run_count); - - // Start pixel run - run_start_pos = writer.position(); - writer.write_long(0); - run_state = opcode::pixel_data; - run_count = constants::advance; - } - else { - // Continue pixel run - run_count += constants::advance; - } - - // Write the pixel - writer.write_short( - (pixel.components.blue >> 3) | - ((pixel.components.green >> 3) << 5) | - ((pixel.components.red >> 3) << 10) - ); - } - } - - // Terminate the current opcode - if (run_state == opcode::pixel_data) { - auto run_end_pos = writer.position(); - writer.set_position(run_start_pos); - writer.write_enum(opcode::pixel_data); - writer.write_triple(run_count); - - // Pad to the nearest 4-byte boundary - if ((run_end_pos - line_start_pos) & 0x3) { - writer.move(4 - ((run_end_pos - line_start_pos) & 0x3)); - } - } - else if (run_state == opcode::transparent_run) { - // Erase the transparent run opcode placeholder -- remaining data is assumed transparent - writer.set_position(run_start_pos); - } - - // Write out the opcode and the size at the start of the line - auto line_end_pos = writer.position(); - writer.set_position(line_start_pos); - writer.write_enum(opcode::line_start); - writer.write_triple(line_end_pos - line_start_pos - 4); - writer.set_position(line_end_pos); - } - - writer.write_enum(opcode::eof); - writer.write_triple(0); - } -} diff --git a/libGraphite/spriteworld/rle.hpp b/libGraphite/spriteworld/rle.hpp deleted file mode 100644 index b6926d8..0000000 --- a/libGraphite/spriteworld/rle.hpp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -#include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" - -namespace graphite::spriteworld -{ - template - struct rle - { - public: - static_assert(Width == 16 || Width == 32); - - static auto type_code() -> std::string - { - if (Width == 16) { - return "rlëD"; - } - else if (Width == 32) { - return "rlëX"; - } - } - - public: - rle() = default; - - rle(const quickdraw::size& size, std::uint16_t frame_count) - : m_id(0), m_name("RLE"), m_frame_size(size), m_frame_count(frame_count), m_bpp(Width), m_palette_id(0) - { - _create_surface(); - } - - explicit rle(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = "") - : m_id(id), m_name(name) - { - data::reader reader(&data); - _decode(reader); - } - - explicit rle(data::reader& reader) - { - _decode(reader); - } - - ~rle() = default; - - auto surface() -> quickdraw::surface& - { - return m_surface; - } - - [[nodiscard]] auto frames() const -> std::vector> - { - return {}; - } - - [[nodiscard]] auto frame_count() const -> std::size_t - { - return m_frame_count; - } - - [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> quickdraw::rect - { - return _frame_rect(idx); - } - - [[nodiscard]] auto frame_surface(std::uint32_t idx) const -> quickdraw::surface - { - return _frame_surface(idx); - } - - auto write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void - { - _write_frame(frame, surface); - } - - auto encode(data::writer& writer) -> void - { - return _encode(writer); - } - - auto data() -> data::block - { - data::writer writer; - _encode(writer); - return std::move(*const_cast(writer.data())); - } - - private: - enum class pixel_type { type1, type2 }; - - enum class opcode : std::uint8_t - { - eof = 0x00, - line_start = 0x01, - pixel_data = 0x02, - transparent_run = 0x03, - pixel_run = 0x04, - }; - - rsrc::resource::identifier m_id { 0 }; - std::string m_name; - std::vector> m_frames; - quickdraw::surface m_surface; - quickdraw::size m_frame_size { 0 }; - quickdraw::size m_grid_size { 0 }; - std::uint16_t m_frame_count { 0 }; - std::uint16_t m_bpp { 0 }; - std::uint16_t m_palette_id { 0 }; - - auto _create_surface() -> void; - - [[nodiscard]] auto _frame_rect(std::uint32_t idx) const -> quickdraw::rect; - [[nodiscard]] auto _frame_surface(std::uint32_t idx) const -> quickdraw::surface; - auto _write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void; - - auto _encode(data::writer& writer) -> void; - auto _decode(data::reader& reader) -> void; - - [[nodiscard]] auto _surface_offset(std::int32_t frame, std::int32_t offset) -> std::uint64_t; - - auto _write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void; - auto _write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void; - }; -} diff --git a/libGraphite/spriteworld/rleD.cpp b/libGraphite/spriteworld/rleD.cpp new file mode 100644 index 0000000..f65ba25 --- /dev/null +++ b/libGraphite/spriteworld/rleD.cpp @@ -0,0 +1,380 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/spriteworld/rleD.hpp" +#include + +// MARK: - Constants + +namespace graphite::spriteworld::constants +{ + static constexpr std::uint16_t rle_grid_width = 6; + static constexpr std::size_t advance = 2; +} + +// MARK: - Construction + +graphite::spriteworld::rleD::rleD(data::reader& reader) +{ + decode(reader); +} + +graphite::spriteworld::rleD::rleD(const quickdraw::size& size, std::uint16_t frame_count) + : m_id(0), m_name(type_code()), m_frame_size(size), m_frame_count(frame_count), m_bpp(16), m_palette_id(0) +{ + // Determine what the grid will be. We need to round up to the next whole number and have blank tiles + // if the frame count is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); +} + +graphite::spriteworld::rleD::rleD(const data::block& data, rsrc::resource::identifier id, const std::string& name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +// MARK: - Accessors + +auto graphite::spriteworld::rleD::surface() -> quickdraw::surface& +{ + return m_surface; +} + +auto graphite::spriteworld::rleD::frames() const -> std::vector> +{ + return m_frames; +} + +auto graphite::spriteworld::rleD::frame_count() const -> std::size_t +{ + return m_frame_count; +} + +auto graphite::spriteworld::rleD::data() -> data::block +{ + data::writer writer; + encode(writer); + return std::move(*const_cast(writer.data())); +} + +// MARK: - Operations + +auto graphite::spriteworld::rleD::frame_rect(std::uint32_t frame) const -> quickdraw::rect +{ + return { + quickdraw::point( + static_cast(frame % constants::rle_grid_width) * m_frame_size.width, + static_cast(frame / constants::rle_grid_width) * m_frame_size.height + ), + m_frame_size + }; +} + +auto graphite::spriteworld::rleD::frame_surface(std::uint32_t frame) const -> quickdraw::surface +{ + quickdraw::surface surface(m_frame_size); + quickdraw::rect src_rect(frame_rect(frame)); + + // Extract the frame area of the origin surface + for (std::int16_t y = 0; y < src_rect.size.height; ++y) { + for (std::int16_t x = 0; x < src_rect.size.width; ++x) { + surface.set(x, y, m_surface.at(x + src_rect.origin.x, y + src_rect.origin.y)); + } + } + + return std::move(surface); +} + +auto graphite::spriteworld::rleD::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +{ + quickdraw::rect dst_rect = frame_rect(frame); + quickdraw::size src_size = surface.size(); + + if (src_size.width != m_frame_size.width || src_size.height != m_frame_size.height) { + throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width) + "x" + std::to_string(src_size.height) + + ", expected " + std::to_string(m_frame_size.width) + "x" + std::to_string(m_frame_size.height)); + } + + // Copy from the source surface into the destination frame + for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { + for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { + m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); + } + } +} + +auto graphite::spriteworld::rleD::write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void +{ + m_surface.set(offset, quickdraw::rgb(static_cast(pixel & 0xFFFF))); +} + +auto graphite::spriteworld::rleD::write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void +{ + switch (type) { + case pixel_type::type1: { + m_surface.set(offset, quickdraw::rgb((pixel >> 16) & 0xFFFF)); + } + case pixel_type::type2: { + m_surface.set(offset, quickdraw::rgb(pixel & 0xFFFF)); + } + } +} + +auto graphite::spriteworld::rleD::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t +{ + quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); + quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); + return static_cast(p.y * m_surface.size().width + p.x); +} + +// MARK: - Decoding + +auto graphite::spriteworld::rleD::decode(data::reader &reader) -> void +{ + // Read the header of the RLE information. This will tell us what we need to do in order to actually + // decode the frames. + m_frame_size = quickdraw::size::read(reader, quickdraw::coding_type::macintosh); + m_bpp = reader.read_short(); + m_palette_id = reader.read_short(); + m_frame_count = reader.read_short(); + reader.move(6); + + // Ensure that the RLE has a BPP of 16. This is the only format that we support currently. + if (m_bpp != 16) { + throw std::runtime_error("Incorrect color depth for rlëD resource: " + std::to_string(m_id) + ", " + m_name); + } + + // Determine what the grid will be. We need to round up to the next whole and have blank tiles if the frame count + // is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface in which all frame will be draw to, and other working variables required to parse and decode + // the RLE data correctly. + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); + + rleD::opcode opcode = opcode::eof; + std::uint64_t position = 0; + std::uint32_t row_start = 0; + std::int32_t current_line = -1; + std::uint64_t current_offset = 0; + std::int32_t count = 0; + std::uint16_t pixel = 0; + std::int32_t current_frame = 0; + std::uint32_t pixel_run = 0; + + while (!reader.eof()) { + if ((row_start != 0) && ((position - row_start) & 0x03)) { + position += 4 - ((position - row_start) & 0x03); + reader.move(4 - (count & 0x03)); + } + + opcode = reader.read_enum(); + count = reader.read_triple(); + + switch (opcode) { + case opcode::eof: { + // Check that we're not erroneously an EOF. + if (current_line != m_frame_size.height - 1) { + throw std::runtime_error("Incorrect number of scanlines in rlëD resource: " + std::to_string(m_id) + ", " + m_name); + } + + // Have we finished decoding the last frame in the data? + if (++current_frame >= m_frame_count) { + goto COMPLETED_LAST_FRAME; + } + + // Prepare for the next frame + current_line = -1; + break; + } + + case opcode::line_start: { + current_offset = surface_offset(current_frame, ++current_line); + row_start = reader.position(); + break; + } + + case opcode::pixel_data: { + for (auto i = 0; i < count; i += 2) { + pixel = reader.read_short(); + write_pixel(pixel, 0xFF, current_offset); + ++current_offset; + } + + if (count & 0x03) { + reader.move(4 - (count & 0x03)); + } + + break; + } + + case opcode::pixel_run: { + pixel_run = reader.read_long(); + for (auto i = 0; i < count; i += 4) { + write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type1); + ++current_offset; + if (i + 2 < count) { + write_pixel(pixel_run, 0xFF, current_offset, pixel_type::type2); + ++current_offset; + } + } + break; + } + + case opcode::transparent_run: { + current_offset += count >> 1; + break; + } + } + } + +COMPLETED_LAST_FRAME: + return; +} + +// MARK: - Encoding + +auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void +{ + // Write out the header + m_frame_size.encode(writer, quickdraw::coding_type::macintosh); + writer.write_short(m_bpp); + writer.write_short(m_palette_id); + writer.write_short(m_frame_count); + + // Reserved fields + writer.write_short(0, 3); + + // Write out the RLE frames + for (auto f = 0; f < m_frame_count; ++f) { + auto frame = frame_rect(f); + + for (std::int16_t y = 0; y < frame.size.height; ++y) { + auto line_start_pos = writer.position(); + writer.write_long(0); + + rleD::opcode run_state = opcode::line_start; + auto run_start_pos = line_start_pos + 4; + auto run_count = 0; + + for (std::int16_t x = 0; x < frame.size.width; ++x) { + auto pixel = m_surface.at(frame.origin.x + x, frame.origin.y + y); + + if (pixel.components.alpha == 0) { + if (run_state == opcode::line_start) { + // Start of a transparent run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::transparent_run; + run_count = constants::advance; + } + else if (run_state == opcode::transparent_run) { + // Continue transparent run + run_count += constants::advance; + } + else { + // End of pixel run, start of transparent run. + auto run_end_pos = writer.position(); + writer.set_position(run_start_pos); + writer.write_enum(opcode::pixel_data); + writer.write_triple(run_count); + writer.set_position(run_end_pos); + + // Pad to nearest 4-byte boundary + if (run_count & 0x3) { + writer.move(4 - (run_count & 0x3)); + } + + // Start transparent run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::transparent_run; + run_count = constants::advance; + } + } + else { + if (run_state == opcode::line_start) { + // Start of pixel run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::pixel_data; + run_count = constants::advance; + } + else if (run_state == opcode::transparent_run) { + // End of transparent run, start of pixel run + writer.move(-4); + writer.write_enum(opcode::transparent_run); + writer.write_triple(run_count); + + // Start pixel run + run_start_pos = writer.position(); + writer.write_long(0); + run_state = opcode::pixel_data; + run_count = constants::advance; + } + else { + // Continue pixel run + run_count += constants::advance; + } + + // Write the pixel + writer.write_short( + (pixel.components.blue >> 3) | + ((pixel.components.green >> 3) << 5) | + ((pixel.components.red >> 3) << 10) + ); + } + } + + // Terminate the current opcode + if (run_state == opcode::pixel_data) { + auto run_end_pos = writer.position(); + writer.set_position(run_start_pos); + writer.write_enum(opcode::pixel_data); + writer.write_triple(run_count); + + // Pad to the nearest 4-byte boundary + if ((run_end_pos - line_start_pos) & 0x3) { + writer.move(4 - ((run_end_pos - line_start_pos) & 0x3)); + } + } + else if (run_state == opcode::transparent_run) { + // Erase the transparent run opcode placeholder -- remaining data is assumed transparent + writer.set_position(run_start_pos); + } + + // Write out the opcode and the size at the start of the line + auto line_end_pos = writer.position(); + writer.set_position(line_start_pos); + writer.write_enum(opcode::line_start); + writer.write_triple(line_end_pos - line_start_pos - 4); + writer.set_position(line_end_pos); + } + + writer.write_enum(opcode::eof); + writer.write_triple(0); + } +} \ No newline at end of file diff --git a/libGraphite/spriteworld/rleD.hpp b/libGraphite/spriteworld/rleD.hpp new file mode 100644 index 0000000..0a37154 --- /dev/null +++ b/libGraphite/spriteworld/rleD.hpp @@ -0,0 +1,83 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" + +namespace graphite::spriteworld +{ + struct rleD + { + public: + static auto type_code() -> std::string { return "rlëD"; } + + public: + rleD() = default; + rleD(const quickdraw::size& size, std::uint16_t frame_count); + explicit rleD(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit rleD(data::reader& reader); + + ~rleD() = default; + + auto surface() -> quickdraw::surface&; + [[nodiscard]] auto frames() const -> std::vector>; + [[nodiscard]] auto frame_count() const -> std::size_t; + + [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> quickdraw::rect; + [[nodiscard]] auto frame_surface(std::uint32_t idx) const -> quickdraw::surface; + auto write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void; + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + private: + enum class pixel_type { type1, type2 }; + + enum class opcode : std::uint8_t + { + eof = 0x00, + line_start = 0x01, + pixel_data = 0x02, + transparent_run = 0x03, + pixel_run = 0x04, + }; + + rsrc::resource::identifier m_id { 0 }; + std::string m_name; + std::vector> m_frames; + quickdraw::surface m_surface; + quickdraw::size m_frame_size { 0 }; + quickdraw::size m_grid_size { 0 }; + std::uint16_t m_frame_count { 0 }; + std::uint16_t m_bpp { 0 }; + std::uint16_t m_palette_id { 0 }; + + auto decode(data::reader& reader) -> void; + + [[nodiscard]] auto surface_offset(std::int32_t frame, std::int32_t offset) -> std::uint64_t; + + auto write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void; + auto write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void; + }; +} diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp new file mode 100644 index 0000000..b3c951a --- /dev/null +++ b/libGraphite/spriteworld/rleX.cpp @@ -0,0 +1,285 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "libGraphite/spriteworld/rleX.hpp" +#include + +// MARK: - Constants + +namespace graphite::spriteworld::constants +{ + static constexpr std::uint16_t rle_grid_width = 6; + static constexpr std::size_t advance = 2; +} + +// MARK: - Construction + +graphite::spriteworld::rleX::rleX(data::reader& reader) +{ + decode(reader); +} + +graphite::spriteworld::rleX::rleX(const quickdraw::size &size, std::uint16_t frame_count) + : m_id(0), m_name(type_code()), m_frame_size(size), m_frame_count(frame_count), m_bpp(32), m_palette_id(0) +{ + // Determine what the grid will be. We need to round up to the next whole number and have blank tiles + // if the frame count is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); +} + +graphite::spriteworld::rleX::rleX(const data::block& data, rsrc::resource::identifier id, const std::string& name) + : m_id(id), m_name(name) +{ + data::reader reader(&data); + decode(reader); +} + +// MARK: - Accessors + +auto graphite::spriteworld::rleX::surface() -> quickdraw::surface& +{ + return m_surface; +} + +auto graphite::spriteworld::rleX::frames() const -> std::vector> +{ + return m_frames; +} + +auto graphite::spriteworld::rleX::frame_count() const -> std::size_t +{ + return m_frame_count; +} + +auto graphite::spriteworld::rleX::data() -> data::block +{ + data::writer writer; + encode(writer); + return std::move(*const_cast(writer.data())); +} + +// MARK: - Operations + +auto graphite::spriteworld::rleX::frame_rect(std::uint32_t frame) const -> quickdraw::rect +{ + return { + quickdraw::point( + static_cast(frame % constants::rle_grid_width) * m_frame_size.width, + static_cast(frame / constants::rle_grid_width) * m_frame_size.height + ), + m_frame_size + }; +} + +auto graphite::spriteworld::rleX::frame_surface(std::uint32_t frame) const -> quickdraw::surface +{ + quickdraw::surface surface(m_frame_size); + quickdraw::rect src_rect(frame_rect(frame)); + + // Extract the frame area of the origin surface + for (std::int16_t y = 0; y < src_rect.size.height; ++y) { + for (std::int16_t x = 0; x < src_rect.size.width; ++x) { + surface.set(x, y, m_surface.at(x + src_rect.origin.x, y + src_rect.origin.y)); + } + } + + return std::move(surface); +} + +auto graphite::spriteworld::rleX::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +{ + quickdraw::rect dst_rect = frame_rect(frame); + quickdraw::size src_size = surface.size(); + + if (src_size.width != m_frame_size.width || src_size.height != m_frame_size.height) { + throw std::runtime_error("Incorrect frame dimensions " + std::to_string(src_size.width) + "x" + std::to_string(src_size.height) + + ", expected " + std::to_string(m_frame_size.width) + "x" + std::to_string(m_frame_size.height)); + } + + // Copy from the source surface into the destination frame + for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { + for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { + m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); + } + } +} + +auto graphite::spriteworld::rleX::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t +{ + quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); + quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); + return static_cast(p.y * m_surface.size().width + p.x); +} + +// MARK: - Decoding + +auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void +{ + // Read the header of the RLE information. This will tell us what we need to do in order to actually + // decode the frame. + m_frame_size = quickdraw::size::read(reader, quickdraw::coding_type::macintosh); + m_bpp = reader.read_short(); + m_palette_id = reader.read_short(); + m_frame_count = reader.read_short(); + reader.move(6); + + // Ensure that the RLE has a BPP of 32. This is the only format that we support currently. + if (m_bpp != 32) { + throw std::runtime_error("Incorrect color depth for rlëX resource: " + std::to_string(m_id) + ", " + m_name); + } + + // Determine what the grid will be. We need to round up to the next whole and have blank tiles if the frame count + // is not divisible by the grid width constant. + auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); + + // Create the surface in which all frames will be drawn to, and other working variables required to parse and + // decode the RLE data correctly. + m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); + + rleX::opcode opcode = opcode::eof; + std::uint64_t current_offset = 0; + std::int32_t current_frame = 0; + std::uint16_t count = 0; + + struct quickdraw::ycrcb yuv { 0 }; + + while (!reader.eof()) { + opcode = reader.read_enum(); + switch (opcode) { + case opcode::eof: { + // Have we finished decoding the last frame in the data? + if (++current_frame >= m_frame_count) { + goto COMPLETED_LAST_FRAME; + } + break; + } + case opcode::set_luma: { + yuv.y = reader.read_byte(); + break; + } + case opcode::set_cr: { + yuv.cr = reader.read_byte(); + break; + } + case opcode::set_cb: { + yuv.cb = reader.read_byte(); + break; + } + case opcode::set_alpha: { + yuv.alpha = reader.read_byte(); + break; + } + case opcode::advance: { + count = reader.read_short(); + } + default: { + if (static_cast(opcode) & static_cast(opcode::short_advance)) { + count = static_cast(opcode) & ~static_cast(opcode::short_advance); + } + auto rgb = quickdraw::rgb(yuv); + for (auto i = 0; i < count; ++i) { + m_surface.set(current_offset++, rgb); + } + break; + } + } + + } + +COMPLETED_LAST_FRAME: + return; +} + +// MARK: - Encoding + +auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void +{ + // Write out the header + m_frame_size.encode(writer, quickdraw::coding_type::macintosh); + writer.write_short(m_bpp); + writer.write_short(m_palette_id); + writer.write_short(m_frame_count); + + // Reserved fields. + writer.write_short(0, 3); + + // Write out the RLE frames + for (auto f = 0; f < m_frame_count; ++f) { + auto frame = frame_rect(f); + struct quickdraw::ycrcb yuv { 0 }; + + std::uint16_t count = 0; + bool new_run = false; + + for (std::int16_t y = 0; y < frame.size.height; ++y) { + for (std::int16_t x = 0; x < frame.size.width; ++x) { + auto next_yuv = quickdraw::ycrcb(m_surface.at(frame.origin.x + x, frame.origin.y + y)); + if (next_yuv.y != yuv.y) { + yuv.y = next_yuv.y; + writer.write_enum(rleX::opcode::set_luma); + writer.write_byte(yuv.y); + new_run = true; + } + + if (next_yuv.cr != yuv.cr) { + yuv.cr = next_yuv.cr; + writer.write_enum(rleX::opcode::set_cr); + writer.write_byte(yuv.cr); + new_run = true; + } + + if (next_yuv.cb != yuv.cb) { + yuv.cb = next_yuv.cb; + writer.write_enum(rleX::opcode::set_cb); + writer.write_byte(yuv.cb); + new_run = true; + } + + if (next_yuv.alpha != yuv.alpha) { + yuv.alpha = next_yuv.alpha; + writer.write_enum(rleX::opcode::set_alpha); + writer.write_byte(yuv.alpha); + new_run = true; + } + + if (new_run) { + if (count < 127) { + auto opcode = static_cast(opcode::short_advance) + count; + writer.write_byte(opcode); + } + else { + writer.write_enum(opcode::advance); + writer.write_short(count); + } + count = 0; + } + + count++; + } + } + + writer.write_enum(opcode::eof); + } +} \ No newline at end of file diff --git a/libGraphite/spriteworld/rleX.hpp b/libGraphite/spriteworld/rleX.hpp new file mode 100644 index 0000000..13fe7ad --- /dev/null +++ b/libGraphite/spriteworld/rleX.hpp @@ -0,0 +1,84 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include "libGraphite/quickdraw/support/surface.hpp" +#include "libGraphite/quickdraw/type/rect.hpp" + +namespace graphite::spriteworld +{ + /* + * This 'rleX' variant of the 'rleD' format, is a custom type created for Graphite/Kestrel. + * It is not part of the original Sprite World. + */ + struct rleX + { + public: + static auto type_code() -> std::string { return "rlëX"; } + + public: + rleX() = default; + rleX(const quickdraw::size& size, std::uint16_t frame_count); + explicit rleX(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit rleX(data::reader& reader); + + ~rleX() = default; + + auto surface() -> quickdraw::surface&; + [[nodiscard]] auto frames() const -> std::vector>; + [[nodiscard]] auto frame_count() const -> std::size_t; + + [[nodiscard]] auto frame_rect(std::uint32_t idx) const -> quickdraw::rect; + [[nodiscard]] auto frame_surface(std::uint32_t idx) const -> quickdraw::surface; + auto write_frame(std::uint32_t frame, const quickdraw::surface& surface) -> void; + + auto encode(data::writer& writer) -> void; + auto data() -> data::block; + + private: + enum class opcode : std::uint8_t + { + eof = 0x00, + set_luma = 0x01, + set_cr = 0x02, + set_cb = 0x03, + set_alpha = 0x04, + advance = 0x05, + short_advance = 0x80, + }; + + rsrc::resource::identifier m_id { 0 }; + std::string m_name; + std::vector> m_frames; + quickdraw::surface m_surface; + quickdraw::size m_frame_size { 0 }; + quickdraw::size m_grid_size { 0 }; + std::uint16_t m_frame_count { 0 }; + std::uint16_t m_bpp { 0 }; + std::uint16_t m_palette_id { 0 }; + + auto decode(data::reader& reader) -> void; + + [[nodiscard]] auto surface_offset(std::int32_t frame, std::int32_t offset) -> std::uint64_t; + }; +} From a8d21302cd31d3c36336654524e9351830640485 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 24 Jul 2022 19:43:14 +0100 Subject: [PATCH 047/113] Fix and issue in the rleD and rleX encoders. --- libGraphite/data/writer.cpp | 2 +- libGraphite/data/writer.hpp | 16 +++++++- libGraphite/quickdraw/support/surface.cpp | 10 +++-- libGraphite/quickdraw/support/surface.hpp | 3 +- libGraphite/spriteworld/rleD.cpp | 48 +++++++++++++---------- libGraphite/spriteworld/rleX.cpp | 9 +++-- 6 files changed, 58 insertions(+), 30 deletions(-) diff --git a/libGraphite/data/writer.cpp b/libGraphite/data/writer.cpp index bb22dec..cf5ad0a 100644 --- a/libGraphite/data/writer.cpp +++ b/libGraphite/data/writer.cpp @@ -189,7 +189,7 @@ auto graphite::data::writer::write_bytes(const std::vector &bytes) -> v auto graphite::data::writer::write_bytes(const std::vector &bytes) -> void { - write_bytes(std::move(std::vector(bytes.begin(), bytes.end()))); + write_bytes(std::vector(bytes.begin(), bytes.end())); } auto graphite::data::writer::write_data(const class block *data) -> void diff --git a/libGraphite/data/writer.hpp b/libGraphite/data/writer.hpp index 5a418b9..b1b25de 100644 --- a/libGraphite/data/writer.hpp +++ b/libGraphite/data/writer.hpp @@ -128,13 +128,27 @@ namespace graphite::data ensure_required_space(position(), size * count); auto ptr = m_data->template get(position()); + // Correct the alignment. + if (m_data->byte_order() == byte_order::msb) { + for (auto i = size; i < sizeof(swapped); ++i) { + swapped >>= 8; + } + } + else { + for (auto i = size; i < sizeof(swapped); ++i) { + swapped <<= 8; + } + } + + for (auto n = 0; n < count; ++n) { for (auto i = 0; i < size; ++i) { auto b = i << 3ULL; *ptr++ = (swapped >> b) & 0xFF; - move(); } } + + move(size * count); } template::value>::type* = nullptr> diff --git a/libGraphite/quickdraw/support/surface.cpp b/libGraphite/quickdraw/support/surface.cpp index b7ee7d7..4769415 100644 --- a/libGraphite/quickdraw/support/surface.cpp +++ b/libGraphite/quickdraw/support/surface.cpp @@ -73,7 +73,9 @@ graphite::quickdraw::surface::surface(surface &&surface) noexcept graphite::quickdraw::surface::~surface() { - delete m_data; + if (!m_weak_data && m_data) { + delete m_data; + } } // MARK: - Operators @@ -85,18 +87,20 @@ auto graphite::quickdraw::surface::operator=(const surface& surface) -> class su } m_data = new data::block(*surface.m_data); + m_weak_data = false; m_size = surface.m_size; m_row_bytes = surface.m_row_bytes; return *this; } -auto graphite::quickdraw::surface::operator=(class surface&& surface) -> class surface& +auto graphite::quickdraw::surface::operator=(class surface&& surface) noexcept -> class surface& { if (this != &surface) { delete m_data; m_data = surface.m_data; + m_weak_data = false; m_size = surface.m_size; m_row_bytes = surface.m_row_bytes; @@ -131,7 +135,7 @@ auto graphite::quickdraw::surface::at(std::int16_t x, std::int16_t y) const -> u auto graphite::quickdraw::surface::at(std::uint32_t offset) const -> union color { - return m_data->get()[offset * constants::color_width]; + return m_data->get()[offset]; } auto graphite::quickdraw::surface::set(const point& p, union color color) -> void diff --git a/libGraphite/quickdraw/support/surface.hpp b/libGraphite/quickdraw/support/surface.hpp index 710dc35..b89f64f 100644 --- a/libGraphite/quickdraw/support/surface.hpp +++ b/libGraphite/quickdraw/support/surface.hpp @@ -41,7 +41,7 @@ namespace graphite::quickdraw ~surface(); auto operator=(const surface&) -> surface&; - auto operator=(surface&&) -> surface&; + auto operator=(surface&&) noexcept -> surface&; [[nodiscard]] auto raw() const -> const data::block&; [[nodiscard]] auto size() const -> struct size; @@ -60,5 +60,6 @@ namespace graphite::quickdraw std::uint32_t m_row_bytes; quickdraw::size m_size; data::block *m_data { nullptr }; + bool m_weak_data { false }; }; } diff --git a/libGraphite/spriteworld/rleD.cpp b/libGraphite/spriteworld/rleD.cpp index f65ba25..3834e2c 100644 --- a/libGraphite/spriteworld/rleD.cpp +++ b/libGraphite/spriteworld/rleD.cpp @@ -118,8 +118,8 @@ auto graphite::spriteworld::rleD::write_frame(std::uint32_t frame, const quickdr } // Copy from the source surface into the destination frame - for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { - for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { + for (std::int16_t y = 0; y < src_size.height; ++y) { + for (std::int16_t x = 0; x < src_size.width; ++x) { m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); } } @@ -259,6 +259,8 @@ auto graphite::spriteworld::rleD::decode(data::reader &reader) -> void auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void { + writer.change_byte_order(data::byte_order::msb); + // Write out the header m_frame_size.encode(writer, quickdraw::coding_type::macintosh); writer.write_short(m_bpp); @@ -271,10 +273,11 @@ auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void // Write out the RLE frames for (auto f = 0; f < m_frame_count; ++f) { auto frame = frame_rect(f); + auto line_count = 0; for (std::int16_t y = 0; y < frame.size.height; ++y) { + ++line_count; auto line_start_pos = writer.position(); - writer.write_long(0); rleD::opcode run_state = opcode::line_start; auto run_start_pos = line_start_pos + 4; @@ -286,8 +289,6 @@ auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void if (pixel.components.alpha == 0) { if (run_state == opcode::line_start) { // Start of a transparent run - run_start_pos = writer.position(); - writer.write_long(0); run_state = opcode::transparent_run; run_count = constants::advance; } @@ -305,17 +306,25 @@ auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void // Pad to nearest 4-byte boundary if (run_count & 0x3) { - writer.move(4 - (run_count & 0x3)); + writer.write_byte(0, 4 - (run_count & 0x3)); } // Start transparent run - run_start_pos = writer.position(); - writer.write_long(0); run_state = opcode::transparent_run; run_count = constants::advance; } } else { + if (line_count != 0) { + // First pixel data for this line, write the line start + // Doing this only on demand allows us to omit trailing blank lines in the frame. + for (auto i = 0; i < line_count; ++i) { + writer.write_enum(opcode::line_start); + writer.write_triple(0); + } + line_count = 0; + } + if (run_state == opcode::line_start) { // Start of pixel run run_start_pos = writer.position(); @@ -325,7 +334,6 @@ auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void } else if (run_state == opcode::transparent_run) { // End of transparent run, start of pixel run - writer.move(-4); writer.write_enum(opcode::transparent_run); writer.write_triple(run_count); @@ -355,23 +363,21 @@ auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void writer.set_position(run_start_pos); writer.write_enum(opcode::pixel_data); writer.write_triple(run_count); + writer.set_position(run_end_pos); // Pad to the nearest 4-byte boundary - if ((run_end_pos - line_start_pos) & 0x3) { - writer.move(4 - ((run_end_pos - line_start_pos) & 0x3)); + if (run_count & 0x3) { + writer.write_byte(0, 4 - (run_count & 0x3)); } } - else if (run_state == opcode::transparent_run) { - // Erase the transparent run opcode placeholder -- remaining data is assumed transparent - writer.set_position(run_start_pos); - } - // Write out the opcode and the size at the start of the line - auto line_end_pos = writer.position(); - writer.set_position(line_start_pos); - writer.write_enum(opcode::line_start); - writer.write_triple(line_end_pos - line_start_pos - 4); - writer.set_position(line_end_pos); + if (run_state != opcode::line_start) { + auto line_end_pos = writer.position(); + writer.set_position(line_start_pos); + writer.write_enum(opcode::line_start); + writer.write_triple((line_end_pos - line_start_pos - 4)); + writer.set_position(line_end_pos); + } } writer.write_enum(opcode::eof); diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index b3c951a..07e8c5e 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -118,8 +118,8 @@ auto graphite::spriteworld::rleX::write_frame(std::uint32_t frame, const quickdr } // Copy from the source surface into the destination frame - for (std::int16_t y = 0; y < dst_rect.size.height; ++y) { - for (std::int16_t x = 0; x < dst_rect.size.width; ++x) { + for (std::int16_t y = 0; y < src_size.height; ++y) { + for (std::int16_t x = 0; x < src_size.width; ++x) { m_surface.set(x + dst_rect.origin.x, y + dst_rect.origin.y, surface.at(x, y)); } } @@ -216,6 +216,8 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void { + writer.change_byte_order(data::byte_order::msb); + // Write out the header m_frame_size.encode(writer, quickdraw::coding_type::macintosh); writer.write_short(m_bpp); @@ -264,7 +266,7 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void new_run = true; } - if (new_run) { + if (new_run && count > 0) { if (count < 127) { auto opcode = static_cast(opcode::short_advance) + count; writer.write_byte(opcode); @@ -275,6 +277,7 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void } count = 0; } + new_run = false; count++; } From 9cbc875afe642235f02ab33628a4512011f28010 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 25 Jul 2022 22:02:11 +0100 Subject: [PATCH 048/113] =?UTF-8?q?Tweaks=20to=20data::block,=20rl=C3=ABX?= =?UTF-8?q?=20and=20color.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/data/data.cpp | 19 ++++++++++ libGraphite/data/data.hpp | 2 ++ libGraphite/data/writer.cpp | 19 ++++++---- libGraphite/quickdraw/type/color.cpp | 52 +++++++++++++++++----------- libGraphite/quickdraw/type/color.hpp | 8 ++--- libGraphite/spriteworld/rleX.cpp | 52 +++++++++++++++------------- 6 files changed, 96 insertions(+), 56 deletions(-) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 6a58d69..75bbe12 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -98,6 +98,17 @@ graphite::data::block::block(std::size_t capacity, enum byte_order order) { } +graphite::data::block::block(std::size_t capacity, std::size_t allocation_size, enum byte_order order) + : m_raw_size(simd_expand_capacity(allocation_size)), + m_data_size(capacity), + m_raw(malloc(m_raw_size)), + m_data(simd_align(m_raw)), + m_allocation_owner(nullptr), + m_byte_order(order), + m_has_ownership(true) +{ +} + graphite::data::block::block(const std::string &path, enum byte_order order) : m_byte_order(order), m_allocation_owner(nullptr), @@ -372,6 +383,14 @@ static inline auto inline_set(graphite::data::block *dst, union simd_value v, st } } +auto graphite::data::block::increase_size_to(std::size_t new_size) -> void +{ + if (new_size > m_raw_size) { + throw std::runtime_error("Attempted to increase size of data::block beyond allowed range."); + } + m_data_size = new_size; +} + auto graphite::data::block::clear() -> void { set((uint32_t)0); diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index 87bf7ec..deb81a8 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -57,6 +57,7 @@ namespace graphite::data public: block() = default; explicit block(std::size_t capacity, enum byte_order order = byte_order::msb); + block(std::size_t capacity, std::size_t allocation_size, enum byte_order order = byte_order::msb); explicit block(const std::string& path, enum byte_order order = byte_order::msb); explicit block(const std::vector& bytes, enum byte_order order = byte_order::msb); block(const void *data, std::size_t count, bool take_ownership = true, enum byte_order order = byte_order::msb); @@ -89,6 +90,7 @@ namespace graphite::data [[nodiscard]] inline auto byte_order() const -> byte_order { return m_byte_order; } auto change_byte_order(enum byte_order order) -> void { m_byte_order = order; } + auto increase_size_to(std::size_t new_size) -> void; auto clear() -> void; diff --git a/libGraphite/data/writer.cpp b/libGraphite/data/writer.cpp index cf5ad0a..05439c1 100644 --- a/libGraphite/data/writer.cpp +++ b/libGraphite/data/writer.cpp @@ -59,13 +59,20 @@ auto graphite::data::writer::expand_storage(std::size_t amount) -> void // Construct a new data object with the appropriate new size, and copy in the old data. auto required_size = size() + amount; - auto new_data = new class block(required_size, m_data->byte_order()); - new_data->set(static_cast(0), required_size); - new_data->copy_from(*m_data); + if (required_size < m_data->raw_size()) { + const_cast(m_data)->increase_size_to(required_size); + } + else { + auto allocation_size = size() + std::max(size(), amount); + auto new_data = new class block(required_size, std::max(allocation_size, required_size), m_data->byte_order()); + new_data->set(static_cast(0), allocation_size); + new_data->copy_from(*m_data); + + // Replace the old data with the new object. + delete m_data; + m_data = new_data; + } - // Replace the old data with the new object. - delete m_data; - m_data = new_data; } auto graphite::data::writer::ensure_required_space(block::position position, std::size_t amount) -> void diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index 366200b..72e17af 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -69,33 +69,43 @@ auto graphite::quickdraw::colors::clear() -> union color // MARK: - YCrCb Color -auto graphite::quickdraw::ycrcb(const union color& rgb) -> struct ycrcb +auto graphite::quickdraw::ycbcr(const union color& rgb) -> struct ycbcr { - double r = rgb.components.red; - double g = rgb.components.green; - double b = rgb.components.blue; - - std::int32_t y = static_cast( 0.299 * r + 0.587 * g + 0.114 * b); - std::int32_t u = static_cast(-0.168736 * r - 0.331264 * g + 0.500 * b + 128); - std::int32_t v = static_cast( 0.500 * r - 0.418688 * g - 0.081312 * b + 128); - - std::uint8_t y_clamped = std::clamp(y, 0, 255); - std::uint8_t u_clamped = std::clamp(u, 0, 255); - std::uint8_t v_clamped = std::clamp(v, 0, 255); - - return (struct ycrcb) { - .y = y_clamped, - .cr = u_clamped, - .cb = v_clamped, + if ((rgb.value & 0x00FFFFFF) == 0) { + return (struct ycbcr) { + .y = 0, + .cb = 0, + .cr = 0, + .alpha = rgb.components.alpha + }; + } + + + std::uint8_t r = rgb.components.red; + std::uint8_t g = rgb.components.green; + std::uint8_t b = rgb.components.blue; + + std::int16_t y = static_cast( 0.29900 * r + 0.58700 * g + 0.11400 * b); + std::int16_t cb = static_cast(-0.16874 * r - 0.33126 * g + 0.50000 * b + 128); + std::int16_t cr = static_cast( 0.50000 * r - 0.41868 * g - 0.08131 * b + 128); + + std::uint8_t y_clamped = std::clamp(y , 0, 255); + std::uint8_t cb_clamped = std::clamp(cb, 0, 255); + std::uint8_t cr_clamped = std::clamp(cr, 0, 255); + + return (struct ycbcr) { + .y = y_clamped, + .cb = cb_clamped, + .cr = cr_clamped, .alpha = rgb.components.alpha }; } -auto graphite::quickdraw::rgb(const struct ycrcb& color) -> union color +auto graphite::quickdraw::rgb(const struct ycbcr& color) -> union color { - auto r = std::clamp(color.y + 1.4075 * (color.cb - 128), 0, 255); - auto g = std::clamp(color.y - (0.3455 * (color.cr - 128)) - (0.7169 * (color.cb - 128)), 0, 255); - auto b = std::clamp(color.y + 1.7790 * (color.cr - 128), 0, 255); + auto r = std::clamp(color.y + (1.4075 * (color.cr - 128)), 0, 255); + auto g = std::clamp(color.y - (0.3455 * (color.cb - 128)) - (0.7169 * (color.cr - 128)), 0, 255); + auto b = std::clamp(color.y + (1.7790 * (color.cb - 128)), 0, 255); return rgb(r, g, b, color.alpha); } diff --git a/libGraphite/quickdraw/type/color.hpp b/libGraphite/quickdraw/type/color.hpp index c928af8..c24ec49 100644 --- a/libGraphite/quickdraw/type/color.hpp +++ b/libGraphite/quickdraw/type/color.hpp @@ -38,11 +38,11 @@ namespace graphite::quickdraw } components; }; - struct ycrcb + struct ycbcr { color_component y; - color_component cr; color_component cb; + color_component cr; color_component alpha; }; @@ -64,6 +64,6 @@ namespace graphite::quickdraw [[nodiscard]] auto clear() -> union color; } - [[nodiscard]] auto ycrcb(const union color& rgb) -> struct ycrcb; - [[nodiscard]] auto rgb(const struct ycrcb& color) -> union color; + [[nodiscard]] auto ycbcr(const union color& rgb) -> struct ycbcr; + [[nodiscard]] auto rgb(const struct ycbcr& color) -> union color; } \ No newline at end of file diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 07e8c5e..3ba923d 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -163,7 +163,7 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void std::int32_t current_frame = 0; std::uint16_t count = 0; - struct quickdraw::ycrcb yuv { 0 }; + struct quickdraw::ycbcr yuv { 0 }; while (!reader.eof()) { opcode = reader.read_enum(); @@ -230,54 +230,56 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void // Write out the RLE frames for (auto f = 0; f < m_frame_count; ++f) { auto frame = frame_rect(f); - struct quickdraw::ycrcb yuv { 0 }; + struct quickdraw::ycbcr yuv { + .y = 0, + .cb = 128, + .cr = 128, + .alpha = 255 + }; std::uint16_t count = 0; - bool new_run = false; for (std::int16_t y = 0; y < frame.size.height; ++y) { for (std::int16_t x = 0; x < frame.size.width; ++x) { - auto next_yuv = quickdraw::ycrcb(m_surface.at(frame.origin.x + x, frame.origin.y + y)); - if (next_yuv.y != yuv.y) { + auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x + x, frame.origin.y + y)); + + if (count > 0 && next_yuv.y > 0) { + if ((next_yuv.y != yuv.y) || (next_yuv.cr != yuv.cr) || (next_yuv.cb != yuv.cb) || (next_yuv.alpha != yuv.alpha)) { + if (count < 127) { + auto opcode = static_cast(opcode::short_advance) + count; + writer.write_byte(opcode); + } + else { + writer.write_enum(opcode::advance); + writer.write_short(count); + } + count = 0; + } + } + + if (std::abs(next_yuv.y - yuv.y) > 1) { yuv.y = next_yuv.y; writer.write_enum(rleX::opcode::set_luma); writer.write_byte(yuv.y); - new_run = true; } - if (next_yuv.cr != yuv.cr) { + if (std::abs(next_yuv.cr - yuv.cr) > 1 && yuv.y > 0) { yuv.cr = next_yuv.cr; writer.write_enum(rleX::opcode::set_cr); writer.write_byte(yuv.cr); - new_run = true; } - if (next_yuv.cb != yuv.cb) { + if (std::abs(next_yuv.cb - yuv.cb) > 1 && yuv.y > 0) { yuv.cb = next_yuv.cb; writer.write_enum(rleX::opcode::set_cb); writer.write_byte(yuv.cb); - new_run = true; } - if (next_yuv.alpha != yuv.alpha) { + if (std::abs(next_yuv.alpha - yuv.alpha) > 1) { yuv.alpha = next_yuv.alpha; writer.write_enum(rleX::opcode::set_alpha); writer.write_byte(yuv.alpha); - new_run = true; - } - - if (new_run && count > 0) { - if (count < 127) { - auto opcode = static_cast(opcode::short_advance) + count; - writer.write_byte(opcode); - } - else { - writer.write_enum(opcode::advance); - writer.write_short(count); - } - count = 0; } - new_run = false; count++; } From 3cce78116673c15d90d14301bf8f1be5ef0d9d44 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 31 Jul 2022 08:49:19 +0100 Subject: [PATCH 049/113] Minor tweak --- libGraphite/spriteworld/rleX.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 3ba923d..4eb833c 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -162,6 +162,7 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void std::uint64_t current_offset = 0; std::int32_t current_frame = 0; std::uint16_t count = 0; + auto frame = frame_rect(0); struct quickdraw::ycbcr yuv { 0 }; @@ -173,6 +174,10 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void if (++current_frame >= m_frame_count) { goto COMPLETED_LAST_FRAME; } + + frame = frame_rect(current_frame); + current_offset = 0; + break; } case opcode::set_luma: { @@ -200,7 +205,7 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void } auto rgb = quickdraw::rgb(yuv); for (auto i = 0; i < count; ++i) { - m_surface.set(current_offset++, rgb); + m_surface.set((current_offset % m_frame_size.width) + frame.origin.x, (current_offset / m_frame_size.width) + frame.origin.y, rgb); } break; } From cb7a38f56a99643d09e2e30dfe72a9829fbb55ba Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 1 Aug 2022 08:05:17 +0100 Subject: [PATCH 050/113] Disable optimization in specific functions to prevent them being incorrectly optimized. --- libGraphite/data/data.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 75bbe12..a34725a 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -336,7 +336,7 @@ auto graphite::data::block::clone_from(const graphite::data::block &source) -> v } } -auto graphite::data::block::copy_from(const block &source) const -> void +__attribute__((optnone)) auto graphite::data::block::copy_from(const block &source) const -> void { auto source_ptr = source.get(); auto dest_ptr = get(); @@ -362,7 +362,7 @@ auto graphite::data::block::copy_from(const block &source) const -> void // MARK: - Operations -static inline auto inline_set(graphite::data::block *dst, union simd_value v, std::size_t bytes, std::size_t start) -> void +__attribute__((optnone)) static inline auto inline_set(graphite::data::block *dst, union simd_value v, std::size_t bytes, std::size_t start) -> void { auto len = std::min(dst->size() - start, bytes); auto ptr = dst->get(start); From cd0b30b79b0dbfa830351ca87f08104211b88322 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 1 Aug 2022 11:25:53 +0100 Subject: [PATCH 051/113] Disable GraphiteTest in CI builds --- CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ba4d85..ed0574d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,14 +36,14 @@ file(GLOB_RECURSE graphite_sources ) add_library(Graphite ${graphite_sources}) -file(GLOB_RECURSE graphite_test_sources - GraphiteTest/*.cpp - libGraphite/fast_data/*.cpp - libGraphite/encoding/*.cpp - libGraphite/new_rsrc/*.cpp - libGraphite/util/*.cpp -) +#file(GLOB_RECURSE graphite_test_sources +# GraphiteTest/*.cpp +# libGraphite/fast_data/*.cpp +# libGraphite/encoding/*.cpp +# libGraphite/new_rsrc/*.cpp +# libGraphite/util/*.cpp +#) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") -add_executable(GraphiteTest ${graphite_test_sources}) -target_link_libraries(GraphiteTest Graphite) +#add_executable(GraphiteTest ${graphite_test_sources}) +#target_link_libraries(GraphiteTest Graphite) From 39518a96097405b2510155e24e0f33ebbc248ec6 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 4 Aug 2022 20:55:49 +0100 Subject: [PATCH 052/113] Small bug fixes and tweaks. --- libGraphite/quickdraw/type/color.cpp | 12 ++++++------ libGraphite/spriteworld/rleX.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index 72e17af..5a81871 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -85,9 +85,9 @@ auto graphite::quickdraw::ycbcr(const union color& rgb) -> struct ycbcr std::uint8_t g = rgb.components.green; std::uint8_t b = rgb.components.blue; - std::int16_t y = static_cast( 0.29900 * r + 0.58700 * g + 0.11400 * b); - std::int16_t cb = static_cast(-0.16874 * r - 0.33126 * g + 0.50000 * b + 128); - std::int16_t cr = static_cast( 0.50000 * r - 0.41868 * g - 0.08131 * b + 128); + auto y = static_cast( 0.299000 * r + 0.587000 * g + 0.114000 * b); + auto cb = static_cast(128 - 0.168736 * r - 0.331264 * g + 0.500000 * b); + auto cr = static_cast(128 + 0.500000 * r - 0.418688 * g - 0.081312 * b); std::uint8_t y_clamped = std::clamp(y , 0, 255); std::uint8_t cb_clamped = std::clamp(cb, 0, 255); @@ -103,9 +103,9 @@ auto graphite::quickdraw::ycbcr(const union color& rgb) -> struct ycbcr auto graphite::quickdraw::rgb(const struct ycbcr& color) -> union color { - auto r = std::clamp(color.y + (1.4075 * (color.cr - 128)), 0, 255); - auto g = std::clamp(color.y - (0.3455 * (color.cb - 128)) - (0.7169 * (color.cr - 128)), 0, 255); - auto b = std::clamp(color.y + (1.7790 * (color.cb - 128)), 0, 255); + auto r = std::clamp(color.y + (1.402000 * (color.cr - 128)), 0, 255); + auto g = std::clamp(color.y - (0.344136 * (color.cb - 128)) - (0.714136 * (color.cr - 128)), 0, 255); + auto b = std::clamp(color.y + (1.772000 * (color.cb - 128)), 0, 255); return rgb(r, g, b, color.alpha); } diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 4eb833c..4da1345 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -248,10 +248,10 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void for (std::int16_t x = 0; x < frame.size.width; ++x) { auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x + x, frame.origin.y + y)); - if (count > 0 && next_yuv.y > 0) { + if (count > 0 && next_yuv.y > 1) { if ((next_yuv.y != yuv.y) || (next_yuv.cr != yuv.cr) || (next_yuv.cb != yuv.cb) || (next_yuv.alpha != yuv.alpha)) { if (count < 127) { - auto opcode = static_cast(opcode::short_advance) + count; + auto opcode = static_cast(opcode::short_advance) | count; writer.write_byte(opcode); } else { From 8e1c11793859237da05e660659c0c2f0a4f86b60 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 4 Aug 2022 21:15:58 +0100 Subject: [PATCH 053/113] =?UTF-8?q?More=20rendering=20fixes=20in=20rl?= =?UTF-8?q?=C3=ABX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/spriteworld/rleX.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 4da1345..e604705 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -164,7 +164,12 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void std::uint16_t count = 0; auto frame = frame_rect(0); - struct quickdraw::ycbcr yuv { 0 }; + struct quickdraw::ycbcr yuv { + .y = 0, + .cb = 128, + .cr = 128, + .alpha = 255 + }; while (!reader.eof()) { opcode = reader.read_enum(); @@ -206,6 +211,7 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void auto rgb = quickdraw::rgb(yuv); for (auto i = 0; i < count; ++i) { m_surface.set((current_offset % m_frame_size.width) + frame.origin.x, (current_offset / m_frame_size.width) + frame.origin.y, rgb); + current_offset++; } break; } From bdb6fe6e871f3aae51a9011420755be3b6b207ce Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 4 Aug 2022 21:17:46 +0100 Subject: [PATCH 054/113] =?UTF-8?q?rl=C3=ABX=20encoding=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/spriteworld/rleX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index e604705..31ab9a0 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -254,7 +254,7 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void for (std::int16_t x = 0; x < frame.size.width; ++x) { auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x + x, frame.origin.y + y)); - if (count > 0 && next_yuv.y > 1) { + if (count > 0 && std::abs(next_yuv.y - yuv.y) > 1) { if ((next_yuv.y != yuv.y) || (next_yuv.cr != yuv.cr) || (next_yuv.cb != yuv.cb) || (next_yuv.alpha != yuv.alpha)) { if (count < 127) { auto opcode = static_cast(opcode::short_advance) | count; From 67a0cd748ec1bc98cbb719ed4970ea4935a04210 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 28 Aug 2022 14:25:37 +0100 Subject: [PATCH 055/113] =?UTF-8?q?Fix=20issue=20in=20rl=C3=ABD=20decoding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/spriteworld/rleD.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libGraphite/spriteworld/rleD.cpp b/libGraphite/spriteworld/rleD.cpp index 3834e2c..16195d7 100644 --- a/libGraphite/spriteworld/rleD.cpp +++ b/libGraphite/spriteworld/rleD.cpp @@ -197,7 +197,7 @@ auto graphite::spriteworld::rleD::decode(data::reader &reader) -> void switch (opcode) { case opcode::eof: { // Check that we're not erroneously an EOF. - if (current_line != m_frame_size.height - 1) { + if (current_line > m_frame_size.height - 1) { throw std::runtime_error("Incorrect number of scanlines in rlëD resource: " + std::to_string(m_id) + ", " + m_name); } From cfeb1ce03fa1ac023ad38da48306924ceea4abcf Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 3 Sep 2022 11:21:30 +0100 Subject: [PATCH 056/113] =?UTF-8?q?Fix=20some=20minor=20issues=20when=20en?= =?UTF-8?q?coding=20rl=C3=ABX.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/spriteworld/rleX.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 31ab9a0..0b830c2 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -241,6 +241,7 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void // Write out the RLE frames for (auto f = 0; f < m_frame_count; ++f) { auto frame = frame_rect(f); + struct quickdraw::ycbcr yuv { .y = 0, .cb = 128, @@ -249,11 +250,10 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void }; std::uint16_t count = 0; + auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x, frame.origin.y)); for (std::int16_t y = 0; y < frame.size.height; ++y) { for (std::int16_t x = 0; x < frame.size.width; ++x) { - auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x + x, frame.origin.y + y)); - if (count > 0 && std::abs(next_yuv.y - yuv.y) > 1) { if ((next_yuv.y != yuv.y) || (next_yuv.cr != yuv.cr) || (next_yuv.cb != yuv.cb) || (next_yuv.alpha != yuv.alpha)) { if (count < 127) { @@ -296,6 +296,15 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void } } + if (count < 127) { + auto opcode = static_cast(opcode::short_advance) | count; + writer.write_byte(opcode); + } + else { + writer.write_enum(opcode::advance); + writer.write_short(count); + } + writer.write_enum(opcode::eof); } } \ No newline at end of file From c8315b525415a0a7d8573eb5965d3c2325e568ba Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 3 Sep 2022 11:26:35 +0100 Subject: [PATCH 057/113] Correct a silly mistake --- libGraphite/spriteworld/rleX.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 0b830c2..9e7ef92 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -250,10 +250,11 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void }; std::uint16_t count = 0; - auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x, frame.origin.y)); - + for (std::int16_t y = 0; y < frame.size.height; ++y) { for (std::int16_t x = 0; x < frame.size.width; ++x) { + auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x, frame.origin.y)); + if (count > 0 && std::abs(next_yuv.y - yuv.y) > 1) { if ((next_yuv.y != yuv.y) || (next_yuv.cr != yuv.cr) || (next_yuv.cb != yuv.cb) || (next_yuv.alpha != yuv.alpha)) { if (count < 127) { From 63c6d0f20c35989adf71f37c9823140e22bc7e40 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 3 Sep 2022 11:28:49 +0100 Subject: [PATCH 058/113] Make sure pixel offsets are present. --- libGraphite/spriteworld/rleX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 9e7ef92..480bb33 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -250,10 +250,10 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void }; std::uint16_t count = 0; - + for (std::int16_t y = 0; y < frame.size.height; ++y) { for (std::int16_t x = 0; x < frame.size.width; ++x) { - auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x, frame.origin.y)); + auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x + x, frame.origin.y + y)); if (count > 0 && std::abs(next_yuv.y - yuv.y) > 1) { if ((next_yuv.y != yuv.y) || (next_yuv.cr != yuv.cr) || (next_yuv.cb != yuv.cb) || (next_yuv.alpha != yuv.alpha)) { From 08729e3d3d41e5f08a2ff2364f8b21ee938c3641 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 3 Sep 2022 11:39:57 +0100 Subject: [PATCH 059/113] =?UTF-8?q?Additional=20rl=C3=ABX=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/quickdraw/type/color.cpp | 32 ++++++------ libGraphite/quickdraw/type/color.hpp | 17 ++++--- libGraphite/spriteworld/rleX.cpp | 73 +++++++++++++--------------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index 5a81871..1a66ab3 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -69,14 +69,14 @@ auto graphite::quickdraw::colors::clear() -> union color // MARK: - YCrCb Color -auto graphite::quickdraw::ycbcr(const union color& rgb) -> struct ycbcr +auto graphite::quickdraw::ycbcr(const union color& rgb) -> union ycbcr { if ((rgb.value & 0x00FFFFFF) == 0) { - return (struct ycbcr) { - .y = 0, - .cb = 0, - .cr = 0, - .alpha = rgb.components.alpha + return (union ycbcr) { + .components.y = 0, + .components.cb = 0, + .components.cr = 0, + .components.alpha = rgb.components.alpha }; } @@ -93,19 +93,19 @@ auto graphite::quickdraw::ycbcr(const union color& rgb) -> struct ycbcr std::uint8_t cb_clamped = std::clamp(cb, 0, 255); std::uint8_t cr_clamped = std::clamp(cr, 0, 255); - return (struct ycbcr) { - .y = y_clamped, - .cb = cb_clamped, - .cr = cr_clamped, - .alpha = rgb.components.alpha + return (union ycbcr) { + .components.y = y_clamped, + .components.cb = cb_clamped, + .components.cr = cr_clamped, + .components.alpha = rgb.components.alpha }; } -auto graphite::quickdraw::rgb(const struct ycbcr& color) -> union color +auto graphite::quickdraw::rgb(const union ycbcr& color) -> union color { - auto r = std::clamp(color.y + (1.402000 * (color.cr - 128)), 0, 255); - auto g = std::clamp(color.y - (0.344136 * (color.cb - 128)) - (0.714136 * (color.cr - 128)), 0, 255); - auto b = std::clamp(color.y + (1.772000 * (color.cb - 128)), 0, 255); + auto r = std::clamp(color.components.y + (1.402000 * (color.components.cr - 128)), 0, 255); + auto g = std::clamp(color.components.y - (0.344136 * (color.components.cb - 128)) - (0.714136 * (color.components.cr - 128)), 0, 255); + auto b = std::clamp(color.components.y + (1.772000 * (color.components.cb - 128)), 0, 255); - return rgb(r, g, b, color.alpha); + return rgb(r, g, b, color.components.alpha); } diff --git a/libGraphite/quickdraw/type/color.hpp b/libGraphite/quickdraw/type/color.hpp index c24ec49..16d5c1b 100644 --- a/libGraphite/quickdraw/type/color.hpp +++ b/libGraphite/quickdraw/type/color.hpp @@ -38,12 +38,15 @@ namespace graphite::quickdraw } components; }; - struct ycbcr + union ycbcr { - color_component y; - color_component cb; - color_component cr; - color_component alpha; + std::uint32_t value; + struct { + color_component y; + color_component cb; + color_component cr; + color_component alpha; + } components; }; static auto operator==(const union color& lhs, const union color& rhs) -> bool { return lhs.value == rhs.value; } @@ -64,6 +67,6 @@ namespace graphite::quickdraw [[nodiscard]] auto clear() -> union color; } - [[nodiscard]] auto ycbcr(const union color& rgb) -> struct ycbcr; - [[nodiscard]] auto rgb(const struct ycbcr& color) -> union color; + [[nodiscard]] auto ycbcr(const union color& rgb) -> union ycbcr; + [[nodiscard]] auto rgb(const union ycbcr& color) -> union color; } \ No newline at end of file diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 480bb33..1588281 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -164,11 +164,11 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void std::uint16_t count = 0; auto frame = frame_rect(0); - struct quickdraw::ycbcr yuv { - .y = 0, - .cb = 128, - .cr = 128, - .alpha = 255 + union quickdraw::ycbcr yuv { + .components.y = 0, + .components.cb = 128, + .components.cr = 128, + .components.alpha = 255 }; while (!reader.eof()) { @@ -186,19 +186,19 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void break; } case opcode::set_luma: { - yuv.y = reader.read_byte(); + yuv.components.y = reader.read_byte(); break; } case opcode::set_cr: { - yuv.cr = reader.read_byte(); + yuv.components.cr = reader.read_byte(); break; } case opcode::set_cb: { - yuv.cb = reader.read_byte(); + yuv.components.cb = reader.read_byte(); break; } case opcode::set_alpha: { - yuv.alpha = reader.read_byte(); + yuv.components.alpha = reader.read_byte(); break; } case opcode::advance: { @@ -242,11 +242,11 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void for (auto f = 0; f < m_frame_count; ++f) { auto frame = frame_rect(f); - struct quickdraw::ycbcr yuv { - .y = 0, - .cb = 128, - .cr = 128, - .alpha = 255 + union quickdraw::ycbcr yuv { + .components.y = 0, + .components.cb = 128, + .components.cr = 128, + .components.alpha = 255 }; std::uint16_t count = 0; @@ -255,42 +255,39 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void for (std::int16_t x = 0; x < frame.size.width; ++x) { auto next_yuv = quickdraw::ycbcr(m_surface.at(frame.origin.x + x, frame.origin.y + y)); - if (count > 0 && std::abs(next_yuv.y - yuv.y) > 1) { - if ((next_yuv.y != yuv.y) || (next_yuv.cr != yuv.cr) || (next_yuv.cb != yuv.cb) || (next_yuv.alpha != yuv.alpha)) { + if (next_yuv.value != yuv.value) { + if (count > 0) { if (count < 127) { auto opcode = static_cast(opcode::short_advance) | count; writer.write_byte(opcode); - } - else { + } else { writer.write_enum(opcode::advance); writer.write_short(count); } count = 0; } - } - if (std::abs(next_yuv.y - yuv.y) > 1) { - yuv.y = next_yuv.y; - writer.write_enum(rleX::opcode::set_luma); - writer.write_byte(yuv.y); - } + if (next_yuv.components.y != yuv.components.y && next_yuv.components.alpha > 0) { + writer.write_enum(rleX::opcode::set_luma); + writer.write_byte(next_yuv.components.y); + } - if (std::abs(next_yuv.cr - yuv.cr) > 1 && yuv.y > 0) { - yuv.cr = next_yuv.cr; - writer.write_enum(rleX::opcode::set_cr); - writer.write_byte(yuv.cr); - } + if (next_yuv.components.cr != yuv.components.cr && next_yuv.components.alpha > 0) { + writer.write_enum(rleX::opcode::set_cr); + writer.write_byte(next_yuv.components.cr); + } - if (std::abs(next_yuv.cb - yuv.cb) > 1 && yuv.y > 0) { - yuv.cb = next_yuv.cb; - writer.write_enum(rleX::opcode::set_cb); - writer.write_byte(yuv.cb); - } + if (next_yuv.components.cb != yuv.components.cb && next_yuv.components.alpha > 0) { + writer.write_enum(rleX::opcode::set_cb); + writer.write_byte(next_yuv.components.cb); + } + + if (next_yuv.components.alpha != yuv.components.alpha) { + writer.write_enum(rleX::opcode::set_alpha); + writer.write_byte(next_yuv.components.alpha); + } - if (std::abs(next_yuv.alpha - yuv.alpha) > 1) { - yuv.alpha = next_yuv.alpha; - writer.write_enum(rleX::opcode::set_alpha); - writer.write_byte(yuv.alpha); + yuv.value = next_yuv.value; } count++; From bb56a2920fd808e5a68fc98cf41d0006c223ac16 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 5 Sep 2022 15:26:58 +0100 Subject: [PATCH 060/113] =?UTF-8?q?Allow=20for=20longer=20advances=20in=20?= =?UTF-8?q?rl=C3=ABX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/spriteworld/rleX.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 1588281..29257d6 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -161,7 +161,7 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void rleX::opcode opcode = opcode::eof; std::uint64_t current_offset = 0; std::int32_t current_frame = 0; - std::uint16_t count = 0; + std::uint32_t count = 0; auto frame = frame_rect(0); union quickdraw::ycbcr yuv { @@ -202,7 +202,7 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void break; } case opcode::advance: { - count = reader.read_short(); + count = reader.read_long(); } default: { if (static_cast(opcode) & static_cast(opcode::short_advance)) { @@ -249,7 +249,7 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void .components.alpha = 255 }; - std::uint16_t count = 0; + std::uint32_t count = 0; for (std::int16_t y = 0; y < frame.size.height; ++y) { for (std::int16_t x = 0; x < frame.size.width; ++x) { @@ -262,7 +262,7 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void writer.write_byte(opcode); } else { writer.write_enum(opcode::advance); - writer.write_short(count); + writer.write_long(count); } count = 0; } @@ -300,7 +300,7 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void } else { writer.write_enum(opcode::advance); - writer.write_short(count); + writer.write_long(count); } writer.write_enum(opcode::eof); From 9162d8361207244a81979a85ed906394be868f7a Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 15 Sep 2022 22:14:06 +0100 Subject: [PATCH 061/113] =?UTF-8?q?Minor=20fixes=20in=20rl=C3=ABX=20encodi?= =?UTF-8?q?ng/decoding=20of=20colors.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/quickdraw/type/color.cpp | 10 ---------- libGraphite/spriteworld/rleX.cpp | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index 1a66ab3..449dfd5 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -71,16 +71,6 @@ auto graphite::quickdraw::colors::clear() -> union color auto graphite::quickdraw::ycbcr(const union color& rgb) -> union ycbcr { - if ((rgb.value & 0x00FFFFFF) == 0) { - return (union ycbcr) { - .components.y = 0, - .components.cb = 0, - .components.cr = 0, - .components.alpha = rgb.components.alpha - }; - } - - std::uint8_t r = rgb.components.red; std::uint8_t g = rgb.components.green; std::uint8_t b = rgb.components.blue; diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 29257d6..a581daf 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -267,17 +267,17 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void count = 0; } - if (next_yuv.components.y != yuv.components.y && next_yuv.components.alpha > 0) { + if (next_yuv.components.y != yuv.components.y) { writer.write_enum(rleX::opcode::set_luma); writer.write_byte(next_yuv.components.y); } - if (next_yuv.components.cr != yuv.components.cr && next_yuv.components.alpha > 0) { + if (next_yuv.components.cr != yuv.components.cr) { writer.write_enum(rleX::opcode::set_cr); writer.write_byte(next_yuv.components.cr); } - if (next_yuv.components.cb != yuv.components.cb && next_yuv.components.alpha > 0) { + if (next_yuv.components.cb != yuv.components.cb) { writer.write_enum(rleX::opcode::set_cb); writer.write_byte(next_yuv.components.cb); } From df2eb9e8a35d31c4fe372da9799a2501be7418f3 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 16 Sep 2022 10:44:24 +0100 Subject: [PATCH 062/113] Data blocks should be aware if they originate from an extended resource file. --- libGraphite/data/data.cpp | 19 ++++++++++++++----- libGraphite/data/data.hpp | 6 +++++- libGraphite/rsrc/file.cpp | 1 + 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index a34725a..8151580 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -156,14 +156,16 @@ graphite::data::block::block(const block &source, bool copy) m_count(source.m_count), m_byte_order(source.m_byte_order), m_allocation_owner(copy ? nullptr : &source), - m_has_ownership(copy) + m_has_ownership(copy), + m_extended(source.m_extended) { clone_from(source); } graphite::data::block::block(const block &source, block::position pos, std::size_t amount, bool copy) : m_allocation_owner(copy ? nullptr : &source), - m_byte_order(source.m_byte_order) + m_byte_order(source.m_byte_order), + m_extended(source.m_extended) { if (m_allocation_owner) { m_raw = source.m_raw; @@ -208,7 +210,8 @@ graphite::data::block::block(const block &data) m_users(0), m_count(data.m_count), m_byte_order(data.m_byte_order), - m_has_ownership(data.m_has_ownership) + m_has_ownership(data.m_has_ownership), + m_extended(data.m_extended) { if (m_has_ownership) { m_raw = malloc(m_raw_size); @@ -231,7 +234,8 @@ graphite::data::block::block(block &&data) noexcept m_users(data.m_users), m_count(data.m_count), m_byte_order(data.m_byte_order), - m_has_ownership(data.m_has_ownership) + m_has_ownership(data.m_has_ownership), + m_extended(data.m_extended) { data.m_raw = nullptr; data.m_data = nullptr; @@ -264,6 +268,7 @@ auto graphite::data::block::operator=(const block &data) -> struct block & m_count = data.m_count; m_byte_order = data.m_byte_order; m_has_ownership = true; + m_extended = data.m_extended; m_raw = malloc(m_raw_size); m_data = simd_align(m_raw); @@ -295,6 +300,7 @@ auto graphite::data::block::operator=(block &&data) noexcept -> struct block & m_count = data.m_count; m_byte_order = data.m_byte_order; m_has_ownership = data.m_has_ownership; + m_extended = data.m_extended; data.m_allocation_owner = nullptr; data.m_raw = nullptr; @@ -322,6 +328,7 @@ graphite::data::block::~block() auto graphite::data::block::clone_from(const graphite::data::block &source) -> void { + m_extended = source.m_extended; if (m_allocation_owner) { m_raw = source.m_raw; m_data = source.m_data; @@ -336,11 +343,13 @@ auto graphite::data::block::clone_from(const graphite::data::block &source) -> v } } -__attribute__((optnone)) auto graphite::data::block::copy_from(const block &source) const -> void +__attribute__((optnone)) auto graphite::data::block::copy_from(const block &source) -> void { auto source_ptr = source.get(); auto dest_ptr = get(); + m_extended = source.m_extended; + std::size_t len = std::min(source.size(), size()); std::size_t n = 0; auto simd_fields_len = simd_fields * simd_field_size; diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index deb81a8..b5fa5e1 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -89,6 +89,9 @@ namespace graphite::data [[nodiscard]] inline auto start() const -> block::position { return m_start_position; } [[nodiscard]] inline auto byte_order() const -> byte_order { return m_byte_order; } + auto originates_from_extended_format() -> void { m_extended = true; } + [[nodiscard]] inline auto is_extended_format() const -> bool { return m_extended; } + auto change_byte_order(enum byte_order order) -> void { m_byte_order = order; } auto increase_size_to(std::size_t new_size) -> void; @@ -98,12 +101,13 @@ namespace graphite::data auto set(uint16_t value, std::size_t bytes = 0, block::position start = 0) -> void; auto set(uint32_t value, std::size_t bytes = 0, block::position start = 0) -> void; - auto copy_from(const block& source) const -> void; + auto copy_from(const block& source) -> void; [[nodiscard]] auto slice(block::position pos, std::size_t size, bool copy = false) const -> block; private: enum byte_order m_byte_order { byte_order::msb }; + bool m_extended { false }; std::size_t m_raw_size { 0 }; std::size_t m_data_size { 0 }; block::position m_start_position { 0 }; diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index f2339b2..394044d 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -283,6 +283,7 @@ auto graphite::rsrc::file::read(const std::string &path) -> void if (rsrc::format::extended::parse(reader, *this)) { m_format = format::extended; + m_data->originates_from_extended_format(); } else if (rsrc::format::rez::parse(reader, *this)) { m_format = format::rez; From fc9a717a14cec3c16c7fe5befd213acd432d3e5c Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Tue, 20 Sep 2022 10:06:04 +0100 Subject: [PATCH 063/113] =?UTF-8?q?Various=20optimisations=20in=20rl=C3=AB?= =?UTF-8?q?X=20to=20help=20with=20load=20performance=20in=20Kestrel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libGraphite/data/data.cpp | 26 +++++-- libGraphite/rsrc/extended/parser.cpp | 2 + libGraphite/rsrc/file.cpp | 1 - libGraphite/spriteworld/rleX.cpp | 105 +++++++++++++++------------ 4 files changed, 80 insertions(+), 54 deletions(-) diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 8151580..7644ed8 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -417,18 +417,32 @@ auto graphite::data::block::set(uint8_t value, std::size_t bytes, block::positio auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void { union simd_value v; - for (auto n = 0; n < simd_fields; ++n) { - v.fields[n] = (value << 16) | value; - } + + v.fields[0] = (value << 16) | value; +#if __x86_64__ + v.fields[1] = v.fields[0]; + v.fields[2] = v.fields[0]; + v.fields[3] = v.fields[0]; +#elif __arm64__ + v.fields[1] = v.fields[0]; +#endif + inline_set(this, v, bytes, start); } auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::position start) -> void { union simd_value v { 0 }; - for (auto n = 0; n < simd_fields; ++n) { - v.fields[n] = value; - } + + v.fields[0] = value; +#if __x86_64__ + v.fields[1] = value; + v.fields[2] = value; + v.fields[3] = value; +#elif __arm64__ + v.fields[1] = value; +#endif + inline_set(this, v, bytes, start); } diff --git a/libGraphite/rsrc/extended/parser.cpp b/libGraphite/rsrc/extended/parser.cpp index e6b4087..e9f36f7 100644 --- a/libGraphite/rsrc/extended/parser.cpp +++ b/libGraphite/rsrc/extended/parser.cpp @@ -81,6 +81,8 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - return false; } + const_cast(reader.data())->originates_from_extended_format(); + // 2. Now that the preamble is parsed and verified, parse the contents // of the ResourceMap. The first two fields are used by the actual Resource Manager in // the Classic Macintosh OS, but are not used by this implementation. diff --git a/libGraphite/rsrc/file.cpp b/libGraphite/rsrc/file.cpp index 394044d..f2339b2 100644 --- a/libGraphite/rsrc/file.cpp +++ b/libGraphite/rsrc/file.cpp @@ -283,7 +283,6 @@ auto graphite::rsrc::file::read(const std::string &path) -> void if (rsrc::format::extended::parse(reader, *this)) { m_format = format::extended; - m_data->originates_from_extended_format(); } else if (rsrc::format::rez::parse(reader, *this)) { m_format = format::rez; diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index a581daf..998dfc2 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -136,6 +136,8 @@ auto graphite::spriteworld::rleX::surface_offset(std::int32_t frame, std::int32_ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void { + reader.change_byte_order(data::byte_order::lsb); + // Read the header of the RLE information. This will tell us what we need to do in order to actually // decode the frame. m_frame_size = quickdraw::size::read(reader, quickdraw::coding_type::macintosh); @@ -159,9 +161,13 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); rleX::opcode opcode = opcode::eof; - std::uint64_t current_offset = 0; std::int32_t current_frame = 0; std::uint32_t count = 0; + std::uint32_t current_offset = 0; + std::uint32_t right_bound = 0; + std::uint32_t pitch = 0; + + bool completed_last_frame = false; auto frame = frame_rect(0); union quickdraw::ycbcr yuv { @@ -171,63 +177,68 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void .components.alpha = 255 }; - while (!reader.eof()) { - opcode = reader.read_enum(); - switch (opcode) { - case opcode::eof: { - // Have we finished decoding the last frame in the data? - if (++current_frame >= m_frame_count) { - goto COMPLETED_LAST_FRAME; - } - - frame = frame_rect(current_frame); - current_offset = 0; - - break; - } - case opcode::set_luma: { - yuv.components.y = reader.read_byte(); - break; - } - case opcode::set_cr: { - yuv.components.cr = reader.read_byte(); - break; - } - case opcode::set_cb: { - yuv.components.cb = reader.read_byte(); - break; + // NOTE: This is a very _hot_ code path and thus we need to squeeze out as much performance as possible. + // Build a lookup table of opcodes, in order to reduce the number of comparisons. + /* quickdraw::surface&, data::reader&, union quickdraw::ycbcr&, std::int32_t&, std::uint32_t&, quickdraw::rect& */ + std::functionvoid> opcode_lut[9] = { + /* EOF */ + /* 0 */ [&] { + if (++current_frame >= m_frame_count) { + completed_last_frame = true; + return; } - case opcode::set_alpha: { - yuv.components.alpha = reader.read_byte(); - break; - } - case opcode::advance: { - count = reader.read_long(); - } - default: { - if (static_cast(opcode) & static_cast(opcode::short_advance)) { - count = static_cast(opcode) & ~static_cast(opcode::short_advance); - } - auto rgb = quickdraw::rgb(yuv); - for (auto i = 0; i < count; ++i) { - m_surface.set((current_offset % m_frame_size.width) + frame.origin.x, (current_offset / m_frame_size.width) + frame.origin.y, rgb); - current_offset++; + opcode_lut[8](); + }, + + /* set components */ + /* 1 */ [&] { yuv.components.y = reader.read_byte(); }, + /* 2 */ [&] { yuv.components.cr = reader.read_byte(); }, + /* 3 */ [&] { yuv.components.cb = reader.read_byte(); }, + /* 4 */ [&] { yuv.components.alpha = reader.read_byte(); }, + + /* advance */ + /* 5 */ [&] { count = reader.read_long(); opcode_lut[7](); }, + /* 6 */ [&] { + count = static_cast(opcode) & ~static_cast(rleX::opcode::short_advance); + opcode_lut[7](); + }, + + /* fill operation */ + /* 7 */ [&] { + auto rgb = quickdraw::rgb(yuv); + for (auto i = 0; i < count; ++i) { + m_surface.set(current_offset, rgb); + if (++current_offset >= right_bound) { + current_offset += pitch; + right_bound = current_offset + frame.size.width; } - break; } - } + }, + /* 8 */ [&] { + frame = frame_rect(current_frame); + current_offset = (frame.origin.y * m_surface.size().width) + frame.origin.x; + right_bound = current_offset + frame.size.width; + pitch = m_surface.size().width - frame.size.width; + }, + }; - } + opcode_lut[8](); -COMPLETED_LAST_FRAME: - return; + while (!reader.eof() && !completed_last_frame) { + opcode = reader.read_enum(); + if (static_cast(opcode) & static_cast(rleX::opcode::short_advance)) { + opcode_lut[6](); + continue; + } + opcode_lut[static_cast(opcode)](); + } } // MARK: - Encoding auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void { - writer.change_byte_order(data::byte_order::msb); + writer.change_byte_order(data::byte_order::lsb); // Write out the header m_frame_size.encode(writer, quickdraw::coding_type::macintosh); From 53a737c67eb1d0d9fb495726bd19a86e7006b090 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Tue, 20 Sep 2022 21:46:34 +0100 Subject: [PATCH 064/113] Large amount of work towards optimizing the loading speeds of various assets for Kestrel. --- libGraphite/data/data.cpp | 154 ++-------- libGraphite/data/data.hpp | 16 +- libGraphite/data/endianess.hpp | 14 + .../data/internals/specialised_reader.hpp | 74 +++++ libGraphite/data/internals/swap_reader.hpp | 74 +++++ libGraphite/data/reader.cpp | 1 + libGraphite/data/reader.hpp | 34 ++- libGraphite/data/simd.hpp | 111 ++++++++ libGraphite/quickdraw/type/color.cpp | 11 + libGraphite/spriteworld/rleX.cpp | 266 ++++++++++++++---- libGraphite/spriteworld/rleX.hpp | 2 +- 11 files changed, 552 insertions(+), 205 deletions(-) create mode 100644 libGraphite/data/internals/specialised_reader.hpp create mode 100644 libGraphite/data/internals/swap_reader.hpp create mode 100644 libGraphite/data/simd.hpp diff --git a/libGraphite/data/data.cpp b/libGraphite/data/data.cpp index 7644ed8..85c3e3d 100644 --- a/libGraphite/data/data.cpp +++ b/libGraphite/data/data.cpp @@ -23,75 +23,15 @@ #include #include #include "libGraphite/data/data.hpp" - -// MARK: - SIMD Support - -#if __x86_64__ - typedef __int128 int128_t; - typedef unsigned __int128 uint128_t; - - typedef uint128_t simd_wide_type; - typedef simd_wide_type simd_type; - typedef uint64_t simd_wide_field_type; - - static constexpr std::size_t simd_alignment_width = 16; - static constexpr std::size_t simd_fields = 4; - static constexpr std::size_t simd_wide_fields = 2; - -#elif __arm64__ - typedef uint64_t simd_wide_type; - typedef simd_wide_type simd_type; - typedef simd_type simd_wide_field_type; - - static constexpr std::size_t simd_alignment_width = 8; - static constexpr std::size_t simd_fields = 2; - static constexpr std::size_t simd_wide_fields = 1; - -#else - typedef uint32_t simd_wide_type; - typedef simd_wide_type simd_type; - - static constexpr std::size_t simd_alignment_width = 4; - static constexpr std::size_t simd_fields = 1; - static constexpr std::size_t simd_wide_fields = 0; - -#endif - -typedef uint32_t simd_field_type; -typedef uint16_t simd_half_field_type; -static constexpr std::size_t simd_field_size = sizeof(simd_field_type); - -union alignas(simd_alignment_width) simd_value -{ - simd_type wide; -#if __x86_64__ || __arm64__ - simd_wide_field_type wide_fields[simd_wide_fields]; -#endif - simd_field_type fields[simd_fields]; - uint8_t bytes[sizeof(simd_type)]; -}; - -static constexpr std::size_t simd_alignment_mask = ~(simd_alignment_width - 1); - -template::value>::type* = nullptr> -static inline auto simd_expand_capacity(T capacity) -> T -{ - return (capacity + simd_alignment_width - 1) & simd_alignment_mask; -} - -template::value>::type* = nullptr> -static inline auto simd_align(T ptr) -> T -{ - return reinterpret_cast((reinterpret_cast(ptr) + simd_alignment_width - 1) & simd_alignment_mask); -} +#include "libGraphite/data/simd.hpp" // MARK: - Construction graphite::data::block::block(std::size_t capacity, enum byte_order order) - : m_raw_size(simd_expand_capacity(capacity)), + : m_raw_size(simd::expand_capacity(capacity)), m_data_size(capacity), m_raw(malloc(m_raw_size)), - m_data(simd_align(m_raw)), + m_data(simd::align(m_raw)), m_allocation_owner(nullptr), m_byte_order(order), m_has_ownership(true) @@ -99,10 +39,10 @@ graphite::data::block::block(std::size_t capacity, enum byte_order order) } graphite::data::block::block(std::size_t capacity, std::size_t allocation_size, enum byte_order order) - : m_raw_size(simd_expand_capacity(allocation_size)), + : m_raw_size(simd::expand_capacity(allocation_size)), m_data_size(capacity), m_raw(malloc(m_raw_size)), - m_data(simd_align(m_raw)), + m_data(simd::align(m_raw)), m_allocation_owner(nullptr), m_byte_order(order), m_has_ownership(true) @@ -124,9 +64,9 @@ graphite::data::block::block(const std::string &path, enum byte_order order) m_data_size = file.tellg(); file.seekg(0, std::ios::beg); - m_raw_size = simd_expand_capacity(m_data_size); + m_raw_size = simd::expand_capacity(m_data_size); m_raw = malloc(m_raw_size); - m_data = simd_align(m_raw); + m_data = simd::align(m_raw); file.read(reinterpret_cast(m_data), m_data_size); file.close(); @@ -138,9 +78,9 @@ graphite::data::block::block(const std::vector& bytes, enum byte_order ord m_has_ownership(true) { m_data_size = bytes.size(); - m_raw_size = simd_expand_capacity(m_data_size); + m_raw_size = simd::expand_capacity(m_data_size); m_raw = malloc(m_raw_size); - m_data = simd_align(m_raw); + m_data = simd::align(m_raw); // TODO: This is slow, and should be speeded up in the future. auto ptr = static_cast(m_data); @@ -179,10 +119,10 @@ graphite::data::block::block(const block &source, block::position pos, std::size const_cast(m_allocation_owner)->m_users++; } else { - m_raw_size = simd_expand_capacity(amount); + m_raw_size = simd::expand_capacity(amount); m_data_size = amount; m_raw = malloc(m_raw_size); - m_data = simd_align(m_raw); + m_data = simd::align(m_raw); m_start_position = 0; m_count = 0; m_has_ownership = true; @@ -215,7 +155,7 @@ graphite::data::block::block(const block &data) { if (m_has_ownership) { m_raw = malloc(m_raw_size); - m_data = simd_align(m_raw); + m_data = simd::align(m_raw); copy_from(data); } else { @@ -271,7 +211,7 @@ auto graphite::data::block::operator=(const block &data) -> struct block & m_extended = data.m_extended; m_raw = malloc(m_raw_size); - m_data = simd_align(m_raw); + m_data = simd::align(m_raw); copy_from(data); return *this; @@ -337,7 +277,7 @@ auto graphite::data::block::clone_from(const graphite::data::block &source) -> v } else { m_raw = malloc(m_raw_size); - m_data = simd_align(m_raw); + m_data = simd::align(m_raw); m_has_ownership = true; copy_from(source); } @@ -352,46 +292,24 @@ __attribute__((optnone)) auto graphite::data::block::copy_from(const block &sour std::size_t len = std::min(source.size(), size()); std::size_t n = 0; - auto simd_fields_len = simd_fields * simd_field_size; while (n < len) { - if ((reinterpret_cast(source_ptr) & simd_alignment_width) || (len - n) < simd_fields_len) { + if ((reinterpret_cast(source_ptr) & simd::alignment_width) || (len - n) < simd::fields_length) { *dest_ptr = *source_ptr; ++dest_ptr; ++source_ptr; - n += simd_field_size; + n += simd::field_size; } else { - *reinterpret_cast(dest_ptr) = *reinterpret_cast(source_ptr); - dest_ptr += simd_fields; - source_ptr += simd_fields; - n += simd_alignment_width; + *reinterpret_cast(dest_ptr) = *reinterpret_cast(source_ptr); + dest_ptr += simd::field_count; + source_ptr += simd::field_count; + n += simd::alignment_width; } } } // MARK: - Operations -__attribute__((optnone)) static inline auto inline_set(graphite::data::block *dst, union simd_value v, std::size_t bytes, std::size_t start) -> void -{ - auto len = std::min(dst->size() - start, bytes); - auto ptr = dst->get(start); - std::size_t n = 0; - - auto simd_fields_len = simd_fields * simd_field_size; - while (n < len) { - if ((reinterpret_cast(ptr) & simd_alignment_width) || (len - n) < simd_fields_len) { - *ptr = v.fields[n & (simd_fields - 1)]; - ++ptr; - n += simd_field_size; - } - else { - *reinterpret_cast(ptr) = v.wide; - ptr += simd_fields; - n += simd_alignment_width; - } - } -} - auto graphite::data::block::increase_size_to(std::size_t new_size) -> void { if (new_size > m_raw_size) { @@ -407,17 +325,16 @@ auto graphite::data::block::clear() -> void auto graphite::data::block::set(uint8_t value, std::size_t bytes, block::position start) -> void { - union simd_value v; - for (auto n = 0; n < simd_alignment_width; ++n) { - v.bytes[n] = value; + union simd::value v; + for (unsigned char & byte : v.bytes) { + byte = value; } - inline_set(this, v, bytes, start); + simd::set(get(start), size() - start, v, bytes); } -auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void +__attribute__((optnone)) auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void { - union simd_value v; - + union simd::value v; v.fields[0] = (value << 16) | value; #if __x86_64__ v.fields[1] = v.fields[0]; @@ -426,24 +343,7 @@ auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::positi #elif __arm64__ v.fields[1] = v.fields[0]; #endif - - inline_set(this, v, bytes, start); -} - -auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::position start) -> void -{ - union simd_value v { 0 }; - - v.fields[0] = value; -#if __x86_64__ - v.fields[1] = value; - v.fields[2] = value; - v.fields[3] = value; -#elif __arm64__ - v.fields[1] = value; -#endif - - inline_set(this, v, bytes, start); + simd::set(get(start), size() - start, v, bytes); } // MARK: - Slicing diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index b5fa5e1..3026ff2 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -26,6 +26,7 @@ #include #include #include "libGraphite/data/endianess.hpp" +#include "libGraphite/data/simd.hpp" namespace graphite::data { @@ -99,7 +100,20 @@ namespace graphite::data auto set(uint8_t value, std::size_t bytes = 0, block::position start = 0) -> void; auto set(uint16_t value, std::size_t bytes = 0, block::position start = 0) -> void; - auto set(uint32_t value, std::size_t bytes = 0, block::position start = 0) -> void; + + inline auto set(uint32_t value, std::size_t bytes = 0, block::position start = 0) -> void + { + union simd::value v; + v.fields[0] = value; +#if __x86_64__ + v.fields[1] = value; + v.fields[2] = value; + v.fields[3] = value; +#elif __arm64__ + v.fields[1] = value; +#endif + simd::set(get(start), size() - start, v, bytes); + } auto copy_from(const block& source) -> void; diff --git a/libGraphite/data/endianess.hpp b/libGraphite/data/endianess.hpp index 8e2b2c9..e5f8ded 100644 --- a/libGraphite/data/endianess.hpp +++ b/libGraphite/data/endianess.hpp @@ -59,4 +59,18 @@ namespace graphite::data return v; } + + template::value>::type* = nullptr> + static auto fixed_swap(T value, std::size_t size = sizeof(T)) -> T + { + T v = 0; + + for (auto i = 0; i < size; ++i) { + auto b = (size - i - 1) << 3ULL; + v |= ((value >> b) & 0xFF) << (i << 3ULL); + } + + return v; + } + } \ No newline at end of file diff --git a/libGraphite/data/internals/specialised_reader.hpp b/libGraphite/data/internals/specialised_reader.hpp new file mode 100644 index 0000000..be4a311 --- /dev/null +++ b/libGraphite/data/internals/specialised_reader.hpp @@ -0,0 +1,74 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/data/endianess.hpp" + +namespace graphite::data::internals +{ + + class specialised_reader + { + public: + + virtual auto swap(std::uint8_t value, std::size_t size = 1) -> std::uint8_t + { + return value; + }; + + virtual auto swap(std::uint16_t value, std::size_t size = 2) -> std::uint16_t + { + return value; + }; + + virtual auto swap(std::uint32_t value, std::size_t size = 4) -> std::uint32_t + { + return value; + }; + + virtual auto swap(std::uint64_t value, std::size_t size = 1) -> std::uint64_t + { + return value; + }; + + virtual auto swap(std::int8_t value, std::size_t size = 1) -> std::int8_t + { + return value; + }; + + virtual auto swap(std::int16_t value, std::size_t size = 2) -> std::int16_t + { + return value; + }; + + virtual auto swap(std::int32_t value, std::size_t size = 4) -> std::int32_t + { + return value; + }; + + virtual auto swap(std::int64_t value, std::size_t size = 1) -> std::int64_t + { + return value; + }; + + }; + +} \ No newline at end of file diff --git a/libGraphite/data/internals/swap_reader.hpp b/libGraphite/data/internals/swap_reader.hpp new file mode 100644 index 0000000..bd99909 --- /dev/null +++ b/libGraphite/data/internals/swap_reader.hpp @@ -0,0 +1,74 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "libGraphite/data/internals/specialised_reader.hpp" + +namespace graphite::data::internals +{ + + class swap_reader: public specialised_reader + { + public: + + auto swap(std::uint8_t value, std::size_t size = 1) -> std::uint8_t override + { + return graphite::data::fixed_swap(value, size); + }; + + auto swap(std::uint16_t value, std::size_t size = 2) -> std::uint16_t override + { + return graphite::data::fixed_swap(value, size); + }; + + auto swap(std::uint32_t value, std::size_t size = 4) -> std::uint32_t override + { + return graphite::data::fixed_swap(value, size); + }; + + auto swap(std::uint64_t value, std::size_t size = 1) -> std::uint64_t override + { + return graphite::data::fixed_swap(value, size); + }; + + auto swap(std::int8_t value, std::size_t size = 1) -> std::int8_t override + { + return graphite::data::fixed_swap(value, size); + }; + + auto swap(std::int16_t value, std::size_t size = 2) -> std::int16_t override + { + return graphite::data::fixed_swap(value, size); + }; + + auto swap(std::int32_t value, std::size_t size = 4) -> std::int32_t override + { + return graphite::data::fixed_swap(value, size); + }; + + auto swap(std::int64_t value, std::size_t size = 8) -> std::int64_t override + { + return graphite::data::fixed_swap(value, size); + }; + + }; + +} \ No newline at end of file diff --git a/libGraphite/data/reader.cpp b/libGraphite/data/reader.cpp index 43bc0cc..137f0c5 100644 --- a/libGraphite/data/reader.cpp +++ b/libGraphite/data/reader.cpp @@ -34,6 +34,7 @@ graphite::data::reader::reader(const class block *data, block::position pos, boo m_owns_data(owns), m_position(pos) { + update_swap_wrapper(); } auto graphite::data::reader::file(const std::string &path, block::position pos) -> reader diff --git a/libGraphite/data/reader.hpp b/libGraphite/data/reader.hpp index f230bdd..f1833d1 100644 --- a/libGraphite/data/reader.hpp +++ b/libGraphite/data/reader.hpp @@ -25,6 +25,8 @@ #include "libGraphite/data/data.hpp" #include "libGraphite/util/concepts.hpp" #include "libGraphite/data/encoding.hpp" +#include "libGraphite/data/internals/specialised_reader.hpp" +#include "libGraphite/data/internals/swap_reader.hpp" namespace graphite::data { @@ -52,7 +54,21 @@ namespace graphite::data [[nodiscard]] inline auto eof() const -> bool { return position() >= size(); } [[nodiscard]] inline auto byte_order() const -> byte_order { return m_data->byte_order(); } - auto change_byte_order(enum byte_order order) -> void { const_cast(m_data)->change_byte_order(order); } + auto change_byte_order(enum byte_order order) -> void + { + const_cast(m_data)->change_byte_order(order); + update_swap_wrapper(); + } + + auto update_swap_wrapper() -> void + { + if (m_data && byte_order() == native_byte_order()) { + m_swap_wrapper = std::make_shared(); + } + else { + m_swap_wrapper = std::make_shared(); + } + } auto set_position(block::position pos) -> void; auto move(block::position delta = 1) -> void; @@ -138,19 +154,8 @@ namespace graphite::data template::value>::type* = nullptr> auto read_integer(block::position offset = 0, mode mode = mode::advance, std::size_t size = sizeof(T)) -> T { - T v = 0; - if (size <= 0 || size > sizeof(T)) { - throw std::runtime_error("Invalid integer size specified in data reader."); - } - - for (block::position i = 0; i < size; ++i) { - auto b = m_data->template operator[](m_position + offset + i); - v |= static_cast(b) << (i << 3ULL); - } - - if (size > 1) { - v = swap(v, m_data->byte_order(), native_byte_order(), size); - } + T v = *reinterpret_cast(m_data->template get(m_position + offset)); + v = m_swap_wrapper->swap(v, size); if (mode == mode::advance) { move(offset + size); @@ -179,6 +184,7 @@ namespace graphite::data private: bool m_owns_data { false }; const class block *m_data { nullptr }; + std::shared_ptr m_swap_wrapper; std::vector m_position_stack; block::position m_position; }; diff --git a/libGraphite/data/simd.hpp b/libGraphite/data/simd.hpp new file mode 100644 index 0000000..33699f6 --- /dev/null +++ b/libGraphite/data/simd.hpp @@ -0,0 +1,111 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace graphite::data +{ + class block; +} + +namespace graphite::data::simd +{ + +#if __x86_64__ + typedef __int128 int128_t; + typedef unsigned __int128 uint128_t; + + typedef uint128_t wide_type; + typedef wide_type type; + typedef uint64_t wide_field_type; + + static constexpr std::size_t alignment_width = 16; + static constexpr std::size_t field_count = 4; + static constexpr std::size_t wide_field_count = 2; + +#elif __arm64__ + typedef uint64_t wide_type; + typedef wide_type type; + typedef type wide_field_type; + + static constexpr std::size_t alignment_width = 8; + static constexpr std::size_t field_count = 2; + static constexpr std::size_t wide_field_count = 1; + +#else + typedef uint32_t simd_wide_type; + typedef simd_wide_type simd_type; + + static constexpr std::size_t alignment_width = 4; + static constexpr std::size_t field_count = 1; + static constexpr std::size_t wide_field_count = 0; + +#endif + + typedef uint32_t field_type; + typedef uint16_t half_field_type; + static constexpr std::size_t field_size = sizeof(field_type); + static constexpr std::size_t fields_length = field_count * field_size; + + union alignas(alignment_width) value + { + type wide; +#if __x86_64__ || __arm64__ + wide_field_type wide_fields[wide_field_count]; +#endif + field_type fields[field_count]; + uint8_t bytes[sizeof(type)]; + }; + + static constexpr std::size_t alignment_mask = ~(alignment_width - 1); + + template::value>::type* = nullptr> + static inline auto expand_capacity(T capacity) -> T + { + return (capacity + alignment_width - 1) & alignment_mask; + } + + template::value>::type* = nullptr> + static inline auto align(T ptr) -> T + { + return reinterpret_cast((reinterpret_cast(ptr) + alignment_width - 1) & alignment_mask); + } + + __attribute__((optnone)) static inline auto set(std::uint32_t *ptr, std::size_t dst_size, union value v, std::size_t bytes) -> void + { + std::size_t n = 0; + auto len = std::min(dst_size, bytes); + while (n < len) { + if ((reinterpret_cast(ptr) & alignment_width) || (len - n) < fields_length) { + *ptr = v.fields[n & (field_count - 1)]; + ++ptr; + n += field_size; + } + else { + *reinterpret_cast(ptr) = v.wide; + ptr += field_count; + n += alignment_width; + } + } + } + +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/color.cpp b/libGraphite/quickdraw/type/color.cpp index 449dfd5..40fcf9d 100644 --- a/libGraphite/quickdraw/type/color.cpp +++ b/libGraphite/quickdraw/type/color.cpp @@ -93,6 +93,17 @@ auto graphite::quickdraw::ycbcr(const union color& rgb) -> union ycbcr auto graphite::quickdraw::rgb(const union ycbcr& color) -> union color { + auto color_value = color.value & 0xFFFFFF; + if (color.components.alpha < 0.05) { + return rgb(0, 0, 0, 0); + } + else if (color_value == 0x008080) { + return rgb(0, 0, 0, color.components.alpha); + } + else if (color_value == 0xFF8080) { + return rgb(255, 255, 255, color.components.alpha); + } + auto r = std::clamp(color.components.y + (1.402000 * (color.components.cr - 128)), 0, 255); auto g = std::clamp(color.components.y - (0.344136 * (color.components.cb - 128)) - (0.714136 * (color.components.cr - 128)), 0, 255); auto b = std::clamp(color.components.y + (1.772000 * (color.components.cb - 128)), 0, 255); diff --git a/libGraphite/spriteworld/rleX.cpp b/libGraphite/spriteworld/rleX.cpp index 998dfc2..d8b1cff 100644 --- a/libGraphite/spriteworld/rleX.cpp +++ b/libGraphite/spriteworld/rleX.cpp @@ -41,7 +41,8 @@ graphite::spriteworld::rleX::rleX(const quickdraw::size &size, std { // Determine what the grid will be. We need to round up to the next whole number and have blank tiles // if the frame count is not divisible by the grid width constant. - auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + auto dim = static_cast(std::ceil(std::sqrt(m_frame_count))); + auto grid_width = std::min(dim, m_frame_count); m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); // Create the surface @@ -85,8 +86,8 @@ auto graphite::spriteworld::rleX::frame_rect(std::uint32_t frame) const -> quick { return { quickdraw::point( - static_cast(frame % constants::rle_grid_width) * m_frame_size.width, - static_cast(frame / constants::rle_grid_width) * m_frame_size.height + static_cast(frame % m_grid_size.width) * m_frame_size.width, + static_cast(frame / m_grid_size.width) * m_frame_size.height ), m_frame_size }; @@ -134,6 +135,172 @@ auto graphite::spriteworld::rleX::surface_offset(std::int32_t frame, std::int32_ // MARK: - Decoding +static inline auto rleX_calculate_sprite_geometry( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame +) -> void { + rect = sprite->frame_rect(frame); + offset = (rect.origin.y * surface.size().width) + rect.origin.x; + right_offset_bound = offset + rect.size.width; + pitch = surface.size().width - rect.size.width; +} + +static inline auto rleX_draw_color( + graphite::quickdraw::surface& surface, + union graphite::quickdraw::ycbcr& color, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t count +) -> void { + auto rgb = graphite::quickdraw::rgb(color); + for (auto i = 0; i < count; ++i) { + surface.set(offset, rgb); + if (++offset >= right_offset_bound) { + offset += pitch; + right_offset_bound = offset + rect.size.width; + } + } +} + +static auto rleX_opcode_handler_eof( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::data::reader& reader, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame, + std::uint16_t frame_count, + bool& completed, + union graphite::quickdraw::ycbcr& color +) -> void { + if (++frame >= frame_count) { + completed = true; + return; + } + rleX_calculate_sprite_geometry(sprite, surface, rect, offset, right_offset_bound, pitch, frame); +} + +static auto rleX_opcode_handler_set_luma( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::data::reader& reader, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame, + std::uint16_t frame_count, + bool& completed, + union graphite::quickdraw::ycbcr& color +) -> void { + color.components.y = reader.read_byte(); +} + +static auto rleX_opcode_handler_set_cr( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::data::reader& reader, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame, + std::uint16_t frame_count, + bool& completed, + union graphite::quickdraw::ycbcr& color +) -> void { + color.components.cr = reader.read_byte(); +} + +static auto rleX_opcode_handler_set_cb( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::data::reader& reader, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame, + std::uint16_t frame_count, + bool& completed, + union graphite::quickdraw::ycbcr& color +) -> void { + color.components.cb = reader.read_byte(); +} + +static auto rleX_opcode_handler_set_alpha( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::data::reader& reader, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame, + std::uint16_t frame_count, + bool& completed, + union graphite::quickdraw::ycbcr& color +) -> void { + color.components.alpha = reader.read_byte(); +} + +static auto rleX_opcode_handler_advance( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::data::reader& reader, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame, + std::uint16_t frame_count, + bool& completed, + union graphite::quickdraw::ycbcr& color +) -> void { + auto count = reader.read_long(); + rleX_draw_color(surface, color, rect, offset, right_offset_bound, pitch, count); +} + +static auto rleX_opcode_handler_short_advance( + graphite::spriteworld::rleX *sprite, + graphite::quickdraw::surface& surface, + graphite::data::reader& reader, + graphite::quickdraw::rect& rect, + std::uint32_t& offset, + std::uint32_t& right_offset_bound, + std::uint32_t& pitch, + std::uint32_t& frame, + std::uint16_t frame_count, + bool& completed, + union graphite::quickdraw::ycbcr& color +) -> void { + auto count = reader.read_byte(); + rleX_draw_color(surface, color, rect, offset, right_offset_bound, pitch, static_cast(count)); +} + +typedef void(*rleX_opcode_handler)( + graphite::spriteworld::rleX*, + graphite::quickdraw::surface&, + graphite::data::reader&, + graphite::quickdraw::rect&, + std::uint32_t&, + std::uint32_t&, + std::uint32_t&, + std::uint32_t&, + std::uint16_t, + bool&, + union graphite::quickdraw::ycbcr& +); + auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void { reader.change_byte_order(data::byte_order::lsb); @@ -153,15 +320,15 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void // Determine what the grid will be. We need to round up to the next whole and have blank tiles if the frame count // is not divisible by the grid width constant. - auto grid_width = std::min(constants::rle_grid_width, m_frame_count); + auto dim = static_cast(std::ceil(std::sqrt(m_frame_count))); + auto grid_width = std::min(dim, m_frame_count); m_grid_size = quickdraw::size(grid_width, std::ceil(m_frame_count / static_cast(grid_width))); // Create the surface in which all frames will be drawn to, and other working variables required to parse and // decode the RLE data correctly. - m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height, quickdraw::colors::clear()); + m_surface = quickdraw::surface(dim * m_frame_size.width, dim * m_frame_size.height, quickdraw::colors::clear()); - rleX::opcode opcode = opcode::eof; - std::int32_t current_frame = 0; + std::uint32_t current_frame = 0; std::uint32_t count = 0; std::uint32_t current_offset = 0; std::uint32_t right_bound = 0; @@ -180,57 +347,32 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void // NOTE: This is a very _hot_ code path and thus we need to squeeze out as much performance as possible. // Build a lookup table of opcodes, in order to reduce the number of comparisons. /* quickdraw::surface&, data::reader&, union quickdraw::ycbcr&, std::int32_t&, std::uint32_t&, quickdraw::rect& */ - std::functionvoid> opcode_lut[9] = { - /* EOF */ - /* 0 */ [&] { - if (++current_frame >= m_frame_count) { - completed_last_frame = true; - return; - } - opcode_lut[8](); - }, - - /* set components */ - /* 1 */ [&] { yuv.components.y = reader.read_byte(); }, - /* 2 */ [&] { yuv.components.cr = reader.read_byte(); }, - /* 3 */ [&] { yuv.components.cb = reader.read_byte(); }, - /* 4 */ [&] { yuv.components.alpha = reader.read_byte(); }, - - /* advance */ - /* 5 */ [&] { count = reader.read_long(); opcode_lut[7](); }, - /* 6 */ [&] { - count = static_cast(opcode) & ~static_cast(rleX::opcode::short_advance); - opcode_lut[7](); - }, - - /* fill operation */ - /* 7 */ [&] { - auto rgb = quickdraw::rgb(yuv); - for (auto i = 0; i < count; ++i) { - m_surface.set(current_offset, rgb); - if (++current_offset >= right_bound) { - current_offset += pitch; - right_bound = current_offset + frame.size.width; - } - } - }, - /* 8 */ [&] { - frame = frame_rect(current_frame); - current_offset = (frame.origin.y * m_surface.size().width) + frame.origin.x; - right_bound = current_offset + frame.size.width; - pitch = m_surface.size().width - frame.size.width; - }, + rleX_opcode_handler opcode_lut[] = { + rleX_opcode_handler_eof, + rleX_opcode_handler_set_luma, + rleX_opcode_handler_set_cr, + rleX_opcode_handler_set_cb, + rleX_opcode_handler_set_alpha, + rleX_opcode_handler_advance, + rleX_opcode_handler_short_advance }; - opcode_lut[8](); - - while (!reader.eof() && !completed_last_frame) { - opcode = reader.read_enum(); - if (static_cast(opcode) & static_cast(rleX::opcode::short_advance)) { - opcode_lut[6](); - continue; - } - opcode_lut[static_cast(opcode)](); + rleX_calculate_sprite_geometry(this, m_surface, frame, current_offset, right_bound, pitch, current_frame); + + while (!completed_last_frame) { + opcode_lut[reader.read_byte()]( + this, + m_surface, + reader, + frame, + current_offset, + right_bound, + pitch, + current_frame, + m_frame_count, + completed_last_frame, + yuv + ); } } @@ -268,9 +410,9 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void if (next_yuv.value != yuv.value) { if (count > 0) { - if (count < 127) { - auto opcode = static_cast(opcode::short_advance) | count; - writer.write_byte(opcode); + if (count < 256) { + writer.write_enum(opcode::short_advance); + writer.write_byte(count); } else { writer.write_enum(opcode::advance); writer.write_long(count); @@ -305,9 +447,9 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void } } - if (count < 127) { - auto opcode = static_cast(opcode::short_advance) | count; - writer.write_byte(opcode); + if (count < 256) { + writer.write_enum(opcode::short_advance); + writer.write_byte(count); } else { writer.write_enum(opcode::advance); diff --git a/libGraphite/spriteworld/rleX.hpp b/libGraphite/spriteworld/rleX.hpp index 13fe7ad..7aeb0ac 100644 --- a/libGraphite/spriteworld/rleX.hpp +++ b/libGraphite/spriteworld/rleX.hpp @@ -64,7 +64,7 @@ namespace graphite::spriteworld set_cb = 0x03, set_alpha = 0x04, advance = 0x05, - short_advance = 0x80, + short_advance = 0x06, }; rsrc::resource::identifier m_id { 0 }; From 8de43a6a24f7c3dac522e7d386ff5a551312c34d Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 24 Sep 2022 20:39:42 +0100 Subject: [PATCH 065/113] Remove old GraphiteTest executable --- CMakeLists.txt | 10 ---------- GraphiteTest/main.cpp | 29 ----------------------------- 2 files changed, 39 deletions(-) delete mode 100644 GraphiteTest/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ed0574d..7a5010a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,14 +36,4 @@ file(GLOB_RECURSE graphite_sources ) add_library(Graphite ${graphite_sources}) -#file(GLOB_RECURSE graphite_test_sources -# GraphiteTest/*.cpp -# libGraphite/fast_data/*.cpp -# libGraphite/encoding/*.cpp -# libGraphite/new_rsrc/*.cpp -# libGraphite/util/*.cpp -#) -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") -#add_executable(GraphiteTest ${graphite_test_sources}) -#target_link_libraries(GraphiteTest Graphite) diff --git a/GraphiteTest/main.cpp b/GraphiteTest/main.cpp deleted file mode 100644 index 4a1b848..0000000 --- a/GraphiteTest/main.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2020 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include "libGraphite/rsrc/manager.hpp" -#include "libGraphite/data/data.hpp" - -int main(int argc, char const *argv[]) -{ - - return 0; -} From 2ee46496262a1dab7e388a8d569286cc7311d94a Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 24 Sep 2022 22:03:09 +0100 Subject: [PATCH 066/113] Begin introducing a test harness for Graphite --- CMakeLists.txt | 8 +++ Tests/data/block_tests.cpp | 25 +++++++++ Tests/runner.cpp | 112 +++++++++++++++++++++++++++++++++++++ Tests/test.hpp | 51 +++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 Tests/data/block_tests.cpp create mode 100644 Tests/runner.cpp create mode 100644 Tests/test.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a5010a..2152836 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ if (APPLE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") endif() +# libGraphite include_directories("${PROJECT_SOURCE_DIR}") file(GLOB_RECURSE graphite_sources @@ -36,4 +37,11 @@ file(GLOB_RECURSE graphite_sources ) add_library(Graphite ${graphite_sources}) +# libGraphite Tests +file(GLOB_RECURSE graphiteTest_sources + Tests/*.cpp +) +add_executable(GraphiteTestRunner ${graphiteTest_sources}) +target_include_directories(GraphiteTestRunner PUBLIC "${PROJECT_SOURCE_DIR}/Tests") + diff --git a/Tests/data/block_tests.cpp b/Tests/data/block_tests.cpp new file mode 100644 index 0000000..16b75d7 --- /dev/null +++ b/Tests/data/block_tests.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "test.hpp" + +TEST("Construct data::block") { + assert_base(1 == 2, "This should always be true"); +}; \ No newline at end of file diff --git a/Tests/runner.cpp b/Tests/runner.cpp new file mode 100644 index 0000000..1a9e8c6 --- /dev/null +++ b/Tests/runner.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include "test.hpp" + +// MARK: - Test Runner Support + +struct test_case +{ + enum class result { not_run, passed, failed }; + std::string name; + test_function_t impl; + enum result result { result::not_run }; + std::string reason; +}; + +struct test_suite +{ + static auto instance() -> test_suite& + { + static struct test_suite _instance; + return _instance; + } + std::uint32_t test_count { 0 }; + std::uint32_t tests_run { 0 }; + std::uint32_t tests_passed { 0 }; + std::uint32_t tests_failed { 0 }; + std::vector tests; + struct test_case *current_test { nullptr }; +}; + +// MARK: - Test Entry Point + +auto main(int argc, const char *argv[]) -> int +{ + // Process each of the test cases. + std::uint32_t test_number = 0; + for (auto it : test_suite::instance().tests) { + test_number++; + test_suite::instance().current_test = ⁢ + + std::cout << "[" << test_number << "/" << test_suite::instance().test_count << "] - " + << it.name << "... "; + + // Execute the test... + it.result = test_case::result::passed; + it.impl(it.name); + test_suite::instance().tests_run++; + + // Report the result to the host + if (it.result == test_case::result::not_run) { + std::cout << "Not Run" << std::endl; + } + else if (it.result == test_case::result::failed) { + std::cout << "Failed" << std::endl; + std::cout << "\t" << it.reason << std::endl; + test_suite::instance().tests_failed++; + } + else if (it.result == test_case::result::passed) { + std::cout << "Passed" << std::endl; + test_suite::instance().tests_passed++; + } + + test_suite::instance().current_test = nullptr; + } + + // Construct a report about tests passed/failed + std::cout << std::endl; + std::cout << test_suite::instance().tests_passed << " tests passed." << std::endl; + std::cout << test_suite::instance().tests_failed << " tests failed." << std::endl; + + // Return the result of the tests to the host. + return (test_suite::instance().tests_failed > 0) ? 1 : 0; +} + +// MARK: - Test Functions + +auto register_unit_test(const char *name, test_function_t test) -> void +{ + struct test_case test_case; + test_case.name = name; + test_case.impl = test; + test_suite::instance().tests.emplace_back(test_case); + test_suite::instance().test_count++; +} + +auto test_fail(const char *reason) -> void +{ + if (test_suite::instance().current_test) { + test_suite::instance().current_test->reason = reason; + test_suite::instance().current_test->result = test_case::result::failed; + } +} \ No newline at end of file diff --git a/Tests/test.hpp b/Tests/test.hpp new file mode 100644 index 0000000..d1531e9 --- /dev/null +++ b/Tests/test.hpp @@ -0,0 +1,51 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +typedef void(*test_function_t)(const std::string&); + +/* + * Register a new unit test. + */ +auto register_unit_test(const char* name, test_function_t test) -> void; + +auto test_fail(const char *reason) -> void; + +/* + * Unit Tests need to be setup and registered when the binary undergoes its initial + * static construction as it launches. Unit tests should be declared using the TEST() + * macro and specifying a plain English name to describe the purpose of the test. + */ +#define TEST(_name) auto test_##__FILE__##_##__LINE__(const std::string&) -> void; \ + __attribute__((constructor)) auto test_stub_##__FILE__##_##__LINE__() -> void { \ + register_unit_test((_name), test_##__FILE__##_##__LINE__); \ + } \ + auto test_##__FILE__##_##__LINE__(const std::string& test_name) -> void + +// MARK: - Test Helpers / Assertions + +#define assert_base(_cond, _note) if (!(_cond)) { \ + test_fail((_note)); \ + return; \ +} \ No newline at end of file From e8c522f33a8a9a700ed9ad0b30b6d3059699f769 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 24 Sep 2022 22:45:59 +0100 Subject: [PATCH 067/113] Expanding upon the initial unit tests for Graphite --- CMakeLists.txt | 1 + Tests/data/block_tests.cpp | 15 +++++++++++-- Tests/data/simd_tests.cpp | 43 ++++++++++++++++++++++++++++++++++++++ Tests/runner.cpp | 5 ++++- Tests/test.hpp | 30 +++++++++++++++++++------- 5 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 Tests/data/simd_tests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2152836..07cd08c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ file(GLOB_RECURSE graphiteTest_sources Tests/*.cpp ) add_executable(GraphiteTestRunner ${graphiteTest_sources}) +target_link_libraries(GraphiteTestRunner Graphite) target_include_directories(GraphiteTestRunner PUBLIC "${PROJECT_SOURCE_DIR}/Tests") diff --git a/Tests/data/block_tests.cpp b/Tests/data/block_tests.cpp index 16b75d7..8a45fac 100644 --- a/Tests/data/block_tests.cpp +++ b/Tests/data/block_tests.cpp @@ -19,7 +19,18 @@ // SOFTWARE. #include "test.hpp" +#include -TEST("Construct data::block") { - assert_base(1 == 2, "This should always be true"); +// MARK: - data::block construction tests + +TEST("Construct data::block with a power of 2 capacity") { + graphite::data::block block(64); + assert_equal(block.raw_size(), 64, "Raw size of block was expected to be 64"); + assert_equal(block.size(), 64, "Size of block was expected to be 64."); +}; + +TEST("Construct data::block with a none power of 2 capacity") { + graphite::data::block block(43); + assert_equal(block.raw_size(), 48, "Raw size of block was expected to be 48. Got " + std::to_string(block.raw_size())); + assert_equal(block.size(), 43, "Size of block was expected to be 43. Got " + std::to_string(block.size())); }; \ No newline at end of file diff --git a/Tests/data/simd_tests.cpp b/Tests/data/simd_tests.cpp new file mode 100644 index 0000000..e7f35ab --- /dev/null +++ b/Tests/data/simd_tests.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "test.hpp" +#include + +// MARK: - SIMD Capacity Expansion + +#if __x86_64__ + +TEST("[x64] Verify SIMD capacity expansion with alignment width of 16-bytes") { + assert_equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); + assert_equal(graphite::data::simd::expand_capacity(8), 16, "Expanded capacity from 8 bytes should expand to 16 bytes."); + assert_equal(graphite::data::simd::expand_capacity(16), 16, "Expanded capacity from 16 bytes should remain the same."); +}; + +#elif __arm64__ + +TEST("[ARM64] Verify SIMD capacity expansion with alignment width of 8-bytes") { + assert_equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); + assert_equal(graphite::data::simd::expand_capacity(2), 8, "Expanded capacity from 2 bytes should expand to 8 bytes."); + assert_equal(graphite::data::simd::expand_capacity(8), 8, "Expanded capacity from 2 bytes should remain the same."); +}; + +#endif + diff --git a/Tests/runner.cpp b/Tests/runner.cpp index 1a9e8c6..73ded9a 100644 --- a/Tests/runner.cpp +++ b/Tests/runner.cpp @@ -31,6 +31,7 @@ struct test_case test_function_t impl; enum result result { result::not_run }; std::string reason; + std::string expression; }; struct test_suite @@ -73,6 +74,7 @@ auto main(int argc, const char *argv[]) -> int else if (it.result == test_case::result::failed) { std::cout << "Failed" << std::endl; std::cout << "\t" << it.reason << std::endl; + std::cout << "\t\t" << it.expression << std::endl; test_suite::instance().tests_failed++; } else if (it.result == test_case::result::passed) { @@ -103,10 +105,11 @@ auto register_unit_test(const char *name, test_function_t test) -> void test_suite::instance().test_count++; } -auto test_fail(const char *reason) -> void +auto test_fail(const std::string &reason, const char *expr) -> void { if (test_suite::instance().current_test) { test_suite::instance().current_test->reason = reason; + test_suite::instance().current_test->expression = expr; test_suite::instance().current_test->result = test_case::result::failed; } } \ No newline at end of file diff --git a/Tests/test.hpp b/Tests/test.hpp index d1531e9..1d30e97 100644 --- a/Tests/test.hpp +++ b/Tests/test.hpp @@ -30,22 +30,38 @@ typedef void(*test_function_t)(const std::string&); */ auto register_unit_test(const char* name, test_function_t test) -> void; -auto test_fail(const char *reason) -> void; +auto test_fail(const std::string &reason, const char *expr) -> void; + +#define TEST_SYMBOL(a,b) X_TEST_SYMBOL(a, b) +#define X_TEST_SYMBOL(a,b) a##b /* * Unit Tests need to be setup and registered when the binary undergoes its initial * static construction as it launches. Unit tests should be declared using the TEST() * macro and specifying a plain English name to describe the purpose of the test. */ -#define TEST(_name) auto test_##__FILE__##_##__LINE__(const std::string&) -> void; \ - __attribute__((constructor)) auto test_stub_##__FILE__##_##__LINE__() -> void { \ - register_unit_test((_name), test_##__FILE__##_##__LINE__); \ +#define TEST(_name) auto TEST_SYMBOL(test_, __LINE__)(const std::string&) -> void; \ + __attribute__((constructor)) auto TEST_SYMBOL(test_stub_, __LINE__)() -> void { \ + register_unit_test((_name), TEST_SYMBOL(test_, __LINE__)); \ } \ - auto test_##__FILE__##_##__LINE__(const std::string& test_name) -> void + auto TEST_SYMBOL(test_, __LINE__)(const std::string& test_name) -> void // MARK: - Test Helpers / Assertions +#define xstr(s) str(s) +#define str(s) #s + #define assert_base(_cond, _note) if (!(_cond)) { \ - test_fail((_note)); \ + test_fail((_note), str((_cond))); \ return; \ -} \ No newline at end of file +} + +#define assert_true(_cond, _note) assert_base((_cond), (_note)) +#define assert_false(_cond, _note) assert_base(!(_cond), (_note)) +#define assert_null(_ptr, _note) assert_base((_ptr) == nullptr, (_note)) +#define assert_equal(_subject, _expect, _note) assert_base((_subject) == (_expect), (_note)) +#define assert_not_equal(_subject, _expect, _note) assert_base((_subject) != (_expect), (_note)) +#define assert_less_than(_subject, _expect, _note) assert_base((_subject) < (_expect), (_note)) +#define assert_less_than_equal(_subject, _expect, _note) assert_base((_subject) <= (_expect), (_note)) +#define assert_greater_than(_subject, _expect, _note) assert_base((_subject) > (_expect), (_note)) +#define assert_greater_than_equal(_subject, _expect, _note) assert_base((_subject) >= (_expect), (_note)) \ No newline at end of file From 4828691231f7a1ca571ddc5a18b58ff10fe28806 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 09:55:01 +0100 Subject: [PATCH 068/113] Make the testing harness its owner library for use in other projects. (libTesting) --- CMakeLists.txt | 9 +- Tests/data/block_tests.cpp | 12 +-- Tests/data/simd_tests.cpp | 14 +-- Tests/test.hpp | 67 --------------- {Tests => libTesting}/runner.cpp | 47 +++++++--- libTesting/testing.hpp | 142 +++++++++++++++++++++++++++++++ 6 files changed, 199 insertions(+), 92 deletions(-) delete mode 100644 Tests/test.hpp rename {Tests => libTesting}/runner.cpp (75%) create mode 100644 libTesting/testing.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 07cd08c..159d0ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,18 +31,23 @@ endif() # libGraphite include_directories("${PROJECT_SOURCE_DIR}") - file(GLOB_RECURSE graphite_sources libGraphite/*.cpp ) add_library(Graphite ${graphite_sources}) +# libTesting +file(GLOB_RECURSE testing_sources + libTesting/*.cpp +) +add_library(Testing ${testing_sources}) + # libGraphite Tests file(GLOB_RECURSE graphiteTest_sources Tests/*.cpp ) add_executable(GraphiteTestRunner ${graphiteTest_sources}) -target_link_libraries(GraphiteTestRunner Graphite) +target_link_libraries(GraphiteTestRunner Graphite Testing) target_include_directories(GraphiteTestRunner PUBLIC "${PROJECT_SOURCE_DIR}/Tests") diff --git a/Tests/data/block_tests.cpp b/Tests/data/block_tests.cpp index 8a45fac..edca28a 100644 --- a/Tests/data/block_tests.cpp +++ b/Tests/data/block_tests.cpp @@ -18,19 +18,21 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "test.hpp" +#include #include // MARK: - data::block construction tests TEST("Construct data::block with a power of 2 capacity") { graphite::data::block block(64); - assert_equal(block.raw_size(), 64, "Raw size of block was expected to be 64"); - assert_equal(block.size(), 64, "Size of block was expected to be 64."); + test::equal(block.raw_size(), 64, "Raw size of block was expected to be 64"); + test::equal(block.size(), 64, "Size of block was expected to be 64."); + + test::equal(54, 11, "Expected values to be equal"); }; TEST("Construct data::block with a none power of 2 capacity") { graphite::data::block block(43); - assert_equal(block.raw_size(), 48, "Raw size of block was expected to be 48. Got " + std::to_string(block.raw_size())); - assert_equal(block.size(), 43, "Size of block was expected to be 43. Got " + std::to_string(block.size())); + test::equal(block.raw_size(), 48, "Raw size of block was expected to be 48. Got " + std::to_string(block.raw_size())); + test::equal(block.size(), 43, "Size of block was expected to be 43. Got " + std::to_string(block.size())); }; \ No newline at end of file diff --git a/Tests/data/simd_tests.cpp b/Tests/data/simd_tests.cpp index e7f35ab..b59b488 100644 --- a/Tests/data/simd_tests.cpp +++ b/Tests/data/simd_tests.cpp @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "test.hpp" +#include #include // MARK: - SIMD Capacity Expansion @@ -26,17 +26,17 @@ #if __x86_64__ TEST("[x64] Verify SIMD capacity expansion with alignment width of 16-bytes") { - assert_equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); - assert_equal(graphite::data::simd::expand_capacity(8), 16, "Expanded capacity from 8 bytes should expand to 16 bytes."); - assert_equal(graphite::data::simd::expand_capacity(16), 16, "Expanded capacity from 16 bytes should remain the same."); + test::equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); + test::equal(graphite::data::simd::expand_capacity(8), 16, "Expanded capacity from 8 bytes should expand to 16 bytes."); + test::equal(graphite::data::simd::expand_capacity(16), 16, "Expanded capacity from 16 bytes should remain the same."); }; #elif __arm64__ TEST("[ARM64] Verify SIMD capacity expansion with alignment width of 8-bytes") { - assert_equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); - assert_equal(graphite::data::simd::expand_capacity(2), 8, "Expanded capacity from 2 bytes should expand to 8 bytes."); - assert_equal(graphite::data::simd::expand_capacity(8), 8, "Expanded capacity from 2 bytes should remain the same."); + test::equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); + test::equal(graphite::data::simd::expand_capacity(2), 8, "Expanded capacity from 2 bytes should expand to 8 bytes."); + test::equal(graphite::data::simd::expand_capacity(8), 8, "Expanded capacity from 2 bytes should remain the same."); }; #endif diff --git a/Tests/test.hpp b/Tests/test.hpp deleted file mode 100644 index 1d30e97..0000000 --- a/Tests/test.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -#include -#include - -typedef void(*test_function_t)(const std::string&); - -/* - * Register a new unit test. - */ -auto register_unit_test(const char* name, test_function_t test) -> void; - -auto test_fail(const std::string &reason, const char *expr) -> void; - -#define TEST_SYMBOL(a,b) X_TEST_SYMBOL(a, b) -#define X_TEST_SYMBOL(a,b) a##b - -/* - * Unit Tests need to be setup and registered when the binary undergoes its initial - * static construction as it launches. Unit tests should be declared using the TEST() - * macro and specifying a plain English name to describe the purpose of the test. - */ -#define TEST(_name) auto TEST_SYMBOL(test_, __LINE__)(const std::string&) -> void; \ - __attribute__((constructor)) auto TEST_SYMBOL(test_stub_, __LINE__)() -> void { \ - register_unit_test((_name), TEST_SYMBOL(test_, __LINE__)); \ - } \ - auto TEST_SYMBOL(test_, __LINE__)(const std::string& test_name) -> void - -// MARK: - Test Helpers / Assertions - -#define xstr(s) str(s) -#define str(s) #s - -#define assert_base(_cond, _note) if (!(_cond)) { \ - test_fail((_note), str((_cond))); \ - return; \ -} - -#define assert_true(_cond, _note) assert_base((_cond), (_note)) -#define assert_false(_cond, _note) assert_base(!(_cond), (_note)) -#define assert_null(_ptr, _note) assert_base((_ptr) == nullptr, (_note)) -#define assert_equal(_subject, _expect, _note) assert_base((_subject) == (_expect), (_note)) -#define assert_not_equal(_subject, _expect, _note) assert_base((_subject) != (_expect), (_note)) -#define assert_less_than(_subject, _expect, _note) assert_base((_subject) < (_expect), (_note)) -#define assert_less_than_equal(_subject, _expect, _note) assert_base((_subject) <= (_expect), (_note)) -#define assert_greater_than(_subject, _expect, _note) assert_base((_subject) > (_expect), (_note)) -#define assert_greater_than_equal(_subject, _expect, _note) assert_base((_subject) >= (_expect), (_note)) \ No newline at end of file diff --git a/Tests/runner.cpp b/libTesting/runner.cpp similarity index 75% rename from Tests/runner.cpp rename to libTesting/runner.cpp index 73ded9a..163309c 100644 --- a/Tests/runner.cpp +++ b/libTesting/runner.cpp @@ -20,18 +20,26 @@ #include #include -#include "test.hpp" +#include +#include // MARK: - Test Runner Support +struct test_failure +{ + std::string expression; + std::string text; + std::string file; + std::uint32_t line; +}; + struct test_case { enum class result { not_run, passed, failed }; std::string name; test_function_t impl; enum result result { result::not_run }; - std::string reason; - std::string expression; + std::vector reasons; }; struct test_suite @@ -59,7 +67,7 @@ auto main(int argc, const char *argv[]) -> int test_number++; test_suite::instance().current_test = ⁢ - std::cout << "[" << test_number << "/" << test_suite::instance().test_count << "] - " + std::cout << "[" << test_number << "/" << test_suite::instance().test_count << "] " << it.name << "... "; // Execute the test... @@ -73,8 +81,6 @@ auto main(int argc, const char *argv[]) -> int } else if (it.result == test_case::result::failed) { std::cout << "Failed" << std::endl; - std::cout << "\t" << it.reason << std::endl; - std::cout << "\t\t" << it.expression << std::endl; test_suite::instance().tests_failed++; } else if (it.result == test_case::result::passed) { @@ -82,6 +88,19 @@ auto main(int argc, const char *argv[]) -> int test_suite::instance().tests_passed++; } + if (!it.reasons.empty()) { + for (const auto& reason : it.reasons) { + std::cout << "\t" << reason.file << " - L" << reason.line << std::endl; + if (!reason.text.empty()) { + std::cout << "\t\t" << reason.text << std::endl; + } + if (!reason.expression.empty()) { + std::cout << "\t\t" << reason.expression << std::endl; + } + } + + } + test_suite::instance().current_test = nullptr; } @@ -94,9 +113,9 @@ auto main(int argc, const char *argv[]) -> int return (test_suite::instance().tests_failed > 0) ? 1 : 0; } -// MARK: - Test Functions +// MARK: - Harness Setup Function -auto register_unit_test(const char *name, test_function_t test) -> void +auto register_unit_test(const std::string& name, test_function_t test) -> void { struct test_case test_case; test_case.name = name; @@ -105,11 +124,17 @@ auto register_unit_test(const char *name, test_function_t test) -> void test_suite::instance().test_count++; } -auto test_fail(const std::string &reason, const char *expr) -> void +// MARK: - Test Assertions + +auto test::fail(const std::string &reason, const char *file, int line) -> void { if (test_suite::instance().current_test) { - test_suite::instance().current_test->reason = reason; - test_suite::instance().current_test->expression = expr; + struct test_failure failure; + failure.file = file; + failure.line = line; + failure.text = reason; + test_suite::instance().current_test->result = test_case::result::failed; + test_suite::instance().current_test->reasons.emplace_back(failure); } } \ No newline at end of file diff --git a/libTesting/testing.hpp b/libTesting/testing.hpp new file mode 100644 index 0000000..2fe17f5 --- /dev/null +++ b/libTesting/testing.hpp @@ -0,0 +1,142 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +typedef void(*test_function_t)(const std::string&); + +/** + * Register a new unit test. + * Must be called prior to main() being called. Typically this isn't done directly, but through the use of + * the TEST() macro. + * @param test_name The name of the test. + * @param fn The test code to be executed. + */ +auto register_unit_test(const std::string& test_name, test_function_t fn) -> void; + +#define TEST_SYMBOL(a,b) X_TEST_SYMBOL(a, b) +#define X_TEST_SYMBOL(a,b) a##b + +/* + * Unit Tests need to be setup and registered when the binary undergoes its initial + * static construction as it launches. Unit tests should be declared using the TEST() + * macro and specifying a plain English name to describe the purpose of the test. + */ +#define TEST(_name) auto TEST_SYMBOL(test_, __LINE__)(const std::string&) -> void; \ + __attribute__((constructor)) auto TEST_SYMBOL(test_stub_, __LINE__)() -> void { \ + register_unit_test((_name), TEST_SYMBOL(test_, __LINE__)); \ + } \ + auto TEST_SYMBOL(test_, __LINE__)(const std::string& test_name) -> void + +// MARK: - Test Assertions + +namespace test +{ + /** + * Indicate that the current test has failed. + * @param reason The message to be shown in the test log describing the failure. + */ + auto fail(const std::string &reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void; + + template::value>::type* = nullptr> + auto equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '==' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs == rhs); + if (!result) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + auto not_equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '!=' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs != rhs); + if (!result) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + auto less_than(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '<' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs < rhs); + if (!result) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + auto less_than_equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '<=' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs <= rhs); + if (!result) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + auto greater_than(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '>' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs > rhs); + if (!result) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + auto greater_than_equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '>=' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs >= rhs); + if (!result) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + auto is_true(bool condition, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + if (!condition) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + auto is_false(bool condition, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + if (condition) { + fail(reason, file, line); + } + } +} \ No newline at end of file From 8fd1d09674bda64c2730d184896c096f4853920f Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 13:01:40 +0100 Subject: [PATCH 069/113] Separate CTest definitions to their own file. --- CMakeLists.txt | 3 ++- CTestTestfile.cmake | 6 +++++ Tests/data/block_tests.cpp | 6 ++--- libTesting/runner.cpp | 49 +++++++++++++++++++++++++++++++------- 4 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 CTestTestfile.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 159d0ee..7e8060d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,4 +50,5 @@ add_executable(GraphiteTestRunner ${graphiteTest_sources}) target_link_libraries(GraphiteTestRunner Graphite Testing) target_include_directories(GraphiteTestRunner PUBLIC "${PROJECT_SOURCE_DIR}/Tests") - +enable_testing() +include("CTestTestfile.cmake") \ No newline at end of file diff --git a/CTestTestfile.cmake b/CTestTestfile.cmake new file mode 100644 index 0000000..99b19b8 --- /dev/null +++ b/CTestTestfile.cmake @@ -0,0 +1,6 @@ + +add_test(NAME ConstructDataBlock_Power2Capacity + COMMAND GraphiteTestRunner -s ConstructDataBlock_Power2Capacity) + +add_test(NAME ConstructDataBlock_NonePower2Capacity + COMMAND GraphiteTestRunner -s ConstructDataBlock_NonePower2Capacity) \ No newline at end of file diff --git a/Tests/data/block_tests.cpp b/Tests/data/block_tests.cpp index edca28a..fa69a12 100644 --- a/Tests/data/block_tests.cpp +++ b/Tests/data/block_tests.cpp @@ -23,15 +23,13 @@ // MARK: - data::block construction tests -TEST("Construct data::block with a power of 2 capacity") { +TEST("ConstructDataBlock_Power2Capacity") { graphite::data::block block(64); test::equal(block.raw_size(), 64, "Raw size of block was expected to be 64"); test::equal(block.size(), 64, "Size of block was expected to be 64."); - - test::equal(54, 11, "Expected values to be equal"); }; -TEST("Construct data::block with a none power of 2 capacity") { +TEST("ConstructDataBlock_NonePower2Capacity") { graphite::data::block block(43); test::equal(block.raw_size(), 48, "Raw size of block was expected to be 48. Got " + std::to_string(block.raw_size())); test::equal(block.size(), 43, "Size of block was expected to be 43. Got " + std::to_string(block.size())); diff --git a/libTesting/runner.cpp b/libTesting/runner.cpp index 163309c..88958e4 100644 --- a/libTesting/runner.cpp +++ b/libTesting/runner.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -61,14 +62,36 @@ struct test_suite auto main(int argc, const char *argv[]) -> int { + // Build a list of the desired tests to be run. + bool test_logs = true; + std::unordered_set enabled_tests; + if (argc > 1) { + for (auto i = 1; i < argc; ++i) { + if (std::string(argv[i]) == "-s") { + test_logs = false; + continue; + } + enabled_tests.emplace(argv[i]); + } + } + // Process each of the test cases. std::uint32_t test_number = 0; for (auto it : test_suite::instance().tests) { + if (!enabled_tests.empty()) { + const auto& flag = enabled_tests.find(it.name); + if (flag == enabled_tests.end()) { + continue; + } + } + test_number++; test_suite::instance().current_test = ⁢ - std::cout << "[" << test_number << "/" << test_suite::instance().test_count << "] " - << it.name << "... "; + if (test_logs) { + std::cout << "[" << test_number << "/" << test_suite::instance().test_count << "] " + << it.name << "... "; + } // Execute the test... it.result = test_case::result::passed; @@ -77,18 +100,24 @@ auto main(int argc, const char *argv[]) -> int // Report the result to the host if (it.result == test_case::result::not_run) { - std::cout << "Not Run" << std::endl; + if (test_logs) { + std::cout << "Not Run" << std::endl; + } } else if (it.result == test_case::result::failed) { - std::cout << "Failed" << std::endl; + if (test_logs) { + std::cout << "Failed" << std::endl; + } test_suite::instance().tests_failed++; } else if (it.result == test_case::result::passed) { - std::cout << "Passed" << std::endl; + if (test_logs) { + std::cout << "Passed" << std::endl; + } test_suite::instance().tests_passed++; } - if (!it.reasons.empty()) { + if (!it.reasons.empty() && test_logs) { for (const auto& reason : it.reasons) { std::cout << "\t" << reason.file << " - L" << reason.line << std::endl; if (!reason.text.empty()) { @@ -105,9 +134,11 @@ auto main(int argc, const char *argv[]) -> int } // Construct a report about tests passed/failed - std::cout << std::endl; - std::cout << test_suite::instance().tests_passed << " tests passed." << std::endl; - std::cout << test_suite::instance().tests_failed << " tests failed." << std::endl; + if (enabled_tests.empty() && test_logs) { + std::cout << std::endl; + std::cout << test_suite::instance().tests_passed << " tests passed." << std::endl; + std::cout << test_suite::instance().tests_failed << " tests failed." << std::endl; + } // Return the result of the tests to the host. return (test_suite::instance().tests_failed > 0) ? 1 : 0; From a3d0fe9d891e9392dfaedb0dc78f3b48e943c7a0 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 13:09:12 +0100 Subject: [PATCH 070/113] Add test step to the CI --- .github/workflows/build.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a80c009..0d2ca36 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,9 @@ jobs: CXX: ${{ matrix.env.CXX }} run: | ./.github/actions/build.sh + - name: Test + run: | + ctest macOS: name: Build on macOS @@ -32,6 +35,9 @@ jobs: - name: Build run: | ./.github/actions/build.sh + - name: Test + run: | + ctest windows: name: Build on Windows @@ -62,3 +68,6 @@ jobs: CXX: ${{ matrix.env.CXX }} run: | ./.github/actions/build.sh + - name: Test + run: | + ctest From 9dbe6492371d7d5b5039878e67406947cdfcfbba Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 13:14:43 +0100 Subject: [PATCH 071/113] Potential fix to unit tests --- .github/workflows/build.yml | 12 ++++-------- CMakeLists.txt | 6 +++--- CTestTestfile.cmake | 5 +++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d2ca36..1fb3416 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,11 +17,9 @@ jobs: env: CC: ${{ matrix.env.CC }} CXX: ${{ matrix.env.CXX }} - run: | - ./.github/actions/build.sh + run: ./.github/actions/build.sh - name: Test - run: | - ctest + run: ctest macOS: name: Build on macOS @@ -36,8 +34,7 @@ jobs: run: | ./.github/actions/build.sh - name: Test - run: | - ctest + run: ctest windows: name: Build on Windows @@ -69,5 +66,4 @@ jobs: run: | ./.github/actions/build.sh - name: Test - run: | - ctest + run: ctest \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e8060d..2869332 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,9 +46,9 @@ add_library(Testing ${testing_sources}) file(GLOB_RECURSE graphiteTest_sources Tests/*.cpp ) -add_executable(GraphiteTestRunner ${graphiteTest_sources}) -target_link_libraries(GraphiteTestRunner Graphite Testing) -target_include_directories(GraphiteTestRunner PUBLIC "${PROJECT_SOURCE_DIR}/Tests") +add_executable(Graphite_TestRunner ${graphiteTest_sources}) +target_link_libraries(Graphite_TestRunner Graphite Testing) +target_include_directories(Graphite_TestRunner PUBLIC "${PROJECT_SOURCE_DIR}/Tests") enable_testing() include("CTestTestfile.cmake") \ No newline at end of file diff --git a/CTestTestfile.cmake b/CTestTestfile.cmake index 99b19b8..cd7a3b0 100644 --- a/CTestTestfile.cmake +++ b/CTestTestfile.cmake @@ -1,6 +1,7 @@ +set(TEST_TARGET_PATH ${CMAKE_SOURCE_DIR}/bin/Graphite_TestRunner -s) add_test(NAME ConstructDataBlock_Power2Capacity - COMMAND GraphiteTestRunner -s ConstructDataBlock_Power2Capacity) + COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_Power2Capacity) add_test(NAME ConstructDataBlock_NonePower2Capacity - COMMAND GraphiteTestRunner -s ConstructDataBlock_NonePower2Capacity) \ No newline at end of file + COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_NonePower2Capacity) \ No newline at end of file From bf0c0f8bc783cc70a43ba11ae97fa14d122bc02d Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 13:19:13 +0100 Subject: [PATCH 072/113] Another attempt at fixing the unit tests on CI --- .github/workflows/build.yml | 6 +++--- CTestTestfile.cmake | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1fb3416..dd6a8f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: CXX: ${{ matrix.env.CXX }} run: ./.github/actions/build.sh - name: Test - run: ctest + run: make test macOS: name: Build on macOS @@ -34,7 +34,7 @@ jobs: run: | ./.github/actions/build.sh - name: Test - run: ctest + run: make test windows: name: Build on Windows @@ -66,4 +66,4 @@ jobs: run: | ./.github/actions/build.sh - name: Test - run: ctest \ No newline at end of file + run: make test \ No newline at end of file diff --git a/CTestTestfile.cmake b/CTestTestfile.cmake index cd7a3b0..a279005 100644 --- a/CTestTestfile.cmake +++ b/CTestTestfile.cmake @@ -1,7 +1,9 @@ +include(CTest) + set(TEST_TARGET_PATH ${CMAKE_SOURCE_DIR}/bin/Graphite_TestRunner -s) add_test(NAME ConstructDataBlock_Power2Capacity - COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_Power2Capacity) + COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_Power2Capacity) add_test(NAME ConstructDataBlock_NonePower2Capacity - COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_NonePower2Capacity) \ No newline at end of file + COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_NonePower2Capacity) \ No newline at end of file From a6489441c3c24e7285a203c3a75e836d52f9ce27 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 13:21:16 +0100 Subject: [PATCH 073/113] Ensure we are in the correct directory for unit tests --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd6a8f3..18e37ca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: CXX: ${{ matrix.env.CXX }} run: ./.github/actions/build.sh - name: Test - run: make test + run: cd build && make test macOS: name: Build on macOS @@ -34,7 +34,7 @@ jobs: run: | ./.github/actions/build.sh - name: Test - run: make test + run: cd build && make test windows: name: Build on Windows @@ -66,4 +66,4 @@ jobs: run: | ./.github/actions/build.sh - name: Test - run: make test \ No newline at end of file + run: cd build && make test \ No newline at end of file From 7576b177bf90bc2a157b2e9242bf7894d97a7f0e Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 13:27:03 +0100 Subject: [PATCH 074/113] Ensure Windows environment has make installed. --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18e37ca..388a398 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,6 +59,7 @@ jobs: pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-clang pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-cmake pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-ninja + pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-make - name: Build env: CC: ${{ matrix.env.CC }} From cca98826ec42df655736ac4df672ab802f05a20b Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 16:43:18 +0100 Subject: [PATCH 075/113] More adjustments to libTesting and formalizing the testing framework. --- CMakeLists.txt | 21 +++++---------------- CTestTestfile.cmake | 9 --------- GraphiteTests.cmake | 6 ++++++ Tests/data/block_tests.cpp | 18 ++++++++++++++---- Tests/data/simd_tests.cpp | 4 ++-- libTesting/runner.cpp | 2 +- libTesting/testing.cmake | 31 +++++++++++++++++++++++++++++++ libTesting/testing.hpp | 16 ++++++++-------- 8 files changed, 67 insertions(+), 40 deletions(-) delete mode 100644 CTestTestfile.cmake create mode 100644 GraphiteTests.cmake create mode 100644 libTesting/testing.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 2869332..ab09cf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,19 +36,8 @@ file(GLOB_RECURSE graphite_sources ) add_library(Graphite ${graphite_sources}) -# libTesting -file(GLOB_RECURSE testing_sources - libTesting/*.cpp -) -add_library(Testing ${testing_sources}) - -# libGraphite Tests -file(GLOB_RECURSE graphiteTest_sources - Tests/*.cpp -) -add_executable(Graphite_TestRunner ${graphiteTest_sources}) -target_link_libraries(Graphite_TestRunner Graphite Testing) -target_include_directories(Graphite_TestRunner PUBLIC "${PROJECT_SOURCE_DIR}/Tests") - -enable_testing() -include("CTestTestfile.cmake") \ No newline at end of file +# Unit Tests +include(libTesting/testing.cmake) +build_testing_library() +add_testing_target(Graphite ${CMAKE_SOURCE_DIR}/Tests) +include("GraphiteTests.cmake") \ No newline at end of file diff --git a/CTestTestfile.cmake b/CTestTestfile.cmake deleted file mode 100644 index a279005..0000000 --- a/CTestTestfile.cmake +++ /dev/null @@ -1,9 +0,0 @@ -include(CTest) - -set(TEST_TARGET_PATH ${CMAKE_SOURCE_DIR}/bin/Graphite_TestRunner -s) - -add_test(NAME ConstructDataBlock_Power2Capacity - COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_Power2Capacity) - -add_test(NAME ConstructDataBlock_NonePower2Capacity - COMMAND ${TEST_TARGET_PATH} ConstructDataBlock_NonePower2Capacity) \ No newline at end of file diff --git a/GraphiteTests.cmake b/GraphiteTests.cmake new file mode 100644 index 0000000..32dd7d8 --- /dev/null +++ b/GraphiteTests.cmake @@ -0,0 +1,6 @@ +test_suite(Graphite + dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect + dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly + dataBlock_construct_defaultByteOrderIsCorrect + dataBlock_construct_usingLSBByteOrder_assignsCorrectly +) diff --git a/Tests/data/block_tests.cpp b/Tests/data/block_tests.cpp index fa69a12..e21d62b 100644 --- a/Tests/data/block_tests.cpp +++ b/Tests/data/block_tests.cpp @@ -21,16 +21,26 @@ #include #include -// MARK: - data::block construction tests +// MARK: - Construction Tests -TEST("ConstructDataBlock_Power2Capacity") { +TEST(dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect) { graphite::data::block block(64); test::equal(block.raw_size(), 64, "Raw size of block was expected to be 64"); test::equal(block.size(), 64, "Size of block was expected to be 64."); }; -TEST("ConstructDataBlock_NonePower2Capacity") { +TEST(dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly) { graphite::data::block block(43); test::equal(block.raw_size(), 48, "Raw size of block was expected to be 48. Got " + std::to_string(block.raw_size())); test::equal(block.size(), 43, "Size of block was expected to be 43. Got " + std::to_string(block.size())); -}; \ No newline at end of file +}; + +TEST(dataBlock_construct_defaultByteOrderIsCorrect) { + graphite::data::block block(8); + test::equal(block.byte_order(), graphite::data::byte_order::msb, "Data Blocks should have a default byte order of MSB."); +} + +TEST(dataBlock_construct_usingLSBByteOrder_assignsCorrectly) { + graphite::data::block block(8, graphite::data::byte_order::lsb); + test::equal(block.byte_order(), graphite::data::byte_order::lsb, "Data Blocks should have a default byte order of LSB."); +} \ No newline at end of file diff --git a/Tests/data/simd_tests.cpp b/Tests/data/simd_tests.cpp index b59b488..28ab03e 100644 --- a/Tests/data/simd_tests.cpp +++ b/Tests/data/simd_tests.cpp @@ -25,7 +25,7 @@ #if __x86_64__ -TEST("[x64] Verify SIMD capacity expansion with alignment width of 16-bytes") { +TEST(simd_x86_64_expandCapacity_expansionRoundsUpCorrectly) { test::equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); test::equal(graphite::data::simd::expand_capacity(8), 16, "Expanded capacity from 8 bytes should expand to 16 bytes."); test::equal(graphite::data::simd::expand_capacity(16), 16, "Expanded capacity from 16 bytes should remain the same."); @@ -33,7 +33,7 @@ TEST("[x64] Verify SIMD capacity expansion with alignment width of 16-bytes") { #elif __arm64__ -TEST("[ARM64] Verify SIMD capacity expansion with alignment width of 8-bytes") { +TEST(simd_arm64_expandCapacity_expansionRoundsUpCorrectly) { test::equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); test::equal(graphite::data::simd::expand_capacity(2), 8, "Expanded capacity from 2 bytes should expand to 8 bytes."); test::equal(graphite::data::simd::expand_capacity(8), 8, "Expanded capacity from 2 bytes should remain the same."); diff --git a/libTesting/runner.cpp b/libTesting/runner.cpp index 88958e4..1539ae7 100644 --- a/libTesting/runner.cpp +++ b/libTesting/runner.cpp @@ -95,7 +95,7 @@ auto main(int argc, const char *argv[]) -> int // Execute the test... it.result = test_case::result::passed; - it.impl(it.name); + it.impl(); test_suite::instance().tests_run++; // Report the result to the host diff --git a/libTesting/testing.cmake b/libTesting/testing.cmake new file mode 100644 index 0000000..abe7346 --- /dev/null +++ b/libTesting/testing.cmake @@ -0,0 +1,31 @@ +enable_testing() + +if(NOT DEFINED CMAKE_OUTPUT_PATH) + set(CMAKE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) +endif() + +# libTesting +function(build_testing_library) + file(GLOB_RECURSE testing_sources + ${CMAKE_SOURCE_DIR}/libTesting/*.cpp + ) + add_library(Testing ${testing_sources}) +endfunction() + +function(add_testing_target name dir) + file(GLOB_RECURSE test_sources ${dir}/*.cpp) + add_executable(${name}_TestRunner ${test_sources}) + target_link_libraries(${name}_TestRunner ${name} Testing) + target_include_directories(${name}_TestRunner PUBLIC ${dir}) +endfunction() + +function(test target name) + add_test(NAME ${name} COMMAND ${CMAKE_OUTPUT_PATH}/${target}_TestRunner -s ${name}) +endfunction() + +function(test_suite target list) + math(EXPR last "${ARGC} - 1") + foreach(n RANGE 1 ${last}) + test(${target} ${ARGV${n}}) + endforeach() +endfunction() diff --git a/libTesting/testing.hpp b/libTesting/testing.hpp index 2fe17f5..04f1a78 100644 --- a/libTesting/testing.hpp +++ b/libTesting/testing.hpp @@ -23,7 +23,7 @@ #include #include -typedef void(*test_function_t)(const std::string&); +typedef void(*test_function_t)(); /** * Register a new unit test. @@ -34,19 +34,19 @@ typedef void(*test_function_t)(const std::string&); */ auto register_unit_test(const std::string& test_name, test_function_t fn) -> void; -#define TEST_SYMBOL(a,b) X_TEST_SYMBOL(a, b) -#define X_TEST_SYMBOL(a,b) a##b +#define XSTR(_s) STR(_s) +#define STR(_s) #_s /* * Unit Tests need to be setup and registered when the binary undergoes its initial * static construction as it launches. Unit tests should be declared using the TEST() * macro and specifying a plain English name to describe the purpose of the test. */ -#define TEST(_name) auto TEST_SYMBOL(test_, __LINE__)(const std::string&) -> void; \ - __attribute__((constructor)) auto TEST_SYMBOL(test_stub_, __LINE__)() -> void { \ - register_unit_test((_name), TEST_SYMBOL(test_, __LINE__)); \ - } \ - auto TEST_SYMBOL(test_, __LINE__)(const std::string& test_name) -> void +#define TEST(_name) auto _name () -> void; \ + __attribute__((constructor)) auto _name##_trampoline() -> void { \ + register_unit_test(XSTR(_name), _name); \ + } \ + auto _name () -> void // MARK: - Test Assertions From 5bf775d98bfc04fd3da21380b139a9a0611c8432 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 22:05:03 +0100 Subject: [PATCH 076/113] Potential fix to Windows CI (make missing) --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 388a398..a1175a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,7 +59,7 @@ jobs: pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-clang pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-cmake pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-ninja - pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-make + mingw-get install msys-make - name: Build env: CC: ${{ matrix.env.CC }} From 4c73b46d857a33d086a6eeef95f748ac864990e6 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 22:05:22 +0100 Subject: [PATCH 077/113] Remove unused subscript from data::block --- libGraphite/data/data.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libGraphite/data/data.hpp b/libGraphite/data/data.hpp index 3026ff2..d7c5f89 100644 --- a/libGraphite/data/data.hpp +++ b/libGraphite/data/data.hpp @@ -79,16 +79,11 @@ namespace graphite::data template::value>::type* = nullptr> [[nodiscard]] inline auto get(block::position offset = 0) const -> T { return swap(*get(offset), m_byte_order); } - template::value>::type* = nullptr> - [[nodiscard]] inline auto operator[] (block::position offset) const -> T - { - return get(offset); - } - [[nodiscard]] inline auto raw_size() const -> std::size_t { return m_raw_size; } [[nodiscard]] inline auto size() const -> std::size_t { return m_count > 0 ? m_count : m_data_size; } [[nodiscard]] inline auto start() const -> block::position { return m_start_position; } [[nodiscard]] inline auto byte_order() const -> byte_order { return m_byte_order; } + [[nodiscard]] inline auto has_ownership() const -> bool { return m_has_ownership; } auto originates_from_extended_format() -> void { m_extended = true; } [[nodiscard]] inline auto is_extended_format() const -> bool { return m_extended; } From b3f362d685bc3db57d2feb4ca2152e3c8b27e0ba Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 22:05:47 +0100 Subject: [PATCH 078/113] Fixes to libTesting --- libTesting/testing.hpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/libTesting/testing.hpp b/libTesting/testing.hpp index 04f1a78..74df206 100644 --- a/libTesting/testing.hpp +++ b/libTesting/testing.hpp @@ -56,10 +56,10 @@ namespace test * Indicate that the current test has failed. * @param reason The message to be shown in the test log describing the failure. */ - auto fail(const std::string &reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void; + auto fail(const std::string &reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void; template::value>::type* = nullptr> - auto equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto equal(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { /* in order to make sure the implementation of a custom '==' operator is valid, we need to explicitly call * it, and not rely on shorthand. */ @@ -70,7 +70,7 @@ namespace test } template::value>::type* = nullptr> - auto not_equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto not_equal(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { /* in order to make sure the implementation of a custom '!=' operator is valid, we need to explicitly call * it, and not rely on shorthand. */ @@ -81,7 +81,7 @@ namespace test } template::value>::type* = nullptr> - auto less_than(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto less_than(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { /* in order to make sure the implementation of a custom '<' operator is valid, we need to explicitly call * it, and not rely on shorthand. */ @@ -92,7 +92,7 @@ namespace test } template::value>::type* = nullptr> - auto less_than_equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto less_than_equal(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { /* in order to make sure the implementation of a custom '<=' operator is valid, we need to explicitly call * it, and not rely on shorthand. */ @@ -103,7 +103,7 @@ namespace test } template::value>::type* = nullptr> - auto greater_than(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto greater_than(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { /* in order to make sure the implementation of a custom '>' operator is valid, we need to explicitly call * it, and not rely on shorthand. */ @@ -114,7 +114,7 @@ namespace test } template::value>::type* = nullptr> - auto greater_than_equal(const T& lhs, const U& rhs, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto greater_than_equal(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { /* in order to make sure the implementation of a custom '>=' operator is valid, we need to explicitly call * it, and not rely on shorthand. */ @@ -124,19 +124,27 @@ namespace test } } - template::value>::type* = nullptr> - auto is_true(bool condition, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto is_true(bool condition, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { if (!condition) { fail(reason, file, line); } } - template::value>::type* = nullptr> - auto is_false(bool condition, const std::string& reason, const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + static auto is_false(bool condition, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { if (condition) { fail(reason, file, line); } } + + static auto bytes_equal(const std::uint8_t *lhs, const std::uint8_t *rhs, std::size_t count, + const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + for (auto i = 0; i < count; ++i) { + if (lhs[i] != rhs[i]) { + fail(reason, file, line); + } + } + } } \ No newline at end of file From 46e74189c02a57b082225ef9518d772519e58603 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 22:06:09 +0100 Subject: [PATCH 079/113] Expand unit test coverage. --- GraphiteTests.cmake | 45 ++++++- Tests/data/block_tests.cpp | 70 ++++++++-- Tests/quickdraw/type/point_tests.cpp | 187 +++++++++++++++++++++++++++ Tests/util/hashing_tests.cpp | 33 +++++ libGraphite/quickdraw/type/point.hpp | 75 ++++++++--- libGraphite/util/hashing.hpp | 10 ++ 6 files changed, 386 insertions(+), 34 deletions(-) create mode 100644 Tests/quickdraw/type/point_tests.cpp create mode 100644 Tests/util/hashing_tests.cpp diff --git a/GraphiteTests.cmake b/GraphiteTests.cmake index 32dd7d8..81dfc47 100644 --- a/GraphiteTests.cmake +++ b/GraphiteTests.cmake @@ -1,6 +1,43 @@ test_suite(Graphite - dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect - dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly - dataBlock_construct_defaultByteOrderIsCorrect - dataBlock_construct_usingLSBByteOrder_assignsCorrectly + + # Data + # Data Block + dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect + dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly + dataBlock_construct_defaultByteOrderIsCorrect + dataBlock_construct_usingLSBByteOrder_assignsCorrectly + dataBlock_construct_hasOwnershipOfInitialData + dataBlock_getByteValue_atOffset_isExpectedValueReturned + dataBlock_getShortValue_atOffset_isExpectedValueReturned + dataBlock_getLongValue_atOffset_isExpectedValueReturned + dataBlock_getQuadValue_atOffset_isExpectedValueReturned + + # QuickDraw + # Point + point_constructUsingEqualCoordinates + point_constructUsingSeparateCoordinates + point_constructUsingReader_quickdraw + point_constructUsingReader_macintosh + point_readPointFromReader + point_encodeInToWriter_quickdraw + point_encodeInToWriter_macintosh + point_assignmentOperator_copyPoint + point_assignmentOperator_movePoint + point_equalsOperator_shouldBeEqual + point_equalsOperator_shouldNotBeEqual + point_notEqualsOperator_shouldNotBeEqual + point_notEqualsOperator_shouldBeEqual + point_addPoint_returnsExpectedPoint + point_subtractPoint_returnsExpectedPoint + point_multiplyPoint_returnsExpectedPoint + point_dividePoint_returnsExpectedPoint + point_castToDifferentType_retainsSameValue + + # Size + # Rect + + # Utility Functions + # XXHash Hashing + xxh64_verifyCorrectHashIsProduced + ) diff --git a/Tests/data/block_tests.cpp b/Tests/data/block_tests.cpp index e21d62b..d9c1f55 100644 --- a/Tests/data/block_tests.cpp +++ b/Tests/data/block_tests.cpp @@ -21,26 +21,74 @@ #include #include +using namespace graphite; + // MARK: - Construction Tests -TEST(dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect) { - graphite::data::block block(64); +TEST(dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect) +{ + data::block block(64); test::equal(block.raw_size(), 64, "Raw size of block was expected to be 64"); test::equal(block.size(), 64, "Size of block was expected to be 64."); }; -TEST(dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly) { - graphite::data::block block(43); +TEST(dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly) +{ + data::block block(43); test::equal(block.raw_size(), 48, "Raw size of block was expected to be 48. Got " + std::to_string(block.raw_size())); test::equal(block.size(), 43, "Size of block was expected to be 43. Got " + std::to_string(block.size())); }; -TEST(dataBlock_construct_defaultByteOrderIsCorrect) { - graphite::data::block block(8); - test::equal(block.byte_order(), graphite::data::byte_order::msb, "Data Blocks should have a default byte order of MSB."); +TEST(dataBlock_construct_defaultByteOrderIsCorrect) +{ + data::block block(8); + test::equal(block.byte_order(), data::byte_order::msb, "Data Blocks should have a default byte order of MSB."); +} + +TEST(dataBlock_construct_usingLSBByteOrder_assignsCorrectly) +{ + data::block block(8, data::byte_order::lsb); + test::equal(block.byte_order(), data::byte_order::lsb, "Data Blocks should have a default byte order of LSB."); +} + +TEST(dataBlock_construct_hasOwnershipOfInitialData) +{ + data::block block(8); + test::is_true(block.has_ownership(), "When constructed, Data Blocks should have ownership over the memory allocation."); +} + +// MARK: - Data Access Test + +static constexpr uint8_t test_data[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, + 0xDE, 0xAD, 0xD0, 0x0D, 0xCA, 0xFE, 0xCA, 0xFE +}; + +TEST(dataBlock_getByteValue_atOffset_isExpectedValueReturned) +{ + data::block block(test_data, sizeof(test_data), false); + test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); + test::equal(block.get(2), 0xBE, "Expected to retrieve the value 0xBE from the data block."); +} + +TEST(dataBlock_getShortValue_atOffset_isExpectedValueReturned) +{ + data::block block(test_data, sizeof(test_data), false); + test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); + test::equal(block.get(2), 0xBEEF, "Expected to retrieve the value 0xBEEF from the data block."); +} + +TEST(dataBlock_getLongValue_atOffset_isExpectedValueReturned) +{ + data::block block(test_data, sizeof(test_data), false); + test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); + test::equal(block.get(4), 0xCAFEBABE, "Expected to retrieve the value 0xCAFEBABE from the data block."); +} + +TEST(dataBlock_getQuadValue_atOffset_isExpectedValueReturned) +{ + data::block block(test_data, sizeof(test_data), false); + test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); + test::equal(block.get(8), 0xDEADD00DCAFECAFE, "Expected to retrieve the value 0xDEADD00DCAFECAFE from the data block."); } -TEST(dataBlock_construct_usingLSBByteOrder_assignsCorrectly) { - graphite::data::block block(8, graphite::data::byte_order::lsb); - test::equal(block.byte_order(), graphite::data::byte_order::lsb, "Data Blocks should have a default byte order of LSB."); -} \ No newline at end of file diff --git a/Tests/quickdraw/type/point_tests.cpp b/Tests/quickdraw/type/point_tests.cpp new file mode 100644 index 0000000..4d57a2c --- /dev/null +++ b/Tests/quickdraw/type/point_tests.cpp @@ -0,0 +1,187 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include + +using namespace graphite; + +// MARK: - Test Data + +static constexpr std::uint8_t point_test_data[] = { + 0x00, 0x80, 0x00, 0x20 +}; + +// MARK: - Construction Tests + +TEST(point_constructUsingEqualCoordinates) +{ + quickdraw::point point(10); + test::equal(point.x, 10); + test::equal(point.y, 10); +} + +TEST(point_constructUsingSeparateCoordinates) +{ + quickdraw::point point(5, 7); + test::equal(point.x, 5); + test::equal(point.y, 7); +} + +TEST(point_constructUsingReader_quickdraw) +{ + data::block block(point_test_data, sizeof(point_test_data), false); + data::reader reader(&block); + + quickdraw::point point(reader, quickdraw::coding_type::quickdraw); + test::equal(point.x, 32); + test::equal(point.y, 128); +} + +TEST(point_constructUsingReader_macintosh) +{ + data::block block(point_test_data, sizeof(point_test_data), false); + data::reader reader(&block); + + quickdraw::point point(reader, quickdraw::coding_type::macintosh); + test::equal(point.x, 128); + test::equal(point.y, 32); +} + +// MARK: - Static Reader + +TEST(point_readPointFromReader) +{ + data::block block(point_test_data, sizeof(point_test_data), false); + data::reader reader(&block); + + auto point = quickdraw::point::read(reader, quickdraw::coding_type::quickdraw); + test::equal(point.x, 32); + test::equal(point.y, 128); +} + +// MARK: - Encoding + +TEST(point_encodeInToWriter_quickdraw) +{ + data::writer writer(data::byte_order::msb); + + quickdraw::point point(32, 128); + point.encode(writer, quickdraw::coding_type::quickdraw); + + test::equal(writer.size(), sizeof(point_test_data)); + test::bytes_equal(writer.data()->get(), point_test_data, sizeof(point_test_data)); +} + +TEST(point_encodeInToWriter_macintosh) +{ + data::writer writer(data::byte_order::msb); + + quickdraw::point point(128, 32); + point.encode(writer, quickdraw::coding_type::macintosh); + + test::equal(writer.size(), sizeof(point_test_data)); + test::bytes_equal(writer.data()->get(), point_test_data, sizeof(point_test_data)); +} + +// MARK: - Operators + +TEST(point_assignmentOperator_copyPoint) +{ + quickdraw::point point(5); + test::equal(point.x, 5); + test::equal(point.y, 5); + + quickdraw::point newPoint(10); + point = newPoint; + test::equal(point.x, 10); + test::equal(point.y, 10); +} + +TEST(point_assignmentOperator_movePoint) +{ + quickdraw::point point(5); + test::equal(point.x, 5); + test::equal(point.y, 5); + + point = quickdraw::point(10); + test::equal(point.x, 10); + test::equal(point.y, 10); +} + +TEST(point_equalsOperator_shouldBeEqual) +{ + test::is_true(quickdraw::point(5) == quickdraw::point(5)); +} + +TEST(point_equalsOperator_shouldNotBeEqual) +{ + test::is_false(quickdraw::point(5) == quickdraw::point(7)); +} + +TEST(point_notEqualsOperator_shouldNotBeEqual) +{ + test::is_true(quickdraw::point(5) != quickdraw::point(7)); +} + +TEST(point_notEqualsOperator_shouldBeEqual) +{ + test::is_false(quickdraw::point(5) != quickdraw::point(5)); +} + +TEST(point_addPoint_returnsExpectedPoint) +{ + auto result = quickdraw::point(5) + quickdraw::point(3); + test::equal(result.x, 8); + test::equal(result.y, 8); +} + +TEST(point_subtractPoint_returnsExpectedPoint) +{ + auto result = quickdraw::point(5) - quickdraw::point(3); + test::equal(result.x, 2); + test::equal(result.y, 2); +} + +TEST(point_multiplyPoint_returnsExpectedPoint) +{ + auto result = quickdraw::point(5) * 3; + test::equal(result.x, 15); + test::equal(result.y, 15); +} + +TEST(point_dividePoint_returnsExpectedPoint) +{ + auto result = quickdraw::point(9) / 3; + test::equal(result.x, 3); + test::equal(result.y, 3); +} + +// MARK: - Casting Tests + +TEST(point_castToDifferentType_retainsSameValue) +{ + quickdraw::point point(76); + auto new_point = point.cast(); + test::equal(new_point.x, 76); + test::equal(new_point.y, 76); +} \ No newline at end of file diff --git a/Tests/util/hashing_tests.cpp b/Tests/util/hashing_tests.cpp new file mode 100644 index 0000000..afaa811 --- /dev/null +++ b/Tests/util/hashing_tests.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +using namespace graphite; + +// MARK: - XXHash64 Verification Tests + +TEST(xxh64_verifyCorrectHashIsProduced) +{ + std::string str = "Giraffe"; + hashing::value expected = 0xC09228325DE7E875; + test::equal(hashing::xxh64(str.c_str(), str.size()), expected); +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/point.hpp b/libGraphite/quickdraw/type/point.hpp index 8c9d529..a60bf1c 100644 --- a/libGraphite/quickdraw/type/point.hpp +++ b/libGraphite/quickdraw/type/point.hpp @@ -29,26 +29,49 @@ namespace graphite::quickdraw { + /** + * Represents a 2D point on a surface. + * @tparam T The type being used for the X & Y values of the point. This can be any arithmetic type. + */ template::value>::type* = nullptr> struct point { public: + /** + * The x-coordinate of the point. + */ T x { 0 }; + + /** + * The y-coordinate of the point. + */ T y { 0 }; point() = default; + + /** + * Construct a point where the X and Y coordinate are equal. + * @param v The value to set both of the X and Y coordinates to. + */ explicit point(T v) : x(v), y(v) {} + + /** + * Construct a point. + * @param x The value of the X coordinate. + * @param y The value of the Y coordinate. + */ point(T x, T y) : x(x), y(y) {} + point(const point&) = default; point(point&&) noexcept = default; - explicit point(data::reader& reader) - { - y = read_component(reader); - x = read_component(reader); - } - - point(data::reader& reader, coding_type type) + /** + * Construct a point, reading the X and Y coordinates from the specified data reader. + * Defaults to using the QuickDraw ordering for coordinates (Y and then X) + * @param reader The data reader to read the X and Y coordinates from. + * @param type The coding type (coordinate ordering) to use when reading the coordinates. + */ + explicit point(data::reader& reader, coding_type type = coding_type::quickdraw) { switch (type) { case coding_type::macintosh: { @@ -64,14 +87,23 @@ namespace graphite::quickdraw } } - static auto read(data::reader& reader, coding_type type) -> point { return { reader, type }; } - - auto encode(data::writer& writer) -> void + /** + * Construct a point, reading the X and Y coordinates from the specified data reader. + * @param reader The data reader to read the X and Y coordinates from. + * @param type The coding type (coordinate ordering) to use when reading the coordinates. + * @return A point with the X and Y coordinate read from the reader. + */ + static auto read(data::reader& reader, coding_type type) -> point { - encode(writer, coding_type::quickdraw); + return point(reader, type); } - auto encode(data::writer& writer, coding_type type) -> void + /** + * Write the X and Y coordinates of the point into the provided data writer, using the specified coding type. + * @param writer The data writer to write the X and Y coordinates to. + * @param type The coding type (coordinate ordering) to use when writing the coordinates. + */ + auto encode(data::writer& writer, coding_type type = coding_type::quickdraw) -> void { switch (type) { case coding_type::macintosh: { @@ -93,16 +125,21 @@ namespace graphite::quickdraw auto operator==(const point& p) const -> bool { return x == p.x && y == p.y; } auto operator!=(const point& p) const -> bool { return x != p.x && y != p.y; } - auto operator+(const point& p) const -> point { return { x + p.x, y + p.y }; } - auto operator-(const point& p) const -> point { return { x - p.x, y - p.y }; } + auto operator+(const point& p) const -> point { return point(x + p.x, y + p.y); } + auto operator-(const point& p) const -> point { return point(x - p.x, y - p.y); } - template::value>> - auto operator*(U v) const -> point { return { x * static_cast(v), y * static_cast(v) }; } + template::value>::type* = nullptr> + auto operator*(U v) const -> point { return point(x * static_cast(v), y * static_cast(v)); } - template::value>> - auto operator/(U v) const -> point { return { x / static_cast(v), y / static_cast(v) }; } + template::value>::type* = nullptr> + auto operator/(U v) const -> point { return point(x / static_cast(v), y / static_cast(v)); } - template::value>> + /** + * Cast the typename of the point to a different compatible type. + * @tparam U The new arithmetic type in which to cast to. + * @return A point using the new arithmetic type. + */ + template::value>::type* = nullptr> auto cast() const -> point { return { static_cast(x), static_cast(y) }; } private: diff --git a/libGraphite/util/hashing.hpp b/libGraphite/util/hashing.hpp index 6ffa256..a183888 100644 --- a/libGraphite/util/hashing.hpp +++ b/libGraphite/util/hashing.hpp @@ -24,8 +24,18 @@ namespace graphite::hashing { + /** + * A hash value. + * This type definition is intended to help provide semantic context. + */ typedef std::uint64_t value; + /** + * Produce a hash value using the 64-bit variant of the XXHash algorithm, using the specified data. + * @param ptr A pointer to the byte sequence to produce a hash from. + * @param length The length of the data being supplied. + * @return A hash value. + */ auto xxh64(const void *ptr, std::size_t length) -> hashing::value; } From ff574fccf9df8575911fb64898764a89073fdfcf Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 22:16:52 +0100 Subject: [PATCH 080/113] Another potential fix for Windows CI --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a1175a3..4475d8e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,6 +59,7 @@ jobs: pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-clang pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-cmake pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-ninja + pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-make mingw-get install msys-make - name: Build env: @@ -67,4 +68,4 @@ jobs: run: | ./.github/actions/build.sh - name: Test - run: cd build && make test \ No newline at end of file + run: cmake --build build --target test \ No newline at end of file From 9b7930ff9f1c88caa97a332069ed590ec96dbfe3 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sun, 25 Sep 2022 22:20:50 +0100 Subject: [PATCH 081/113] Windows CI Fix --- .github/workflows/build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4475d8e..dc7df21 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,8 +59,6 @@ jobs: pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-clang pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-cmake pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-ninja - pacman -S --noconfirm mingw-w64-${{ matrix.env.arch }}-make - mingw-get install msys-make - name: Build env: CC: ${{ matrix.env.CC }} From e7b620669864b1385c16e3cf8232e6e77b7b9986 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 26 Sep 2022 08:08:06 +0100 Subject: [PATCH 082/113] Add tests for quickdraw::size --- GraphiteTests.cmake | 19 +++ Tests/quickdraw/type/size_tests.cpp | 187 ++++++++++++++++++++++++++++ libGraphite/quickdraw/type/size.hpp | 79 +++++++++--- 3 files changed, 265 insertions(+), 20 deletions(-) create mode 100644 Tests/quickdraw/type/size_tests.cpp diff --git a/GraphiteTests.cmake b/GraphiteTests.cmake index 81dfc47..6519348 100644 --- a/GraphiteTests.cmake +++ b/GraphiteTests.cmake @@ -34,6 +34,25 @@ test_suite(Graphite point_castToDifferentType_retainsSameValue # Size + size_constructUsingEqualDimensions + size_constructUsingSeparateDimensions + size_constructUsingReader_quickdraw + size_constructUsingReader_macintosh + size_readSizeFromReader + size_encodeInToWriter_quickdraw + size_encodeInToWriter_macintosh + size_assignmentOperator_copySize + size_assignmentOperator_moveSize + size_equalsOperator_shouldBeEqual + size_equalsOperator_shouldNotBeEqual + size_notEqualsOperator_shouldNotBeEqual + size_notEqualsOperator_shouldBeEqual + size_addSize_returnsExpectedSize + size_subtractSize_returnsExpectedSize + size_multiplySize_returnsExpectedSize + size_divideSize_returnsExpectedSize + size_castToDifferentType_retainsSameValue + # Rect # Utility Functions diff --git a/Tests/quickdraw/type/size_tests.cpp b/Tests/quickdraw/type/size_tests.cpp new file mode 100644 index 0000000..a8acdb5 --- /dev/null +++ b/Tests/quickdraw/type/size_tests.cpp @@ -0,0 +1,187 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include + +using namespace graphite; + +// MARK: - Test Data + +static constexpr std::uint8_t size_test_data[] = { + 0x00, 0x80, 0x00, 0x20 +}; + +// MARK: - Construction Tests + +TEST(size_constructUsingEqualDimensions) +{ + quickdraw::size size(10); + test::equal(size.width, 10); + test::equal(size.height, 10); +} + +TEST(size_constructUsingSeparateDimensions) +{ + quickdraw::size size(5, 7); + test::equal(size.width, 5); + test::equal(size.height, 7); +} + +TEST(size_constructUsingReader_quickdraw) +{ + data::block block(size_test_data, sizeof(size_test_data), false); + data::reader reader(&block); + + quickdraw::size size(reader, quickdraw::coding_type::quickdraw); + test::equal(size.width, 32); + test::equal(size.height, 128); +} + +TEST(size_constructUsingReader_macintosh) +{ + data::block block(size_test_data, sizeof(size_test_data), false); + data::reader reader(&block); + + quickdraw::size size(reader, quickdraw::coding_type::macintosh); + test::equal(size.width, 128); + test::equal(size.height, 32); +} + +// MARK: - Static Reader + +TEST(size_readsizeFromReader) +{ + data::block block(size_test_data, sizeof(size_test_data), false); + data::reader reader(&block); + + auto size = quickdraw::size::read(reader, quickdraw::coding_type::quickdraw); + test::equal(size.width, 32); + test::equal(size.height, 128); +} + +// MARK: - Encoding + +TEST(size_encodeInToWriter_quickdraw) +{ + data::writer writer(data::byte_order::msb); + + quickdraw::size size(32, 128); + size.encode(writer, quickdraw::coding_type::quickdraw); + + test::equal(writer.size(), sizeof(size_test_data)); + test::bytes_equal(writer.data()->get(), size_test_data, sizeof(size_test_data)); +} + +TEST(size_encodeInToWriter_macintosh) +{ + data::writer writer(data::byte_order::msb); + + quickdraw::size size(128, 32); + size.encode(writer, quickdraw::coding_type::macintosh); + + test::equal(writer.size(), sizeof(size_test_data)); + test::bytes_equal(writer.data()->get(), size_test_data, sizeof(size_test_data)); +} + +// MARK: - Operators + +TEST(size_assignmentOperator_copysize) +{ + quickdraw::size size(5); + test::equal(size.width, 5); + test::equal(size.height, 5); + + quickdraw::size newsize(10); + size = newsize; + test::equal(size.width, 10); + test::equal(size.height, 10); +} + +TEST(size_assignmentOperator_movesize) +{ + quickdraw::size size(5); + test::equal(size.width, 5); + test::equal(size.height, 5); + + size = quickdraw::size(10); + test::equal(size.width, 10); + test::equal(size.height, 10); +} + +TEST(size_equalsOperator_shouldBeEqual) +{ + test::is_true(quickdraw::size(5) == quickdraw::size(5)); +} + +TEST(size_equalsOperator_shouldNotBeEqual) +{ + test::is_false(quickdraw::size(5) == quickdraw::size(7)); +} + +TEST(size_notEqualsOperator_shouldNotBeEqual) +{ + test::is_true(quickdraw::size(5) != quickdraw::size(7)); +} + +TEST(size_notEqualsOperator_shouldBeEqual) +{ + test::is_false(quickdraw::size(5) != quickdraw::size(5)); +} + +TEST(size_addsize_returnsExpectedsize) +{ + auto result = quickdraw::size(5) + quickdraw::size(3); + test::equal(result.width, 8); + test::equal(result.height, 8); +} + +TEST(size_subtractsize_returnsExpectedsize) +{ + auto result = quickdraw::size(5) - quickdraw::size(3); + test::equal(result.width, 2); + test::equal(result.height, 2); +} + +TEST(size_multiplysize_returnsExpectedsize) +{ + auto result = quickdraw::size(5) * 3; + test::equal(result.width, 15); + test::equal(result.height, 15); +} + +TEST(size_dividesize_returnsExpectedsize) +{ + auto result = quickdraw::size(9) / 3; + test::equal(result.width, 3); + test::equal(result.height, 3); +} + +// MARK: - Casting Tests + +TEST(size_castToDifferentType_retainsSameValue) +{ + quickdraw::size size(76); + auto new_size = size.cast(); + test::equal(new_size.width, 76); + test::equal(new_size.height, 76); +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/size.hpp b/libGraphite/quickdraw/type/size.hpp index 6c0718f..1af405a 100644 --- a/libGraphite/quickdraw/type/size.hpp +++ b/libGraphite/quickdraw/type/size.hpp @@ -28,26 +28,50 @@ namespace graphite::quickdraw { + /** + * Represents a size of a 2D area on a surface. + * @tparam T The type being used for the Width and Height values of a size. + * This can be any arithmetic type. + */ template::value>::type* = nullptr> struct size { public: + /** + * The width of the size. + */ T width { 0 }; + + /** + * The height of the size. + */ T height { 0 }; size() = default; + + /** + * Construct a size where the width and height dimensions are equal. + * @param v The value to set both of the width and height dimensions to. + */ explicit size(T v) : width(v), height(v) {} + + /** + * Construct a size. + * @param width The value of the width dimension. + * @param height The value of the height dimension. + */ size(T width, T height) : width(width), height(height) {} + size(const size&) = default; size(size&&) noexcept = default; - explicit size(data::reader& reader) - { - height = read_component(reader); - width = read_component(reader); - } - - size(data::reader& reader, coding_type type) + /** + * Construct a size, reading the width and height dimensions from the specified data reader. + * Defaults to using the QuickDraw ordering for dimensions (height and then width) + * @param reader The data reader to read the width and height dimensions from. + * @param type The coding type (dimension ordering) to use when reading the dimensions. + */ + explicit size(data::reader& reader, coding_type type = coding_type::quickdraw) { switch (type) { case coding_type::macintosh: { @@ -63,14 +87,24 @@ namespace graphite::quickdraw } } - static auto read(data::reader& reader, coding_type type) -> size { return { reader, type }; } - - auto encode(data::writer& writer) -> void + /** + * Construct a size, reading the width and height dimensions from the specified data reader. + * @param reader The data reader to read the width and height dimensions from. + * @param type The coding type (dimension ordering) to use when reading the dimensions. + * @return A size with the width and height dimensions read from the reader. + */ + static auto read(data::reader& reader, coding_type type) -> size { - encode(writer, coding_type::quickdraw); + return size(reader, type); } - auto encode(data::writer& writer, coding_type type) -> void + /** + * Write the width and height coordinates of the size into the provided data writer, using the specified coding + * type. + * @param writer The data writer to write the width and height dimensions to. + * @param type The coding type (dimension ordering) to use when writing the dimensions. + */ + auto encode(data::writer& writer, coding_type type = coding_type::quickdraw) -> void { switch (type) { case coding_type::macintosh: { @@ -92,17 +126,22 @@ namespace graphite::quickdraw auto operator==(const size& s) const -> bool { return width == s.width && height == s.height; } auto operator!=(const size& s) const -> bool { return width != s.width && height != s.height; } - auto operator+(const size& s) const -> size { return { width + s.width, height + s.height }; } - auto operator-(const size& s) const -> size { return { width - s.width, height - s.height }; } + auto operator+(const size& s) const -> size { return size(width + s.width, height + s.height); } + auto operator-(const size& s) const -> size { return size(width - s.width, height - s.height); } - template::value>> - auto operator*(U v) const -> size { return { width * static_cast(v), height * static_cast(v) }; } + template::value>::type* = nullptr> + auto operator*(U v) const -> size { return size(width * static_cast(v), height * static_cast(v)); } - template::value>> - auto operator/(U v) const -> size { return { width / static_cast(v), height / static_cast(v) }; } + template::value>::type* = nullptr> + auto operator/(U v) const -> size { return size(width / static_cast(v), height / static_cast(v)); } - template::value>> - auto cast() const -> size { return { static_cast(width), static_cast(height) }; } + /** + * Cast the typename of the size to a different compatible type. + * @tparam U The new arithmetic type in which to cast to. + * @return A size using the new arithmetic type. + */ + template::value>::type* = nullptr> + auto cast() const -> size { return size(static_cast(width), static_cast(height)); } private: static auto read_component(data::reader& reader) -> T { return reader.read_integer(); } From 295dc693302868390028043a84cdf7253e31950a Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 26 Sep 2022 11:08:52 +0100 Subject: [PATCH 083/113] Introduce quickdraw::rect tests, and fix issue in quickdraw::rect. --- GraphiteTests.cmake | 19 +++ Tests/quickdraw/type/rect_tests.cpp | 224 ++++++++++++++++++++++++++++ libGraphite/quickdraw/type/rect.hpp | 85 +++++++++-- 3 files changed, 312 insertions(+), 16 deletions(-) create mode 100644 Tests/quickdraw/type/rect_tests.cpp diff --git a/GraphiteTests.cmake b/GraphiteTests.cmake index 6519348..2c55ecb 100644 --- a/GraphiteTests.cmake +++ b/GraphiteTests.cmake @@ -54,6 +54,25 @@ test_suite(Graphite size_castToDifferentType_retainsSameValue # Rect + rect_constructUsingEqualValues + rect_constructUsingSeparateValues + rect_constructUsingPointAndSize + rect_constructUsingReader_quickdraw + rect_constructUsingReader_macintosh + rect_readRectFromReader + rect_encodeInToWriter_quickdraw + rect_encodeInToWriter_macintosh + rect_assignmentOperator_copyRect + rect_assignmentOperator_moveRect + rect_equalsOperator_shouldBeEqual + rect_equalsOperator_shouldNotBeEqual + rect_notEqualsOperator_shouldNotBeEqual + rect_notEqualsOperator_shouldBeEqual + rect_addRect_returnsExpectedRect + rect_subtractRect_returnsExpectedRect + rect_multiplyRect_returnsExpectedRect + rect_divideRect_returnsExpectedRect + rect_castToDifferentType_retainsSameValue # Utility Functions # XXHash Hashing diff --git a/Tests/quickdraw/type/rect_tests.cpp b/Tests/quickdraw/type/rect_tests.cpp new file mode 100644 index 0000000..cfad368 --- /dev/null +++ b/Tests/quickdraw/type/rect_tests.cpp @@ -0,0 +1,224 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include + +using namespace graphite; + +// MARK: - Test Data + +static constexpr std::uint8_t rect_test_data[] = { + 0x00, 0x20, 0x00, 0x80, 0x00, 0x30, 0x00, 0xC0 +}; + +// MARK: - Construction Tests + +TEST(rect_constructUsingEqualValues) +{ + quickdraw::rect rect(5); + test::equal(rect.origin.x, 5); + test::equal(rect.origin.y, 5); + test::equal(rect.size.width, 5); + test::equal(rect.size.height, 5); +} + +TEST(rect_constructUsingSeparateValues) +{ + quickdraw::rect rect(1, 2, 3, 4); + test::equal(rect.origin.x, 1); + test::equal(rect.origin.y, 2); + test::equal(rect.size.width, 3); + test::equal(rect.size.height, 4); +} + +TEST(rect_constructUsingPointAndSize) +{ + quickdraw::rect rect(quickdraw::point(1, 2), quickdraw::size(3, 4)); + test::equal(rect.origin.x, 1); + test::equal(rect.origin.y, 2); + test::equal(rect.size.width, 3); + test::equal(rect.size.height, 4); +} + +TEST(rect_constructUsingReader_quickdraw) +{ + data::block block(rect_test_data, sizeof(rect_test_data), false); + data::reader reader(&block); + + quickdraw::rect rect(reader, quickdraw::coding_type::quickdraw); + test::equal(rect.origin.x, 128); + test::equal(rect.origin.y, 32); + test::equal(rect.size.width, 64); + test::equal(rect.size.height, 16); +} + +TEST(rect_constructUsingReader_macintosh) +{ + data::block block(rect_test_data, sizeof(rect_test_data), false); + data::reader reader(&block); + + quickdraw::rect rect(reader, quickdraw::coding_type::macintosh); + test::equal(rect.origin.x, 32); + test::equal(rect.origin.y, 128); + test::equal(rect.size.width, 16); + test::equal(rect.size.height, 64); +} + +// MARK: - Static Reader + +TEST(rect_readRectFromReader) +{ + data::block block(rect_test_data, sizeof(rect_test_data), false); + data::reader reader(&block); + + auto rect = quickdraw::rect::read(reader, quickdraw::coding_type::quickdraw); + test::equal(rect.origin.x, 128); + test::equal(rect.origin.y, 32); + test::equal(rect.size.width, 64); + test::equal(rect.size.height, 16); +} + +// MARK: - Encoding + +TEST(rect_encodeInToWriter_quickdraw) +{ + data::writer writer(data::byte_order::msb); + + quickdraw::rect rect(128, 32, 64, 16); + rect.encode(writer, quickdraw::coding_type::quickdraw); + + test::equal(writer.size(), sizeof(rect_test_data)); + test::bytes_equal(writer.data()->get(), rect_test_data, sizeof(rect_test_data)); +} + +TEST(rect_encodeInToWriter_macintosh) +{ + data::writer writer(data::byte_order::msb); + + quickdraw::rect rect(32, 128, 16, 64); + rect.encode(writer, quickdraw::coding_type::macintosh); + + test::equal(writer.size(), sizeof(rect_test_data)); + test::bytes_equal(writer.data()->get(), rect_test_data, sizeof(rect_test_data)); +} + +// MARK: - Operators + +TEST(rect_assignmentOperator_copyrect) +{ + quickdraw::rect rect(5); + test::equal(rect.origin.x, 5); + test::equal(rect.origin.y, 5); + test::equal(rect.size.width, 5); + test::equal(rect.size.height, 5); + + quickdraw::rect new_rect(10); + rect = new_rect; + test::equal(rect.origin.x, 10); + test::equal(rect.origin.y, 10); + test::equal(rect.size.width, 10); + test::equal(rect.size.height, 10); +} + +TEST(rect_assignmentOperator_moverect) +{ + quickdraw::rect rect(5); + test::equal(rect.origin.x, 5); + test::equal(rect.origin.y, 5); + test::equal(rect.size.width, 5); + test::equal(rect.size.height, 5); + + rect = quickdraw::rect(10); + test::equal(rect.origin.x, 10); + test::equal(rect.origin.y, 10); + test::equal(rect.size.width, 10); + test::equal(rect.size.height, 10); +} + +TEST(rect_equalsOperator_shouldBeEqual) +{ + test::is_true(quickdraw::rect(5) == quickdraw::rect(5)); +} + +TEST(rect_equalsOperator_shouldNotBeEqual) +{ + test::is_false(quickdraw::rect(5) == quickdraw::rect(7)); +} + +TEST(rect_notEqualsOperator_shouldNotBeEqual) +{ + test::is_true(quickdraw::rect(5) != quickdraw::rect(7)); +} + +TEST(rect_notEqualsOperator_shouldBeEqual) +{ + test::is_false(quickdraw::rect(5) != quickdraw::rect(5)); +} + +TEST(rect_addRect_returnsExpectedrect) +{ + auto result = quickdraw::rect(5) + quickdraw::rect(3); + test::equal(result.origin.x, 8); + test::equal(result.origin.y, 8); + test::equal(result.size.width, 8); + test::equal(result.size.height, 8); +} + +TEST(rect_subtractRect_returnsExpectedRect) +{ + auto result = quickdraw::rect(5) - quickdraw::rect(3); + test::equal(result.origin.x, 2); + test::equal(result.origin.y, 2); + test::equal(result.size.width, 2); + test::equal(result.size.height, 2); +} + +TEST(rect_multiplyRect_returnsExpectedRect) +{ + auto result = quickdraw::rect(5) * 3; + test::equal(result.origin.x, 15); + test::equal(result.origin.y, 15); + test::equal(result.size.width, 15); + test::equal(result.size.height, 15); +} + +TEST(rect_divideRect_returnsExpectedRect) +{ + auto result = quickdraw::rect(9) / 3; + test::equal(result.origin.x, 3); + test::equal(result.origin.y, 3); + test::equal(result.size.width, 3); + test::equal(result.size.height, 3); +} + +// MARK: - Casting Tests + +TEST(rect_castToDifferentType_retainsSameValue) +{ + quickdraw::rect rect(76); + auto new_rect = rect.cast(); + test::equal(new_rect.origin.x, 76); + test::equal(new_rect.origin.y, 76); + test::equal(new_rect.size.width, 76); + test::equal(new_rect.size.height, 76); +} \ No newline at end of file diff --git a/libGraphite/quickdraw/type/rect.hpp b/libGraphite/quickdraw/type/rect.hpp index 4e1402a..5b142ff 100644 --- a/libGraphite/quickdraw/type/rect.hpp +++ b/libGraphite/quickdraw/type/rect.hpp @@ -30,38 +30,86 @@ namespace graphite::quickdraw { + /** + * Represents a rectangle or frame within a surface. + * @tparam T The type being used for the origin and size values of the rect. + * This can be any arithmetic type. + */ template::value>::type* = nullptr> struct rect { public: + /** + * The origin of the rect. + */ point origin { 0 }; + + /** + * The size of the rect + */ size size { 0 }; rect() = default; + + /** + * Construct a rect where the X and Y coordinates of the origin, as well as the width and height dimensions + * of the size, are all equal. + * @param v The value to set both of the origin and size components to. + */ explicit rect(T v) : origin(v), size(v) {} + + /** + * Construct a rect. + * @param x The value of the origin X coordinate. + * @param y The value of the origin Y coordinate. + * @param width The value of the width dimension of the size. + * @param height The value of the height dimension of the size. + */ rect(T x, T y, T width, T height) : origin(x, y), size(width, height) {} + + /** + * Construct a rect. + * @param origin The origin of the rect. + * @param size The size of the rect. + */ rect(struct point origin, struct quickdraw::size size) : origin(origin), size(size) {} + rect(const rect&) = default; rect(rect&&) noexcept = default; - explicit rect(data::reader& reader) : origin(reader), size(reader) {} - rect(data::reader& reader, coding_type type) : origin(reader, type), size(reader, type) + /** + * Construct a point, reading the origin and the size from the specified data reader. + * Defaults to using the QuickDraw ordering for both the origin and size. + * @param reader The data reader to read the origin and size from. + * @param type The coding type (ordering) to use when reading the origin and size. + */ + explicit rect(data::reader& reader, coding_type type = coding_type::quickdraw) + : origin(reader, type), size(reader, type) { size.width -= origin.x; size.height -= origin.y; } - static auto read(data::reader& reader, coding_type type) -> rect { return { reader, type }; } - - auto encode(data::writer& writer) -> void + /** + * Construct a rect, reading the origin and size from the specified data reader. + * @param reader The data reader to read the origin and size from. + * @param type The coding type (ordering) to use when reading the origin and size. + * @return A size with the origin and size read from the reader. + */ + static auto read(data::reader& reader, coding_type type) -> rect { - encode(writer, coding_type::quickdraw); + return rect(reader, type); } - auto encode(data::writer& writer, coding_type type) -> void + /** + * Write the origin and size of the rect into the provided data writer, using the specified coding type. + * @param writer The data writer to write the origin and size to. + * @param type The coding type (ordering) to use when writing the origin and size. + */ + auto encode(data::writer& writer, coding_type type = coding_type::quickdraw) -> void { origin.encode(writer, type); - size.encode(writer, type); + (size + quickdraw::size(origin.x, origin.y)).encode(writer, type); } auto operator=(const rect& r) -> rect& { origin = r.origin; size = r.size; return *this; } @@ -70,17 +118,22 @@ namespace graphite::quickdraw auto operator==(const rect& r) const -> bool { return origin == r.origin && size == r.size; } auto operator!=(const rect& r) const -> bool { return origin != r.origin && size != r.size; } - auto operator+(const rect& r) const -> rect { return { origin + r.origin, size + r.size }; } - auto operator-(const rect& r) const -> rect { return { origin - r.origin, size - r.size }; } + auto operator+(const rect& r) const -> rect { return rect(origin + r.origin, size + r.size); } + auto operator-(const rect& r) const -> rect { return rect(origin - r.origin, size - r.size); } - template::value>> - auto operator*(U v) const -> rect { return { origin * static_cast(v), size * static_cast(v) }; } + template::value>::type* = nullptr> + auto operator*(U v) const -> rect { return rect(origin * static_cast(v), size * static_cast(v)); } - template::value>> - auto operator/(U v) const -> rect { return { origin / static_cast(v), size / static_cast(v) }; } + template::value>::type* = nullptr> + auto operator/(U v) const -> rect { return rect(origin / static_cast(v), size / static_cast(v)); } - template::value>> - auto cast() const -> rect { return { origin.template cast(), size.template cast() }; } + /** + * Cast the typename of the rect to a different compatible type. + * @tparam U The new arithmetic type in which to cast to. + * @return A rect using the new arithmetic type. + */ + template::value>::type* = nullptr> + auto cast() const -> rect { return rect(origin.template cast(), size.template cast()); } }; } \ No newline at end of file From 24691b5b7ea44d997be68181cb47a7b2938f0b7b Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 26 Sep 2022 12:45:41 +0100 Subject: [PATCH 084/113] Update README --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05328d4..b3128c9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,19 @@ +[![Graphite CI](https://github.com/TheDiamondProject/Graphite/actions/workflows/build.yml/badge.svg)](https://github.com/TheDiamondProject/Graphite/actions/workflows/build.yml) [![Version](https://img.shields.io/badge/version-v1.0-blue.svg)](#) [![Version](https://img.shields.io/badge/license-MIT-blue.svg)](#) + # Graphite The Graphite Library is part of _The Diamond Project_ and aims to provide modern, cross platform implementations of various features and aspects of functionality from the Classic Macintosh OS and Carbon Frameworks. +## Using libGraphite +TBC + +## libTesting +The Graphite library includes a secondary library designed for providing the required functionality for basic unit testing. You can find documentation for this in the `libTesting` directory. Graphite uses this library to test the core functionality and performance of main `libGraphite` library, along with CMake and GitHub Actions to ensure that no regressions occur and that all added functionality is actually correct and verified. + +It is provided in such a way that you can use it in your own projects should you wish to. + +## Contributing +TBC + ## License -Graphite is available under the MIT license. \ No newline at end of file +Graphite is available under the MIT license, which can be [found here](). \ No newline at end of file From 4057edcfe90c741bb3e091359d1c85a54f169b04 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 26 Sep 2022 12:59:56 +0100 Subject: [PATCH 085/113] Fix libTesting when project is included as a submodule. --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ab09cf7..48ad568 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,9 @@ file(GLOB_RECURSE graphite_sources add_library(Graphite ${graphite_sources}) # Unit Tests -include(libTesting/testing.cmake) -build_testing_library() -add_testing_target(Graphite ${CMAKE_SOURCE_DIR}/Tests) -include("GraphiteTests.cmake") \ No newline at end of file +if (EXISTS libTesting/testing.cmake) + include(libTesting/testing.cmake) + build_testing_library() + add_testing_target(Graphite ${CMAKE_SOURCE_DIR}/Tests) + include("GraphiteTests.cmake") +endif() \ No newline at end of file From 934d9a5127097e9f123493444aa49568a3d55545 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 26 Sep 2022 22:31:00 +0100 Subject: [PATCH 086/113] Update to testing.cmake --- libTesting/testing.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libTesting/testing.cmake b/libTesting/testing.cmake index abe7346..c58832a 100644 --- a/libTesting/testing.cmake +++ b/libTesting/testing.cmake @@ -1,15 +1,19 @@ enable_testing() +set(LIB_TESTING_PATH ${CMAKE_CURRENT_LIST_DIR}) + if(NOT DEFINED CMAKE_OUTPUT_PATH) set(CMAKE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) endif() # libTesting function(build_testing_library) + message(${LIB_TESTING_PATH}) file(GLOB_RECURSE testing_sources - ${CMAKE_SOURCE_DIR}/libTesting/*.cpp + ${LIB_TESTING_PATH}/../libTesting/*.cpp ) add_library(Testing ${testing_sources}) + target_include_directories(Testing PUBLIC ${LIB_TESTING_PATH}/..) endfunction() function(add_testing_target name dir) From db9f826b9711b36a5fb7ef2be824d1f0b10d8d61 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 29 Sep 2022 08:25:12 +0100 Subject: [PATCH 087/113] Add test conditions to libTesting for testing exceptions. --- libTesting/testing.hpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/libTesting/testing.hpp b/libTesting/testing.hpp index 74df206..00c4840 100644 --- a/libTesting/testing.hpp +++ b/libTesting/testing.hpp @@ -147,4 +147,35 @@ namespace test } } } + + template::value>::type* = nullptr> + static auto does_throw(const std::functionvoid>& fn, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + bool should_fail = true; + + try { + fn(); + } + catch (const T& e) { + should_fail = false; + } + catch (...) { + // Still fail but warn? + fail("Unexpected exception was reached.", file, line); + } + + if (should_fail) { + fail(reason, file, line); + } + } + + static auto does_not_throw(const std::functionvoid>& fn, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + try { + fn(); + } + catch (...) { + fail(reason, file, line); + } + } } \ No newline at end of file From aaa0ab3b9aeaf371fdb199921e41af95f92beaf9 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 29 Sep 2022 22:33:34 +0100 Subject: [PATCH 088/113] Add capability for measuring performance in tests. --- libTesting/testing.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libTesting/testing.hpp b/libTesting/testing.hpp index 00c4840..d60bb25 100644 --- a/libTesting/testing.hpp +++ b/libTesting/testing.hpp @@ -22,6 +22,8 @@ #include #include +#include +#include typedef void(*test_function_t)(); @@ -178,4 +180,22 @@ namespace test fail(reason, file, line); } } + + static auto measure(const std::functionvoid>& fn, const std::string& name = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + auto start = std::chrono::high_resolution_clock::now(); + fn(); + auto elapsed = std::chrono::high_resolution_clock::now() - start; + + // Report the time + std::int64_t microseconds = std::chrono::duration_cast(elapsed).count(); + std::string report; + + if (!name.empty()) { + report += name + ": "; + } + + report += std::to_string(microseconds) + "µs"; + std::cout << report << std::endl; + } } \ No newline at end of file From 145ab119cefa382422334371e38a53b419a25103 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 29 Sep 2022 22:33:45 +0100 Subject: [PATCH 089/113] Enable reporting in tests. --- libTesting/testing.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libTesting/testing.cmake b/libTesting/testing.cmake index c58832a..3d8a960 100644 --- a/libTesting/testing.cmake +++ b/libTesting/testing.cmake @@ -24,7 +24,7 @@ function(add_testing_target name dir) endfunction() function(test target name) - add_test(NAME ${name} COMMAND ${CMAKE_OUTPUT_PATH}/${target}_TestRunner -s ${name}) + add_test(NAME ${name} COMMAND ${CMAKE_OUTPUT_PATH}/${target}_TestRunner ${name}) endfunction() function(test_suite target list) From ee6c186db496258dfe3b9de8c98fb7839455e031 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 30 Sep 2022 09:19:02 +0100 Subject: [PATCH 090/113] Add XXH32 hashing algorithm to Graphite. Update libTesting --- libGraphite/util/hashing.cpp | 93 ++++++++++++++++++++++++++++++++---- libGraphite/util/hashing.hpp | 20 ++++++-- libTesting/testing.cmake | 8 ++-- 3 files changed, 105 insertions(+), 16 deletions(-) diff --git a/libGraphite/util/hashing.cpp b/libGraphite/util/hashing.cpp index 68a76cd..8f07cc2 100644 --- a/libGraphite/util/hashing.cpp +++ b/libGraphite/util/hashing.cpp @@ -23,15 +23,22 @@ // MARK: - Constants -struct uint64_unaligned { uint64_t v; } __attribute__((packed)); -struct uint32_unaligned { uint32_t v; } __attribute__((packed)); - -static uint64_t xxhash64_seed = 0; -static uint64_t xxhash64_p1 = 11400714785074694791ULL; -static uint64_t xxhash64_p2 = 14029467366897019727ULL; -static uint64_t xxhash64_p3 = 1609587929392839161ULL; -static uint64_t xxhash64_p4 = 9650029242287828579ULL; -static uint64_t xxhash64_p5 = 2870177450012600261ULL; +struct uint64_unaligned { std::uint64_t v; } __attribute__((packed)); +struct uint32_unaligned { std::uint32_t v; } __attribute__((packed)); + +static std::uint64_t xxhash64_seed = 0; +static std::uint64_t xxhash64_p1 = 11400714785074694791ULL; +static std::uint64_t xxhash64_p2 = 14029467366897019727ULL; +static std::uint64_t xxhash64_p3 = 1609587929392839161ULL; +static std::uint64_t xxhash64_p4 = 9650029242287828579ULL; +static std::uint64_t xxhash64_p5 = 2870177450012600261ULL; + +static std::uint32_t xxhash32_seed = 0; +static std::uint32_t xxhash32_p1 = 2654435761U; +static std::uint32_t xxhash32_p2 = 2246822519U; +static std::uint32_t xxhash32_p3 = 3266489917U; +static std::uint32_t xxhash32_p4 = 668265263U; +static std::uint32_t xxhash32_p5 = 374761393U; #define ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) #define ROTL64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) @@ -40,7 +47,7 @@ static uint64_t xxhash64_p5 = 2870177450012600261ULL; // MARK: - XXHash64 -auto graphite::hashing::xxh64(const void *src, std::size_t length) -> hashing::value +auto graphite::hashing::xxh64(const void *src, std::size_t length) -> hashing::value64 { uint64_t h64 { 0 }; auto ptr = const_cast(reinterpret_cast(src)); @@ -137,4 +144,70 @@ auto graphite::hashing::xxh64(const void *src, std::size_t length) -> hashing::v h64 ^= h64 >> 32; return h64; +} + + +auto graphite::hashing::xxh32(const void *src, std::size_t length) -> value32 +{ + uint32_t h32 { 0 }; + auto ptr = const_cast(reinterpret_cast(src)); + auto end = ptr + length; + + if (length >= 16) { + uint8_t *limit = end - 16; + uint32_t v2 = xxhash32_seed + xxhash32_p2; + uint32_t v1 = v2 + xxhash32_p1; + uint32_t v3 = xxhash32_seed; + uint32_t v4 = xxhash32_seed - xxhash32_p1; + + do { + v1 += UNALGINED32(ptr) * xxhash32_p2; + ptr += 4; + v1 = ROTL32(v1, 13); + v1 *= xxhash32_p1; + + v2 += UNALGINED32(ptr) * xxhash32_p2; + ptr += 4; + v2 = ROTL32(v2, 13); + v2 *= xxhash32_p1; + + v3 += UNALGINED32(ptr) * xxhash32_p2; + ptr += 4; + v3 = ROTL32(v3, 13); + v3 *= xxhash32_p1; + + v4 += UNALGINED32(ptr) * xxhash32_p2; + ptr += 4; + v4 = ROTL32(v4, 13); + v4 *= xxhash32_p1; + } + while (ptr <= limit); + + h32 = ROTL32(v1, 1) + ROTL32(v2, 7) + ROTL32(v3, 12) + ROTL32(v4, 18); + } + else { + h32 = xxhash32_seed + xxhash32_p5; + } + + h32 += length; + + while (ptr+4 <= end) { + h32 += UNALGINED32(ptr) * xxhash32_p3; + h32 = ROTL32(h32, 17) * xxhash32_p4; + ptr += 4; + } + + while (ptr < end) { + h32 += *ptr * xxhash32_p5; + h32 = ROTL32(h32, 11) * xxhash32_p1; + ++ptr; + } + + h32 ^= h32 >> 15; + h32 *= xxhash32_p2; + h32 ^= h32 >> 13; + h32 *= xxhash32_p3; + h32 ^= h32 >> 16; + + return h32; } \ No newline at end of file diff --git a/libGraphite/util/hashing.hpp b/libGraphite/util/hashing.hpp index a183888..7378991 100644 --- a/libGraphite/util/hashing.hpp +++ b/libGraphite/util/hashing.hpp @@ -25,10 +25,16 @@ namespace graphite::hashing { /** - * A hash value. + * A 64-bit hash value. * This type definition is intended to help provide semantic context. */ - typedef std::uint64_t value; + typedef std::uint64_t value64; + + /** + * A 32-bit hash value. + * This type definition is intended to help provide semantic context. + */ + typedef std::uint32_t value32; /** * Produce a hash value using the 64-bit variant of the XXHash algorithm, using the specified data. @@ -36,6 +42,14 @@ namespace graphite::hashing * @param length The length of the data being supplied. * @return A hash value. */ - auto xxh64(const void *ptr, std::size_t length) -> hashing::value; + auto xxh64(const void *ptr, std::size_t length) -> hashing::value64; + + /** + * Produce a hash value using the 32-bit variant of the XXHash algorithm, using the specified data. + * @param ptr A pointer to the byte sequence to produce a hash from. + * @param length The length of the data being supplied. + * @return A hash value. + */ + auto xxh32(const void *ptr, std::size_t length) -> hashing::value32; } diff --git a/libTesting/testing.cmake b/libTesting/testing.cmake index 3d8a960..68b2124 100644 --- a/libTesting/testing.cmake +++ b/libTesting/testing.cmake @@ -17,14 +17,16 @@ function(build_testing_library) endfunction() function(add_testing_target name dir) - file(GLOB_RECURSE test_sources ${dir}/*.cpp) - add_executable(${name}_TestRunner ${test_sources}) + message("Adding Test Target: ${name}") + file(GLOB_RECURSE ${name}_test_sources ${dir}/*.cpp) + add_executable(${name}_TestRunner ${${name}_test_sources}) target_link_libraries(${name}_TestRunner ${name} Testing) target_include_directories(${name}_TestRunner PUBLIC ${dir}) endfunction() function(test target name) - add_test(NAME ${name} COMMAND ${CMAKE_OUTPUT_PATH}/${target}_TestRunner ${name}) + message(" - test: ${name}") + add_test(NAME ${target}_${name} COMMAND ${CMAKE_OUTPUT_PATH}/${target}_TestRunner ${name}) endfunction() function(test_suite target list) From 45c6ef43f243acbb205a85b66a2cfc9f499ff439 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 30 Sep 2022 20:10:49 +0100 Subject: [PATCH 091/113] Allow the ResourceManager to be purged/torn down. --- libGraphite/rsrc/manager.cpp | 10 ++++++++++ libGraphite/rsrc/manager.hpp | 2 ++ 2 files changed, 12 insertions(+) diff --git a/libGraphite/rsrc/manager.cpp b/libGraphite/rsrc/manager.cpp index d1fe46d..e4878bf 100644 --- a/libGraphite/rsrc/manager.cpp +++ b/libGraphite/rsrc/manager.cpp @@ -163,4 +163,14 @@ auto graphite::rsrc::manager::find(const std::string &type_code, const std::stri return false; } })); +} + +// MARK: - Tear Down + +auto graphite::rsrc::manager::tear_down() -> void +{ + for (const auto& file : m_files) { + delete file.second; + } + m_files = {}; } \ No newline at end of file diff --git a/libGraphite/rsrc/manager.hpp b/libGraphite/rsrc/manager.hpp index 1bc1ab0..cbc38b5 100644 --- a/libGraphite/rsrc/manager.hpp +++ b/libGraphite/rsrc/manager.hpp @@ -41,6 +41,8 @@ namespace graphite::rsrc static auto shared_manager() -> manager&; + auto tear_down() -> void; + auto import_file(class file *file) -> class file *; auto import_file(const std::string& path) -> class file *; From fff593e3735827ec70f8fd58998d305de0faf427 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 25 Nov 2022 09:24:35 +0000 Subject: [PATCH 092/113] Add more assertions to libTesting --- libTesting/testing.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libTesting/testing.hpp b/libTesting/testing.hpp index d60bb25..b8d3abc 100644 --- a/libTesting/testing.hpp +++ b/libTesting/testing.hpp @@ -60,6 +60,22 @@ namespace test */ auto fail(const std::string &reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void; + template::value>::type* = nullptr> + static auto is_null(T ptr, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + if (ptr != nullptr) { + fail(reason, file, line); + } + } + + template::value>::type* = nullptr> + static auto not_null(T ptr, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + if (ptr == nullptr) { + fail(reason, file, line); + } + } + template::value>::type* = nullptr> static auto equal(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { From b5949c874afd8c3e9fec68feea14ae5fa4fe7c07 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 25 Nov 2022 11:29:56 +0000 Subject: [PATCH 093/113] Add functional include --- libTesting/testing.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libTesting/testing.hpp b/libTesting/testing.hpp index b8d3abc..a8e06a7 100644 --- a/libTesting/testing.hpp +++ b/libTesting/testing.hpp @@ -24,6 +24,7 @@ #include #include #include +#include typedef void(*test_function_t)(); From aa45cd294e0f97f3fb4829526740405ece4edc49 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 27 Apr 2023 19:13:13 +0100 Subject: [PATCH 094/113] General improvements --- CMakeLists.txt | 20 +- libTesting/testing.cmake | 37 -- libs/libGraphite/CMakeLists.txt | 38 ++ .../libGraphite}/compression/packbits.hpp | 5 +- .../libGraphite}/data/data.cpp | 76 ++-- .../libGraphite}/data/data.hpp | 29 +- .../libGraphite}/data/encoding.hpp | 0 .../libGraphite}/data/endianess.hpp | 0 .../data/internals/specialised_reader.hpp | 0 .../data/internals/swap_reader.hpp | 0 .../libGraphite}/data/reader.cpp | 0 .../libGraphite}/data/reader.hpp | 2 +- .../libGraphite}/data/simd.hpp | 0 .../libGraphite}/data/writer.cpp | 5 +- .../libGraphite}/data/writer.hpp | 5 +- .../encoding/macroman/macroman.cpp | 0 .../encoding/macroman/macroman.hpp | 0 .../libGraphite}/font/fond.cpp | 0 .../libGraphite}/font/fond.hpp | 0 .../libGraphite}/font/manager.cpp | 0 .../libGraphite}/font/manager.hpp | 0 .../libGraphite}/font/nfnt.cpp | 0 .../libGraphite}/font/nfnt.hpp | 0 .../libGraphite}/font/sfnt.cpp | 0 .../libGraphite}/font/sfnt.hpp | 0 {libGraphite => libs/libGraphite}/hints.hpp | 0 libs/libGraphite/memory/alignment.hpp | 43 ++ .../libGraphite}/quickdraw/format/cicn.cpp | 0 .../libGraphite}/quickdraw/format/cicn.hpp | 0 .../libGraphite}/quickdraw/format/clut.cpp | 0 .../libGraphite}/quickdraw/format/clut.hpp | 0 .../libGraphite}/quickdraw/format/pict.cpp | 19 +- .../libGraphite}/quickdraw/format/pict.hpp | 0 .../libGraphite}/quickdraw/format/ppat.cpp | 0 .../libGraphite}/quickdraw/format/ppat.hpp | 0 .../quickdraw/support/drawing/depth_2_bpp.cpp | 0 .../quickdraw/support/drawing/depth_2_bpp.hpp | 0 .../quickdraw/support/drawing/depth_4bpp.cpp | 0 .../quickdraw/support/drawing/depth_4bpp.hpp | 0 .../quickdraw/support/drawing/monochrome.cpp | 1 - .../quickdraw/support/drawing/monochrome.hpp | 0 .../quickdraw/support/drawing/true_color.cpp | 0 .../quickdraw/support/drawing/true_color.hpp | 0 .../libGraphite}/quickdraw/support/pixmap.cpp | 11 +- .../libGraphite}/quickdraw/support/pixmap.hpp | 2 +- .../quickdraw/support/surface.cpp | 0 .../quickdraw/support/surface.hpp | 0 .../quickdraw/type/coding_type.hpp | 0 .../libGraphite}/quickdraw/type/color.cpp | 0 .../libGraphite}/quickdraw/type/color.hpp | 1 + .../quickdraw/type/pixel_format.hpp | 0 .../libGraphite}/quickdraw/type/point.hpp | 19 +- .../libGraphite}/quickdraw/type/rect.hpp | 0 .../libGraphite}/quickdraw/type/size.hpp | 0 .../libGraphite}/quicktime/animation.cpp | 0 .../libGraphite}/quicktime/animation.hpp | 0 .../quicktime/image_description.cpp | 0 .../quicktime/image_description.hpp | 0 .../libGraphite}/quicktime/planar.cpp | 0 .../libGraphite}/quicktime/planar.hpp | 0 .../libGraphite}/quicktime/raw.cpp | 0 .../libGraphite}/quicktime/raw.hpp | 0 .../libGraphite}/rsrc/attribute.cpp | 0 .../libGraphite}/rsrc/attribute.hpp | 0 .../libGraphite}/rsrc/classic/classic.hpp | 0 .../libGraphite}/rsrc/classic/parser.cpp | 0 .../libGraphite}/rsrc/classic/parser.hpp | 0 .../libGraphite}/rsrc/classic/writer.cpp | 0 .../libGraphite}/rsrc/classic/writer.hpp | 0 .../libGraphite}/rsrc/extended/extended.hpp | 0 .../libGraphite}/rsrc/extended/parser.cpp | 0 .../libGraphite}/rsrc/extended/parser.hpp | 0 .../libGraphite}/rsrc/extended/writer.cpp | 0 .../libGraphite}/rsrc/extended/writer.hpp | 0 .../libGraphite}/rsrc/file.cpp | 0 .../libGraphite}/rsrc/file.hpp | 0 .../libGraphite}/rsrc/manager.cpp | 0 .../libGraphite}/rsrc/manager.hpp | 0 .../libGraphite}/rsrc/resource.cpp | 0 .../libGraphite}/rsrc/resource.hpp | 0 .../libGraphite}/rsrc/result.cpp | 0 .../libGraphite}/rsrc/result.hpp | 0 .../libGraphite}/rsrc/rez/parser.cpp | 0 .../libGraphite}/rsrc/rez/parser.hpp | 0 .../libGraphite}/rsrc/rez/rez.hpp | 0 .../libGraphite}/rsrc/rez/writer.cpp | 0 .../libGraphite}/rsrc/rez/writer.hpp | 0 .../libGraphite}/rsrc/type.cpp | 0 .../libGraphite}/rsrc/type.hpp | 0 .../libGraphite}/sound/codec/descriptor.hpp | 0 .../libGraphite}/sound/codec/ima4.cpp | 0 .../libGraphite}/sound/codec/ima4.hpp | 0 .../libGraphite}/sound/sound.cpp | 20 + .../libGraphite}/sound/sound.hpp | 4 + .../libGraphite}/spriteworld/rleD.cpp | 0 .../libGraphite}/spriteworld/rleD.hpp | 0 .../libGraphite}/spriteworld/rleX.cpp | 0 .../libGraphite}/spriteworld/rleX.hpp | 0 .../libGraphite}/sys/types.hpp | 0 .../libGraphite}/toolbox/dialog.cpp | 0 .../libGraphite}/toolbox/dialog.hpp | 0 .../libGraphite}/toolbox/dialog_item_list.cpp | 0 .../libGraphite}/toolbox/dialog_item_list.hpp | 0 .../libGraphite}/toolbox/string.cpp | 0 .../libGraphite}/toolbox/string.hpp | 0 .../libGraphite}/toolbox/string_list.cpp | 0 .../libGraphite}/toolbox/string_list.hpp | 0 .../libGraphite}/util/concepts.hpp | 0 .../libGraphite}/util/hashing.cpp | 0 .../libGraphite}/util/hashing.hpp | 0 libs/libSIMD/CMakeLists.txt | 37 ++ libs/libSIMD/SIMD.hpp | 75 ++++ libs/libSIMD/arm/arm_neon.hpp | 210 +++++++++ libs/libSIMD/arm/float64.cpp | 252 +++++++++++ libs/libSIMD/arm/integer16.cpp | 337 ++++++++++++++ libs/libSIMD/arm/integer32.cpp | 337 ++++++++++++++ libs/libSIMD/arm/integer64.cpp | 338 ++++++++++++++ libs/libSIMD/arm/integer8.cpp | 292 ++++++++++++ libs/libSIMD/cpu.cpp | 105 +++++ libs/libSIMD/cpu.hpp | 36 ++ libs/libSIMD/float32.hpp | 127 ++++++ libs/libSIMD/float64.hpp | 119 +++++ libs/libSIMD/integer16.hpp | 176 ++++++++ libs/libSIMD/integer32.hpp | 176 ++++++++ libs/libSIMD/integer64.hpp | 176 ++++++++ libs/libSIMD/integer8.hpp | 169 +++++++ libs/libSIMD/intel/float64.cpp | 297 +++++++++++++ libs/libSIMD/intel/integer16.cpp | 374 ++++++++++++++++ libs/libSIMD/intel/integer32.cpp | 343 +++++++++++++++ libs/libSIMD/intel/integer64.cpp | 339 ++++++++++++++ libs/libSIMD/intel/integer8.cpp | 416 ++++++++++++++++++ libs/libSIMD/intel/intel_sse.hpp | 179 ++++++++ libs/libSIMD/memory.hpp | 37 ++ libs/libSIMD/string.hpp | 83 ++++ {libTesting => libs/libTesting}/runner.cpp | 0 libs/libTesting/testing.cmake | 60 +++ {libTesting => libs/libTesting}/testing.hpp | 36 ++ 137 files changed, 5309 insertions(+), 154 deletions(-) delete mode 100644 libTesting/testing.cmake create mode 100644 libs/libGraphite/CMakeLists.txt rename {libGraphite => libs/libGraphite}/compression/packbits.hpp (97%) rename {libGraphite => libs/libGraphite}/data/data.cpp (82%) rename {libGraphite => libs/libGraphite}/data/data.hpp (84%) rename {libGraphite => libs/libGraphite}/data/encoding.hpp (100%) rename {libGraphite => libs/libGraphite}/data/endianess.hpp (100%) rename {libGraphite => libs/libGraphite}/data/internals/specialised_reader.hpp (100%) rename {libGraphite => libs/libGraphite}/data/internals/swap_reader.hpp (100%) rename {libGraphite => libs/libGraphite}/data/reader.cpp (100%) rename {libGraphite => libs/libGraphite}/data/reader.hpp (99%) rename {libGraphite => libs/libGraphite}/data/simd.hpp (100%) rename {libGraphite => libs/libGraphite}/data/writer.cpp (98%) rename {libGraphite => libs/libGraphite}/data/writer.hpp (98%) rename {libGraphite => libs/libGraphite}/encoding/macroman/macroman.cpp (100%) rename {libGraphite => libs/libGraphite}/encoding/macroman/macroman.hpp (100%) rename {libGraphite => libs/libGraphite}/font/fond.cpp (100%) rename {libGraphite => libs/libGraphite}/font/fond.hpp (100%) rename {libGraphite => libs/libGraphite}/font/manager.cpp (100%) rename {libGraphite => libs/libGraphite}/font/manager.hpp (100%) rename {libGraphite => libs/libGraphite}/font/nfnt.cpp (100%) rename {libGraphite => libs/libGraphite}/font/nfnt.hpp (100%) rename {libGraphite => libs/libGraphite}/font/sfnt.cpp (100%) rename {libGraphite => libs/libGraphite}/font/sfnt.hpp (100%) rename {libGraphite => libs/libGraphite}/hints.hpp (100%) create mode 100644 libs/libGraphite/memory/alignment.hpp rename {libGraphite => libs/libGraphite}/quickdraw/format/cicn.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/format/cicn.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/format/clut.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/format/clut.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/format/pict.cpp (97%) rename {libGraphite => libs/libGraphite}/quickdraw/format/pict.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/format/ppat.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/format/ppat.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/depth_2_bpp.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/depth_2_bpp.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/depth_4bpp.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/depth_4bpp.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/monochrome.cpp (99%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/monochrome.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/true_color.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/drawing/true_color.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/pixmap.cpp (96%) rename {libGraphite => libs/libGraphite}/quickdraw/support/pixmap.hpp (98%) rename {libGraphite => libs/libGraphite}/quickdraw/support/surface.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/support/surface.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/type/coding_type.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/type/color.cpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/type/color.hpp (97%) rename {libGraphite => libs/libGraphite}/quickdraw/type/pixel_format.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/type/point.hpp (90%) rename {libGraphite => libs/libGraphite}/quickdraw/type/rect.hpp (100%) rename {libGraphite => libs/libGraphite}/quickdraw/type/size.hpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/animation.cpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/animation.hpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/image_description.cpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/image_description.hpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/planar.cpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/planar.hpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/raw.cpp (100%) rename {libGraphite => libs/libGraphite}/quicktime/raw.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/attribute.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/attribute.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/classic/classic.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/classic/parser.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/classic/parser.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/classic/writer.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/classic/writer.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/extended/extended.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/extended/parser.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/extended/parser.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/extended/writer.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/extended/writer.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/file.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/file.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/manager.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/manager.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/resource.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/resource.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/result.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/result.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/rez/parser.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/rez/parser.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/rez/rez.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/rez/writer.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/rez/writer.hpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/type.cpp (100%) rename {libGraphite => libs/libGraphite}/rsrc/type.hpp (100%) rename {libGraphite => libs/libGraphite}/sound/codec/descriptor.hpp (100%) rename {libGraphite => libs/libGraphite}/sound/codec/ima4.cpp (100%) rename {libGraphite => libs/libGraphite}/sound/codec/ima4.hpp (100%) rename {libGraphite => libs/libGraphite}/sound/sound.cpp (96%) rename {libGraphite => libs/libGraphite}/sound/sound.hpp (93%) rename {libGraphite => libs/libGraphite}/spriteworld/rleD.cpp (100%) rename {libGraphite => libs/libGraphite}/spriteworld/rleD.hpp (100%) rename {libGraphite => libs/libGraphite}/spriteworld/rleX.cpp (100%) rename {libGraphite => libs/libGraphite}/spriteworld/rleX.hpp (100%) rename {libGraphite => libs/libGraphite}/sys/types.hpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/dialog.cpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/dialog.hpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/dialog_item_list.cpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/dialog_item_list.hpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/string.cpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/string.hpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/string_list.cpp (100%) rename {libGraphite => libs/libGraphite}/toolbox/string_list.hpp (100%) rename {libGraphite => libs/libGraphite}/util/concepts.hpp (100%) rename {libGraphite => libs/libGraphite}/util/hashing.cpp (100%) rename {libGraphite => libs/libGraphite}/util/hashing.hpp (100%) create mode 100644 libs/libSIMD/CMakeLists.txt create mode 100644 libs/libSIMD/SIMD.hpp create mode 100644 libs/libSIMD/arm/arm_neon.hpp create mode 100644 libs/libSIMD/arm/float64.cpp create mode 100644 libs/libSIMD/arm/integer16.cpp create mode 100644 libs/libSIMD/arm/integer32.cpp create mode 100644 libs/libSIMD/arm/integer64.cpp create mode 100644 libs/libSIMD/arm/integer8.cpp create mode 100644 libs/libSIMD/cpu.cpp create mode 100644 libs/libSIMD/cpu.hpp create mode 100644 libs/libSIMD/float32.hpp create mode 100644 libs/libSIMD/float64.hpp create mode 100644 libs/libSIMD/integer16.hpp create mode 100644 libs/libSIMD/integer32.hpp create mode 100644 libs/libSIMD/integer64.hpp create mode 100644 libs/libSIMD/integer8.hpp create mode 100644 libs/libSIMD/intel/float64.cpp create mode 100644 libs/libSIMD/intel/integer16.cpp create mode 100644 libs/libSIMD/intel/integer32.cpp create mode 100644 libs/libSIMD/intel/integer64.cpp create mode 100644 libs/libSIMD/intel/integer8.cpp create mode 100644 libs/libSIMD/intel/intel_sse.hpp create mode 100644 libs/libSIMD/memory.hpp create mode 100644 libs/libSIMD/string.hpp rename {libTesting => libs/libTesting}/runner.cpp (100%) create mode 100644 libs/libTesting/testing.cmake rename {libTesting => libs/libTesting}/testing.hpp (85%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48ad568..d76ebe2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,17 +29,15 @@ if (APPLE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") endif() -# libGraphite -include_directories("${PROJECT_SOURCE_DIR}") -file(GLOB_RECURSE graphite_sources - libGraphite/*.cpp -) -add_library(Graphite ${graphite_sources}) +set(PROJECT_LIBS_DIR ${CMAKE_CURRENT_LIST_DIR}/libs) + +# Libraries +add_subdirectory(${PROJECT_LIBS_DIR}/libSIMD) +add_subdirectory(${PROJECT_LIBS_DIR}/libGraphite) # Unit Tests -if (EXISTS libTesting/testing.cmake) - include(libTesting/testing.cmake) - build_testing_library() - add_testing_target(Graphite ${CMAKE_SOURCE_DIR}/Tests) - include("GraphiteTests.cmake") +if (EXISTS ${PROJECT_LIBS_DIR}/libTesting/testing.cmake) + include(${PROJECT_LIBS_DIR}/libTesting/testing.cmake) +# add_testing_target(Graphite ${CMAKE_CURRENT_LIST_DIR}/Tests) +# include("GraphiteTests.cmake") endif() \ No newline at end of file diff --git a/libTesting/testing.cmake b/libTesting/testing.cmake deleted file mode 100644 index 68b2124..0000000 --- a/libTesting/testing.cmake +++ /dev/null @@ -1,37 +0,0 @@ -enable_testing() - -set(LIB_TESTING_PATH ${CMAKE_CURRENT_LIST_DIR}) - -if(NOT DEFINED CMAKE_OUTPUT_PATH) - set(CMAKE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) -endif() - -# libTesting -function(build_testing_library) - message(${LIB_TESTING_PATH}) - file(GLOB_RECURSE testing_sources - ${LIB_TESTING_PATH}/../libTesting/*.cpp - ) - add_library(Testing ${testing_sources}) - target_include_directories(Testing PUBLIC ${LIB_TESTING_PATH}/..) -endfunction() - -function(add_testing_target name dir) - message("Adding Test Target: ${name}") - file(GLOB_RECURSE ${name}_test_sources ${dir}/*.cpp) - add_executable(${name}_TestRunner ${${name}_test_sources}) - target_link_libraries(${name}_TestRunner ${name} Testing) - target_include_directories(${name}_TestRunner PUBLIC ${dir}) -endfunction() - -function(test target name) - message(" - test: ${name}") - add_test(NAME ${target}_${name} COMMAND ${CMAKE_OUTPUT_PATH}/${target}_TestRunner ${name}) -endfunction() - -function(test_suite target list) - math(EXPR last "${ARGC} - 1") - foreach(n RANGE 1 ${last}) - test(${target} ${ARGV${n}}) - endforeach() -endfunction() diff --git a/libs/libGraphite/CMakeLists.txt b/libs/libGraphite/CMakeLists.txt new file mode 100644 index 0000000..ac68153 --- /dev/null +++ b/libs/libGraphite/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libGraphite_Sources + *.cpp +) + +add_library(Graphite ${libGraphite_Sources}) +target_link_libraries(Graphite SIMD) +target_include_directories(Graphite PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libGraphite/compression/packbits.hpp b/libs/libGraphite/compression/packbits.hpp similarity index 97% rename from libGraphite/compression/packbits.hpp rename to libs/libGraphite/compression/packbits.hpp index b8f6614..2b5c5a3 100644 --- a/libGraphite/compression/packbits.hpp +++ b/libs/libGraphite/compression/packbits.hpp @@ -69,9 +69,8 @@ namespace graphite::compression } static auto compress(const data::block& uncompressed) -> data::block { - data::block result; data::block buffer(128); - data::writer writer(&result); + data::writer writer; auto offset = 0; const auto max = uncompressed.size() - 1; @@ -117,7 +116,7 @@ namespace graphite::compression } } - return std::move(result); + return std::move(*const_cast(writer.data())); } }; } \ No newline at end of file diff --git a/libGraphite/data/data.cpp b/libs/libGraphite/data/data.cpp similarity index 82% rename from libGraphite/data/data.cpp rename to libs/libGraphite/data/data.cpp index 85c3e3d..3004b06 100644 --- a/libGraphite/data/data.cpp +++ b/libs/libGraphite/data/data.cpp @@ -22,16 +22,18 @@ #include #include #include +#include +#include +#include "libGraphite/memory/alignment.hpp" #include "libGraphite/data/data.hpp" -#include "libGraphite/data/simd.hpp" // MARK: - Construction graphite::data::block::block(std::size_t capacity, enum byte_order order) - : m_raw_size(simd::expand_capacity(capacity)), + : m_raw_size(memory::alignment::expand_capacity(capacity)), m_data_size(capacity), m_raw(malloc(m_raw_size)), - m_data(simd::align(m_raw)), + m_data(memory::alignment::align(m_raw)), m_allocation_owner(nullptr), m_byte_order(order), m_has_ownership(true) @@ -39,10 +41,10 @@ graphite::data::block::block(std::size_t capacity, enum byte_order order) } graphite::data::block::block(std::size_t capacity, std::size_t allocation_size, enum byte_order order) - : m_raw_size(simd::expand_capacity(allocation_size)), + : m_raw_size(memory::alignment::expand_capacity(allocation_size)), m_data_size(capacity), m_raw(malloc(m_raw_size)), - m_data(simd::align(m_raw)), + m_data(memory::alignment::align(m_raw)), m_allocation_owner(nullptr), m_byte_order(order), m_has_ownership(true) @@ -64,9 +66,9 @@ graphite::data::block::block(const std::string &path, enum byte_order order) m_data_size = file.tellg(); file.seekg(0, std::ios::beg); - m_raw_size = simd::expand_capacity(m_data_size); + m_raw_size = memory::alignment::expand_capacity(m_data_size); m_raw = malloc(m_raw_size); - m_data = simd::align(m_raw); + m_data = memory::alignment::align(m_raw); file.read(reinterpret_cast(m_data), m_data_size); file.close(); @@ -78,9 +80,9 @@ graphite::data::block::block(const std::vector& bytes, enum byte_order ord m_has_ownership(true) { m_data_size = bytes.size(); - m_raw_size = simd::expand_capacity(m_data_size); + m_raw_size = memory::alignment::expand_capacity(m_data_size); m_raw = malloc(m_raw_size); - m_data = simd::align(m_raw); + m_data = memory::alignment::align(m_raw); // TODO: This is slow, and should be speeded up in the future. auto ptr = static_cast(m_data); @@ -119,10 +121,10 @@ graphite::data::block::block(const block &source, block::position pos, std::size const_cast(m_allocation_owner)->m_users++; } else { - m_raw_size = simd::expand_capacity(amount); + m_raw_size = memory::alignment::expand_capacity(amount); m_data_size = amount; m_raw = malloc(m_raw_size); - m_data = simd::align(m_raw); + m_data = memory::alignment::align(m_raw); m_start_position = 0; m_count = 0; m_has_ownership = true; @@ -155,7 +157,7 @@ graphite::data::block::block(const block &data) { if (m_has_ownership) { m_raw = malloc(m_raw_size); - m_data = simd::align(m_raw); + m_data = memory::alignment::align(m_raw); copy_from(data); } else { @@ -211,7 +213,7 @@ auto graphite::data::block::operator=(const block &data) -> struct block & m_extended = data.m_extended; m_raw = malloc(m_raw_size); - m_data = simd::align(m_raw); + m_data = memory::alignment::align(m_raw); copy_from(data); return *this; @@ -277,7 +279,7 @@ auto graphite::data::block::clone_from(const graphite::data::block &source) -> v } else { m_raw = malloc(m_raw_size); - m_data = simd::align(m_raw); + m_data = memory::alignment::align(m_raw); m_has_ownership = true; copy_from(source); } @@ -287,25 +289,7 @@ __attribute__((optnone)) auto graphite::data::block::copy_from(const block &sour { auto source_ptr = source.get(); auto dest_ptr = get(); - - m_extended = source.m_extended; - - std::size_t len = std::min(source.size(), size()); - std::size_t n = 0; - while (n < len) { - if ((reinterpret_cast(source_ptr) & simd::alignment_width) || (len - n) < simd::fields_length) { - *dest_ptr = *source_ptr; - ++dest_ptr; - ++source_ptr; - n += simd::field_size; - } - else { - *reinterpret_cast(dest_ptr) = *reinterpret_cast(source_ptr); - dest_ptr += simd::field_count; - source_ptr += simd::field_count; - n += simd::alignment_width; - } - } + simd::string::copy(dest_ptr, source_ptr, std::min(source.size(), size())); } // MARK: - Operations @@ -320,30 +304,22 @@ auto graphite::data::block::increase_size_to(std::size_t new_size) -> void auto graphite::data::block::clear() -> void { - set((uint32_t)0); + simd::memory::zero(get(), size()); } auto graphite::data::block::set(uint8_t value, std::size_t bytes, block::position start) -> void { - union simd::value v; - for (unsigned char & byte : v.bytes) { - byte = value; - } - simd::set(get(start), size() - start, v, bytes); + simd::string::set(get(start), value, std::min(static_cast(size() - start), bytes)); +} + +auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void +{ + simd::string::setw(get(start), value, std::min(static_cast(size() - start), bytes)); } -__attribute__((optnone)) auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void +auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::position start) -> void { - union simd::value v; - v.fields[0] = (value << 16) | value; -#if __x86_64__ - v.fields[1] = v.fields[0]; - v.fields[2] = v.fields[0]; - v.fields[3] = v.fields[0]; -#elif __arm64__ - v.fields[1] = v.fields[0]; -#endif - simd::set(get(start), size() - start, v, bytes); + simd::string::setl(get(start), value, std::min(static_cast(size() - start), bytes)); } // MARK: - Slicing diff --git a/libGraphite/data/data.hpp b/libs/libGraphite/data/data.hpp similarity index 84% rename from libGraphite/data/data.hpp rename to libs/libGraphite/data/data.hpp index d7c5f89..04a39da 100644 --- a/libGraphite/data/data.hpp +++ b/libs/libGraphite/data/data.hpp @@ -26,7 +26,7 @@ #include #include #include "libGraphite/data/endianess.hpp" -#include "libGraphite/data/simd.hpp" +//#include "libGraphite/data/simd.hpp" namespace graphite::data { @@ -47,14 +47,6 @@ namespace graphite::data public: typedef std::int64_t position; -#if __x86_64__ - static constexpr std::size_t minimum_chunk_size = sizeof(unsigned __int128); -#elif __arm64__ - static constexpr std::size_t minimum_chunk_size = sizeof(uint64_t); -#else - static constexpr std::size_t minimum_chunk_size = sizeof(uint32_t); -#endif - public: block() = default; explicit block(std::size_t capacity, enum byte_order order = byte_order::msb); @@ -93,22 +85,9 @@ namespace graphite::data auto clear() -> void; - auto set(uint8_t value, std::size_t bytes = 0, block::position start = 0) -> void; - auto set(uint16_t value, std::size_t bytes = 0, block::position start = 0) -> void; - - inline auto set(uint32_t value, std::size_t bytes = 0, block::position start = 0) -> void - { - union simd::value v; - v.fields[0] = value; -#if __x86_64__ - v.fields[1] = value; - v.fields[2] = value; - v.fields[3] = value; -#elif __arm64__ - v.fields[1] = value; -#endif - simd::set(get(start), size() - start, v, bytes); - } + auto set(std::uint8_t value, std::size_t bytes = 0, block::position start = 0) -> void; + auto set(std::uint16_t value, std::size_t bytes = 0, block::position start = 0) -> void; + auto set(uint32_t value, std::size_t bytes = 0, block::position start = 0) -> void; auto copy_from(const block& source) -> void; diff --git a/libGraphite/data/encoding.hpp b/libs/libGraphite/data/encoding.hpp similarity index 100% rename from libGraphite/data/encoding.hpp rename to libs/libGraphite/data/encoding.hpp diff --git a/libGraphite/data/endianess.hpp b/libs/libGraphite/data/endianess.hpp similarity index 100% rename from libGraphite/data/endianess.hpp rename to libs/libGraphite/data/endianess.hpp diff --git a/libGraphite/data/internals/specialised_reader.hpp b/libs/libGraphite/data/internals/specialised_reader.hpp similarity index 100% rename from libGraphite/data/internals/specialised_reader.hpp rename to libs/libGraphite/data/internals/specialised_reader.hpp diff --git a/libGraphite/data/internals/swap_reader.hpp b/libs/libGraphite/data/internals/swap_reader.hpp similarity index 100% rename from libGraphite/data/internals/swap_reader.hpp rename to libs/libGraphite/data/internals/swap_reader.hpp diff --git a/libGraphite/data/reader.cpp b/libs/libGraphite/data/reader.cpp similarity index 100% rename from libGraphite/data/reader.cpp rename to libs/libGraphite/data/reader.cpp diff --git a/libGraphite/data/reader.hpp b/libs/libGraphite/data/reader.hpp similarity index 99% rename from libGraphite/data/reader.hpp rename to libs/libGraphite/data/reader.hpp index f1833d1..aaab4da 100644 --- a/libGraphite/data/reader.hpp +++ b/libs/libGraphite/data/reader.hpp @@ -136,7 +136,7 @@ namespace graphite::data } move(offset); - auto object = T(*this); + graphite::data::decodable auto object = T(*this); if (mode == mode::peek) { restore_position(); diff --git a/libGraphite/data/simd.hpp b/libs/libGraphite/data/simd.hpp similarity index 100% rename from libGraphite/data/simd.hpp rename to libs/libGraphite/data/simd.hpp diff --git a/libGraphite/data/writer.cpp b/libs/libGraphite/data/writer.cpp similarity index 98% rename from libGraphite/data/writer.cpp rename to libs/libGraphite/data/writer.cpp index 05439c1..62b1b27 100644 --- a/libGraphite/data/writer.cpp +++ b/libs/libGraphite/data/writer.cpp @@ -204,10 +204,11 @@ auto graphite::data::writer::write_data(const class block *data) -> void assert(data != m_data); ensure_required_space(position(), data->size()); - auto ptr = m_data->template get(position()); + auto dst = m_data->template get(position()); + auto src = data->get(); for (auto i = 0; i < data->size(); ++i) { - ptr[i] = *data->get(i); + *dst++ = *src++; move(); } } diff --git a/libGraphite/data/writer.hpp b/libs/libGraphite/data/writer.hpp similarity index 98% rename from libGraphite/data/writer.hpp rename to libs/libGraphite/data/writer.hpp index b1b25de..42d669d 100644 --- a/libGraphite/data/writer.hpp +++ b/libs/libGraphite/data/writer.hpp @@ -131,16 +131,15 @@ namespace graphite::data // Correct the alignment. if (m_data->byte_order() == byte_order::msb) { for (auto i = size; i < sizeof(swapped); ++i) { - swapped >>= 8; + swapped >>= 8ULL; } } else { for (auto i = size; i < sizeof(swapped); ++i) { - swapped <<= 8; + swapped <<= 8ULL; } } - for (auto n = 0; n < count; ++n) { for (auto i = 0; i < size; ++i) { auto b = i << 3ULL; diff --git a/libGraphite/encoding/macroman/macroman.cpp b/libs/libGraphite/encoding/macroman/macroman.cpp similarity index 100% rename from libGraphite/encoding/macroman/macroman.cpp rename to libs/libGraphite/encoding/macroman/macroman.cpp diff --git a/libGraphite/encoding/macroman/macroman.hpp b/libs/libGraphite/encoding/macroman/macroman.hpp similarity index 100% rename from libGraphite/encoding/macroman/macroman.hpp rename to libs/libGraphite/encoding/macroman/macroman.hpp diff --git a/libGraphite/font/fond.cpp b/libs/libGraphite/font/fond.cpp similarity index 100% rename from libGraphite/font/fond.cpp rename to libs/libGraphite/font/fond.cpp diff --git a/libGraphite/font/fond.hpp b/libs/libGraphite/font/fond.hpp similarity index 100% rename from libGraphite/font/fond.hpp rename to libs/libGraphite/font/fond.hpp diff --git a/libGraphite/font/manager.cpp b/libs/libGraphite/font/manager.cpp similarity index 100% rename from libGraphite/font/manager.cpp rename to libs/libGraphite/font/manager.cpp diff --git a/libGraphite/font/manager.hpp b/libs/libGraphite/font/manager.hpp similarity index 100% rename from libGraphite/font/manager.hpp rename to libs/libGraphite/font/manager.hpp diff --git a/libGraphite/font/nfnt.cpp b/libs/libGraphite/font/nfnt.cpp similarity index 100% rename from libGraphite/font/nfnt.cpp rename to libs/libGraphite/font/nfnt.cpp diff --git a/libGraphite/font/nfnt.hpp b/libs/libGraphite/font/nfnt.hpp similarity index 100% rename from libGraphite/font/nfnt.hpp rename to libs/libGraphite/font/nfnt.hpp diff --git a/libGraphite/font/sfnt.cpp b/libs/libGraphite/font/sfnt.cpp similarity index 100% rename from libGraphite/font/sfnt.cpp rename to libs/libGraphite/font/sfnt.cpp diff --git a/libGraphite/font/sfnt.hpp b/libs/libGraphite/font/sfnt.hpp similarity index 100% rename from libGraphite/font/sfnt.hpp rename to libs/libGraphite/font/sfnt.hpp diff --git a/libGraphite/hints.hpp b/libs/libGraphite/hints.hpp similarity index 100% rename from libGraphite/hints.hpp rename to libs/libGraphite/hints.hpp diff --git a/libs/libGraphite/memory/alignment.hpp b/libs/libGraphite/memory/alignment.hpp new file mode 100644 index 0000000..94b2b0d --- /dev/null +++ b/libs/libGraphite/memory/alignment.hpp @@ -0,0 +1,43 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace graphite::memory::alignment +{ + static constexpr std::size_t width = sizeof(std::uintptr_t); + static constexpr std::size_t mask = ~(width - 1); + + template::value>::type* = nullptr> + static inline auto expand_capacity(T capacity) -> T + { + return (capacity + width - 1) & mask; + } + + template::value>::type* = nullptr> + static inline auto align(T ptr) -> T + { + return reinterpret_cast((reinterpret_cast(ptr) + width - 1) & mask); + } +} \ No newline at end of file diff --git a/libGraphite/quickdraw/format/cicn.cpp b/libs/libGraphite/quickdraw/format/cicn.cpp similarity index 100% rename from libGraphite/quickdraw/format/cicn.cpp rename to libs/libGraphite/quickdraw/format/cicn.cpp diff --git a/libGraphite/quickdraw/format/cicn.hpp b/libs/libGraphite/quickdraw/format/cicn.hpp similarity index 100% rename from libGraphite/quickdraw/format/cicn.hpp rename to libs/libGraphite/quickdraw/format/cicn.hpp diff --git a/libGraphite/quickdraw/format/clut.cpp b/libs/libGraphite/quickdraw/format/clut.cpp similarity index 100% rename from libGraphite/quickdraw/format/clut.cpp rename to libs/libGraphite/quickdraw/format/clut.cpp diff --git a/libGraphite/quickdraw/format/clut.hpp b/libs/libGraphite/quickdraw/format/clut.hpp similarity index 100% rename from libGraphite/quickdraw/format/clut.hpp rename to libs/libGraphite/quickdraw/format/clut.hpp diff --git a/libGraphite/quickdraw/format/pict.cpp b/libs/libGraphite/quickdraw/format/pict.cpp similarity index 97% rename from libGraphite/quickdraw/format/pict.cpp rename to libs/libGraphite/quickdraw/format/pict.cpp index 0471498..fd93888 100644 --- a/libGraphite/quickdraw/format/pict.cpp +++ b/libs/libGraphite/quickdraw/format/pict.cpp @@ -47,8 +47,9 @@ graphite::quickdraw::pict::pict(data::reader &reader) } graphite::quickdraw::pict::pict(quickdraw::surface &surface) - : m_surface(std::move(surface)) + : m_surface(std::move(surface)), m_dpi(72, 72) { + m_frame.size = m_surface.size(); } // MARK: - Accessors @@ -539,9 +540,9 @@ auto graphite::quickdraw::pict::write_header(data::writer &writer) -> void writer.write_long(0xFFFE0000); // Image resolution (72dpi - writer.write_short(72); + writer.write_short(static_cast(m_dpi.x)); writer.write_short(0); - writer.write_short(72); + writer.write_short(static_cast(m_dpi.y)); writer.write_short(0); // Optimal source frame. (Identical to the image frame) @@ -589,13 +590,13 @@ auto graphite::quickdraw::pict::write_direct_bits_rect(data::writer &writer) -> auto pixel = m_surface.at(x, y); scanline.set_position(x); - writer.write_byte(pixel.components.red); + scanline.write_byte(pixel.components.red); scanline.set_position(x + m_frame.size.width); - writer.write_byte(pixel.components.green); + scanline.write_byte(pixel.components.green); scanline.set_position(x + m_frame.size.width * 2); - writer.write_byte(pixel.components.blue); + scanline.write_byte(pixel.components.blue); } } else if (pm.component_count() == 4) { @@ -603,13 +604,13 @@ auto graphite::quickdraw::pict::write_direct_bits_rect(data::writer &writer) -> auto pixel = m_surface.at(x, y); scanline.set_position(x); - writer.write_byte(pixel.components.alpha); + scanline.write_byte(pixel.components.alpha); scanline.set_position(x + m_frame.size.width); - writer.write_byte(pixel.components.red); + scanline.write_byte(pixel.components.red); scanline.set_position(x + m_frame.size.width * 2); - writer.write_byte(pixel.components.green); + scanline.write_byte(pixel.components.green); scanline.set_position(x + m_frame.size.width * 3); writer.write_byte(pixel.components.blue); diff --git a/libGraphite/quickdraw/format/pict.hpp b/libs/libGraphite/quickdraw/format/pict.hpp similarity index 100% rename from libGraphite/quickdraw/format/pict.hpp rename to libs/libGraphite/quickdraw/format/pict.hpp diff --git a/libGraphite/quickdraw/format/ppat.cpp b/libs/libGraphite/quickdraw/format/ppat.cpp similarity index 100% rename from libGraphite/quickdraw/format/ppat.cpp rename to libs/libGraphite/quickdraw/format/ppat.cpp diff --git a/libGraphite/quickdraw/format/ppat.hpp b/libs/libGraphite/quickdraw/format/ppat.hpp similarity index 100% rename from libGraphite/quickdraw/format/ppat.hpp rename to libs/libGraphite/quickdraw/format/ppat.hpp diff --git a/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp b/libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp similarity index 100% rename from libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp rename to libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp diff --git a/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp b/libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp similarity index 100% rename from libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp rename to libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp diff --git a/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp b/libs/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp similarity index 100% rename from libGraphite/quickdraw/support/drawing/depth_4bpp.cpp rename to libs/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp diff --git a/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp b/libs/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp similarity index 100% rename from libGraphite/quickdraw/support/drawing/depth_4bpp.hpp rename to libs/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp diff --git a/libGraphite/quickdraw/support/drawing/monochrome.cpp b/libs/libGraphite/quickdraw/support/drawing/monochrome.cpp similarity index 99% rename from libGraphite/quickdraw/support/drawing/monochrome.cpp rename to libs/libGraphite/quickdraw/support/drawing/monochrome.cpp index 442d1e4..9fbf7a2 100644 --- a/libGraphite/quickdraw/support/drawing/monochrome.cpp +++ b/libs/libGraphite/quickdraw/support/drawing/monochrome.cpp @@ -18,7 +18,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include #include "libGraphite/quickdraw/support/drawing/monochrome.hpp" #include "libGraphite/data/data.hpp" diff --git a/libGraphite/quickdraw/support/drawing/monochrome.hpp b/libs/libGraphite/quickdraw/support/drawing/monochrome.hpp similarity index 100% rename from libGraphite/quickdraw/support/drawing/monochrome.hpp rename to libs/libGraphite/quickdraw/support/drawing/monochrome.hpp diff --git a/libGraphite/quickdraw/support/drawing/true_color.cpp b/libs/libGraphite/quickdraw/support/drawing/true_color.cpp similarity index 100% rename from libGraphite/quickdraw/support/drawing/true_color.cpp rename to libs/libGraphite/quickdraw/support/drawing/true_color.cpp diff --git a/libGraphite/quickdraw/support/drawing/true_color.hpp b/libs/libGraphite/quickdraw/support/drawing/true_color.hpp similarity index 100% rename from libGraphite/quickdraw/support/drawing/true_color.hpp rename to libs/libGraphite/quickdraw/support/drawing/true_color.hpp diff --git a/libGraphite/quickdraw/support/pixmap.cpp b/libs/libGraphite/quickdraw/support/pixmap.cpp similarity index 96% rename from libGraphite/quickdraw/support/pixmap.cpp rename to libs/libGraphite/quickdraw/support/pixmap.cpp index c8fd62a..e2fcb0c 100644 --- a/libGraphite/quickdraw/support/pixmap.cpp +++ b/libs/libGraphite/quickdraw/support/pixmap.cpp @@ -22,9 +22,16 @@ // MARK: - Construction -graphite::quickdraw::pixmap::pixmap(const rect& frame) +graphite::quickdraw::pixmap::pixmap(const rect& frame, bool rgb555) : m_bounds(frame), - m_row_bytes(frame.size.width * constants::color_width) + m_row_bytes(frame.size.width * (rgb555 ? constants::rgb555_color_width : constants::color_width)), + m_pack_type(rgb555 ? pack_type::packbits_word : pack_type::packbits_component), + m_pack_size(0), + m_dpi(72, 72), + m_pixel_type(16), + m_pixel_size(rgb555 ? 16 : 32), + m_component_count(3), + m_component_size(rgb555 ? 5 : 8) { } diff --git a/libGraphite/quickdraw/support/pixmap.hpp b/libs/libGraphite/quickdraw/support/pixmap.hpp similarity index 98% rename from libGraphite/quickdraw/support/pixmap.hpp rename to libs/libGraphite/quickdraw/support/pixmap.hpp index 6279b01..6a8baec 100644 --- a/libGraphite/quickdraw/support/pixmap.hpp +++ b/libs/libGraphite/quickdraw/support/pixmap.hpp @@ -67,7 +67,7 @@ namespace graphite::quickdraw static constexpr std::size_t length = 50; pixmap() = default; - explicit pixmap(const rect& frame); + explicit pixmap(const rect& frame, bool rgb555 = false); explicit pixmap(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); explicit pixmap(data::reader& reader); pixmap(const pixmap&) noexcept = default; diff --git a/libGraphite/quickdraw/support/surface.cpp b/libs/libGraphite/quickdraw/support/surface.cpp similarity index 100% rename from libGraphite/quickdraw/support/surface.cpp rename to libs/libGraphite/quickdraw/support/surface.cpp diff --git a/libGraphite/quickdraw/support/surface.hpp b/libs/libGraphite/quickdraw/support/surface.hpp similarity index 100% rename from libGraphite/quickdraw/support/surface.hpp rename to libs/libGraphite/quickdraw/support/surface.hpp diff --git a/libGraphite/quickdraw/type/coding_type.hpp b/libs/libGraphite/quickdraw/type/coding_type.hpp similarity index 100% rename from libGraphite/quickdraw/type/coding_type.hpp rename to libs/libGraphite/quickdraw/type/coding_type.hpp diff --git a/libGraphite/quickdraw/type/color.cpp b/libs/libGraphite/quickdraw/type/color.cpp similarity index 100% rename from libGraphite/quickdraw/type/color.cpp rename to libs/libGraphite/quickdraw/type/color.cpp diff --git a/libGraphite/quickdraw/type/color.hpp b/libs/libGraphite/quickdraw/type/color.hpp similarity index 97% rename from libGraphite/quickdraw/type/color.hpp rename to libs/libGraphite/quickdraw/type/color.hpp index 16d5c1b..c269870 100644 --- a/libGraphite/quickdraw/type/color.hpp +++ b/libs/libGraphite/quickdraw/type/color.hpp @@ -58,6 +58,7 @@ namespace graphite::quickdraw namespace constants { constexpr std::size_t color_width = sizeof(union color); + constexpr std::size_t rgb555_color_width = 2; } namespace colors diff --git a/libGraphite/quickdraw/type/pixel_format.hpp b/libs/libGraphite/quickdraw/type/pixel_format.hpp similarity index 100% rename from libGraphite/quickdraw/type/pixel_format.hpp rename to libs/libGraphite/quickdraw/type/pixel_format.hpp diff --git a/libGraphite/quickdraw/type/point.hpp b/libs/libGraphite/quickdraw/type/point.hpp similarity index 90% rename from libGraphite/quickdraw/type/point.hpp rename to libs/libGraphite/quickdraw/type/point.hpp index a60bf1c..c08616b 100644 --- a/libGraphite/quickdraw/type/point.hpp +++ b/libs/libGraphite/quickdraw/type/point.hpp @@ -147,16 +147,17 @@ namespace graphite::quickdraw static auto write_component(T value, data::writer& writer) -> void { writer.write_integer(value); } }; -} -template<> -inline auto graphite::quickdraw::point::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } + template<> + inline auto point::read_component(data::reader &reader) -> double { return reader.read_fixed_point(); } + + template<> + inline auto point::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } -template<> -inline auto graphite::quickdraw::point::read_component(data::reader &reader) -> float { return static_cast(reader.read_fixed_point()); } + template<> + inline auto point::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } -template<> -inline auto graphite::quickdraw::point::write_component(double value, data::writer &writer) -> void { writer.write_fixed_point(value); } + template<> + inline auto point::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } -template<> -inline auto graphite::quickdraw::point::write_component(float value, data::writer &writer) -> void { writer.write_fixed_point(static_cast(value)); } \ No newline at end of file +} diff --git a/libGraphite/quickdraw/type/rect.hpp b/libs/libGraphite/quickdraw/type/rect.hpp similarity index 100% rename from libGraphite/quickdraw/type/rect.hpp rename to libs/libGraphite/quickdraw/type/rect.hpp diff --git a/libGraphite/quickdraw/type/size.hpp b/libs/libGraphite/quickdraw/type/size.hpp similarity index 100% rename from libGraphite/quickdraw/type/size.hpp rename to libs/libGraphite/quickdraw/type/size.hpp diff --git a/libGraphite/quicktime/animation.cpp b/libs/libGraphite/quicktime/animation.cpp similarity index 100% rename from libGraphite/quicktime/animation.cpp rename to libs/libGraphite/quicktime/animation.cpp diff --git a/libGraphite/quicktime/animation.hpp b/libs/libGraphite/quicktime/animation.hpp similarity index 100% rename from libGraphite/quicktime/animation.hpp rename to libs/libGraphite/quicktime/animation.hpp diff --git a/libGraphite/quicktime/image_description.cpp b/libs/libGraphite/quicktime/image_description.cpp similarity index 100% rename from libGraphite/quicktime/image_description.cpp rename to libs/libGraphite/quicktime/image_description.cpp diff --git a/libGraphite/quicktime/image_description.hpp b/libs/libGraphite/quicktime/image_description.hpp similarity index 100% rename from libGraphite/quicktime/image_description.hpp rename to libs/libGraphite/quicktime/image_description.hpp diff --git a/libGraphite/quicktime/planar.cpp b/libs/libGraphite/quicktime/planar.cpp similarity index 100% rename from libGraphite/quicktime/planar.cpp rename to libs/libGraphite/quicktime/planar.cpp diff --git a/libGraphite/quicktime/planar.hpp b/libs/libGraphite/quicktime/planar.hpp similarity index 100% rename from libGraphite/quicktime/planar.hpp rename to libs/libGraphite/quicktime/planar.hpp diff --git a/libGraphite/quicktime/raw.cpp b/libs/libGraphite/quicktime/raw.cpp similarity index 100% rename from libGraphite/quicktime/raw.cpp rename to libs/libGraphite/quicktime/raw.cpp diff --git a/libGraphite/quicktime/raw.hpp b/libs/libGraphite/quicktime/raw.hpp similarity index 100% rename from libGraphite/quicktime/raw.hpp rename to libs/libGraphite/quicktime/raw.hpp diff --git a/libGraphite/rsrc/attribute.cpp b/libs/libGraphite/rsrc/attribute.cpp similarity index 100% rename from libGraphite/rsrc/attribute.cpp rename to libs/libGraphite/rsrc/attribute.cpp diff --git a/libGraphite/rsrc/attribute.hpp b/libs/libGraphite/rsrc/attribute.hpp similarity index 100% rename from libGraphite/rsrc/attribute.hpp rename to libs/libGraphite/rsrc/attribute.hpp diff --git a/libGraphite/rsrc/classic/classic.hpp b/libs/libGraphite/rsrc/classic/classic.hpp similarity index 100% rename from libGraphite/rsrc/classic/classic.hpp rename to libs/libGraphite/rsrc/classic/classic.hpp diff --git a/libGraphite/rsrc/classic/parser.cpp b/libs/libGraphite/rsrc/classic/parser.cpp similarity index 100% rename from libGraphite/rsrc/classic/parser.cpp rename to libs/libGraphite/rsrc/classic/parser.cpp diff --git a/libGraphite/rsrc/classic/parser.hpp b/libs/libGraphite/rsrc/classic/parser.hpp similarity index 100% rename from libGraphite/rsrc/classic/parser.hpp rename to libs/libGraphite/rsrc/classic/parser.hpp diff --git a/libGraphite/rsrc/classic/writer.cpp b/libs/libGraphite/rsrc/classic/writer.cpp similarity index 100% rename from libGraphite/rsrc/classic/writer.cpp rename to libs/libGraphite/rsrc/classic/writer.cpp diff --git a/libGraphite/rsrc/classic/writer.hpp b/libs/libGraphite/rsrc/classic/writer.hpp similarity index 100% rename from libGraphite/rsrc/classic/writer.hpp rename to libs/libGraphite/rsrc/classic/writer.hpp diff --git a/libGraphite/rsrc/extended/extended.hpp b/libs/libGraphite/rsrc/extended/extended.hpp similarity index 100% rename from libGraphite/rsrc/extended/extended.hpp rename to libs/libGraphite/rsrc/extended/extended.hpp diff --git a/libGraphite/rsrc/extended/parser.cpp b/libs/libGraphite/rsrc/extended/parser.cpp similarity index 100% rename from libGraphite/rsrc/extended/parser.cpp rename to libs/libGraphite/rsrc/extended/parser.cpp diff --git a/libGraphite/rsrc/extended/parser.hpp b/libs/libGraphite/rsrc/extended/parser.hpp similarity index 100% rename from libGraphite/rsrc/extended/parser.hpp rename to libs/libGraphite/rsrc/extended/parser.hpp diff --git a/libGraphite/rsrc/extended/writer.cpp b/libs/libGraphite/rsrc/extended/writer.cpp similarity index 100% rename from libGraphite/rsrc/extended/writer.cpp rename to libs/libGraphite/rsrc/extended/writer.cpp diff --git a/libGraphite/rsrc/extended/writer.hpp b/libs/libGraphite/rsrc/extended/writer.hpp similarity index 100% rename from libGraphite/rsrc/extended/writer.hpp rename to libs/libGraphite/rsrc/extended/writer.hpp diff --git a/libGraphite/rsrc/file.cpp b/libs/libGraphite/rsrc/file.cpp similarity index 100% rename from libGraphite/rsrc/file.cpp rename to libs/libGraphite/rsrc/file.cpp diff --git a/libGraphite/rsrc/file.hpp b/libs/libGraphite/rsrc/file.hpp similarity index 100% rename from libGraphite/rsrc/file.hpp rename to libs/libGraphite/rsrc/file.hpp diff --git a/libGraphite/rsrc/manager.cpp b/libs/libGraphite/rsrc/manager.cpp similarity index 100% rename from libGraphite/rsrc/manager.cpp rename to libs/libGraphite/rsrc/manager.cpp diff --git a/libGraphite/rsrc/manager.hpp b/libs/libGraphite/rsrc/manager.hpp similarity index 100% rename from libGraphite/rsrc/manager.hpp rename to libs/libGraphite/rsrc/manager.hpp diff --git a/libGraphite/rsrc/resource.cpp b/libs/libGraphite/rsrc/resource.cpp similarity index 100% rename from libGraphite/rsrc/resource.cpp rename to libs/libGraphite/rsrc/resource.cpp diff --git a/libGraphite/rsrc/resource.hpp b/libs/libGraphite/rsrc/resource.hpp similarity index 100% rename from libGraphite/rsrc/resource.hpp rename to libs/libGraphite/rsrc/resource.hpp diff --git a/libGraphite/rsrc/result.cpp b/libs/libGraphite/rsrc/result.cpp similarity index 100% rename from libGraphite/rsrc/result.cpp rename to libs/libGraphite/rsrc/result.cpp diff --git a/libGraphite/rsrc/result.hpp b/libs/libGraphite/rsrc/result.hpp similarity index 100% rename from libGraphite/rsrc/result.hpp rename to libs/libGraphite/rsrc/result.hpp diff --git a/libGraphite/rsrc/rez/parser.cpp b/libs/libGraphite/rsrc/rez/parser.cpp similarity index 100% rename from libGraphite/rsrc/rez/parser.cpp rename to libs/libGraphite/rsrc/rez/parser.cpp diff --git a/libGraphite/rsrc/rez/parser.hpp b/libs/libGraphite/rsrc/rez/parser.hpp similarity index 100% rename from libGraphite/rsrc/rez/parser.hpp rename to libs/libGraphite/rsrc/rez/parser.hpp diff --git a/libGraphite/rsrc/rez/rez.hpp b/libs/libGraphite/rsrc/rez/rez.hpp similarity index 100% rename from libGraphite/rsrc/rez/rez.hpp rename to libs/libGraphite/rsrc/rez/rez.hpp diff --git a/libGraphite/rsrc/rez/writer.cpp b/libs/libGraphite/rsrc/rez/writer.cpp similarity index 100% rename from libGraphite/rsrc/rez/writer.cpp rename to libs/libGraphite/rsrc/rez/writer.cpp diff --git a/libGraphite/rsrc/rez/writer.hpp b/libs/libGraphite/rsrc/rez/writer.hpp similarity index 100% rename from libGraphite/rsrc/rez/writer.hpp rename to libs/libGraphite/rsrc/rez/writer.hpp diff --git a/libGraphite/rsrc/type.cpp b/libs/libGraphite/rsrc/type.cpp similarity index 100% rename from libGraphite/rsrc/type.cpp rename to libs/libGraphite/rsrc/type.cpp diff --git a/libGraphite/rsrc/type.hpp b/libs/libGraphite/rsrc/type.hpp similarity index 100% rename from libGraphite/rsrc/type.hpp rename to libs/libGraphite/rsrc/type.hpp diff --git a/libGraphite/sound/codec/descriptor.hpp b/libs/libGraphite/sound/codec/descriptor.hpp similarity index 100% rename from libGraphite/sound/codec/descriptor.hpp rename to libs/libGraphite/sound/codec/descriptor.hpp diff --git a/libGraphite/sound/codec/ima4.cpp b/libs/libGraphite/sound/codec/ima4.cpp similarity index 100% rename from libGraphite/sound/codec/ima4.cpp rename to libs/libGraphite/sound/codec/ima4.cpp diff --git a/libGraphite/sound/codec/ima4.hpp b/libs/libGraphite/sound/codec/ima4.hpp similarity index 100% rename from libGraphite/sound/codec/ima4.hpp rename to libs/libGraphite/sound/codec/ima4.hpp diff --git a/libGraphite/sound/sound.cpp b/libs/libGraphite/sound/sound.cpp similarity index 96% rename from libGraphite/sound/sound.cpp rename to libs/libGraphite/sound/sound.cpp index 491ad95..932d567 100644 --- a/libGraphite/sound/sound.cpp +++ b/libs/libGraphite/sound/sound.cpp @@ -211,6 +211,12 @@ graphite::sound_manager::sound::sound(const data::block &data, rsrc::resource::i decode(reader); } +graphite::sound_manager::sound::sound(data::reader &reader, rsrc::resource::identifier id, const std::string &name) + : m_id(id), m_name(name) +{ + decode(reader); +} + graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) { m_descriptor.sample_rate = sample_rate; @@ -453,3 +459,17 @@ auto graphite::sound_manager::sound::format_flags() const -> std::uint32_t { return m_descriptor.format_flags; } + +// MARK: - Decoding + +auto graphite::sound_manager::sound::data() -> data::block +{ + data::writer writer; + encode(writer); + return std::move(*const_cast(writer.data())); +} + +auto graphite::sound_manager::sound::encode(data::writer &writer) -> void +{ + // TODO: Implement this... +} \ No newline at end of file diff --git a/libGraphite/sound/sound.hpp b/libs/libGraphite/sound/sound.hpp similarity index 93% rename from libGraphite/sound/sound.hpp rename to libs/libGraphite/sound/sound.hpp index cb3520d..e26c178 100644 --- a/libGraphite/sound/sound.hpp +++ b/libs/libGraphite/sound/sound.hpp @@ -36,9 +36,13 @@ namespace graphite::sound_manager public: explicit sound(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit sound(data::reader& reader, rsrc::resource::identifier id = 0, const std::string& name = ""); explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const graphite::data::block& sample_data); explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector>& sample_data); + auto data() -> data::block; + auto encode(data::writer& writer) -> void; + [[nodiscard]] auto samples() const -> const data::block&; [[nodiscard]] auto codec_descriptor() const -> const codec::descriptor&; diff --git a/libGraphite/spriteworld/rleD.cpp b/libs/libGraphite/spriteworld/rleD.cpp similarity index 100% rename from libGraphite/spriteworld/rleD.cpp rename to libs/libGraphite/spriteworld/rleD.cpp diff --git a/libGraphite/spriteworld/rleD.hpp b/libs/libGraphite/spriteworld/rleD.hpp similarity index 100% rename from libGraphite/spriteworld/rleD.hpp rename to libs/libGraphite/spriteworld/rleD.hpp diff --git a/libGraphite/spriteworld/rleX.cpp b/libs/libGraphite/spriteworld/rleX.cpp similarity index 100% rename from libGraphite/spriteworld/rleX.cpp rename to libs/libGraphite/spriteworld/rleX.cpp diff --git a/libGraphite/spriteworld/rleX.hpp b/libs/libGraphite/spriteworld/rleX.hpp similarity index 100% rename from libGraphite/spriteworld/rleX.hpp rename to libs/libGraphite/spriteworld/rleX.hpp diff --git a/libGraphite/sys/types.hpp b/libs/libGraphite/sys/types.hpp similarity index 100% rename from libGraphite/sys/types.hpp rename to libs/libGraphite/sys/types.hpp diff --git a/libGraphite/toolbox/dialog.cpp b/libs/libGraphite/toolbox/dialog.cpp similarity index 100% rename from libGraphite/toolbox/dialog.cpp rename to libs/libGraphite/toolbox/dialog.cpp diff --git a/libGraphite/toolbox/dialog.hpp b/libs/libGraphite/toolbox/dialog.hpp similarity index 100% rename from libGraphite/toolbox/dialog.hpp rename to libs/libGraphite/toolbox/dialog.hpp diff --git a/libGraphite/toolbox/dialog_item_list.cpp b/libs/libGraphite/toolbox/dialog_item_list.cpp similarity index 100% rename from libGraphite/toolbox/dialog_item_list.cpp rename to libs/libGraphite/toolbox/dialog_item_list.cpp diff --git a/libGraphite/toolbox/dialog_item_list.hpp b/libs/libGraphite/toolbox/dialog_item_list.hpp similarity index 100% rename from libGraphite/toolbox/dialog_item_list.hpp rename to libs/libGraphite/toolbox/dialog_item_list.hpp diff --git a/libGraphite/toolbox/string.cpp b/libs/libGraphite/toolbox/string.cpp similarity index 100% rename from libGraphite/toolbox/string.cpp rename to libs/libGraphite/toolbox/string.cpp diff --git a/libGraphite/toolbox/string.hpp b/libs/libGraphite/toolbox/string.hpp similarity index 100% rename from libGraphite/toolbox/string.hpp rename to libs/libGraphite/toolbox/string.hpp diff --git a/libGraphite/toolbox/string_list.cpp b/libs/libGraphite/toolbox/string_list.cpp similarity index 100% rename from libGraphite/toolbox/string_list.cpp rename to libs/libGraphite/toolbox/string_list.cpp diff --git a/libGraphite/toolbox/string_list.hpp b/libs/libGraphite/toolbox/string_list.hpp similarity index 100% rename from libGraphite/toolbox/string_list.hpp rename to libs/libGraphite/toolbox/string_list.hpp diff --git a/libGraphite/util/concepts.hpp b/libs/libGraphite/util/concepts.hpp similarity index 100% rename from libGraphite/util/concepts.hpp rename to libs/libGraphite/util/concepts.hpp diff --git a/libGraphite/util/hashing.cpp b/libs/libGraphite/util/hashing.cpp similarity index 100% rename from libGraphite/util/hashing.cpp rename to libs/libGraphite/util/hashing.cpp diff --git a/libGraphite/util/hashing.hpp b/libs/libGraphite/util/hashing.hpp similarity index 100% rename from libGraphite/util/hashing.hpp rename to libs/libGraphite/util/hashing.hpp diff --git a/libs/libSIMD/CMakeLists.txt b/libs/libSIMD/CMakeLists.txt new file mode 100644 index 0000000..0aebbdd --- /dev/null +++ b/libs/libSIMD/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(SIMD LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libSIMD_Sources + *.cpp +) + +add_library(SIMD ${libSIMD_Sources}) +target_include_directories(SIMD PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libSIMD/SIMD.hpp b/libs/libSIMD/SIMD.hpp new file mode 100644 index 0000000..a758687 --- /dev/null +++ b/libs/libSIMD/SIMD.hpp @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#if (__arm64 || __arm64__) && (__ARM_NEON || __ARM_NEON__) +# define ARM true +# define ARM_NEON true +# if __APPLE__ +# define APPLE_SILICON true +# endif +# define INTEL_SIMD false +#elif (__x86_64__) +# define ARM false +# define ARM_NEON false +# define APPLE_SILICON false +# define INTEL_SIMD true +#endif + +#if ARM_NEON +# include + typedef ::int8x16_t i8x16; + typedef ::int16x8_t i16x8; + typedef ::int32x4_t i32x4; + typedef ::int64x2_t i64x2; + typedef ::float32x4_t f32x4; + typedef ::float64x2_t f64x2; +#endif + +#if INTEL_SIMD +# include +# include +# include +# include +# include +# include + typedef __m128i i8x16; + typedef __m128i i16x8; + typedef __m128i i32x4; + typedef __m128i i64x2; + typedef __m128 f32x4; + typedef __m128 f64x2; +#endif + +/* Not all targets implement `memcpy`, `memset`, etc with SIMD operations + * and as such we need to provide an implementation for these functions. + */ +#if !defined(USE_TARGET_MEMORY_FUNCTIONS) +# if __APPLE__ +# define USE_TARGET_MEMORY_FUNCTIONS true +# else +# define USE_TARGET_MEMORY_FUNCTIONS false +# endif +#endif + +#if !defined(APPROX_VALUE) +# define APPROX_VALUE +#endif \ No newline at end of file diff --git a/libs/libSIMD/arm/arm_neon.hpp b/libs/libSIMD/arm/arm_neon.hpp new file mode 100644 index 0000000..a181b47 --- /dev/null +++ b/libs/libSIMD/arm/arm_neon.hpp @@ -0,0 +1,210 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#if (__ARM_NEON || __ARM_NEON__) +#include +#include + +// Hints / Macros +#define SIMD_FUNCTION __attribute__((__always_inline__, __nodebug__, __min_vector_width__(128))) + +// Types +typedef float f32x4 __attribute__((neon_vector_type((4)))); + +namespace simd +{ + + SIMD_FUNCTION + static inline auto store_vector(float *p, f32x4 a) -> void + { + vst1q_f32(p, a); + } + + SIMD_FUNCTION + static inline auto load_vector(float *p) -> f32x4 + { + return vld1q_f32(p); + } + + SIMD_FUNCTION + static inline auto single_value_vector(float w) -> f32x4 + { + return vdupq_n_f32(w); + } + + SIMD_FUNCTION + static inline auto vector(float z, float y, float x, float w) -> f32x4 + { + float __attribute__((__aligned__(16))) data[4] = { z, y, x, w }; + return vld1q_f32(data); + } + + SIMD_FUNCTION + static inline auto vector_shuffle_lower_higher(f32x4 a, f32x4 b) -> f32x4 + { + return vcombine_f32(vget_high_f32(b), vget_low_f32(a)); + } + + SIMD_FUNCTION + static inline auto vector_slice_lower(f32x4 a) -> f32x4 + { + return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_low_f32(a))); + } + + SIMD_FUNCTION + static inline auto vector_slice_upper(f32x4 a) -> f32x4 + { + return vcombine_f32(vrev64_f32(vget_high_f32(a)), vrev64_f32(vget_high_f32(a))); + } + + SIMD_FUNCTION + static inline auto swap_lower_upper(f32x4 a) -> f32x4 + { + return vector_shuffle_lower_higher(a, a); + } + + SIMD_FUNCTION + static inline auto reverse(f32x4 a) -> f32x4 + { + return vcombine_f32(vget_high_f32(a), vget_low_f32(a)); + } + + SIMD_FUNCTION + static inline auto add(f32x4 a, f32x4 b) -> f32x4 + { + return vaddq_f32(a, b); + } + + SIMD_FUNCTION + static inline auto sub(f32x4 a, f32x4 b) -> f32x4 + { + return vsubq_f32(a, b); + } + + SIMD_FUNCTION + static inline auto mul(f32x4 a, f32x4 b) -> f32x4 + { + return vmulq_f32(a, b); + } + + SIMD_FUNCTION + static inline auto div(f32x4 a, f32x4 b) -> f32x4 + { + return vdivq_f32(a, b); + } + + SIMD_FUNCTION + static inline auto abs(f32x4 a) -> f32x4 + { + return vabsq_f32(a); + } + + SIMD_FUNCTION + static inline auto round(f32x4 a) -> f32x4 + { + auto r = vaddq_f32(a, vdupq_n_f32(0.5f)); + return vreinterpretq_f32_s32(vreinterpretq_s32_f32(r)); + } + + SIMD_FUNCTION + static inline auto floor(f32x4 a) -> f32x4 + { + return vreinterpretq_f32_s32(vreinterpretq_s32_f32(a)); + } + + SIMD_FUNCTION + static inline auto ceil(f32x4 a) -> f32x4 + { + auto r = vaddq_f32(a, vdupq_n_f32(0.999999f)); + return vreinterpretq_f32_s32(vreinterpretq_s32_f32(r)); + } + + SIMD_FUNCTION + static inline auto pow(f32x4 a, float exp) -> f32x4 + { + if (exp == 2.0) { + return vmulq_f32(a, a); + } + else { + vector_float4 v = a; + for (auto i = 0; i < 4; ++i) { + v[i] = std::powf(v[i], exp); + } + return v; + } + } + + SIMD_FUNCTION + static inline auto sqrt(f32x4 a) -> f32x4 + { + return vsqrtq_f32(a); + } + + SIMD_FUNCTION + static inline auto rsqrt(f32x4 a) -> f32x4 + { + return vrsqrteq_f32(a); + } + + SIMD_FUNCTION + static inline auto sin(f32x4 a) -> f32x4 + { + vector_float4 v = a; + for (auto i = 0; i < 4; ++i) { + v[i] = std::sinf(v[i]); + } + return v; + } + + SIMD_FUNCTION + static inline auto cos(f32x4 a) -> f32x4 + { + vector_float4 v = a; + for (auto i = 0; i < 4; ++i) { + v[i] = std::cosf(v[i]); + } + return v; + } + + SIMD_FUNCTION + static inline auto rcp(f32x4 a) -> f32x4 + { + auto r = vrecpeq_f32(a); + r = vmulq_f32(r, vrecpsq_f32(r, a)); + return r; + } + + SIMD_FUNCTION + static inline auto min(f32x4 a, f32x4 b) -> f32x4 + { + return vminq_f32(a, b); + } + + SIMD_FUNCTION + static inline auto max(f32x4 a, f32x4 b) -> f32x4 + { + return vmaxq_f32(a, b); + } + +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/arm/float64.cpp b/libs/libSIMD/arm/float64.cpp new file mode 100644 index 0000000..98288a1 --- /dev/null +++ b/libs/libSIMD/arm/float64.cpp @@ -0,0 +1,252 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +#if ARM_NEON +#include +#include +#include + +// MARK: - Construction + +simd::float64_s::float64_s(double f0, double f1) +{ + double __attribute__((__aligned__(16))) data[4] = { f0, f1 }; + vst1q_f64(&m_values[0], vld1q_f64(data)); +} + +simd::float64_s::float64_s(f64x2 v) +{ + vst1q_f64(&m_values[0], v); +} + +auto simd::float64_s::constant(double v) -> float64 +{ + return float64(vdupq_n_f64(v)); +} + +// MARK: - Accessors + +auto simd::float64_s::operator[](int i) const -> double +{ + assert(i >= 0 && i < element_count); + return m_values[i]; +} + +auto simd::float64_s::set(int i, double f) -> float64& +{ + assert(i >= 0 && i < element_count); + m_values[i] = f; + return *this; +} + +auto simd::float64_s::vector() const -> f64x2 +{ + return vld1q_f64(&m_values[0]); +} + +auto simd::float64_s::set(f64x2 v) -> void +{ + vst1q_f64(&m_values[0], v); +} + +// MARK: - Operators + +auto simd::float64_s::operator+ (const float64& other) const -> float64 +{ + return float64(vaddq_f64(vector(), other.vector())); +} + +auto simd::float64_s::operator+ (double f) const -> float64 +{ + return *this + float64::constant(f); +} + +auto simd::float64_s::operator+=(const float64& other) -> float64& +{ + set((*this + other).vector()); + return *this; +} + +auto simd::float64_s::operator+=(double f) -> float64& +{ + set((*this + float64::constant(f)).vector()); + return *this; +} + +auto simd::float64_s::operator- (const float64& other) const -> float64 +{ + return float64(vsubq_f32(vector(), other.vector())); +} + +auto simd::float64_s::operator- (double f) const -> float64 +{ + return *this - float64::constant(f); +} + +auto simd::float64_s::operator-=(const float64& other) -> float64& +{ + set((*this - other).vector()); + return *this; +} + +auto simd::float64_s::operator-=(double f) -> float64& +{ + set((*this - float64::constant(f)).vector()); + return *this; +} + +auto simd::float64_s::operator* (const float64& other) const -> float64 +{ + return float64(vmulq_f64(vector(), other.vector())); +} + +auto simd::float64_s::operator* (double f) const -> float64 +{ + return *this * float64::constant(f); +} + +auto simd::float64_s::operator*=(const float64& other) -> float64& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::float64_s::operator*=(double f) -> float64& +{ + set((*this * float64::constant(f)).vector()); + return *this; +} + +auto simd::float64_s::operator/ (const float64& other) const -> float64 +{ + return float64(vdivq_f64(vector(), other.vector())); +} + +auto simd::float64_s::operator/ (double f) const -> float64 +{ + return *this / float64::constant(f); +} + +auto simd::float64_s::operator/=(const float64& other) -> float64& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::float64_s::operator/=(double f) -> float64& +{ + set((*this / float64::constant(f)).vector()); + return *this; +} + +// MARK: - Operations + +auto simd::float64_s::abs() const -> float64 +{ + return float64(vabsq_f64(vector())); +} + +auto simd::float64_s::round() const -> float64 +{ + return float64(vrndnq_f64(vector())); +} + +auto simd::float64_s::floor() const -> float64 +{ + return float64(vrndmq_f64(vector())); +} + +auto simd::float64_s::ceil() const -> float64 +{ + return float64(vrndpq_f64(vector())); +} + +auto simd::float64_s::pow(double exp) const -> float64 +{ + if (exp == 2.0) { + auto v = vector(); + return float64(vmulq_f64(v, v)); + } + else { + // TODO: Find an implementation that uses SSE/AVX in the future + double v[element_count]; + for (auto n = 0; n < element_count; ++n) { + v[n] = std::powf(m_values[n], m_values[n]); + } + return float64(v[0], v[1]); + } +} + +auto simd::float64_s::sqrt() const -> float64 +{ + return float64(vsqrtq_f64(vector())); +} + +auto simd::float64_s::sin() const -> float64 +{ + // TODO: Find an implementation that uses SSE/AVX in the future + double v[element_count]; + for (auto n = 0; n < element_count; ++n) { + v[n] = std::sin(m_values[n]); + } + return float64(v[0], v[1]); +} + +auto simd::float64_s::cos() const -> float64 +{ + // TODO: Find an implementation that uses SSE/AVX in the future + double v[element_count]; + for (auto n = 0; n < element_count; ++n) { + v[n] = std::cos(m_values[n]); + } + return float64(v[0], v[1]); +} + +auto simd::float64_s::rcp() const -> float64 +{ + auto recip = vrecpeq_f64(vector()); + recip = vmulq_f64(recip, vrecpsq_f64(recip, vector())); + return float64(recip); +} + +auto simd::float64_s::min(const float64 &other) const -> float64 +{ + return float64(vminq_f64(vector(), other.vector())); +} + +auto simd::float64_s::min(double f) const -> float64 +{ + return float64(vminq_f64(vector(), float64::constant(f).vector())); +} + +auto simd::float64_s::max(const float64 &other) const -> float64 +{ + return float64(vmaxq_f64(vector(), other.vector())); +} + +auto simd::float64_s::max(double f) const -> float64 +{ + return float64(vmaxq_f64(vector(), float64::constant(f).vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/arm/integer16.cpp b/libs/libSIMD/arm/integer16.cpp new file mode 100644 index 0000000..ec095ba --- /dev/null +++ b/libs/libSIMD/arm/integer16.cpp @@ -0,0 +1,337 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if ARM_NEON +#include +#include +#include + +// MARK: - Construction + +simd::integer16_s::integer16_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + std::int8_t __attribute__((__aligned__(16))) data[16] = { + i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15 + }; + vst1q_s16(&m_values[0], vld1q_s8(data)); +} + +simd::integer16_s::integer16_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + std::int16_t __attribute__((__aligned__(16))) data[8] = { + i0, i1, i2, i3, i4, i5, i6, i7 + }; + vst1q_s16(&m_values[0], vld1q_s16(data)); +} + +simd::integer16_s::integer16_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + std::int32_t __attribute__((__aligned__(16))) data[4] = { + i0, i1, i2, i3 + }; + vst1q_s16(&m_values[0], vld1q_s32(data)); +} + +simd::integer16_s::integer16_s(std::int64_t i0, std::int64_t i1) +{ + std::int64_t __attribute__((__aligned__(16))) data[2] = { + i0, i1 + }; + vst1q_s16(&m_values[0], vld1q_s64(data)); +} + +simd::integer16_s::integer16_s(i16x8 v) +{ + vst1q_s16(&m_values[0], v); +} + +auto simd::integer16_s::constant(std::int16_t v) -> integer16 +{ + return integer16(vdupq_n_s16(v)); +} + +// MARK: - Accessors + +auto simd::integer16_s::operator[](int i) const -> std::int16_t +{ + assert(i >= 0 && i < element_count); + return m_values[i]; +} + +auto simd::integer16_s::set(int i, std::int16_t v) -> integer16& +{ + assert(i >= 0 && i < element_count); + m_values[i] = v; + return *this; +} + +auto simd::integer16_s::vector() const -> i16x8 +{ + return vld1q_s16(&m_values[0]); +} + +auto simd::integer16_s::set(i16x8 v) -> void +{ + vst1q_s16(&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer16_s::operator+(const integer16& other) const -> integer16 +{ + return integer16(vaddq_s16(vector(), other.vector())); +} + +auto simd::integer16_s::operator+(std::int16_t i) const -> integer16 +{ + return *this + integer16::constant(i); +} + +auto simd::integer16_s::operator+=(const integer16& other) -> integer16& +{ + set(vaddq_s16(vector(), other.vector())); + return *this; +} + +auto simd::integer16_s::operator+=(std::int16_t i) -> integer16 & +{ + set(vaddq_s16(vector(), integer16::constant(i).vector())); + return *this; +} + +auto simd::integer16_s::operator-(const integer16& other) const -> integer16 +{ + return integer16(vsubq_s16(vector(), other.vector())); +} + +auto simd::integer16_s::operator-(std::int16_t i) const -> integer16 +{ + return *this - integer16::constant(i); +} + +auto simd::integer16_s::operator-=(const integer16& other) -> integer16& +{ + set(vsubq_s16(vector(), other.vector())); + return *this; +} + +auto simd::integer16_s::operator-=(std::int16_t i) -> integer16 & +{ + set(vsubq_s16(vector(), integer16::constant(i).vector())); + return *this; +} + +auto simd::integer16_s::operator*(const integer16& other) const -> integer16 +{ + return integer16(vmulq_s16(vector(), other.vector())); +} + +auto simd::integer16_s::operator*(std::int16_t i) const -> integer16 +{ + return *this * integer16::constant(i); +} + +auto simd::integer16_s::operator*=(const integer16& other) -> integer16& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer16_s::operator*=(std::int16_t i) -> integer16 & +{ + set((*this * integer16::constant(i)).vector()); + return *this; +} + +auto simd::integer16::operator*(float f) const -> integer16 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer16_s::operator*=(float f) -> integer16& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer16_s::operator/(const integer16& other) const -> integer16 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer16_s::operator/(std::int16_t i) const -> integer16 +{ + return *this / integer16::constant(i); +} + +auto simd::integer16_s::operator/=(const integer16& other) -> integer16& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer16_s::operator/=(std::int16_t i) -> integer16 & +{ + set((*this / integer16::constant(i)).vector()); + return *this; +} + +auto simd::integer16_s::operator/(float f) const -> integer16 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer16_s::operator/=(float f) -> integer16& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer16_s::operator&(const integer16& other) const -> integer16 +{ + return integer16(vandq_u8(vector(), other.vector())); +} + +auto simd::integer16_s::operator&(std::int16_t i) const -> integer16 +{ + return *this & integer16::constant(i); +} + +auto simd::integer16_s::operator&=(const integer16& other) -> integer16& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer16_s::operator&=(std::int16_t i) -> integer16& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer16_s::operator|(const integer16& other) const -> integer16 +{ + return integer16(vorrq_u16(vector(), other.vector())); +} + +auto simd::integer16_s::operator|(std::int16_t i) const -> integer16 +{ + return *this | integer16::constant(i); +} + +auto simd::integer16_s::operator|=(const integer16& other) -> integer16& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer16_s::operator|=(std::int16_t i) -> integer16& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer16_s::operator^(const integer16& other) const -> integer16 +{ + return integer16(veorq_u8(vector(), other.vector())); +} + +auto simd::integer16_s::operator^(std::int16_t i) const -> integer16 +{ + return *this ^ integer16::constant(i); +} + +auto simd::integer16_s::operator^=(const integer16& other) -> integer16& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer16_s::operator^=(std::int16_t i) -> integer16& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer16_s::operator~() const -> integer16 +{ + return integer16(veorq_u16(vector(), vdupq_n_u16(0xFFFF))); +} + +auto simd::integer16_s::operator<<(const integer16& other) const -> integer16 +{ + return integer16(vshlq_u8(vector(), other.vector())); +} + +auto simd::integer16_s::operator<<(std::int16_t i) const -> integer16 +{ + return *this << integer16::constant(i); +} + +auto simd::integer16_s::operator<<=(const integer16& other) -> integer16& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer16_s::operator<<=(std::int16_t i) -> integer16& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer16_s::operator>>(const integer16& other) const -> integer16 +{ + // TODO: Implement this + return *this; +} + +auto simd::integer16_s::operator>>(std::int16_t i) const -> integer16 +{ + return *this << integer16::constant(i); +} + +auto simd::integer16_s::operator>>=(const integer16& other) -> integer16& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer16_s::operator>>=(std::int16_t i) -> integer16& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer16_s::abs() const -> integer16 +{ + return integer16(vabsq_s16(vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/arm/integer32.cpp b/libs/libSIMD/arm/integer32.cpp new file mode 100644 index 0000000..b35e4ad --- /dev/null +++ b/libs/libSIMD/arm/integer32.cpp @@ -0,0 +1,337 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if ARM_NEON +#include +#include +#include + +// MARK: - Construction + +simd::integer32_s::integer32_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + std::int8_t __attribute__((__aligned__(16))) data[16] = { + i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15 + }; + vst1q_s32(&m_values[0], vld1q_s8(data)); +} + +simd::integer32_s::integer32_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + std::int16_t __attribute__((__aligned__(16))) data[8] = { + i0, i1, i2, i3, i4, i5, i6, i7 + }; + vst1q_s32(&m_values[0], vld1q_s16(data)); +} + +simd::integer32_s::integer32_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + std::int32_t __attribute__((__aligned__(16))) data[4] = { + i0, i1, i2, i3 + }; + vst1q_s32(&m_values[0], vld1q_s32(data)); +} + +simd::integer32_s::integer32_s(std::int64_t i0, std::int64_t i1) +{ + std::int64_t __attribute__((__aligned__(16))) data[2] = { + i0, i1 + }; + vst1q_s32(&m_values[0], vld1q_s64(data)); +} + +simd::integer32_s::integer32_s(i32x4 v) +{ + vst1q_s32(&m_values[0], v); +} + +auto simd::integer32_s::constant(std::int32_t v) -> integer32 +{ + return integer32(vdupq_n_s32(v)); +} + +// MARK: - Accessors + +auto simd::integer32_s::operator[](int i) const -> std::int32_t +{ + assert(i >= 0 && i < element_count); + return m_values[i]; +} + +auto simd::integer32_s::set(int i, std::int32_t v) -> integer32& +{ + assert(i >= 0 && i < element_count); + m_values[i] = v; + return *this; +} + +auto simd::integer32_s::vector() const -> i32x4 +{ + return vld1q_s32(&m_values[0]); +} + +auto simd::integer32_s::set(i32x4 v) -> void +{ + vst1q_s32(&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer32_s::operator+(const integer32& other) const -> integer32 +{ + return integer32(vaddq_s32(vector(), other.vector())); +} + +auto simd::integer32_s::operator+(std::int32_t i) const -> integer32 +{ + return *this + integer32::constant(i); +} + +auto simd::integer32_s::operator+=(const integer32& other) -> integer32& +{ + set(vaddq_s32(vector(), other.vector())); + return *this; +} + +auto simd::integer32_s::operator+=(std::int32_t i) -> integer32 & +{ + set(vaddq_s32(vector(), integer32::constant(i).vector())); + return *this; +} + +auto simd::integer32_s::operator-(const integer32& other) const -> integer32 +{ + return integer32(vsubq_s32(vector(), other.vector())); +} + +auto simd::integer32_s::operator-(std::int32_t i) const -> integer32 +{ + return *this - integer32::constant(i); +} + +auto simd::integer32_s::operator-=(const integer32& other) -> integer32& +{ + set(vsubq_s32(vector(), other.vector())); + return *this; +} + +auto simd::integer32_s::operator-=(std::int32_t i) -> integer32 & +{ + set(vsubq_s32(vector(), integer32::constant(i).vector())); + return *this; +} + +auto simd::integer32_s::operator*(const integer32& other) const -> integer32 +{ + return integer32(vmulq_s32(vector(), other.vector())); +} + +auto simd::integer32_s::operator*(std::int32_t i) const -> integer32 +{ + return *this * integer32::constant(i); +} + +auto simd::integer32_s::operator*=(const integer32& other) -> integer32& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer32_s::operator*=(std::int32_t i) -> integer32 & +{ + set((*this * integer32::constant(i)).vector()); + return *this; +} + +auto simd::integer32::operator*(float f) const -> integer32 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer32_s::operator*=(float f) -> integer32& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer32_s::operator/(const integer32& other) const -> integer32 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer32_s::operator/(std::int32_t i) const -> integer32 +{ + return *this / integer32::constant(i); +} + +auto simd::integer32_s::operator/=(const integer32& other) -> integer32& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer32_s::operator/=(std::int32_t i) -> integer32 & +{ + set((*this / integer32::constant(i)).vector()); + return *this; +} + +auto simd::integer32_s::operator/(float f) const -> integer32 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer32_s::operator/=(float f) -> integer32& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer32_s::operator&(const integer32& other) const -> integer32 +{ + return integer32(vandq_u8(vector(), other.vector())); +} + +auto simd::integer32_s::operator&(std::int32_t i) const -> integer32 +{ + return *this & integer32::constant(i); +} + +auto simd::integer32_s::operator&=(const integer32& other) -> integer32& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer32_s::operator&=(std::int32_t i) -> integer32& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer32_s::operator|(const integer32& other) const -> integer32 +{ + return integer32(vorrq_u16(vector(), other.vector())); +} + +auto simd::integer32_s::operator|(std::int32_t i) const -> integer32 +{ + return *this | integer32::constant(i); +} + +auto simd::integer32_s::operator|=(const integer32& other) -> integer32& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer32_s::operator|=(std::int32_t i) -> integer32& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer32_s::operator^(const integer32& other) const -> integer32 +{ + return integer32(veorq_u8(vector(), other.vector())); +} + +auto simd::integer32_s::operator^(std::int32_t i) const -> integer32 +{ + return *this ^ integer32::constant(i); +} + +auto simd::integer32_s::operator^=(const integer32& other) -> integer32& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer32_s::operator^=(std::int32_t i) -> integer32& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer32_s::operator~() const -> integer32 +{ + return integer32(veorq_u16(vector(), vdupq_n_u16(0xFFFF))); +} + +auto simd::integer32_s::operator<<(const integer32& other) const -> integer32 +{ + return integer32(vshlq_u8(vector(), other.vector())); +} + +auto simd::integer32_s::operator<<(std::int32_t i) const -> integer32 +{ + return *this << integer32::constant(i); +} + +auto simd::integer32_s::operator<<=(const integer32& other) -> integer32& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer32_s::operator<<=(std::int32_t i) -> integer32& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer32_s::operator>>(const integer32& other) const -> integer32 +{ + // TODO: Implement this + return *this; +} + +auto simd::integer32_s::operator>>(std::int32_t i) const -> integer32 +{ + return *this << integer32::constant(i); +} + +auto simd::integer32_s::operator>>=(const integer32& other) -> integer32& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer32_s::operator>>=(std::int32_t i) -> integer32& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer32_s::abs() const -> integer32 +{ + return integer32(vabsq_s32(vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/arm/integer64.cpp b/libs/libSIMD/arm/integer64.cpp new file mode 100644 index 0000000..3f4763a --- /dev/null +++ b/libs/libSIMD/arm/integer64.cpp @@ -0,0 +1,338 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if ARM_NEON +#include +#include +#include + +// MARK: - Construction + +simd::integer64_s::integer64_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + std::int8_t __attribute__((__aligned__(16))) data[16] = { + i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15 + }; + vst1q_s64(&m_values[0], vld1q_s8(data)); +} + +simd::integer64_s::integer64_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + std::int16_t __attribute__((__aligned__(16))) data[8] = { + i0, i1, i2, i3, i4, i5, i6, i7 + }; + vst1q_s64(&m_values[0], vld1q_s16(data)); +} + +simd::integer64_s::integer64_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + std::int32_t __attribute__((__aligned__(16))) data[4] = { + i0, i1, i2, i3 + }; + vst1q_s64(&m_values[0], vld1q_s32(data)); +} + +simd::integer64_s::integer64_s(std::int64_t i0, std::int64_t i1) +{ + std::int64_t __attribute__((__aligned__(16))) data[2] = { + i0, i1 + }; + vst1q_s64(&m_values[0], vld1q_s64(data)); +} + +simd::integer64_s::integer64_s(i64x2 v) +{ + vst1q_s64(&m_values[0], v); +} + +auto simd::integer64_s::constant(std::int64_t v) -> integer64 +{ + return integer64(vdupq_n_s64(v)); +} + +// MARK: - Accessors + +auto simd::integer64_s::operator[](int i) const -> std::int64_t +{ + assert(i >= 0 && i < element_count); + return m_values[i]; +} + +auto simd::integer64_s::set(int i, std::int64_t v) -> integer64& +{ + assert(i >= 0 && i < element_count); + m_values[i] = v; + return *this; +} + +auto simd::integer64_s::vector() const -> i64x2 +{ + return vld1q_s64(&m_values[0]); +} + +auto simd::integer64_s::set(i64x2 v) -> void +{ + vst1q_s64(&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer64_s::operator+(const integer64& other) const -> integer64 +{ + return integer64(vaddq_s64(vector(), other.vector())); +} + +auto simd::integer64_s::operator+(std::int64_t i) const -> integer64 +{ + return *this + integer64::constant(i); +} + +auto simd::integer64_s::operator+=(const integer64& other) -> integer64& +{ + set(vaddq_s64(vector(), other.vector())); + return *this; +} + +auto simd::integer64_s::operator+=(std::int64_t i) -> integer64 & +{ + set(vaddq_s64(vector(), integer64::constant(i).vector())); + return *this; +} + +auto simd::integer64_s::operator-(const integer64& other) const -> integer64 +{ + return integer64(vsubq_s64(vector(), other.vector())); +} + +auto simd::integer64_s::operator-(std::int64_t i) const -> integer64 +{ + return *this - integer64::constant(i); +} + +auto simd::integer64_s::operator-=(const integer64& other) -> integer64& +{ + set(vsubq_s64(vector(), other.vector())); + return *this; +} + +auto simd::integer64_s::operator-=(std::int64_t i) -> integer64 & +{ + set(vsubq_s64(vector(), integer64::constant(i).vector())); + return *this; +} + +auto simd::integer64_s::operator*(const integer64& other) const -> integer64 +{ + // TODO: Implement this... + return *this; +} + +auto simd::integer64_s::operator*(std::int64_t i) const -> integer64 +{ + return *this * integer64::constant(i); +} + +auto simd::integer64_s::operator*=(const integer64& other) -> integer64& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer64_s::operator*=(std::int64_t i) -> integer64 & +{ + set((*this * integer64::constant(i)).vector()); + return *this; +} + +auto simd::integer64::operator*(float f) const -> integer64 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer64_s::operator*=(float f) -> integer64& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer64_s::operator/(const integer64& other) const -> integer64 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer64_s::operator/(std::int64_t i) const -> integer64 +{ + return *this / integer64::constant(i); +} + +auto simd::integer64_s::operator/=(const integer64& other) -> integer64& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer64_s::operator/=(std::int64_t i) -> integer64 & +{ + set((*this / integer64::constant(i)).vector()); + return *this; +} + +auto simd::integer64_s::operator/(float f) const -> integer64 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer64_s::operator/=(float f) -> integer64& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer64_s::operator&(const integer64& other) const -> integer64 +{ + return integer64(vandq_u8(vector(), other.vector())); +} + +auto simd::integer64_s::operator&(std::int64_t i) const -> integer64 +{ + return *this & integer64::constant(i); +} + +auto simd::integer64_s::operator&=(const integer64& other) -> integer64& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer64_s::operator&=(std::int64_t i) -> integer64& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer64_s::operator|(const integer64& other) const -> integer64 +{ + return integer64(vorrq_u16(vector(), other.vector())); +} + +auto simd::integer64_s::operator|(std::int64_t i) const -> integer64 +{ + return *this | integer64::constant(i); +} + +auto simd::integer64_s::operator|=(const integer64& other) -> integer64& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer64_s::operator|=(std::int64_t i) -> integer64& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer64_s::operator^(const integer64& other) const -> integer64 +{ + return integer64(veorq_u8(vector(), other.vector())); +} + +auto simd::integer64_s::operator^(std::int64_t i) const -> integer64 +{ + return *this ^ integer64::constant(i); +} + +auto simd::integer64_s::operator^=(const integer64& other) -> integer64& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer64_s::operator^=(std::int64_t i) -> integer64& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer64_s::operator~() const -> integer64 +{ + return integer64(veorq_u16(vector(), vdupq_n_u16(0xFFFF))); +} + +auto simd::integer64_s::operator<<(const integer64& other) const -> integer64 +{ + return integer64(vshlq_u8(vector(), other.vector())); +} + +auto simd::integer64_s::operator<<(std::int64_t i) const -> integer64 +{ + return *this << integer64::constant(i); +} + +auto simd::integer64_s::operator<<=(const integer64& other) -> integer64& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer64_s::operator<<=(std::int64_t i) -> integer64& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer64_s::operator>>(const integer64& other) const -> integer64 +{ + // TODO: Implement this + return *this; +} + +auto simd::integer64_s::operator>>(std::int64_t i) const -> integer64 +{ + return *this << integer64::constant(i); +} + +auto simd::integer64_s::operator>>=(const integer64& other) -> integer64& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer64_s::operator>>=(std::int64_t i) -> integer64& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer64_s::abs() const -> integer64 +{ + return integer64(vabsq_s64(vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/arm/integer8.cpp b/libs/libSIMD/arm/integer8.cpp new file mode 100644 index 0000000..22ef0ef --- /dev/null +++ b/libs/libSIMD/arm/integer8.cpp @@ -0,0 +1,292 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if ARM_NEON +#include +#include +#include + +// MARK: - Construction + +simd::integer8_s::integer8_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + std::int8_t __attribute__((__aligned__(16))) data[16] = { + i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15 + }; + vst1q_s8(&m_values[0], vld1q_s8(data)); +} + +simd::integer8_s::integer8_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + std::int16_t __attribute__((__aligned__(16))) data[8] = { + i0, i1, i2, i3, i4, i5, i6, i7 + }; + vst1q_s8(&m_values[0], vld1q_s16(data)); +} + +simd::integer8_s::integer8_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + std::int32_t __attribute__((__aligned__(16))) data[4] = { + i0, i1, i2, i3 + }; + vst1q_s8(&m_values[0], vld1q_s32(data)); +} + +simd::integer8_s::integer8_s(std::int64_t i0, std::int64_t i1) +{ + std::int64_t __attribute__((__aligned__(16))) data[2] = { + i0, i1 + }; + vst1q_s8(&m_values[0], vld1q_s64(data)); +} + +simd::integer8_s::integer8_s(i8x16 v) +{ + vst1q_s8(&m_values[0], v); +} + +auto simd::integer8_s::constant(std::int8_t v) -> integer8 +{ + return integer8(vdupq_n_s8(v)); +} + +// MARK: - Accessors + +auto simd::integer8_s::operator[](int i) const -> std::int8_t +{ + assert(i >= 0 && i < element_count); + return m_values[i]; +} + +auto simd::integer8_s::set(int i, std::int8_t v) -> integer8& +{ + assert(i >= 0 && i < element_count); + m_values[i] = v; + return *this; +} + +auto simd::integer8_s::vector() const -> i8x16 +{ + return vld1q_s8(&m_values[0]); +} + +auto simd::integer8_s::set(i8x16 v) -> void +{ + vst1q_s8(&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer8_s::operator+(const integer8& other) const -> integer8 +{ + return integer8(vaddq_s8(vector(), other.vector())); +} + +auto simd::integer8_s::operator+(std::int8_t i) const -> integer8 +{ + return *this + integer8::constant(i); +} + +auto simd::integer8_s::operator+=(const integer8& other) -> integer8& +{ + set(vaddq_s8(vector(), other.vector())); + return *this; +} + +auto simd::integer8_s::operator+=(std::int8_t i) -> integer8 & +{ + set(vaddq_s8(vector(), integer8::constant(i).vector())); + return *this; +} + +auto simd::integer8_s::operator-(const integer8& other) const -> integer8 +{ + return integer8(vsubq_s8(vector(), other.vector())); +} + +auto simd::integer8_s::operator-(std::int8_t i) const -> integer8 +{ + return *this - integer8::constant(i); +} + +auto simd::integer8_s::operator-=(const integer8& other) -> integer8& +{ + set(vsubq_s8(vector(), other.vector())); + return *this; +} + +auto simd::integer8_s::operator-=(std::int8_t i) -> integer8 & +{ + set(vsubq_s8(vector(), integer8::constant(i).vector())); + return *this; +} + +auto simd::integer8_s::operator*(const integer8& other) const -> integer8 +{ + return integer8(vmulq_s8(vector(), other.vector())); +} + +auto simd::integer8_s::operator*(std::int8_t i) const -> integer8 +{ + return *this * integer8::constant(i); +} + +auto simd::integer8_s::operator*=(const integer8& other) -> integer8& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer8_s::operator*=(std::int8_t i) -> integer8 & +{ + set((*this * integer8::constant(i)).vector()); + return *this; +} + +auto simd::integer8::operator*(float f) const -> integer8 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer8_s::operator*=(float f) -> integer8& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer8_s::operator/(const integer8& other) const -> integer8 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer8_s::operator/(std::int8_t i) const -> integer8 +{ + return *this / integer8::constant(i); +} + +auto simd::integer8_s::operator/=(const integer8& other) -> integer8& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer8_s::operator/=(std::int8_t i) -> integer8 & +{ + set((*this / integer8::constant(i)).vector()); + return *this; +} + +auto simd::integer8_s::operator/(float f) const -> integer8 +{ + // TODO: Implement this. + return *this; +} + +auto simd::integer8_s::operator/=(float f) -> integer8& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer8_s::operator&(const integer8& other) const -> integer8 +{ + return integer8(vandq_u8(vector(), other.vector())); +} + +auto simd::integer8_s::operator&(std::int8_t i) const -> integer8 +{ + return *this & integer8::constant(i); +} + +auto simd::integer8_s::operator&=(const integer8& other) -> integer8& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer8_s::operator&=(std::int8_t i) -> integer8& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer8_s::operator|(const integer8& other) const -> integer8 +{ + return integer8(vorrq_u8(vector(), other.vector())); +} + +auto simd::integer8_s::operator|(std::int8_t i) const -> integer8 +{ + return *this | integer8::constant(i); +} + +auto simd::integer8_s::operator|=(const integer8& other) -> integer8& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer8_s::operator|=(std::int8_t i) -> integer8& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer8_s::operator^(const integer8& other) const -> integer8 +{ + return integer8(veorq_u8(vector(), other.vector())); +} + +auto simd::integer8_s::operator^(std::int8_t i) const -> integer8 +{ + return *this ^ integer8::constant(i); +} + +auto simd::integer8_s::operator^=(const integer8& other) -> integer8& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer8_s::operator^=(std::int8_t i) -> integer8& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer8_s::operator~() const -> integer8 +{ + return integer8(veorq_u8(vector(), vdupq_n_u8(0xFF))); +} + +auto simd::integer8_s::abs() const -> integer8 +{ + return integer8(vabsq_s8(vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/cpu.cpp b/libs/libSIMD/cpu.cpp new file mode 100644 index 0000000..38e5a20 --- /dev/null +++ b/libs/libSIMD/cpu.cpp @@ -0,0 +1,105 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +// MARK: - Static Information + +static struct +{ + std::string vendor { "Unknown" }; + std::string name { "Unknown" }; + struct { + bool mmx { false }; + bool sse { false }; + bool sse2 { false }; + bool sse3 { false }; + bool ssse3 { false }; + bool sse4_1 { false }; + bool sse4_2 { false }; + bool sse4_a { false }; + bool avx { false }; + bool avx2 { false }; + bool neon { false }; + } features; +} s_cpu_info; + +// MARK: - Initialisation and Setup + + +#if INTEL_SIMD +#include + +__attribute__((constructor)) +static auto simd_initialise_cpu_info() -> void +{ + s_cpu_info.vendor = "???"; // TODO: Find the vendor + s_cpu_info.name = "???"; // TODO: Find the name of the CPU. + + std::uint32_t info[4]; + __cpuid(0x00000000, info[0], info[1], info[2], info[3]); + auto nIds = info[0]; + + __cpuid(0x80000000, info[0], info[1], info[2], info[3]); + auto nExIds = info[0]; + + // Features + if (nIds & 0x00000001) { + __cpuid(0x00000001, info[0], info[1], info[2], info[3]); + s_cpu_info.features.mmx = (info[3] & ((std::uint32_t)1 << 23)) != 0; + s_cpu_info.features.sse = (info[3] & ((std::uint32_t)1 << 25)) != 0; + s_cpu_info.features.sse2 = (info[3] & ((std::uint32_t)1 << 26)) != 0; + s_cpu_info.features.sse3 = (info[2] & ((std::uint32_t)1 << 0)) != 0; + s_cpu_info.features.ssse3 = (info[2] & ((std::uint32_t)1 << 9)) != 0; + s_cpu_info.features.sse4_1 = (info[2] & ((std::uint32_t)1 << 19)) != 0; + s_cpu_info.features.sse4_2 = (info[2] & ((std::uint32_t)1 << 20)) != 0; + s_cpu_info.features.avx = (info[2] & ((std::uint32_t)1 << 28)) != 0; + } + + if (nIds & 0x00000007) { + __cpuid(0x00000007, info[0], info[1], info[2], info[3]); + s_cpu_info.features.avx2 = (info[2] & ((std::uint32_t)1 << 28)) != 0; + } + + if (nExIds & 0x80000001) { + __cpuid(0x80000001, info[0], info[1], info[2], info[3]); + s_cpu_info.features.sse4_a = (info[2] & ((std::uint32_t)1 << 6)) != 0; + } +} + +#elif APPLE_SILICON +__attribute__((constructor)) +static auto simd_initialise_cpu_info() -> void +{ + s_cpu_info.vendor = "Apple Silcon"; + s_cpu_info.name = "???"; // TODO: Find the name of the CPU. + s_cpu_info.features.neon = true; +} + +#elif ARM +__attribute__((constructor)) +static auto simd_initialise_cpu_info() -> void +{ + s_cpu_info.vendor = "ARM"; + s_cpu_info.name = "???"; // TODO: Find the name of the CPU. + s_cpu_info.features.neon = true; +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/cpu.hpp b/libs/libSIMD/cpu.hpp new file mode 100644 index 0000000..f24f259 --- /dev/null +++ b/libs/libSIMD/cpu.hpp @@ -0,0 +1,36 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace simd::cpu +{ + enum class feature + { + SSE, AVX, NEON + }; + + auto vendor() -> std::string; + auto name() -> std::string; + + auto has(enum feature f) -> bool; +} \ No newline at end of file diff --git a/libs/libSIMD/float32.hpp b/libs/libSIMD/float32.hpp new file mode 100644 index 0000000..f1f20a4 --- /dev/null +++ b/libs/libSIMD/float32.hpp @@ -0,0 +1,127 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include + +namespace simd +{ + struct float32_s; + typedef struct float32_s float32; + + struct float32_s + { + // MARK: - Construction + + explicit inline float32_s(float f0 = 0.f, float f1 = 0.f, float f2 = 0.f, float f3 = 0.f) + { + m_values = vector(f0, f1, f2, f3); + } + + explicit inline float32_s(f32x4 v) + : m_values(v) + {} + + inline float32_s(const float32&) = default; + inline float32_s(float32&&) = default; + auto operator=(const float32&) -> float32& = default; + + static inline auto constant(float v) -> float32 + { + return float32(single_value_vector(v)); + } + + static inline auto lower_upper_merge(const float32& lower, const float32& upper) -> float32 + { + return float32(vector_shuffle_lower_higher(lower.m_values, upper.m_values)); + } + + static inline auto lower(const float32& lower) -> float32 { return float32(vector_slice_lower(lower.m_values)); } + static inline auto upper(const float32& upper) -> float32 { return float32(vector_slice_upper(upper.m_values)); } + + // MARK: - Accessors + inline auto operator[] (int i) const -> float { return m_values[i]; }; + inline auto set(int i, float v) -> float32& { m_values[i] = v; return *this; } + + // MARK: - Operators + inline auto operator+ (const float32& other) const -> float32 { return float32(simd::add(m_values, other.m_values)); } + inline auto operator+ (float f) const -> float32 { return float32(simd::add(m_values, simd::single_value_vector(f))); } + inline auto operator+=(const float32& other) -> float32& { m_values = simd::add(m_values, other.m_values); return *this; } + inline auto operator+=(float f) -> float32& { m_values = simd::add(m_values, simd::single_value_vector(f)); return *this; } + + inline auto operator- (const float32& other) const -> float32 { return float32(simd::sub(m_values, other.m_values)); } + inline auto operator- (float f) const -> float32 { return float32(simd::sub(m_values, simd::single_value_vector(f))); } + inline auto operator-=(const float32& other) -> float32& { m_values = simd::sub(m_values, other.m_values); return *this; } + inline auto operator-=(float f) -> float32& { m_values = simd::sub(m_values, simd::single_value_vector(f)); return *this; } + + inline auto operator* (const float32& other) const -> float32 { return float32(simd::mul(m_values, other.m_values)); } + inline auto operator* (float f) const -> float32 { return float32(simd::mul(m_values, simd::single_value_vector(f))); } + inline auto operator*=(const float32& other) -> float32& { m_values = simd::mul(m_values, other.m_values); return *this; } + inline auto operator*=(float f) -> float32& { m_values = simd::mul(m_values, simd::single_value_vector(f)); return *this; } + + inline auto operator/ (const float32& other) const -> float32 { return float32(simd::div(m_values, other.m_values)); } + inline auto operator/ (float f) const -> float32 { return float32(simd::div(m_values, simd::single_value_vector(f))); } + inline auto operator/=(const float32& other) -> float32& { m_values =simd::div(m_values, other.m_values); return *this; } + inline auto operator/=(float f) -> float32& { m_values = simd::div(m_values, simd::single_value_vector(f)); return *this; } + + [[nodiscard]] inline auto abs() const -> float32 { return float32(simd::abs(m_values)); } + [[nodiscard]] inline auto round() const -> float32 { return float32(simd::round(m_values)); } + [[nodiscard]] inline auto floor() const -> float32 { return float32(simd::floor(m_values)); } + [[nodiscard]] inline auto ceil() const -> float32 { return float32(simd::ceil(m_values)); } + [[nodiscard]] inline auto pow(float exp) const -> float32 { return float32(simd::pow(m_values, exp)); } + [[nodiscard]] inline auto sqrt() const -> float32 { return float32(simd::sqrt(m_values)); } + [[nodiscard]] inline auto rsqrt() const -> float32 { return float32(simd::rsqrt(m_values)); } + [[nodiscard]] inline auto sin() const -> float32 { return float32(simd::sin(m_values)); } + [[nodiscard]] inline auto cos() const -> float32 { return float32(simd::cos(m_values)); } + [[nodiscard]] inline auto rcp() const -> float32 { return float32(simd::rcp(m_values)); } + [[nodiscard]] inline auto min(const float32& other) const -> float32 { return float32(simd::min(m_values, other.m_values)); } + [[nodiscard]] inline auto min(float f) const -> float32 { return float32(simd::min(m_values, simd::single_value_vector(f))); } + [[nodiscard]] inline auto max(const float32& other) const -> float32 { return float32(simd::max(m_values, other.m_values)); } + [[nodiscard]] inline auto max(float f) const -> float32 { return float32(simd::max(m_values, simd::single_value_vector(f))); } + + [[nodiscard]] inline auto upper() const -> float32 { return float32(simd::vector_slice_upper(m_values)); } + [[nodiscard]] inline auto lower() const -> float32 { return float32(simd::vector_slice_lower(m_values)); } + [[nodiscard]] inline auto swapped() const -> float32 { return float32(simd::swap_lower_upper(m_values)); } + [[nodiscard]] inline auto reversed() const -> float32 { return float32(simd::reverse(m_values)); } + + inline auto set_lower(const float32& lower) -> void + { + m_values[0] = lower[0]; m_values[1] = lower[1]; + } + + inline auto set_upper(const float32& upper) -> void + { + m_values[2] = upper[2]; m_values[3] = upper[3]; + } + + friend struct integer16_s; + friend struct integer32_s; + friend struct integer64_s; + friend struct float32_s; + friend struct double64_s; + + private: + f32x4 m_values; + }; +} \ No newline at end of file diff --git a/libs/libSIMD/float64.hpp b/libs/libSIMD/float64.hpp new file mode 100644 index 0000000..ffd102b --- /dev/null +++ b/libs/libSIMD/float64.hpp @@ -0,0 +1,119 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace simd +{ + struct float64_s; + typedef struct float64_s float64; + + struct float64_s + { + static constexpr std::int32_t element_count = 2; + + // MARK: - Construction + + /** + * Creates a 128-bit SIMD Vector from 3 single precision floats. + * @param f0 Element 1 + * @param f1 Element 2 + */ + explicit float64_s(double f0 = 0.f, double f1 = 0.f); + + explicit float64_s(f64x2 v); + + float64_s(const float64_s&) = default; + float64_s(float64_s&&) = default; + auto operator=(const float64&) -> float64& = default; + + /** + * Creates a 128-bit SIMD Vector using one single precision float for each of the elements. + * @param v Value to duplicate into all elements. + */ + static auto constant(double v) -> float64; + + static auto lower_upper_merge(const float64& lower, const float64& upper) -> float64; + static auto lower(const float64& lower) -> float64; + static auto upper(const float64& upper) -> float64; + + // MARK: - Accessors + auto operator[] (int i) const -> double; + auto set(int i, double v) -> float64&; + + // MARK: - Operators + auto operator+ (const float64& other) const -> float64; + auto operator+ (double f) const -> float64; + auto operator+=(const float64& other) -> float64&; + auto operator+=(double f) -> float64&; + + auto operator- (const float64& other) const -> float64; + auto operator- (double f) const -> float64; + auto operator-=(const float64& other) -> float64&; + auto operator-=(double f) -> float64&; + + auto operator* (const float64& other) const -> float64; + auto operator* (double f) const -> float64; + auto operator*=(const float64& other) -> float64&; + auto operator*=(double f) -> float64&; + + auto operator/ (const float64& other) const -> float64; + auto operator/ (double f) const -> float64; + auto operator/=(const float64& other) -> float64&; + auto operator/=(double f) -> float64&; + + [[nodiscard]] auto abs() const -> float64; + [[nodiscard]] auto round() const -> float64; + [[nodiscard]] auto floor() const -> float64; + [[nodiscard]] auto ceil() const -> float64; + [[nodiscard]] auto pow(double exp) const -> float64; + [[nodiscard]] auto sqrt() const -> float64; + [[nodiscard]] auto sin() const -> float64; + [[nodiscard]] auto cos() const -> float64; + [[nodiscard]] auto rcp() const -> float64; + [[nodiscard]] auto min(const float64& other) const -> float64; + [[nodiscard]] auto min(double f) const -> float64; + [[nodiscard]] auto max(const float64& other) const -> float64; + [[nodiscard]] auto max(double f) const -> float64; + + [[nodiscard]] auto upper() const -> float64; + [[nodiscard]] auto lower() const -> float64; + [[nodiscard]] auto swapped() const -> float64; + [[nodiscard]] auto reversed() const -> float64; + + auto set_lower(const float64& lower) -> void; + auto set_upper(const float64& upper) -> void; + + friend struct integer16_s; + friend struct integer32_s; + friend struct integer64_s; + friend struct float64_s; + friend struct float32_s; + + private: + double __attribute__((__aligned__(16))) m_values[element_count] { 0 }; + + [[nodiscard]] auto vector() const -> f64x2; + auto set(f64x2 v) -> void; + }; +} \ No newline at end of file diff --git a/libs/libSIMD/integer16.hpp b/libs/libSIMD/integer16.hpp new file mode 100644 index 0000000..e83d911 --- /dev/null +++ b/libs/libSIMD/integer16.hpp @@ -0,0 +1,176 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace simd +{ + struct integer16_s; + typedef struct integer16_s integer16; + + struct integer16_s + { + static constexpr std::int32_t element_count = 8; + + // MARK: - Construction + + /** + * Creates a 128-bit SIMD Vector from 16 8-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + * @param i8 Element 9 + * @param i9 Element 10 + * @param i10 Element 11 + * @param i11 Element 12 + * @param i12 Element 13 + * @param i13 Element 14 + * @param i14 Element 15 + * @param i16 Element 16 + */ + explicit integer16_s( + std::int8_t i0 = 0, std::int8_t i1 = 0, std::int8_t i2 = 0, std::int8_t i3 = 0, + std::int8_t i4 = 0, std::int8_t i5 = 0, std::int8_t i6 = 0, std::int8_t i7 = 0, + std::int8_t i8 = 0, std::int8_t i9 = 0, std::int8_t i10 = 0, std::int8_t i11 = 0, + std::int8_t i12 = 0, std::int8_t i13 = 0, std::int8_t i14 = 0, std::int8_t i15 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 8 16-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + */ + explicit integer16_s( + std::int16_t i0 = 0, std::int16_t i1 = 0, std::int16_t i2 = 0, std::int16_t i3 = 0, + std::int16_t i4 = 0, std::int16_t i5 = 0, std::int16_t i6 = 0, std::int16_t i7 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 4 32-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + */ + explicit integer16_s(std::int32_t i0 = 0, std::int32_t i1 = 0, std::int32_t i2 = 0, std::int32_t i3 = 0); + + /** + * Creates a 128-bit SIMD Vector from 2 64-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + */ + explicit integer16_s(std::int64_t i0 = 0, std::int64_t i1 = 0); + + explicit integer16_s(i16x8 v); + + integer16_s(const integer16&) = default; + integer16_s(integer16&&) = default; + auto operator=(const integer16&) -> integer16& = default; + + /** + * Creates a 128-bit SIMD Vector using a single 8-bit integer for each of the elements. + * @param v Value to duplicate into all elements. + */ + static auto constant(std::int16_t v) -> integer16_s; + + // MARK: - Accessors + auto operator[] (int i) const -> std::int16_t; + auto set(int i, std::int16_t v) -> integer16_s&; + + // MARK: - Operators + auto operator+ (const integer16& other) const -> integer16_s; + auto operator+ (std::int16_t i) const -> integer16; + auto operator+=(const integer16& other) -> integer16&; + auto operator+=(std::int16_t i) -> integer16&; + + auto operator- (const integer16& other) const -> integer16; + auto operator- (std::int16_t i) const -> integer16; + auto operator-=(const integer16& other) -> integer16&; + auto operator-=(std::int16_t i) -> integer16&; + + auto operator* (const integer16& other) const -> integer16; + auto operator* (std::int16_t i) const -> integer16; + auto operator* (float f) const -> integer16; + auto operator*=(const integer16& other) -> integer16&; + auto operator*=(std::int16_t i) -> integer16&; + auto operator*=(float f) -> integer16&; + + auto operator/ (const integer16& other) const -> integer16; + auto operator/ (std::int16_t i) const -> integer16; + auto operator/ (float f) const -> integer16; + auto operator/=(const integer16& other) -> integer16&; + auto operator/=(std::int16_t i) -> integer16&; + auto operator/=(float f) -> integer16&; + + auto operator& (const integer16& other) const -> integer16; + auto operator& (std::int16_t i) const -> integer16; + auto operator&=(const integer16& other) -> integer16&; + auto operator&=(std::int16_t i) -> integer16&; + + auto operator| (const integer16& other) const -> integer16; + auto operator| (std::int16_t i) const -> integer16; + auto operator|=(const integer16& other) -> integer16&; + auto operator|=(std::int16_t i) -> integer16&; + + auto operator^ (const integer16& other) const -> integer16; + auto operator^ (std::int16_t i) const -> integer16; + auto operator^=(const integer16& other) -> integer16&; + auto operator^=(std::int16_t i) -> integer16&; + + auto operator<<(const integer16& other) const -> integer16; + auto operator<<(std::int16_t i) const -> integer16; + auto operator<<=(const integer16& other) -> integer16&; + auto operator<<=(std::int16_t i) -> integer16&; + + auto operator>>(const integer16& other) const -> integer16; + auto operator>>(std::int16_t i) const -> integer16; + auto operator>>=(const integer16& other) -> integer16&; + auto operator>>=(std::int16_t i) -> integer16&; + + auto operator~() const -> integer16; + + [[nodiscard]] auto abs() const -> integer16; + + friend struct integer8_s; + friend struct integer32_s; + friend struct integer64_s; + friend struct float_s; + friend struct double_s; + + private: + std::int16_t __attribute__((__aligned__(16))) m_values[element_count]; + + [[nodiscard]] auto vector() const -> i16x8; + auto set(i16x8 v) -> void; + }; +} \ No newline at end of file diff --git a/libs/libSIMD/integer32.hpp b/libs/libSIMD/integer32.hpp new file mode 100644 index 0000000..3559868 --- /dev/null +++ b/libs/libSIMD/integer32.hpp @@ -0,0 +1,176 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace simd +{ + struct integer32_s; + typedef struct integer32_s integer32; + + struct integer32_s + { + static constexpr std::int32_t element_count = 4; + + // MARK: - Construction + + /** + * Creates a 128-bit SIMD Vector from 16 8-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + * @param i8 Element 9 + * @param i9 Element 10 + * @param i10 Element 11 + * @param i11 Element 12 + * @param i12 Element 13 + * @param i13 Element 14 + * @param i14 Element 15 + * @param i16 Element 16 + */ + explicit integer32_s( + std::int8_t i0 = 0, std::int8_t i1 = 0, std::int8_t i2 = 0, std::int8_t i3 = 0, + std::int8_t i4 = 0, std::int8_t i5 = 0, std::int8_t i6 = 0, std::int8_t i7 = 0, + std::int8_t i8 = 0, std::int8_t i9 = 0, std::int8_t i10 = 0, std::int8_t i11 = 0, + std::int8_t i12 = 0, std::int8_t i13 = 0, std::int8_t i14 = 0, std::int8_t i15 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 8 16-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + */ + explicit integer32_s( + std::int16_t i0 = 0, std::int16_t i1 = 0, std::int16_t i2 = 0, std::int16_t i3 = 0, + std::int16_t i4 = 0, std::int16_t i5 = 0, std::int16_t i6 = 0, std::int16_t i7 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 4 32-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + */ + explicit integer32_s(std::int32_t i0 = 0, std::int32_t i1 = 0, std::int32_t i2 = 0, std::int32_t i3 = 0); + + /** + * Creates a 128-bit SIMD Vector from 2 64-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + */ + explicit integer32_s(std::int64_t i0 = 0, std::int64_t i1 = 0); + + explicit integer32_s(i32x4 v); + + integer32_s(const integer32&) = default; + integer32_s(integer32&&) = default; + auto operator=(const integer32&) -> integer32& = default; + + /** + * Creates a 128-bit SIMD Vector using a single 32-bit integer for each of the elements. + * @param v Value to duplicate into all elements. + */ + static auto constant(std::int32_t v) -> integer32_s; + + // MARK: - Accessors + auto operator[] (int i) const -> std::int32_t; + auto set(int i, std::int32_t v) -> integer32_s&; + + // MARK: - Operators + auto operator+ (const integer32& other) const -> integer32_s; + auto operator+ (std::int32_t i) const -> integer32; + auto operator+=(const integer32& other) -> integer32&; + auto operator+=(std::int32_t i) -> integer32&; + + auto operator- (const integer32& other) const -> integer32; + auto operator- (std::int32_t i) const -> integer32; + auto operator-=(const integer32& other) -> integer32&; + auto operator-=(std::int32_t i) -> integer32&; + + auto operator* (const integer32& other) const -> integer32; + auto operator* (std::int32_t i) const -> integer32; + auto operator* (float f) const -> integer32; + auto operator*=(const integer32& other) -> integer32&; + auto operator*=(std::int32_t i) -> integer32&; + auto operator*=(float f) -> integer32&; + + auto operator/ (const integer32& other) const -> integer32; + auto operator/ (std::int32_t i) const -> integer32; + auto operator/ (float f) const -> integer32; + auto operator/=(const integer32& other) -> integer32&; + auto operator/=(std::int32_t i) -> integer32&; + auto operator/=(float f) -> integer32&; + + auto operator& (const integer32& other) const -> integer32; + auto operator& (std::int32_t i) const -> integer32; + auto operator&=(const integer32& other) -> integer32&; + auto operator&=(std::int32_t i) -> integer32&; + + auto operator| (const integer32& other) const -> integer32; + auto operator| (std::int32_t i) const -> integer32; + auto operator|=(const integer32& other) -> integer32&; + auto operator|=(std::int32_t i) -> integer32&; + + auto operator^ (const integer32& other) const -> integer32; + auto operator^ (std::int32_t i) const -> integer32; + auto operator^=(const integer32& other) -> integer32&; + auto operator^=(std::int32_t i) -> integer32&; + + auto operator<<(const integer32& other) const -> integer32; + auto operator<<(std::int32_t i) const -> integer32; + auto operator<<=(const integer32& other) -> integer32&; + auto operator<<=(std::int32_t i) -> integer32&; + + auto operator>>(const integer32& other) const -> integer32; + auto operator>>(std::int32_t i) const -> integer32; + auto operator>>=(const integer32& other) -> integer32&; + auto operator>>=(std::int32_t i) -> integer32&; + + auto operator~() const -> integer32; + + [[nodiscard]] auto abs() const -> integer32; + + friend struct integer8_s; + friend struct integer16_s; + friend struct integer64_s; + friend struct float_s; + friend struct double_s; + + private: + std::int32_t __attribute__((__aligned__(16))) m_values[element_count]; + + [[nodiscard]] auto vector() const -> i32x4; + auto set(i32x4 v) -> void; + }; +} \ No newline at end of file diff --git a/libs/libSIMD/integer64.hpp b/libs/libSIMD/integer64.hpp new file mode 100644 index 0000000..bae63a6 --- /dev/null +++ b/libs/libSIMD/integer64.hpp @@ -0,0 +1,176 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace simd +{ + struct integer64_s; + typedef struct integer64_s integer64; + + struct integer64_s + { + static constexpr std::int32_t element_count = 2; + + // MARK: - Construction + + /** + * Creates a 128-bit SIMD Vector from 16 8-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + * @param i8 Element 9 + * @param i9 Element 10 + * @param i10 Element 11 + * @param i11 Element 12 + * @param i12 Element 13 + * @param i13 Element 14 + * @param i14 Element 15 + * @param i16 Element 16 + */ + explicit integer64_s( + std::int8_t i0 = 0, std::int8_t i1 = 0, std::int8_t i2 = 0, std::int8_t i3 = 0, + std::int8_t i4 = 0, std::int8_t i5 = 0, std::int8_t i6 = 0, std::int8_t i7 = 0, + std::int8_t i8 = 0, std::int8_t i9 = 0, std::int8_t i10 = 0, std::int8_t i11 = 0, + std::int8_t i12 = 0, std::int8_t i13 = 0, std::int8_t i14 = 0, std::int8_t i15 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 8 16-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + */ + explicit integer64_s( + std::int16_t i0 = 0, std::int16_t i1 = 0, std::int16_t i2 = 0, std::int16_t i3 = 0, + std::int16_t i4 = 0, std::int16_t i5 = 0, std::int16_t i6 = 0, std::int16_t i7 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 4 32-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + */ + explicit integer64_s(std::int32_t i0 = 0, std::int32_t i1 = 0, std::int32_t i2 = 0, std::int32_t i3 = 0); + + /** + * Creates a 128-bit SIMD Vector from 2 64-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + */ + explicit integer64_s(std::int64_t i0 = 0, std::int64_t i1 = 0); + + explicit integer64_s(i64x2 v); + + integer64_s(const integer64&) = default; + integer64_s(integer64&&) = default; + auto operator=(const integer64&) -> integer64& = default; + + /** + * Creates a 128-bit SIMD Vector using a single 64-bit integer for each of the elements. + * @param v Value to duplicate into all elements. + */ + static auto constant(std::int64_t v) -> integer64_s; + + // MARK: - Accessors + auto operator[] (int i) const -> std::int64_t; + auto set(int i, std::int64_t v) -> integer64_s&; + + // MARK: - Operators + auto operator+ (const integer64& other) const -> integer64_s; + auto operator+ (std::int64_t i) const -> integer64; + auto operator+=(const integer64& other) -> integer64&; + auto operator+=(std::int64_t i) -> integer64&; + + auto operator- (const integer64& other) const -> integer64; + auto operator- (std::int64_t i) const -> integer64; + auto operator-=(const integer64& other) -> integer64&; + auto operator-=(std::int64_t i) -> integer64&; + + auto operator* (const integer64& other) const -> integer64; + auto operator* (std::int64_t i) const -> integer64; + auto operator* (float f) const -> integer64; + auto operator*=(const integer64& other) -> integer64&; + auto operator*=(std::int64_t i) -> integer64&; + auto operator*=(float f) -> integer64&; + + auto operator/ (const integer64& other) const -> integer64; + auto operator/ (std::int64_t i) const -> integer64; + auto operator/ (float f) const -> integer64; + auto operator/=(const integer64& other) -> integer64&; + auto operator/=(std::int64_t i) -> integer64&; + auto operator/=(float f) -> integer64&; + + auto operator& (const integer64& other) const -> integer64; + auto operator& (std::int64_t i) const -> integer64; + auto operator&=(const integer64& other) -> integer64&; + auto operator&=(std::int64_t i) -> integer64&; + + auto operator| (const integer64& other) const -> integer64; + auto operator| (std::int64_t i) const -> integer64; + auto operator|=(const integer64& other) -> integer64&; + auto operator|=(std::int64_t i) -> integer64&; + + auto operator^ (const integer64& other) const -> integer64; + auto operator^ (std::int64_t i) const -> integer64; + auto operator^=(const integer64& other) -> integer64&; + auto operator^=(std::int64_t i) -> integer64&; + + auto operator<<(const integer64& other) const -> integer64; + auto operator<<(std::int64_t i) const -> integer64; + auto operator<<=(const integer64& other) -> integer64&; + auto operator<<=(std::int64_t i) -> integer64&; + + auto operator>>(const integer64& other) const -> integer64; + auto operator>>(std::int64_t i) const -> integer64; + auto operator>>=(const integer64& other) -> integer64&; + auto operator>>=(std::int64_t i) -> integer64&; + + auto operator~() const -> integer64; + + [[nodiscard]] auto abs() const -> integer64; + + friend struct integer8_s; + friend struct integer16_s; + friend struct integer32_s; + friend struct float_s; + friend struct double_s; + + private: + std::int64_t __attribute__((__aligned__(16))) m_values[element_count]; + + [[nodiscard]] auto vector() const -> i64x2; + auto set(i64x2 v) -> void; + }; +} \ No newline at end of file diff --git a/libs/libSIMD/integer8.hpp b/libs/libSIMD/integer8.hpp new file mode 100644 index 0000000..763f6ca --- /dev/null +++ b/libs/libSIMD/integer8.hpp @@ -0,0 +1,169 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace simd +{ + struct integer8_s; + typedef struct integer8_s integer8; + + struct integer8_s + { + static constexpr std::int32_t element_count = 16; + + // MARK: - Construction + + integer8_s() = default; + + /** + * Creates a 128-bit SIMD Vector from 16 8-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + * @param i8 Element 9 + * @param i9 Element 10 + * @param i10 Element 11 + * @param i11 Element 12 + * @param i12 Element 13 + * @param i13 Element 14 + * @param i14 Element 15 + * @param i16 Element 16 + */ + explicit integer8_s( + std::int8_t i0, std::int8_t i1 = 0, std::int8_t i2 = 0, std::int8_t i3 = 0, + std::int8_t i4 = 0, std::int8_t i5 = 0, std::int8_t i6 = 0, std::int8_t i7 = 0, + std::int8_t i8 = 0, std::int8_t i9 = 0, std::int8_t i10 = 0, std::int8_t i11 = 0, + std::int8_t i12 = 0, std::int8_t i13 = 0, std::int8_t i14 = 0, std::int8_t i15 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 8 16-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + * @param i4 Element 5 + * @param i5 Element 6 + * @param i6 Element 7 + * @param i7 Element 8 + */ + explicit integer8_s( + std::int16_t i0, std::int16_t i1 = 0, std::int16_t i2 = 0, std::int16_t i3 = 0, + std::int16_t i4 = 0, std::int16_t i5 = 0, std::int16_t i6 = 0, std::int16_t i7 = 0 + ); + + /** + * Creates a 128-bit SIMD Vector from 4 32-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + * @param i2 Element 3 + * @param i3 Element 4 + */ + explicit integer8_s(std::int32_t i0, std::int32_t i1 = 0, std::int32_t i2 = 0, std::int32_t i3 = 0); + + /** + * Creates a 128-bit SIMD Vector from 2 64-bit integers. + * @param i0 Element 1 + * @param i1 Element 2 + */ + explicit integer8_s(std::int64_t i0, std::int64_t i1 = 0); + + explicit integer8_s(i8x16 v); + + integer8_s(const integer8_s&) = default; + integer8_s(integer8_s&&) = default; + auto operator=(const integer8&) -> integer8& = default; + + /** + * Creates a 128-bit SIMD Vector using a single 8-bit integer for each of the elements. + * @param v Value to duplicate into all elements. + */ + static auto constant(std::int8_t v) -> integer8; + + // MARK: - Accessors + auto operator[] (int i) const -> std::int8_t; + auto set(int i, std::int8_t v) -> integer8&; + + // MARK: - Operators + auto operator+ (const integer8& other) const -> integer8; + auto operator+ (std::int8_t i) const -> integer8; + auto operator+=(const integer8& other) -> integer8&; + auto operator+=(std::int8_t i) -> integer8&; + + auto operator- (const integer8& other) const -> integer8; + auto operator- (std::int8_t i) const -> integer8; + auto operator-=(const integer8& other) -> integer8&; + auto operator-=(std::int8_t i) -> integer8&; + + APPROX_VALUE auto operator* (const integer8& other) const -> integer8; + APPROX_VALUE auto operator* (std::int8_t i) const -> integer8; + APPROX_VALUE auto operator* (float f) const -> integer8; + APPROX_VALUE auto operator*=(const integer8& other) -> integer8&; + APPROX_VALUE auto operator*=(std::int8_t i) -> integer8&; + APPROX_VALUE auto operator*=(float f) -> integer8&; + + APPROX_VALUE auto operator/ (const integer8& other) const -> integer8; + APPROX_VALUE auto operator/ (std::int8_t i) const -> integer8; + APPROX_VALUE auto operator/ (float f) const -> integer8; + APPROX_VALUE auto operator/=(const integer8& other) -> integer8&; + APPROX_VALUE auto operator/=(std::int8_t i) -> integer8&; + APPROX_VALUE auto operator/=(float f) -> integer8&; + + auto operator& (const integer8& other) const -> integer8; + auto operator& (std::int8_t i) const -> integer8; + auto operator&=(const integer8& other) -> integer8&; + auto operator&=(std::int8_t i) -> integer8&; + + auto operator| (const integer8& other) const -> integer8; + auto operator| (std::int8_t i) const -> integer8; + auto operator|=(const integer8& other) -> integer8&; + auto operator|=(std::int8_t i) -> integer8&; + + auto operator^ (const integer8& other) const -> integer8; + auto operator^ (std::int8_t i) const -> integer8; + auto operator^=(const integer8& other) -> integer8&; + auto operator^=(std::int8_t i) -> integer8&; + + auto operator~() const -> integer8; + + [[nodiscard]] auto abs() const -> integer8; + + friend struct integer16_s; + friend struct integer32_s; + friend struct integer64_s; + friend struct float32_s; + friend struct double64_s; + + private: + std::int8_t __attribute__((__aligned__(16))) m_values[element_count] { 0 }; + + [[nodiscard]] auto vector() const -> i8x16; + auto set(i8x16 v) -> void; + }; +} \ No newline at end of file diff --git a/libs/libSIMD/intel/float64.cpp b/libs/libSIMD/intel/float64.cpp new file mode 100644 index 0000000..6edfad7 --- /dev/null +++ b/libs/libSIMD/intel/float64.cpp @@ -0,0 +1,297 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +#if INTEL_SIMD +#include +#include +#include + +// MARK: - Construction + +simd::float64_s::float64_s(double f0, double f1) +{ + m_values[0] = f0; + m_values[1] = f1; +} + +simd::float64_s::float64_s(f64x2 v) +{ + _mm_store_pd(&m_values[0], v); +} + +auto simd::float64_s::constant(double v) -> float64 +{ + return float64(_mm_set1_ps(v)); +} + +auto simd::float64_s::lower_upper_merge(const float64 &lower, const float64 &upper) -> float64 +{ + return float64(lower[0], upper[1]); +} + +auto simd::float64_s::lower(const float64& lower) -> float64 +{ + return float64(lower[0], lower[0]); +} + +auto simd::float64_s::upper(const float64& upper) -> float64 +{ + return float64(upper[1], upper[1]); +} + +// MARK: - Accessors + +auto simd::float64_s::operator[](int i) const -> double +{ + assert(i >= 0 && i < element_count); + return m_values[element_count - 1 - i]; +} + +auto simd::float64_s::set(int i, double f) -> float64& +{ + assert(i >= 0 && i < element_count); + m_values[element_count - 1 - i] = f; + return *this; +} + +auto simd::float64_s::vector() const -> f64x2 +{ + return _mm_loadu_pd(&m_values[0]); +} + +auto simd::float64_s::set(f64x2 v) -> void +{ + _mm_storeu_pd(&m_values[0], v); +} + +// MARK: - Operators + +auto simd::float64_s::operator+ (const float64& other) const -> float64 +{ + return float64(_mm_add_pd(vector(), other.vector())); +} + +auto simd::float64_s::operator+ (double f) const -> float64 +{ + return *this + float64::constant(f); +} + +auto simd::float64_s::operator+=(const float64& other) -> float64& +{ + set((*this + other).vector()); + return *this; +} + +auto simd::float64_s::operator+=(double f) -> float64& +{ + set((*this + float64::constant(f)).vector()); + return *this; +} + +auto simd::float64_s::operator- (const float64& other) const -> float64 +{ + return float64(_mm_sub_pd(vector(), other.vector())); +} + +auto simd::float64_s::operator- (double f) const -> float64 +{ + return *this - float64::constant(f); +} + +auto simd::float64_s::operator-=(const float64& other) -> float64& +{ + set((*this - other).vector()); + return *this; +} + +auto simd::float64_s::operator-=(double f) -> float64& +{ + set((*this - float64::constant(f)).vector()); + return *this; +} + +auto simd::float64_s::operator* (const float64& other) const -> float64 +{ + return float64(_mm_mul_pd(vector(), other.vector())); +} + +auto simd::float64_s::operator* (double f) const -> float64 +{ + return *this * float64::constant(f); +} + +auto simd::float64_s::operator*=(const float64& other) -> float64& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::float64_s::operator*=(double f) -> float64& +{ + set((*this * float64::constant(f)).vector()); + return *this; +} + +auto simd::float64_s::operator/ (const float64& other) const -> float64 +{ + return float64(_mm_div_pd(vector(), other.vector())); +} + +auto simd::float64_s::operator/ (double f) const -> float64 +{ + return *this / float64::constant(f); +} + +auto simd::float64_s::operator/=(const float64& other) -> float64& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::float64_s::operator/=(double f) -> float64& +{ + set((*this / float64::constant(f)).vector()); + return *this; +} + +// MARK: - Operations + +auto simd::float64_s::abs() const -> float64 +{ + // TODO: Implement this + return *this; +} + +auto simd::float64_s::round() const -> float64 +{ + return float64(_mm_round_pd(vector(), _MM_ROUND_NEAREST)); +} + +auto simd::float64_s::floor() const -> float64 +{ + return float64(_mm_floor_pd(vector())); +} + +auto simd::float64_s::ceil() const -> float64 +{ + return float64(_mm_ceil_pd(vector())); +} + +auto simd::float64_s::pow(double exp) const -> float64 +{ + if (exp == 2.0) { + auto v = vector(); + return float64(_mm_mul_pd(v, v)); + } + else { + // TODO: Find an implementation that uses SSE/AVX in the future + double v[element_count]; + for (auto n = 0; n < element_count; ++n) { + v[n] = std::pow(m_values[n], m_values[n]); + } + return float64(v[0], v[1]); + } +} + +auto simd::float64_s::sqrt() const -> float64 +{ + return float64(_mm_sqrt_pd(vector())); +} + +auto simd::float64_s::sin() const -> float64 +{ + // TODO: Find an implementation that uses SSE/AVX in the future + double v[element_count]; + for (auto n = 0; n < element_count; ++n) { + v[n] = std::sin(m_values[n]); + } + return float64(v[0], v[1]); +} + +auto simd::float64_s::cos() const -> float64 +{ + // TODO: Find an implementation that uses SSE/AVX in the future + double v[element_count]; + for (auto n = 0; n < element_count; ++n) { + v[n] = std::cos(m_values[n]); + } + return float64(v[0], v[1]); +} + +auto simd::float64_s::rcp() const -> float64 +{ + // TODO: Implement this + return *this; +} + +auto simd::float64_s::min(const float64 &other) const -> float64 +{ + return float64(_mm_min_pd(vector(), other.vector())); +} + +auto simd::float64_s::min(double f) const -> float64 +{ + return float64(_mm_min_pd(vector(), float64::constant(f).vector())); +} + +auto simd::float64_s::max(const float64 &other) const -> float64 +{ + return float64(_mm_max_pd(vector(), other.vector())); +} + +auto simd::float64_s::max(double f) const -> float64 +{ + return float64(_mm_max_pd(vector(), float64::constant(f).vector())); +} + +auto simd::float64_s::upper() const -> float64 +{ + return float64(m_values[1], m_values[1]); +} + +auto simd::float64_s::lower() const -> float64 +{ + return float64(m_values[0], m_values[0]); +} + +auto simd::float64_s::swapped() const -> float64 +{ + return float64(m_values[1], m_values[0]); +} + +auto simd::float64_s::reversed() const -> float64 +{ + return float64(m_values[1], m_values[0]); +} + +auto simd::float64_s::set_lower(const float64& lower) -> void +{ + m_values[0] = lower[0]; +} + +auto simd::float64_s::set_upper(const float64& upper) -> void +{ + m_values[1] = upper[1]; +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/intel/integer16.cpp b/libs/libSIMD/intel/integer16.cpp new file mode 100644 index 0000000..e5a1e7d --- /dev/null +++ b/libs/libSIMD/intel/integer16.cpp @@ -0,0 +1,374 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if INTEL_SIMD +#include +#include +#include + +// MARK: - Construction + +simd::integer16_s::integer16_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi8(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15)); +} + +simd::integer16_s::integer16_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi16(i0, i1, i2, i3, i4, i5, i6, i7)); +} + +simd::integer16_s::integer16_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi32(i0, i1, i2, i3)); +} + +simd::integer16_s::integer16_s(std::int64_t i0, std::int64_t i1) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi64x(i0, i1)); +} + +simd::integer16_s::integer16_s(i16x8 v) +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +auto simd::integer16_s::constant(std::int16_t v) -> integer16 +{ + return integer16(_mm_set1_epi16(v)); +} + +// MARK: - Accessors + +auto simd::integer16_s::operator[](int i) const -> std::int16_t +{ + assert(i >= 0 && i < element_count); + return m_values[element_count - 1 - i]; +} + +auto simd::integer16_s::set(int i, std::int16_t v) -> integer16& +{ + assert(i >= 0 && i < element_count); + m_values[element_count - 1 - i] = v; + return *this; +} + +auto simd::integer16_s::vector() const -> i16x8 +{ + return _mm_loadu_si16((__m128i *)&m_values[0]); +} + +auto simd::integer16_s::set(i8x16 v) -> void +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer16_s::operator+(const integer16& other) const -> integer16 +{ + return integer16(_mm_add_epi16(vector(), other.vector())); +} + +auto simd::integer16_s::operator+(std::int16_t i) const -> integer16 +{ + return *this + integer16::constant(i); +} + +auto simd::integer16_s::operator+=(const integer16& other) -> integer16& +{ + set(_mm_add_epi16(vector(), other.vector())); + return *this; +} + +auto simd::integer16_s::operator+=(std::int16_t i) -> integer16 & +{ + set(_mm_add_epi16(vector(), integer16::constant(i).vector())); + return *this; +} + +auto simd::integer16_s::operator-(const integer16& other) const -> integer16 +{ + return integer16(_mm_sub_epi16(vector(), other.vector())); +} + +auto simd::integer16_s::operator-(std::int16_t i) const -> integer16 +{ + return *this - integer16::constant(i); +} + +auto simd::integer16_s::operator-=(const integer16& other) -> integer16& +{ + set(_mm_sub_epi16(vector(), other.vector())); + return *this; +} + +auto simd::integer16_s::operator-=(std::int16_t i) -> integer16 & +{ + set(_mm_sub_epi16(vector(), integer16::constant(i).vector())); + return *this; +} + +auto simd::integer16_s::operator*(const integer16& other) const -> integer16 +{ + // Load the source and destinations + auto s1 = _mm_loadu_si16((__m128i *)&m_values[0]); + auto d1 = _mm_loadu_si16((__m128i *)&other.m_values[0]); + auto r1 = _mm_mullo_epi16(s1, d1); + return integer16(r1); +} + +auto simd::integer16_s::operator*(std::int16_t i) const -> integer16 +{ + return *this * integer16::constant(i); +} + +auto simd::integer16_s::operator*=(const integer16& other) -> integer16& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer16_s::operator*=(std::int16_t i) -> integer16 & +{ + set((*this * integer16::constant(i)).vector()); + return *this; +} + +auto simd::integer16::operator*(float f) const -> integer16 +{ + // Load the source and destinations + __m128i r1; + auto op = _mm_set1_ps(f); + auto s1 = _mm_castsi128_ps(_mm_loadu_si32((__m128i *)&m_values[0])); + auto s2 = _mm_castsi128_ps(_mm_loadu_si32((__m128i *)&m_values[4])); + s1 = _mm_mul_ps(s1, op); + s2 = _mm_mul_ps(s2, op); + + auto d1 = _mm_castps_si128(s1); + auto d2 = _mm_castps_si128(s2); + d1 = _mm_and_si128(d1, _mm_set1_epi32(0x0000FFFF)); + d2 = _mm_and_si128(d2, _mm_set1_epi32(0x0000FFFF)); + d2 = _mm_sll_epi32(d2, _mm_set1_epi32(16)); + r1 = _mm_or_si128(d1, d2); + return integer16(r1); +} + +auto simd::integer16_s::operator*=(float f) -> integer16& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer16_s::operator/(const integer16& other) const -> integer16 +{ + // Load the source and destinations + __m128i r1; + auto s1 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&m_values[0])); + auto s2 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&m_values[4])); + auto op1 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&other.m_values[0])); + auto op2 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&other.m_values[4])); + s1 = _mm_div_ps(s1, op1); + s2 = _mm_div_ps(s2, op2); + + auto d1 = _mm_castps_si128(s1); + auto d2 = _mm_castps_si128(s2); + d1 = _mm_and_si128(d1, _mm_set1_epi32(0x0000FFFF)); + d2 = _mm_and_si128(d2, _mm_set1_epi32(0x0000FFFF)); + d2 = _mm_sll_epi32(d2, _mm_set1_epi32(16)); + r1 = _mm_or_si128(d1, d2); + return integer16(r1); +} + +auto simd::integer16_s::operator/(std::int16_t i) const -> integer16 +{ + return *this / integer16::constant(i); +} + +auto simd::integer16_s::operator/=(const integer16& other) -> integer16& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer16_s::operator/=(std::int16_t i) -> integer16 & +{ + set((*this / integer16::constant(i)).vector()); + return *this; +} + +auto simd::integer16_s::operator/(float f) const -> integer16 +{ + // Load the source and destinations + __m128i r1; + auto op = _mm_set1_ps(f); + auto s1 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&m_values[0])); + auto s2 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&m_values[4])); + s1 = _mm_div_ps(s1, op); + s2 = _mm_div_ps(s2, op); + + auto d1 = _mm_castps_si128(s1); + auto d2 = _mm_castps_si128(s2); + d1 = _mm_and_si128(d1, _mm_set1_epi32(0x0000FFFF)); + d2 = _mm_and_si128(d2, _mm_set1_epi32(0x0000FFFF)); + d2 = _mm_sll_epi32(d2, _mm_set1_epi32(16)); + r1 = _mm_or_si128(d1, d2); + return integer16(r1); +} + +auto simd::integer16_s::operator/=(float f) -> integer16& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer16_s::operator&(const integer16& other) const -> integer16 +{ + return integer16(_mm_and_si128(vector(), other.vector())); +} + +auto simd::integer16_s::operator&(std::int16_t i) const -> integer16 +{ + return *this & integer16::constant(i); +} + +auto simd::integer16_s::operator&=(const integer16& other) -> integer16& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer16_s::operator&=(std::int16_t i) -> integer16& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer16_s::operator|(const integer16& other) const -> integer16 +{ + return integer16(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer16_s::operator|(std::int16_t i) const -> integer16 +{ + return *this | integer16::constant(i); +} + +auto simd::integer16_s::operator|=(const integer16& other) -> integer16& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer16_s::operator|=(std::int16_t i) -> integer16& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer16_s::operator^(const integer16& other) const -> integer16 +{ + return integer16(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer16_s::operator^(std::int16_t i) const -> integer16 +{ + return *this ^ integer16::constant(i); +} + +auto simd::integer16_s::operator^=(const integer16& other) -> integer16& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer16_s::operator^=(std::int16_t i) -> integer16& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer16_s::operator~() const -> integer16 +{ + return integer16(_mm_xor_si128(vector(), _mm_set1_epi16(0xFF))); +} + +auto simd::integer16_s::operator<<(const integer16& other) const -> integer16 +{ + auto s1 = _mm_loadu_si128((__m128i *)&m_values[0]); + auto d1 = _mm_loadu_si128((__m128i *)&other.m_values[0]); + auto r1 = _mm_sll_epi16(s1, d1); + return integer16(r1); +} + +auto simd::integer16_s::operator<<(std::int16_t i) const -> integer16 +{ + return *this << integer16::constant(i); +} + +auto simd::integer16_s::operator<<=(const integer16& other) -> integer16& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer16_s::operator<<=(std::int16_t i) -> integer16& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer16_s::operator>>(const integer16& other) const -> integer16 +{ + auto s1 = _mm_loadu_si128((__m128i *)&m_values[0]); + auto d1 = _mm_loadu_si128((__m128i *)&other.m_values[0]); + auto r1 = _mm_sra_epi16(s1, d1); + return integer16(r1); +} + +auto simd::integer16_s::operator>>(std::int16_t i) const -> integer16 +{ + return *this << integer16::constant(i); +} + +auto simd::integer16_s::operator>>=(const integer16& other) -> integer16& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer16_s::operator>>=(std::int16_t i) -> integer16& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer16_s::abs() const -> integer16 +{ + return integer16(_mm_abs_epi16(vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/intel/integer32.cpp b/libs/libSIMD/intel/integer32.cpp new file mode 100644 index 0000000..f090817 --- /dev/null +++ b/libs/libSIMD/intel/integer32.cpp @@ -0,0 +1,343 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if INTEL_SIMD +#include +#include +#include + +// MARK: - Construction + +simd::integer32_s::integer32_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi8(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15)); +} + +simd::integer32_s::integer32_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi16(i0, i1, i2, i3, i4, i5, i6, i7)); +} + +simd::integer32_s::integer32_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi32(i0, i1, i2, i3)); +} + +simd::integer32_s::integer32_s(std::int64_t i0, std::int64_t i1) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi64x(i0, i1)); +} + +simd::integer32_s::integer32_s(i32x4 v) +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +auto simd::integer32_s::constant(std::int32_t v) -> integer32 +{ + return integer32(_mm_set1_epi32(v)); +} + +// MARK: - Accessors + +auto simd::integer32_s::operator[](int i) const -> std::int32_t +{ + assert(i >= 0 && i < element_count); + return m_values[element_count - 1 - i]; +} + +auto simd::integer32_s::set(int i, std::int32_t v) -> integer32& +{ + assert(i >= 0 && i < element_count); + m_values[element_count - 1 - i] = v; + return *this; +} + +auto simd::integer32_s::vector() const -> i32x4 +{ + return _mm_loadu_si32((__m128i *)&m_values[0]); +} + +auto simd::integer32_s::set(i32x4 v) -> void +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer32_s::operator+(const integer32& other) const -> integer32 +{ + return integer32(_mm_add_epi32(vector(), other.vector())); +} + +auto simd::integer32_s::operator+(std::int32_t i) const -> integer32 +{ + return *this + integer32::constant(i); +} + +auto simd::integer32_s::operator+=(const integer32& other) -> integer32& +{ + set(_mm_add_epi32(vector(), other.vector())); + return *this; +} + +auto simd::integer32_s::operator+=(std::int32_t i) -> integer32 & +{ + set(_mm_add_epi32(vector(), integer32::constant(i).vector())); + return *this; +} + +auto simd::integer32_s::operator-(const integer32& other) const -> integer32 +{ + return integer32(_mm_sub_epi32(vector(), other.vector())); +} + +auto simd::integer32_s::operator-(std::int32_t i) const -> integer32 +{ + return *this - integer32::constant(i); +} + +auto simd::integer32_s::operator-=(const integer32& other) -> integer32& +{ + set(_mm_sub_epi16(vector(), other.vector())); + return *this; +} + +auto simd::integer32_s::operator-=(std::int32_t i) -> integer32 & +{ + set(_mm_sub_epi32(vector(), integer32::constant(i).vector())); + return *this; +} + +auto simd::integer32_s::operator*(const integer32& other) const -> integer32 +{ + // Load the source and destinations + auto s1 = _mm_loadu_si32((__m128i *)&m_values[0]); + auto d1 = _mm_loadu_si32((__m128i *)&other.m_values[0]); + auto r1 = _mm_mullo_epi32(s1, d1); + return integer32(r1); +} + +auto simd::integer32_s::operator*(std::int32_t i) const -> integer32 +{ + return *this * integer32::constant(i); +} + +auto simd::integer32_s::operator*=(const integer32& other) -> integer32& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer32_s::operator*=(std::int32_t i) -> integer32 & +{ + set((*this * integer32::constant(i)).vector()); + return *this; +} + +auto simd::integer32::operator*(float f) const -> integer32 +{ + // Load the source and destinations + auto s1 = _mm_castsi128_ps(_mm_loadu_si32((__m128i *)&m_values[0])); + auto op = _mm_set1_ps(f); + auto d1 = _mm_mul_ps(s1, op); + return integer32(_mm_castps_si128(d1)); +} + +auto simd::integer32_s::operator*=(float f) -> integer32& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer32_s::operator/(const integer32& other) const -> integer32 +{ + // Load the source and destinations + auto s1 = _mm_castsi128_ps(_mm_loadu_si32((__m128i *)&m_values[0])); + auto op = _mm_castsi128_ps(_mm_loadu_si32((__m128i *)&other.m_values[0])); + auto d1 = _mm_div_ps(s1, op); + return integer32(_mm_castps_si128(d1)); +} + +auto simd::integer32_s::operator/(std::int32_t i) const -> integer32 +{ + return *this / integer32::constant(i); +} + +auto simd::integer32_s::operator/=(const integer32& other) -> integer32& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer32_s::operator/=(std::int32_t i) -> integer32 & +{ + set((*this / integer32::constant(i)).vector()); + return *this; +} + +auto simd::integer32_s::operator/(float f) const -> integer32 +{ + // Load the source and destinations + auto s1 = _mm_castsi128_ps(_mm_loadu_si32((__m128i *)&m_values[0])); + auto op = _mm_set1_ps(f); + auto d1 = _mm_div_ps(s1, op); + return integer32(_mm_castps_si128(d1)); +} + +auto simd::integer32_s::operator/=(float f) -> integer32& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer32_s::operator&(const integer32& other) const -> integer32 +{ + return integer32(_mm_and_si128(vector(), other.vector())); +} + +auto simd::integer32_s::operator&(std::int32_t i) const -> integer32 +{ + return *this & integer32::constant(i); +} + +auto simd::integer32_s::operator&=(const integer32& other) -> integer32& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer32_s::operator&=(std::int32_t i) -> integer32& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer32_s::operator|(const integer32& other) const -> integer32 +{ + return integer32(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer32_s::operator|(std::int32_t i) const -> integer32 +{ + return *this | integer32::constant(i); +} + +auto simd::integer32_s::operator|=(const integer32& other) -> integer32& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer32_s::operator|=(std::int32_t i) -> integer32& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer32_s::operator^(const integer32& other) const -> integer32 +{ + return integer32(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer32_s::operator^(std::int32_t i) const -> integer32 +{ + return *this ^ integer32::constant(i); +} + +auto simd::integer32_s::operator^=(const integer32& other) -> integer32& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer32_s::operator^=(std::int32_t i) -> integer32& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer32_s::operator~() const -> integer32 +{ + return integer32(_mm_xor_si128(vector(), _mm_set1_epi32(0xFFFFFFFF))); +} + +auto simd::integer32_s::operator<<(const integer32& other) const -> integer32 +{ + auto s1 = _mm_loadu_si32((__m128i *)&m_values[0]); + auto d1 = _mm_loadu_si32((__m128i *)&other.m_values[0]); + auto r1 = _mm_sll_epi32(s1, d1); + return integer32(r1); +} + +auto simd::integer32_s::operator<<(std::int32_t i) const -> integer32 +{ + return *this << integer32::constant(i); +} + +auto simd::integer32_s::operator<<=(const integer32& other) -> integer32& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer32_s::operator<<=(std::int32_t i) -> integer32& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer32_s::operator>>(const integer32& other) const -> integer32 +{ + auto s1 = _mm_loadu_si32((__m128i *)&m_values[0]); + auto d1 = _mm_loadu_si32((__m128i *)&other.m_values[0]); + auto r1 = _mm_sra_epi32(s1, d1); + return integer32(r1); +} + +auto simd::integer32_s::operator>>(std::int32_t i) const -> integer32 +{ + return *this << integer32::constant(i); +} + +auto simd::integer32_s::operator>>=(const integer32& other) -> integer32& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer32_s::operator>>=(std::int32_t i) -> integer32& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer32_s::abs() const -> integer32 +{ + return integer32(_mm_abs_epi32(vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/intel/integer64.cpp b/libs/libSIMD/intel/integer64.cpp new file mode 100644 index 0000000..7512e18 --- /dev/null +++ b/libs/libSIMD/intel/integer64.cpp @@ -0,0 +1,339 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if INTEL_SIMD +#include +#include +#include + +// MARK: - Construction + +simd::integer64_s::integer64_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi8(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15)); +} + +simd::integer64_s::integer64_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi16(i0, i1, i2, i3, i4, i5, i6, i7)); +} + +simd::integer64_s::integer64_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi32(i0, i1, i2, i3)); +} + +simd::integer64_s::integer64_s(std::int64_t i0, std::int64_t i1) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi64x(i0, i1)); +} + +simd::integer64_s::integer64_s(i64x2 v) +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +auto simd::integer64_s::constant(std::int64_t v) -> integer64 +{ + return integer64(_mm_set1_epi64x(v)); +} + +// MARK: - Accessors + +auto simd::integer64_s::operator[](int i) const -> std::int64_t +{ + assert(i >= 0 && i < element_count); + return m_values[element_count - 1 - i]; +} + +auto simd::integer64_s::set(int i, std::int64_t v) -> integer64& +{ + assert(i >= 0 && i < element_count); + m_values[element_count - 1 - i] = v; + return *this; +} + +auto simd::integer64_s::vector() const -> i64x2 +{ + return _mm_loadu_si64((__m128i *)&m_values[0]); +} + +auto simd::integer64_s::set(i64x2 v) -> void +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer64_s::operator+(const integer64& other) const -> integer64 +{ + return integer64(_mm_add_epi64(vector(), other.vector())); +} + +auto simd::integer64_s::operator+(std::int64_t i) const -> integer64 +{ + return *this + integer64::constant(i); +} + +auto simd::integer64_s::operator+=(const integer64& other) -> integer64& +{ + set(_mm_add_epi64(vector(), other.vector())); + return *this; +} + +auto simd::integer64_s::operator+=(std::int64_t i) -> integer64 & +{ + set(_mm_add_epi64(vector(), integer64::constant(i).vector())); + return *this; +} + +auto simd::integer64_s::operator-(const integer64& other) const -> integer64 +{ + return integer64(_mm_sub_epi64(vector(), other.vector())); +} + +auto simd::integer64_s::operator-(std::int64_t i) const -> integer64 +{ + return *this - integer64::constant(i); +} + +auto simd::integer64_s::operator-=(const integer64& other) -> integer64& +{ + set(_mm_sub_epi16(vector(), other.vector())); + return *this; +} + +auto simd::integer64_s::operator-=(std::int64_t i) -> integer64 & +{ + set(_mm_sub_epi64(vector(), integer64::constant(i).vector())); + return *this; +} + +auto simd::integer64_s::operator*(const integer64& other) const -> integer64 +{ + // TODO: Implement this + return *this; +} + +auto simd::integer64_s::operator*(std::int64_t i) const -> integer64 +{ + return *this * integer64::constant(i); +} + +auto simd::integer64_s::operator*=(const integer64& other) -> integer64& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer64_s::operator*=(std::int64_t i) -> integer64 & +{ + set((*this * integer64::constant(i)).vector()); + return *this; +} + +auto simd::integer64::operator*(float f) const -> integer64 +{ + // Load the source and destinations + auto s1 = _mm_castsi128_pd(_mm_loadu_si128((__m128i *)&m_values[0])); + auto op = _mm_set1_pd(f); + auto d1 = _mm_mul_pd(s1, op); + return integer64(_mm_castpd_si128(d1)); +} + +auto simd::integer64_s::operator*=(float f) -> integer64& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer64_s::operator/(const integer64& other) const -> integer64 +{ + // Load the source and destinations + auto s1 = _mm_castsi128_pd(_mm_loadu_si128((__m128i *)&m_values[0])); + auto op = _mm_castsi128_pd(_mm_loadu_si128((__m128i *)&other.m_values[0])); + auto d1 = _mm_div_pd(s1, op); + return integer64(_mm_castpd_si128(d1)); +} + +auto simd::integer64_s::operator/(std::int64_t i) const -> integer64 +{ + return *this / integer64::constant(i); +} + +auto simd::integer64_s::operator/=(const integer64& other) -> integer64& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer64_s::operator/=(std::int64_t i) -> integer64 & +{ + set((*this / integer64::constant(i)).vector()); + return *this; +} + +auto simd::integer64_s::operator/(float f) const -> integer64 +{ + // Load the source and destinations + auto s1 = _mm_castsi128_pd(_mm_loadu_si128((__m128i *)&m_values[0])); + auto op = _mm_set1_pd(f); + auto d1 = _mm_div_pd(s1, op); + return integer64(_mm_castpd_si128(d1)); +} + +auto simd::integer64_s::operator/=(float f) -> integer64& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer64_s::operator&(const integer64& other) const -> integer64 +{ + return integer64(_mm_and_si128(vector(), other.vector())); +} + +auto simd::integer64_s::operator&(std::int64_t i) const -> integer64 +{ + return *this & integer64::constant(i); +} + +auto simd::integer64_s::operator&=(const integer64& other) -> integer64& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer64_s::operator&=(std::int64_t i) -> integer64& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer64_s::operator|(const integer64& other) const -> integer64 +{ + return integer64(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer64_s::operator|(std::int64_t i) const -> integer64 +{ + return *this | integer64::constant(i); +} + +auto simd::integer64_s::operator|=(const integer64& other) -> integer64& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer64_s::operator|=(std::int64_t i) -> integer64& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer64_s::operator^(const integer64& other) const -> integer64 +{ + return integer64(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer64_s::operator^(std::int64_t i) const -> integer64 +{ + return *this ^ integer64::constant(i); +} + +auto simd::integer64_s::operator^=(const integer64& other) -> integer64& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer64_s::operator^=(std::int64_t i) -> integer64& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer64_s::operator~() const -> integer64 +{ + return integer64(_mm_xor_si128(vector(), _mm_set1_epi64x(0xFFFFFFFF'FFFFFFFF))); +} + +auto simd::integer64_s::operator<<(const integer64& other) const -> integer64 +{ + auto s1 = _mm_loadu_si128((__m128i *)&m_values[0]); + auto d1 = _mm_loadu_si128((__m128i *)&other.m_values[0]); + auto r1 = _mm_sll_epi64(s1, d1); + return integer64(r1); +} + +auto simd::integer64_s::operator<<(std::int64_t i) const -> integer64 +{ + return *this << integer64::constant(i); +} + +auto simd::integer64_s::operator<<=(const integer64& other) -> integer64& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer64_s::operator<<=(std::int64_t i) -> integer64& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer64_s::operator>>(const integer64& other) const -> integer64 +{ + // TODO: Implement this + return *this; +} + +auto simd::integer64_s::operator>>(std::int64_t i) const -> integer64 +{ + return *this << integer64::constant(i); +} + +auto simd::integer64_s::operator>>=(const integer64& other) -> integer64& +{ + set((*this << other).vector()); + return *this; +} + +auto simd::integer64_s::operator>>=(std::int64_t i) -> integer64& +{ + set((*this << i).vector()); + return *this; +} + +auto simd::integer64_s::abs() const -> integer64 +{ + // TODO: Implement this... + return *this; +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/intel/integer8.cpp b/libs/libSIMD/intel/integer8.cpp new file mode 100644 index 0000000..371f5af --- /dev/null +++ b/libs/libSIMD/intel/integer8.cpp @@ -0,0 +1,416 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#if INTEL_SIMD +#include +#include +#include + +// MARK: - Construction + +simd::integer8_s::integer8_s(std::int8_t i0, std::int8_t i1, std::int8_t i2, std::int8_t i3, std::int8_t i4, + std::int8_t i5, std::int8_t i6, std::int8_t i7, std::int8_t i8, std::int8_t i9, + std::int8_t i10, std::int8_t i11, std::int8_t i12, std::int8_t i13, std::int8_t i14, + std::int8_t i15) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi8(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15)); +} + +simd::integer8_s::integer8_s(std::int16_t i0, std::int16_t i1, std::int16_t i2, std::int16_t i3, std::int16_t i4, + std::int16_t i5, std::int16_t i6, std::int16_t i7) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi16(i0, i1, i2, i3, i4, i5, i6, i7)); +} + +simd::integer8_s::integer8_s(std::int32_t i0, std::int32_t i1, std::int32_t i2, std::int32_t i3) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi32(i0, i1, i2, i3)); +} + +simd::integer8_s::integer8_s(std::int64_t i0, std::int64_t i1) +{ + _mm_store_si128((__m128i *)&m_values[0], _mm_set_epi64x(i0, i1)); +} + +simd::integer8_s::integer8_s(i8x16 v) +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +auto simd::integer8_s::constant(std::int8_t v) -> integer8 +{ + return integer8(_mm_set1_epi8(v)); +} + +// MARK: - Accessors + +auto simd::integer8_s::operator[](int i) const -> std::int8_t +{ + assert(i >= 0 && i < element_count); + return m_values[element_count - 1 - i]; +} + +auto simd::integer8_s::set(int i, std::int8_t v) -> integer8& +{ + assert(i >= 0 && i < element_count); + m_values[element_count - 1 - i] = v; + return *this; +} + +auto simd::integer8_s::vector() const -> i8x16 +{ + return _mm_load_si128((__m128i *)&m_values[0]); +} + +auto simd::integer8_s::set(i8x16 v) -> void +{ + _mm_store_si128((__m128i *)&m_values[0], v); +} + +// MARK: - Operators + +auto simd::integer8_s::operator+(const integer8& other) const -> integer8 +{ + return integer8(_mm_add_epi8(vector(), other.vector())); +} + +auto simd::integer8_s::operator+(std::int8_t i) const -> integer8 +{ + return *this + integer8::constant(i); +} + +auto simd::integer8_s::operator+=(const integer8& other) -> integer8& +{ + set(_mm_add_epi8(vector(), other.vector())); + return *this; +} + +auto simd::integer8_s::operator+=(std::int8_t i) -> integer8 & +{ + set(_mm_add_epi8(vector(), integer8::constant(i).vector())); + return *this; +} + +auto simd::integer8_s::operator-(const integer8& other) const -> integer8 +{ + return integer8(_mm_sub_epi8(vector(), other.vector())); +} + +auto simd::integer8_s::operator-(std::int8_t i) const -> integer8 +{ + return *this - integer8::constant(i); +} + +auto simd::integer8_s::operator-=(const integer8& other) -> integer8& +{ + set(_mm_sub_epi8(vector(), other.vector())); + return *this; +} + +auto simd::integer8_s::operator-=(std::int8_t i) -> integer8 & +{ + set(_mm_sub_epi8(vector(), integer8::constant(i).vector())); + return *this; +} + +auto simd::integer8_s::operator*(const integer8& other) const -> integer8 +{ + std::int16_t words[element_count << 1] = { + // Source - Op1 + m_values[0], m_values[1], m_values[2], m_values[3], + m_values[4], m_values[5], m_values[6], m_values[7], + + // Source Op2 + m_values[8], m_values[9], m_values[10], m_values[11], + m_values[12], m_values[13], m_values[14], m_values[15], + + // Destination Op1 + other.m_values[0], other.m_values[1], other.m_values[2], other.m_values[3], + other.m_values[4], other.m_values[5], other.m_values[6], other.m_values[7], + + // Destination Op2 + other.m_values[8], other.m_values[9], other.m_values[10], other.m_values[11], + other.m_values[12], other.m_values[13], other.m_values[14], other.m_values[15], + }; + + // Load the source and destinations + auto s1 = _mm_loadu_si16((__m128i *)&words[0]); + auto s2 = _mm_loadu_si16((__m128i *)&words[8]); + auto d1 = _mm_loadu_si16((__m128i *)&words[16]); + auto d2 = _mm_loadu_si16((__m128i *)&words[24]); + + // Perform the calculations, and clip down to single byte values. + // Shift the second result to occupy the hi byte, and the first result to occupy the lo byte + auto r1 = _mm_and_si128(_mm_mullo_epi16(s1, d1), _mm_set1_epi32(0x00FF00FF)); + auto r2 = _mm_sll_epi32(_mm_and_si128(_mm_mullo_epi16(s2, d2), _mm_set1_epi32(0x00FF00FF)), _mm_set1_epi32(16)); + + // Merge the results + auto r = _mm_or_si128(r1, r2); + return integer8(r); +} + +auto simd::integer8_s::operator*(std::int8_t i) const -> integer8 +{ + return *this * integer8::constant(i); +} + +auto simd::integer8_s::operator*=(const integer8& other) -> integer8& +{ + set((*this * other).vector()); + return *this; +} + +auto simd::integer8_s::operator*=(std::int8_t i) -> integer8 & +{ + set((*this * integer8::constant(i)).vector()); + return *this; +} + +auto simd::integer8::operator*(float f) const -> integer8 +{ + std::int32_t words[element_count] = { + // Source - Op1 + m_values[0], m_values[1], m_values[2], m_values[3], + + // Source - Op2 + m_values[4], m_values[5], m_values[6], m_values[7], + + // Source - Op3 + m_values[8], m_values[9], m_values[10], m_values[11], + + // Source - Op4 + m_values[12], m_values[13], m_values[14], m_values[15], + }; + + // Load the source and destinations + __m128i r1, r2, r3, r4; + auto op = _mm_set1_ps(f); + auto s1 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[0])); + auto s2 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[4])); + auto s3 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[8])); + auto s4 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[12])); + r1 = _mm_castps_si128(_mm_mul_ps(s1, op)); + r2 = _mm_castps_si128(_mm_mul_ps(s2, op)); + r3 = _mm_castps_si128(_mm_mul_ps(s3, op)); + r4 = _mm_castps_si128(_mm_mul_ps(s4, op)); + r1 = _mm_and_si128(r1, _mm_set1_epi32(0x000000FF)); + r2 = _mm_and_si128(r2, _mm_set1_epi32(0x000000FF)); + r3 = _mm_and_si128(r3, _mm_set1_epi32(0x000000FF)); + r4 = _mm_and_si128(r4, _mm_set1_epi32(0x000000FF)); + r2 = _mm_sll_epi32(r2, _mm_set1_epi32(8)); + r3 = _mm_sll_epi32(r3, _mm_set1_epi32(16)); + r4 = _mm_sll_epi32(r4, _mm_set1_epi32(24)); + r1 = _mm_or_si128(r1, r2); + r1 = _mm_or_si128(r1, r3); + r1 = _mm_or_si128(r1, r4); + + return integer8(r1); +} + +auto simd::integer8_s::operator*=(float f) -> integer8& +{ + set((*this * f).vector()); + return *this; +} + +auto simd::integer8_s::operator/(const integer8& other) const -> integer8 +{ + std::int32_t words[element_count] = { + // Source - Op1 + m_values[0], m_values[1], m_values[2], m_values[3], + + // Source - Op2 + m_values[4], m_values[5], m_values[6], m_values[7], + + // Source - Op3 + m_values[8], m_values[9], m_values[10], m_values[11], + + // Source - Op4 + m_values[12], m_values[13], m_values[14], m_values[15], + }; + + // Load the source and destinations + __m128i r1, r2, r3, r4; + auto op = _mm_castsi128_ps(other.vector()); + auto s1 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[0])); + auto s2 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[4])); + auto s3 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[8])); + auto s4 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[12])); + r1 = _mm_castps_si128(_mm_div_ps(s1, op)); + r2 = _mm_castps_si128(_mm_div_ps(s2, op)); + r3 = _mm_castps_si128(_mm_div_ps(s3, op)); + r4 = _mm_castps_si128(_mm_div_ps(s4, op)); + r1 = _mm_and_si128(r1, _mm_set1_epi32(0x000000FF)); + r2 = _mm_and_si128(r2, _mm_set1_epi32(0x000000FF)); + r3 = _mm_and_si128(r3, _mm_set1_epi32(0x000000FF)); + r4 = _mm_and_si128(r4, _mm_set1_epi32(0x000000FF)); + r2 = _mm_sll_epi32(r2, _mm_set1_epi32(8)); + r3 = _mm_sll_epi32(r3, _mm_set1_epi32(16)); + r4 = _mm_sll_epi32(r4, _mm_set1_epi32(24)); + r1 = _mm_or_si128(r1, r2); + r1 = _mm_or_si128(r1, r3); + r1 = _mm_or_si128(r1, r4); + + return integer8(r1); +} + +auto simd::integer8_s::operator/(std::int8_t i) const -> integer8 +{ + return *this / integer8::constant(i); +} + +auto simd::integer8_s::operator/=(const integer8& other) -> integer8& +{ + set((*this / other).vector()); + return *this; +} + +auto simd::integer8_s::operator/=(std::int8_t i) -> integer8 & +{ + set((*this / integer8::constant(i)).vector()); + return *this; +} + +auto simd::integer8_s::operator/(float f) const -> integer8 +{ + std::int32_t words[element_count] = { + // Source - Op1 + m_values[0], m_values[1], m_values[2], m_values[3], + + // Source - Op2 + m_values[4], m_values[5], m_values[6], m_values[7], + + // Source - Op3 + m_values[8], m_values[9], m_values[10], m_values[11], + + // Source - Op4 + m_values[12], m_values[13], m_values[14], m_values[15], + }; + + // Load the source and destinations + __m128i r1, r2, r3, r4; + auto op = _mm_set1_ps(f); + auto s1 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[0])); + auto s2 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[4])); + auto s3 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[8])); + auto s4 = _mm_castsi128_ps(_mm_loadu_si128((__m128i *)&words[12])); + r1 = _mm_castps_si128(_mm_div_ps(s1, op)); + r2 = _mm_castps_si128(_mm_div_ps(s2, op)); + r3 = _mm_castps_si128(_mm_div_ps(s3, op)); + r4 = _mm_castps_si128(_mm_div_ps(s4, op)); + r1 = _mm_and_si128(r1, _mm_set1_epi32(0x000000FF)); + r2 = _mm_and_si128(r2, _mm_set1_epi32(0x000000FF)); + r3 = _mm_and_si128(r3, _mm_set1_epi32(0x000000FF)); + r4 = _mm_and_si128(r4, _mm_set1_epi32(0x000000FF)); + r2 = _mm_sll_epi32(r2, _mm_set1_epi32(8)); + r3 = _mm_sll_epi32(r3, _mm_set1_epi32(16)); + r4 = _mm_sll_epi32(r4, _mm_set1_epi32(24)); + r1 = _mm_or_si128(r1, r2); + r1 = _mm_or_si128(r1, r3); + r1 = _mm_or_si128(r1, r4); + + return integer8(r1); +} + +auto simd::integer8_s::operator/=(float f) -> integer8& +{ + set((*this / f).vector()); + return *this; +} + +auto simd::integer8_s::operator&(const integer8& other) const -> integer8 +{ + return integer8(_mm_and_si128(vector(), other.vector())); +} + +auto simd::integer8_s::operator&(std::int8_t i) const -> integer8 +{ + return *this & integer8::constant(i); +} + +auto simd::integer8_s::operator&=(const integer8& other) -> integer8& +{ + set((*this & other).vector()); + return *this; +} + +auto simd::integer8_s::operator&=(std::int8_t i) -> integer8& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer8_s::operator|(const integer8& other) const -> integer8 +{ + return integer8(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer8_s::operator|(std::int8_t i) const -> integer8 +{ + return *this | integer8::constant(i); +} + +auto simd::integer8_s::operator|=(const integer8& other) -> integer8& +{ + set((*this | other).vector()); + return *this; +} + +auto simd::integer8_s::operator|=(std::int8_t i) -> integer8& +{ + set((*this & i).vector()); + return *this; +} + +auto simd::integer8_s::operator^(const integer8& other) const -> integer8 +{ + return integer8(_mm_or_si128(vector(), other.vector())); +} + +auto simd::integer8_s::operator^(std::int8_t i) const -> integer8 +{ + return *this ^ integer8::constant(i); +} + +auto simd::integer8_s::operator^=(const integer8& other) -> integer8& +{ + set((*this ^ other).vector()); + return *this; +} + +auto simd::integer8_s::operator^=(std::int8_t i) -> integer8& +{ + set((*this ^ i).vector()); + return *this; +} + +auto simd::integer8_s::operator~() const -> integer8 +{ + return integer8(_mm_xor_si128(vector(), _mm_set1_epi8(0xFF))); +} + +auto simd::integer8_s::abs() const -> integer8 +{ + return integer8(_mm_abs_epi8(vector())); +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/intel/intel_sse.hpp b/libs/libSIMD/intel/intel_sse.hpp new file mode 100644 index 0000000..20c0163 --- /dev/null +++ b/libs/libSIMD/intel/intel_sse.hpp @@ -0,0 +1,179 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#if (__x86_64__) +#include +#include + +// MARK: - Types +typedef __m128_u f32x4; + +// MARK: - Hints + +namespace simd +{ + + static inline auto store_vector(float *p, f32x4 a) -> void + { + _mm_storeu_ps(p, a); + } + + static inline auto load_vector(float *p) -> f32x4 + { + return _mm_loadu_ps(p); + } + + static inline auto single_value_vector(float w) -> f32x4 + { + return _mm_set1_ps(w); + } + + static inline auto vector(float z, float y, float x, float w) -> f32x4 + { + return _mm_setr_ps(z, y, x, w); + } + + static inline auto vector_shuffle_lower_higher(f32x4 a, f32x4 b) -> f32x4 + { + return _mm_shuffle_ps(a, b, _MM_SHUFFLE(0, 1, 2, 3)); + } + + static inline auto vector_slice_lower(f32x4 a) -> f32x4 + { + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 1, 0)); + } + + static inline auto vector_slice_upper(f32x4 a) -> f32x4 + { + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 3, 2)); + } + + static inline auto swap_lower_upper(f32x4 a) -> f32x4 + { + return vector_shuffle_lower_higher(a, a); + } + + static inline auto reverse(f32x4 a) -> f32x4 + { + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 2, 3)); + } + + static inline auto add(f32x4 a, f32x4 b) -> f32x4 + { + return _mm_add_ps(a, b); + } + + static inline auto sub(f32x4 a, f32x4 b) -> f32x4 + { + return _mm_sub_ps(a, b); + } + + static inline auto mul(f32x4 a, f32x4 b) -> f32x4 + { + return _mm_mul_ps(a, b); + } + + static inline auto div(f32x4 a, f32x4 b) -> f32x4 + { + return _mm_div_ps(a, b); + } + + static inline auto abs(f32x4 a) -> f32x4 + { + return _mm_castsi128_ps(_mm_abs_epi32(_mm_castps_si128(a))); + } + + static inline auto round(f32x4 a) -> f32x4 + { + return _mm_round_ps(a, _MM_ROUND_NEAREST); + } + + static inline auto floor(f32x4 a) -> f32x4 + { + return _mm_floor_ps(a); + } + + static inline auto ceil(f32x4 a) -> f32x4 + { + return _mm_ceil_ps(a); + } + + static inline auto pow(f32x4 a, float exp) -> f32x4 + { + if (exp == 2.0) { + return _mm_mul_ps(a, a); + } + else { + f32x4 v = a; + for (auto i = 0; i < 4; ++i) { + v[i] = std::powf(v[i], exp); + } + return v; + } + } + + static inline auto sqrt(f32x4 a) -> f32x4 + { + return _mm_sqrt_ps(a); + } + + static inline auto rsqrt(f32x4 a) -> f32x4 + { + return _mm_rsqrt_ps(a); + } + + static inline auto sin(f32x4 a) -> f32x4 + { + f32x4 v = a; + for (auto i = 0; i < 4; ++i) { + v[i] = std::sinf(v[i]); + } + return v; + } + + static inline auto cos(f32x4 a) -> f32x4 + { + f32x4 v = a; + for (auto i = 0; i < 4; ++i) { + v[i] = std::cosf(v[i]); + } + return v; + } + + static inline auto rcp(f32x4 a) -> f32x4 + { + return _mm_rcp_ps(a); + } + + static inline auto min(f32x4 a, f32x4 b) -> f32x4 + { + return _mm_min_ps(a, b); + } + + static inline auto max(f32x4 a, f32x4 b) -> f32x4 + { + return _mm_max_ps(a, b); + } + +} + +#endif \ No newline at end of file diff --git a/libs/libSIMD/memory.hpp b/libs/libSIMD/memory.hpp new file mode 100644 index 0000000..2537234 --- /dev/null +++ b/libs/libSIMD/memory.hpp @@ -0,0 +1,37 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include + +namespace simd::memory +{ + + template::value>::type * = nullptr> + inline auto zero(T dst, std::size_t n) -> void + { + string::set(dst, 0, n); + } + +} \ No newline at end of file diff --git a/libs/libSIMD/string.hpp b/libs/libSIMD/string.hpp new file mode 100644 index 0000000..f6e6490 --- /dev/null +++ b/libs/libSIMD/string.hpp @@ -0,0 +1,83 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include + +namespace simd::string +{ + + template::value>::type* = nullptr> + inline auto copy(T dst, const T src, std::size_t n) -> T + { +#if !USE_TARGET_MEMORY_FUNCTIONS + // TODO: Implement +#else + return reinterpret_cast(::memcpy(dst, src, n)); +#endif + } + + template::value>::type* = nullptr> + inline auto set(T ptr, std::uint8_t v, std::size_t n) -> void + { +#if !USE_TARGET_MEMORY_FUNCTIONS + // TODO: Implement +#else + ::memset(ptr, v, n); +#endif + } + + template::value>::type* = nullptr> + inline auto setw(T ptr, std::uint16_t v, std::int32_t n) -> void + { + // TODO: Implement + } + + template::value>::type* = nullptr> + inline auto setl(T ptr, std::uint32_t v, std::int32_t n) -> void + { + // TODO: Implement a better version of this. + auto dst = reinterpret_cast(ptr); + auto len = n >> 2; + auto rem = n - (len << 2); + + while (len--) { + *dst++ = v; + } + + if (rem) { + auto dst_byte = reinterpret_cast(dst); + while (rem--) { + *dst_byte++ = (v >> (8 * rem)) & 0xFF; + } + } + } + + template::value>::type* = nullptr> + inline auto setq(T ptr, std::uint64_t v, std::int32_t n) -> void + { + // TODO: Implement + } + +} \ No newline at end of file diff --git a/libTesting/runner.cpp b/libs/libTesting/runner.cpp similarity index 100% rename from libTesting/runner.cpp rename to libs/libTesting/runner.cpp diff --git a/libs/libTesting/testing.cmake b/libs/libTesting/testing.cmake new file mode 100644 index 0000000..2da038f --- /dev/null +++ b/libs/libTesting/testing.cmake @@ -0,0 +1,60 @@ +enable_testing() +set(LIB_TESTING_PATH ${CMAKE_CURRENT_LIST_DIR}) + +if(NOT DEFINED CMAKE_OUTPUT_PATH) + set(CMAKE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) +endif() + +# libTesting +function(build_testing_library) + message("libTesting @ ${LIB_TESTING_PATH}") + file(GLOB_RECURSE testing_sources + ${LIB_TESTING_PATH}/*.cpp + ) + add_library(Testing ${testing_sources}) + target_include_directories(Testing PUBLIC ${LIB_TESTING_PATH}/..) +endfunction() + +set(_TESTING_CURRENT_TEST_TARGET "" CACHE INTERNAL "") +set(_TESTING_CURRENT_TEST_SUITE "" CACHE INTERNAL "") +set(_TESTING_CURRENT_TEST_CASE "" CACHE INTERNAL "") + +function(add_test_target name dir ) + message("Adding test target: ${name} @ ${dir}") + set(_TESTING_CURRENT_TEST_TARGET ${name} CACHE INTERNAL "") + + file(GLOB_RECURSE ${name}_test_sources ${dir}/*.cpp) + add_executable(${name}_TestRunner ${${name}_test_sources}) + target_link_libraries(${name}_TestRunner ${name} Testing) + target_include_directories(${name}_TestRunner PUBLIC ${dir}) + + include(${dir}/CMakeLists.txt) +endfunction() + +function(test_include_directory dir) + target_include_directories(${_TESTING_CURRENT_TEST_TARGET}_TestRunner PUBLIC ${dir}) +endfunction() + +function(test_suite name) + set(_TESTING_CURRENT_TEST_SUITE ${name} CACHE INTERNAL "") + message(" Test Suite '${name}'") +endfunction() + +function(end_test_suite) + set(_TESTING_CURRENT_TEST_SUITE "" CACHE INTERNAL "") + set(_TESTING_CURRENT_TEST_CASE "" CACHE INTERNAL "") +endfunction() + +function(test_case name) + set(_TESTING_CURRENT_TEST_CASE ${name} CACHE INTERNAL "") + message(" Test case '${name}'") +endfunction() + +function(end_test_case) + set(_TESTING_CURRENT_TEST_CASE "" CACHE INTERNAL "") +endfunction() + +function(test name) + message(" - ${name}") + add_test(NAME ${_TESTING_CURRENT_TEST_TARGET}_${name} COMMAND ${CMAKE_OUTPUT_PATH}/${_TESTING_CURRENT_TEST_TARGET}_TestRunner ${name}) +endfunction() diff --git a/libTesting/testing.hpp b/libs/libTesting/testing.hpp similarity index 85% rename from libTesting/testing.hpp rename to libs/libTesting/testing.hpp index a8e06a7..c659977 100644 --- a/libTesting/testing.hpp +++ b/libs/libTesting/testing.hpp @@ -77,6 +77,16 @@ namespace test } } + static auto equal(const std::string& lhs, const std::string& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '==' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs == rhs); + if (!result) { + fail(reason, file, line); + } + } + template::value>::type* = nullptr> static auto equal(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { @@ -88,6 +98,32 @@ namespace test } } + template< + typename T, typename U, + typename std::enable_if::value>::type* = nullptr, + typename std::enable_if::value>::type* = nullptr + > + static auto equal(const T& lhs, const U& rhs, const T& tolerance, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '==' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs - rhs) < tolerance; + if (!result) { + fail(reason, file, line); + } + } + + + static auto not_equal(const std::string& lhs, const std::string& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void + { + /* in order to make sure the implementation of a custom '==' operator is valid, we need to explicitly call + * it, and not rely on shorthand. */ + bool result = (lhs != rhs); + if (!result) { + fail(reason, file, line); + } + } + template::value>::type* = nullptr> static auto not_equal(const T& lhs, const U& rhs, const std::string& reason = "", const char *file = __builtin_FILE(), int line = __builtin_LINE()) -> void { From b216e703cc4f97fc97bbd3250094aa1972dcb0cc Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 1 Jun 2023 21:02:19 +0100 Subject: [PATCH 095/113] Add an include for complex in intel sse --- libs/libSIMD/intel/intel_sse.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/libSIMD/intel/intel_sse.hpp b/libs/libSIMD/intel/intel_sse.hpp index 20c0163..44a0728 100644 --- a/libs/libSIMD/intel/intel_sse.hpp +++ b/libs/libSIMD/intel/intel_sse.hpp @@ -23,6 +23,7 @@ #if (__x86_64__) #include #include +#include // MARK: - Types typedef __m128_u f32x4; From f1acc212a3ab6460e1e56004956257080d345155 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 09:08:46 +0100 Subject: [PATCH 096/113] Restructure and better modularize the project into smaller libraries. --- CMakeLists.txt | 8 +- GraphiteTests.cmake | 81 ------- Tests/data/block_tests.cpp | 94 -------- Tests/data/simd_tests.cpp | 43 ---- Tests/quickdraw/type/point_tests.cpp | 187 --------------- Tests/quickdraw/type/rect_tests.cpp | 224 ------------------ Tests/quickdraw/type/size_tests.cpp | 187 --------------- Tests/util/hashing_tests.cpp | 33 --- .../util => libCommon}/concepts.hpp | 17 +- libs/{libGraphite => libCommon}/hints.hpp | 0 .../memory/alignment.hpp | 2 +- libs/{libGraphite => libCommon}/sys/types.hpp | 2 +- .../packbits.hpp | 8 +- libs/{libGraphite => libData}/CMakeLists.txt | 8 +- .../data/data.cpp => libData/block.cpp} | 75 +++--- .../data/data.hpp => libData/block.hpp} | 7 +- .../data => libData}/encoding.hpp | 8 +- .../data => libData}/endianess.hpp | 10 +- .../internals/specialised_reader.hpp | 7 +- .../internals/swap_reader.hpp | 22 +- libs/{libGraphite/data => libData}/reader.cpp | 71 +++--- libs/{libGraphite/data => libData}/reader.hpp | 19 +- libs/{libGraphite/data => libData}/simd.hpp | 7 +- libs/{libGraphite/data => libData}/writer.cpp | 52 ++-- libs/{libGraphite/data => libData}/writer.hpp | 9 +- libs/libEncoding/CMakeLists.txt | 37 +++ .../macroman/macroman.cpp | 16 +- .../macroman/macroman.hpp | 6 +- libs/libGraphite/rsrc/resource.cpp | 164 ------------- libs/libHashing/CMakeLists.txt | 37 +++ .../xxhash/xxhash.cpp} | 9 +- .../xxhash/xxhash.hpp} | 8 +- libs/libQuickdraw/CMakeLists.txt | 38 +++ .../type => libQuickdraw/color}/color.cpp | 16 +- .../type => libQuickdraw/color}/color.hpp | 2 +- .../colorspace}/depth_2_bpp.cpp | 8 +- .../colorspace}/depth_2_bpp.hpp | 8 +- .../colorspace}/depth_4bpp.cpp | 8 +- .../colorspace}/depth_4bpp.hpp | 8 +- .../colorspace}/monochrome.cpp | 8 +- .../colorspace}/monochrome.hpp | 8 +- .../colorspace}/true_color.cpp | 8 +- .../colorspace}/true_color.hpp | 8 +- .../format/color_icon.cpp} | 37 ++- .../format/color_icon.hpp} | 24 +- .../format/color_lookup_table.cpp} | 42 ++-- .../format/color_lookup_table.hpp} | 22 +- .../format/picture.cpp} | 66 +++--- .../format/picture.hpp} | 19 +- .../format/pixel_pattern.cpp} | 20 +- .../format/pixel_pattern.hpp} | 24 +- .../pixmap}/pixmap.cpp | 65 ++--- .../pixmap}/pixmap.hpp | 24 +- .../quicktime/animation.cpp | 4 +- .../quicktime/animation.hpp | 10 +- .../quicktime/image_description.cpp | 44 ++-- .../quicktime/image_description.hpp | 10 +- .../quicktime/planar.cpp | 6 +- .../quicktime/planar.hpp | 8 +- .../quicktime/raw.cpp | 4 +- .../quicktime/raw.hpp | 10 +- .../surface}/surface.cpp | 38 +-- .../surface}/surface.hpp | 12 +- .../type/coding_type.hpp | 2 +- .../type/pixel_format.hpp | 2 +- .../quickdraw => libQuickdraw}/type/point.hpp | 10 +- .../quickdraw => libQuickdraw}/type/rect.hpp | 12 +- .../quickdraw => libQuickdraw}/type/size.hpp | 8 +- libs/libResource/CMakeLists.txt | 38 +++ libs/libResource/concepts.hpp | 35 +++ .../rsrc => libResource}/file.cpp | 110 +++++---- .../rsrc => libResource}/file.hpp | 21 +- .../format}/classic/classic.hpp | 4 +- .../format}/classic/parser.cpp | 23 +- .../format}/classic/parser.hpp | 6 +- .../format}/classic/writer.cpp | 56 +++-- .../format}/classic/writer.hpp | 7 +- .../format}/extended/extended.hpp | 4 +- .../format}/extended/parser.cpp | 27 +-- .../format/extended}/parser.hpp | 6 +- .../format}/extended/writer.cpp | 57 +++-- .../format}/extended/writer.hpp | 7 +- .../format}/rez/parser.cpp | 41 ++-- .../format/rez}/parser.hpp | 6 +- .../rsrc => libResource/format}/rez/rez.hpp | 4 +- .../format}/rez/writer.cpp | 51 ++-- .../format}/rez/writer.hpp | 7 +- libs/libResource/identifier.hpp | 31 +++ .../rsrc => libResource}/manager.cpp | 57 ++--- .../rsrc => libResource}/manager.hpp | 40 ++-- .../rsrc => libResource}/result.cpp | 42 ++-- .../rsrc => libResource}/result.hpp | 30 +-- .../structure}/attribute.cpp | 14 +- .../structure}/attribute.hpp | 2 +- libs/libResource/structure/instance.cpp | 157 ++++++++++++ .../structure/instance.hpp} | 30 +-- .../rsrc => libResource/structure}/type.cpp | 69 +++--- .../rsrc => libResource/structure}/type.hpp | 34 +-- libs/libSound/CMakeLists.txt | 38 +++ .../sound => libSound}/codec/descriptor.hpp | 2 +- .../codec => libSound/codec/ima4}/ima4.cpp | 14 +- .../codec => libSound/codec/ima4}/ima4.hpp | 6 +- .../sound => libSound/format}/sound.cpp | 50 ++-- .../sound => libSound/format}/sound.hpp | 20 +- libs/libSpriteWorld/CMakeLists.txt | 38 +++ .../formats}/rleD.cpp | 34 +-- .../formats}/rleD.hpp | 11 +- .../formats}/rleX.cpp | 124 +++++----- .../formats}/rleX.hpp | 11 +- libs/libToolbox/CMakeLists.txt | 38 +++ .../{libGraphite => libToolbox}/font/fond.cpp | 8 +- .../{libGraphite => libToolbox}/font/fond.hpp | 10 +- .../font/manager.cpp | 22 +- .../font/manager.hpp | 11 +- .../{libGraphite => libToolbox}/font/nfnt.cpp | 8 +- .../{libGraphite => libToolbox}/font/nfnt.hpp | 12 +- .../{libGraphite => libToolbox}/font/sfnt.cpp | 12 +- .../{libGraphite => libToolbox}/font/sfnt.hpp | 10 +- .../toolbox => libToolbox/strings}/string.cpp | 13 +- .../toolbox => libToolbox/strings}/string.hpp | 12 +- .../strings}/string_list.cpp | 16 +- .../strings}/string_list.hpp | 10 +- .../toolbox => libToolbox/ui}/dialog.cpp | 46 ++-- .../toolbox => libToolbox/ui}/dialog.hpp | 18 +- .../ui}/dialog_item_list.cpp | 14 +- .../ui}/dialog_item_list.hpp | 12 +- 126 files changed, 1597 insertions(+), 2140 deletions(-) delete mode 100644 GraphiteTests.cmake delete mode 100644 Tests/data/block_tests.cpp delete mode 100644 Tests/data/simd_tests.cpp delete mode 100644 Tests/quickdraw/type/point_tests.cpp delete mode 100644 Tests/quickdraw/type/rect_tests.cpp delete mode 100644 Tests/quickdraw/type/size_tests.cpp delete mode 100644 Tests/util/hashing_tests.cpp rename libs/{libGraphite/util => libCommon}/concepts.hpp (78%) rename libs/{libGraphite => libCommon}/hints.hpp (100%) rename libs/{libGraphite => libCommon}/memory/alignment.hpp (97%) rename libs/{libGraphite => libCommon}/sys/types.hpp (99%) rename libs/{libGraphite/compression => libCompression}/packbits.hpp (97%) rename libs/{libGraphite => libData}/CMakeLists.txt (90%) rename libs/{libGraphite/data/data.cpp => libData/block.cpp} (77%) rename libs/{libGraphite/data/data.hpp => libData/block.hpp} (96%) rename libs/{libGraphite/data => libData}/encoding.hpp (89%) rename libs/{libGraphite/data => libData}/endianess.hpp (91%) rename libs/{libGraphite/data => libData}/internals/specialised_reader.hpp (95%) rename libs/{libGraphite/data => libData}/internals/swap_reader.hpp (78%) rename libs/{libGraphite/data => libData}/reader.cpp (59%) rename libs/{libGraphite/data => libData}/reader.hpp (94%) rename libs/{libGraphite/data => libData}/simd.hpp (97%) rename libs/{libGraphite/data => libData}/writer.cpp (70%) rename libs/{libGraphite/data => libData}/writer.hpp (98%) create mode 100644 libs/libEncoding/CMakeLists.txt rename libs/{libGraphite/encoding => libEncoding}/macroman/macroman.cpp (90%) rename libs/{libGraphite/encoding => libEncoding}/macroman/macroman.hpp (93%) delete mode 100644 libs/libGraphite/rsrc/resource.cpp create mode 100644 libs/libHashing/CMakeLists.txt rename libs/{libGraphite/util/hashing.cpp => libHashing/xxhash/xxhash.cpp} (95%) rename libs/{libGraphite/util/hashing.hpp => libHashing/xxhash/xxhash.hpp} (95%) create mode 100644 libs/libQuickdraw/CMakeLists.txt rename libs/{libGraphite/quickdraw/type => libQuickdraw/color}/color.cpp (86%) rename libs/{libGraphite/quickdraw/type => libQuickdraw/color}/color.hpp (98%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/depth_2_bpp.cpp (85%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/depth_2_bpp.hpp (87%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/depth_4bpp.cpp (85%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/depth_4bpp.hpp (87%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/monochrome.cpp (86%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/monochrome.hpp (87%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/true_color.cpp (85%) rename libs/{libGraphite/quickdraw/support/drawing => libQuickdraw/colorspace}/true_color.hpp (87%) rename libs/{libGraphite/quickdraw/format/cicn.cpp => libQuickdraw/format/color_icon.cpp} (83%) rename libs/{libGraphite/quickdraw/format/cicn.hpp => libQuickdraw/format/color_icon.hpp} (77%) rename libs/{libGraphite/quickdraw/format/clut.cpp => libQuickdraw/format/color_lookup_table.cpp} (71%) rename libs/{libGraphite/quickdraw/format/clut.hpp => libQuickdraw/format/color_lookup_table.hpp} (84%) rename libs/{libGraphite/quickdraw/format/pict.cpp => libQuickdraw/format/picture.cpp} (89%) rename libs/{libGraphite/quickdraw/format/pict.hpp => libQuickdraw/format/picture.hpp} (90%) rename libs/{libGraphite/quickdraw/format/ppat.cpp => libQuickdraw/format/pixel_pattern.cpp} (88%) rename libs/{libGraphite/quickdraw/format/ppat.hpp => libQuickdraw/format/pixel_pattern.hpp} (74%) rename libs/{libGraphite/quickdraw/support => libQuickdraw/pixmap}/pixmap.cpp (73%) rename libs/{libGraphite/quickdraw/support => libQuickdraw/pixmap}/pixmap.hpp (89%) rename libs/{libGraphite => libQuickdraw}/quicktime/animation.cpp (96%) rename libs/{libGraphite => libQuickdraw}/quicktime/animation.hpp (79%) rename libs/{libGraphite => libQuickdraw}/quicktime/image_description.cpp (70%) rename libs/{libGraphite => libQuickdraw}/quicktime/image_description.hpp (91%) rename libs/{libGraphite => libQuickdraw}/quicktime/planar.cpp (94%) rename libs/{libGraphite => libQuickdraw}/quicktime/planar.hpp (86%) rename libs/{libGraphite => libQuickdraw}/quicktime/raw.cpp (92%) rename libs/{libGraphite => libQuickdraw}/quicktime/raw.hpp (79%) rename libs/{libGraphite/quickdraw/support => libQuickdraw/surface}/surface.cpp (69%) rename libs/{libGraphite/quickdraw/support => libQuickdraw/surface}/surface.hpp (90%) rename libs/{libGraphite/quickdraw => libQuickdraw}/type/coding_type.hpp (97%) rename libs/{libGraphite/quickdraw => libQuickdraw}/type/pixel_format.hpp (97%) rename libs/{libGraphite/quickdraw => libQuickdraw}/type/point.hpp (97%) rename libs/{libGraphite/quickdraw => libQuickdraw}/type/rect.hpp (95%) rename libs/{libGraphite/quickdraw => libQuickdraw}/type/size.hpp (97%) create mode 100644 libs/libResource/CMakeLists.txt create mode 100644 libs/libResource/concepts.hpp rename libs/{libGraphite/rsrc => libResource}/file.cpp (61%) rename libs/{libGraphite/rsrc => libResource}/file.hpp (84%) rename libs/{libGraphite/rsrc => libResource/format}/classic/classic.hpp (92%) rename libs/{libGraphite/rsrc => libResource/format}/classic/parser.cpp (87%) rename libs/{libGraphite/rsrc => libResource/format}/classic/parser.hpp (90%) rename libs/{libGraphite/rsrc => libResource/format}/classic/writer.cpp (82%) rename libs/{libGraphite/rsrc => libResource/format}/classic/writer.hpp (91%) rename libs/{libGraphite/rsrc => libResource/format}/extended/extended.hpp (91%) rename libs/{libGraphite/rsrc => libResource/format}/extended/parser.cpp (87%) rename libs/{libGraphite/rsrc/rez => libResource/format/extended}/parser.hpp (91%) rename libs/{libGraphite/rsrc => libResource/format}/extended/writer.cpp (83%) rename libs/{libGraphite/rsrc => libResource/format}/extended/writer.hpp (91%) rename libs/{libGraphite/rsrc => libResource/format}/rez/parser.cpp (77%) rename libs/{libGraphite/rsrc/extended => libResource/format/rez}/parser.hpp (90%) rename libs/{libGraphite/rsrc => libResource/format}/rez/rez.hpp (92%) rename libs/{libGraphite/rsrc => libResource/format}/rez/writer.cpp (72%) rename libs/{libGraphite/rsrc => libResource/format}/rez/writer.hpp (91%) create mode 100644 libs/libResource/identifier.hpp rename libs/{libGraphite/rsrc => libResource}/manager.cpp (61%) rename libs/{libGraphite/rsrc => libResource}/manager.hpp (76%) rename libs/{libGraphite/rsrc => libResource}/result.cpp (65%) rename libs/{libGraphite/rsrc => libResource}/result.hpp (81%) rename libs/{libGraphite/rsrc => libResource/structure}/attribute.cpp (75%) rename libs/{libGraphite/rsrc => libResource/structure}/attribute.hpp (98%) create mode 100644 libs/libResource/structure/instance.cpp rename libs/{libGraphite/rsrc/resource.hpp => libResource/structure/instance.hpp} (70%) rename libs/{libGraphite/rsrc => libResource/structure}/type.cpp (65%) rename libs/{libGraphite/rsrc => libResource/structure}/type.hpp (76%) create mode 100644 libs/libSound/CMakeLists.txt rename libs/{libGraphite/sound => libSound}/codec/descriptor.hpp (97%) rename libs/{libGraphite/sound/codec => libSound/codec/ima4}/ima4.cpp (89%) rename libs/{libGraphite/sound/codec => libSound/codec/ima4}/ima4.hpp (91%) rename libs/{libGraphite/sound => libSound/format}/sound.cpp (87%) rename libs/{libGraphite/sound => libSound/format}/sound.hpp (81%) create mode 100644 libs/libSpriteWorld/CMakeLists.txt rename libs/{libGraphite/spriteworld => libSpriteWorld/formats}/rleD.cpp (90%) rename libs/{libGraphite/spriteworld => libSpriteWorld/formats}/rleD.hpp (91%) rename libs/{libGraphite/spriteworld => libSpriteWorld/formats}/rleX.cpp (79%) rename libs/{libGraphite/spriteworld => libSpriteWorld/formats}/rleX.hpp (90%) create mode 100644 libs/libToolbox/CMakeLists.txt rename libs/{libGraphite => libToolbox}/font/fond.cpp (95%) rename libs/{libGraphite => libToolbox}/font/fond.hpp (91%) rename libs/{libGraphite => libToolbox}/font/manager.cpp (74%) rename libs/{libGraphite => libToolbox}/font/manager.hpp (90%) rename libs/{libGraphite => libToolbox}/font/nfnt.cpp (86%) rename libs/{libGraphite => libToolbox}/font/nfnt.hpp (86%) rename libs/{libGraphite => libToolbox}/font/sfnt.cpp (76%) rename libs/{libGraphite => libToolbox}/font/sfnt.hpp (85%) rename libs/{libGraphite/toolbox => libToolbox/strings}/string.cpp (50%) rename libs/{libGraphite/toolbox => libToolbox/strings}/string.hpp (65%) rename libs/{libGraphite/toolbox => libToolbox/strings}/string_list.cpp (74%) rename libs/{libGraphite/toolbox => libToolbox/strings}/string_list.hpp (86%) rename libs/{libGraphite/toolbox => libToolbox/ui}/dialog.cpp (59%) rename libs/{libGraphite/toolbox => libToolbox/ui}/dialog.hpp (83%) rename libs/{libGraphite/toolbox => libToolbox/ui}/dialog_item_list.cpp (81%) rename libs/{libGraphite/toolbox => libToolbox/ui}/dialog_item_list.hpp (88%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d76ebe2..051a12e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,13 @@ set(PROJECT_LIBS_DIR ${CMAKE_CURRENT_LIST_DIR}/libs) # Libraries add_subdirectory(${PROJECT_LIBS_DIR}/libSIMD) -add_subdirectory(${PROJECT_LIBS_DIR}/libGraphite) +add_subdirectory(${PROJECT_LIBS_DIR}/libHashing) +add_subdirectory(${PROJECT_LIBS_DIR}/libEncoding) +add_subdirectory(${PROJECT_LIBS_DIR}/libData) +add_subdirectory(${PROJECT_LIBS_DIR}/libResource) +add_subdirectory(${PROJECT_LIBS_DIR}/libQuickDraw) +add_subdirectory(${PROJECT_LIBS_DIR}/libSound) +add_subdirectory(${PROJECT_LIBS_DIR}/libToolbox) # Unit Tests if (EXISTS ${PROJECT_LIBS_DIR}/libTesting/testing.cmake) diff --git a/GraphiteTests.cmake b/GraphiteTests.cmake deleted file mode 100644 index 2c55ecb..0000000 --- a/GraphiteTests.cmake +++ /dev/null @@ -1,81 +0,0 @@ -test_suite(Graphite - - # Data - # Data Block - dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect - dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly - dataBlock_construct_defaultByteOrderIsCorrect - dataBlock_construct_usingLSBByteOrder_assignsCorrectly - dataBlock_construct_hasOwnershipOfInitialData - dataBlock_getByteValue_atOffset_isExpectedValueReturned - dataBlock_getShortValue_atOffset_isExpectedValueReturned - dataBlock_getLongValue_atOffset_isExpectedValueReturned - dataBlock_getQuadValue_atOffset_isExpectedValueReturned - - # QuickDraw - # Point - point_constructUsingEqualCoordinates - point_constructUsingSeparateCoordinates - point_constructUsingReader_quickdraw - point_constructUsingReader_macintosh - point_readPointFromReader - point_encodeInToWriter_quickdraw - point_encodeInToWriter_macintosh - point_assignmentOperator_copyPoint - point_assignmentOperator_movePoint - point_equalsOperator_shouldBeEqual - point_equalsOperator_shouldNotBeEqual - point_notEqualsOperator_shouldNotBeEqual - point_notEqualsOperator_shouldBeEqual - point_addPoint_returnsExpectedPoint - point_subtractPoint_returnsExpectedPoint - point_multiplyPoint_returnsExpectedPoint - point_dividePoint_returnsExpectedPoint - point_castToDifferentType_retainsSameValue - - # Size - size_constructUsingEqualDimensions - size_constructUsingSeparateDimensions - size_constructUsingReader_quickdraw - size_constructUsingReader_macintosh - size_readSizeFromReader - size_encodeInToWriter_quickdraw - size_encodeInToWriter_macintosh - size_assignmentOperator_copySize - size_assignmentOperator_moveSize - size_equalsOperator_shouldBeEqual - size_equalsOperator_shouldNotBeEqual - size_notEqualsOperator_shouldNotBeEqual - size_notEqualsOperator_shouldBeEqual - size_addSize_returnsExpectedSize - size_subtractSize_returnsExpectedSize - size_multiplySize_returnsExpectedSize - size_divideSize_returnsExpectedSize - size_castToDifferentType_retainsSameValue - - # Rect - rect_constructUsingEqualValues - rect_constructUsingSeparateValues - rect_constructUsingPointAndSize - rect_constructUsingReader_quickdraw - rect_constructUsingReader_macintosh - rect_readRectFromReader - rect_encodeInToWriter_quickdraw - rect_encodeInToWriter_macintosh - rect_assignmentOperator_copyRect - rect_assignmentOperator_moveRect - rect_equalsOperator_shouldBeEqual - rect_equalsOperator_shouldNotBeEqual - rect_notEqualsOperator_shouldNotBeEqual - rect_notEqualsOperator_shouldBeEqual - rect_addRect_returnsExpectedRect - rect_subtractRect_returnsExpectedRect - rect_multiplyRect_returnsExpectedRect - rect_divideRect_returnsExpectedRect - rect_castToDifferentType_retainsSameValue - - # Utility Functions - # XXHash Hashing - xxh64_verifyCorrectHashIsProduced - -) diff --git a/Tests/data/block_tests.cpp b/Tests/data/block_tests.cpp deleted file mode 100644 index d9c1f55..0000000 --- a/Tests/data/block_tests.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include - -using namespace graphite; - -// MARK: - Construction Tests - -TEST(dataBlock_constructWithPowerOfTwoCapacity_sizeIsCorrect) -{ - data::block block(64); - test::equal(block.raw_size(), 64, "Raw size of block was expected to be 64"); - test::equal(block.size(), 64, "Size of block was expected to be 64."); -}; - -TEST(dataBlock_constructWithCapacity_rawSizeIsAdjustedCorrectly) -{ - data::block block(43); - test::equal(block.raw_size(), 48, "Raw size of block was expected to be 48. Got " + std::to_string(block.raw_size())); - test::equal(block.size(), 43, "Size of block was expected to be 43. Got " + std::to_string(block.size())); -}; - -TEST(dataBlock_construct_defaultByteOrderIsCorrect) -{ - data::block block(8); - test::equal(block.byte_order(), data::byte_order::msb, "Data Blocks should have a default byte order of MSB."); -} - -TEST(dataBlock_construct_usingLSBByteOrder_assignsCorrectly) -{ - data::block block(8, data::byte_order::lsb); - test::equal(block.byte_order(), data::byte_order::lsb, "Data Blocks should have a default byte order of LSB."); -} - -TEST(dataBlock_construct_hasOwnershipOfInitialData) -{ - data::block block(8); - test::is_true(block.has_ownership(), "When constructed, Data Blocks should have ownership over the memory allocation."); -} - -// MARK: - Data Access Test - -static constexpr uint8_t test_data[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, - 0xDE, 0xAD, 0xD0, 0x0D, 0xCA, 0xFE, 0xCA, 0xFE -}; - -TEST(dataBlock_getByteValue_atOffset_isExpectedValueReturned) -{ - data::block block(test_data, sizeof(test_data), false); - test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); - test::equal(block.get(2), 0xBE, "Expected to retrieve the value 0xBE from the data block."); -} - -TEST(dataBlock_getShortValue_atOffset_isExpectedValueReturned) -{ - data::block block(test_data, sizeof(test_data), false); - test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); - test::equal(block.get(2), 0xBEEF, "Expected to retrieve the value 0xBEEF from the data block."); -} - -TEST(dataBlock_getLongValue_atOffset_isExpectedValueReturned) -{ - data::block block(test_data, sizeof(test_data), false); - test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); - test::equal(block.get(4), 0xCAFEBABE, "Expected to retrieve the value 0xCAFEBABE from the data block."); -} - -TEST(dataBlock_getQuadValue_atOffset_isExpectedValueReturned) -{ - data::block block(test_data, sizeof(test_data), false); - test::equal(block.size(), sizeof(test_data), "Unexpected data block size when allocating from a byte array"); - test::equal(block.get(8), 0xDEADD00DCAFECAFE, "Expected to retrieve the value 0xDEADD00DCAFECAFE from the data block."); -} - diff --git a/Tests/data/simd_tests.cpp b/Tests/data/simd_tests.cpp deleted file mode 100644 index 28ab03e..0000000 --- a/Tests/data/simd_tests.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include - -// MARK: - SIMD Capacity Expansion - -#if __x86_64__ - -TEST(simd_x86_64_expandCapacity_expansionRoundsUpCorrectly) { - test::equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); - test::equal(graphite::data::simd::expand_capacity(8), 16, "Expanded capacity from 8 bytes should expand to 16 bytes."); - test::equal(graphite::data::simd::expand_capacity(16), 16, "Expanded capacity from 16 bytes should remain the same."); -}; - -#elif __arm64__ - -TEST(simd_arm64_expandCapacity_expansionRoundsUpCorrectly) { - test::equal(graphite::data::simd::expand_capacity(0), 0, "Expanded capacity from 0 bytes should remain the same."); - test::equal(graphite::data::simd::expand_capacity(2), 8, "Expanded capacity from 2 bytes should expand to 8 bytes."); - test::equal(graphite::data::simd::expand_capacity(8), 8, "Expanded capacity from 2 bytes should remain the same."); -}; - -#endif - diff --git a/Tests/quickdraw/type/point_tests.cpp b/Tests/quickdraw/type/point_tests.cpp deleted file mode 100644 index 4d57a2c..0000000 --- a/Tests/quickdraw/type/point_tests.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include -#include -#include - -using namespace graphite; - -// MARK: - Test Data - -static constexpr std::uint8_t point_test_data[] = { - 0x00, 0x80, 0x00, 0x20 -}; - -// MARK: - Construction Tests - -TEST(point_constructUsingEqualCoordinates) -{ - quickdraw::point point(10); - test::equal(point.x, 10); - test::equal(point.y, 10); -} - -TEST(point_constructUsingSeparateCoordinates) -{ - quickdraw::point point(5, 7); - test::equal(point.x, 5); - test::equal(point.y, 7); -} - -TEST(point_constructUsingReader_quickdraw) -{ - data::block block(point_test_data, sizeof(point_test_data), false); - data::reader reader(&block); - - quickdraw::point point(reader, quickdraw::coding_type::quickdraw); - test::equal(point.x, 32); - test::equal(point.y, 128); -} - -TEST(point_constructUsingReader_macintosh) -{ - data::block block(point_test_data, sizeof(point_test_data), false); - data::reader reader(&block); - - quickdraw::point point(reader, quickdraw::coding_type::macintosh); - test::equal(point.x, 128); - test::equal(point.y, 32); -} - -// MARK: - Static Reader - -TEST(point_readPointFromReader) -{ - data::block block(point_test_data, sizeof(point_test_data), false); - data::reader reader(&block); - - auto point = quickdraw::point::read(reader, quickdraw::coding_type::quickdraw); - test::equal(point.x, 32); - test::equal(point.y, 128); -} - -// MARK: - Encoding - -TEST(point_encodeInToWriter_quickdraw) -{ - data::writer writer(data::byte_order::msb); - - quickdraw::point point(32, 128); - point.encode(writer, quickdraw::coding_type::quickdraw); - - test::equal(writer.size(), sizeof(point_test_data)); - test::bytes_equal(writer.data()->get(), point_test_data, sizeof(point_test_data)); -} - -TEST(point_encodeInToWriter_macintosh) -{ - data::writer writer(data::byte_order::msb); - - quickdraw::point point(128, 32); - point.encode(writer, quickdraw::coding_type::macintosh); - - test::equal(writer.size(), sizeof(point_test_data)); - test::bytes_equal(writer.data()->get(), point_test_data, sizeof(point_test_data)); -} - -// MARK: - Operators - -TEST(point_assignmentOperator_copyPoint) -{ - quickdraw::point point(5); - test::equal(point.x, 5); - test::equal(point.y, 5); - - quickdraw::point newPoint(10); - point = newPoint; - test::equal(point.x, 10); - test::equal(point.y, 10); -} - -TEST(point_assignmentOperator_movePoint) -{ - quickdraw::point point(5); - test::equal(point.x, 5); - test::equal(point.y, 5); - - point = quickdraw::point(10); - test::equal(point.x, 10); - test::equal(point.y, 10); -} - -TEST(point_equalsOperator_shouldBeEqual) -{ - test::is_true(quickdraw::point(5) == quickdraw::point(5)); -} - -TEST(point_equalsOperator_shouldNotBeEqual) -{ - test::is_false(quickdraw::point(5) == quickdraw::point(7)); -} - -TEST(point_notEqualsOperator_shouldNotBeEqual) -{ - test::is_true(quickdraw::point(5) != quickdraw::point(7)); -} - -TEST(point_notEqualsOperator_shouldBeEqual) -{ - test::is_false(quickdraw::point(5) != quickdraw::point(5)); -} - -TEST(point_addPoint_returnsExpectedPoint) -{ - auto result = quickdraw::point(5) + quickdraw::point(3); - test::equal(result.x, 8); - test::equal(result.y, 8); -} - -TEST(point_subtractPoint_returnsExpectedPoint) -{ - auto result = quickdraw::point(5) - quickdraw::point(3); - test::equal(result.x, 2); - test::equal(result.y, 2); -} - -TEST(point_multiplyPoint_returnsExpectedPoint) -{ - auto result = quickdraw::point(5) * 3; - test::equal(result.x, 15); - test::equal(result.y, 15); -} - -TEST(point_dividePoint_returnsExpectedPoint) -{ - auto result = quickdraw::point(9) / 3; - test::equal(result.x, 3); - test::equal(result.y, 3); -} - -// MARK: - Casting Tests - -TEST(point_castToDifferentType_retainsSameValue) -{ - quickdraw::point point(76); - auto new_point = point.cast(); - test::equal(new_point.x, 76); - test::equal(new_point.y, 76); -} \ No newline at end of file diff --git a/Tests/quickdraw/type/rect_tests.cpp b/Tests/quickdraw/type/rect_tests.cpp deleted file mode 100644 index cfad368..0000000 --- a/Tests/quickdraw/type/rect_tests.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include -#include -#include - -using namespace graphite; - -// MARK: - Test Data - -static constexpr std::uint8_t rect_test_data[] = { - 0x00, 0x20, 0x00, 0x80, 0x00, 0x30, 0x00, 0xC0 -}; - -// MARK: - Construction Tests - -TEST(rect_constructUsingEqualValues) -{ - quickdraw::rect rect(5); - test::equal(rect.origin.x, 5); - test::equal(rect.origin.y, 5); - test::equal(rect.size.width, 5); - test::equal(rect.size.height, 5); -} - -TEST(rect_constructUsingSeparateValues) -{ - quickdraw::rect rect(1, 2, 3, 4); - test::equal(rect.origin.x, 1); - test::equal(rect.origin.y, 2); - test::equal(rect.size.width, 3); - test::equal(rect.size.height, 4); -} - -TEST(rect_constructUsingPointAndSize) -{ - quickdraw::rect rect(quickdraw::point(1, 2), quickdraw::size(3, 4)); - test::equal(rect.origin.x, 1); - test::equal(rect.origin.y, 2); - test::equal(rect.size.width, 3); - test::equal(rect.size.height, 4); -} - -TEST(rect_constructUsingReader_quickdraw) -{ - data::block block(rect_test_data, sizeof(rect_test_data), false); - data::reader reader(&block); - - quickdraw::rect rect(reader, quickdraw::coding_type::quickdraw); - test::equal(rect.origin.x, 128); - test::equal(rect.origin.y, 32); - test::equal(rect.size.width, 64); - test::equal(rect.size.height, 16); -} - -TEST(rect_constructUsingReader_macintosh) -{ - data::block block(rect_test_data, sizeof(rect_test_data), false); - data::reader reader(&block); - - quickdraw::rect rect(reader, quickdraw::coding_type::macintosh); - test::equal(rect.origin.x, 32); - test::equal(rect.origin.y, 128); - test::equal(rect.size.width, 16); - test::equal(rect.size.height, 64); -} - -// MARK: - Static Reader - -TEST(rect_readRectFromReader) -{ - data::block block(rect_test_data, sizeof(rect_test_data), false); - data::reader reader(&block); - - auto rect = quickdraw::rect::read(reader, quickdraw::coding_type::quickdraw); - test::equal(rect.origin.x, 128); - test::equal(rect.origin.y, 32); - test::equal(rect.size.width, 64); - test::equal(rect.size.height, 16); -} - -// MARK: - Encoding - -TEST(rect_encodeInToWriter_quickdraw) -{ - data::writer writer(data::byte_order::msb); - - quickdraw::rect rect(128, 32, 64, 16); - rect.encode(writer, quickdraw::coding_type::quickdraw); - - test::equal(writer.size(), sizeof(rect_test_data)); - test::bytes_equal(writer.data()->get(), rect_test_data, sizeof(rect_test_data)); -} - -TEST(rect_encodeInToWriter_macintosh) -{ - data::writer writer(data::byte_order::msb); - - quickdraw::rect rect(32, 128, 16, 64); - rect.encode(writer, quickdraw::coding_type::macintosh); - - test::equal(writer.size(), sizeof(rect_test_data)); - test::bytes_equal(writer.data()->get(), rect_test_data, sizeof(rect_test_data)); -} - -// MARK: - Operators - -TEST(rect_assignmentOperator_copyrect) -{ - quickdraw::rect rect(5); - test::equal(rect.origin.x, 5); - test::equal(rect.origin.y, 5); - test::equal(rect.size.width, 5); - test::equal(rect.size.height, 5); - - quickdraw::rect new_rect(10); - rect = new_rect; - test::equal(rect.origin.x, 10); - test::equal(rect.origin.y, 10); - test::equal(rect.size.width, 10); - test::equal(rect.size.height, 10); -} - -TEST(rect_assignmentOperator_moverect) -{ - quickdraw::rect rect(5); - test::equal(rect.origin.x, 5); - test::equal(rect.origin.y, 5); - test::equal(rect.size.width, 5); - test::equal(rect.size.height, 5); - - rect = quickdraw::rect(10); - test::equal(rect.origin.x, 10); - test::equal(rect.origin.y, 10); - test::equal(rect.size.width, 10); - test::equal(rect.size.height, 10); -} - -TEST(rect_equalsOperator_shouldBeEqual) -{ - test::is_true(quickdraw::rect(5) == quickdraw::rect(5)); -} - -TEST(rect_equalsOperator_shouldNotBeEqual) -{ - test::is_false(quickdraw::rect(5) == quickdraw::rect(7)); -} - -TEST(rect_notEqualsOperator_shouldNotBeEqual) -{ - test::is_true(quickdraw::rect(5) != quickdraw::rect(7)); -} - -TEST(rect_notEqualsOperator_shouldBeEqual) -{ - test::is_false(quickdraw::rect(5) != quickdraw::rect(5)); -} - -TEST(rect_addRect_returnsExpectedrect) -{ - auto result = quickdraw::rect(5) + quickdraw::rect(3); - test::equal(result.origin.x, 8); - test::equal(result.origin.y, 8); - test::equal(result.size.width, 8); - test::equal(result.size.height, 8); -} - -TEST(rect_subtractRect_returnsExpectedRect) -{ - auto result = quickdraw::rect(5) - quickdraw::rect(3); - test::equal(result.origin.x, 2); - test::equal(result.origin.y, 2); - test::equal(result.size.width, 2); - test::equal(result.size.height, 2); -} - -TEST(rect_multiplyRect_returnsExpectedRect) -{ - auto result = quickdraw::rect(5) * 3; - test::equal(result.origin.x, 15); - test::equal(result.origin.y, 15); - test::equal(result.size.width, 15); - test::equal(result.size.height, 15); -} - -TEST(rect_divideRect_returnsExpectedRect) -{ - auto result = quickdraw::rect(9) / 3; - test::equal(result.origin.x, 3); - test::equal(result.origin.y, 3); - test::equal(result.size.width, 3); - test::equal(result.size.height, 3); -} - -// MARK: - Casting Tests - -TEST(rect_castToDifferentType_retainsSameValue) -{ - quickdraw::rect rect(76); - auto new_rect = rect.cast(); - test::equal(new_rect.origin.x, 76); - test::equal(new_rect.origin.y, 76); - test::equal(new_rect.size.width, 76); - test::equal(new_rect.size.height, 76); -} \ No newline at end of file diff --git a/Tests/quickdraw/type/size_tests.cpp b/Tests/quickdraw/type/size_tests.cpp deleted file mode 100644 index a8acdb5..0000000 --- a/Tests/quickdraw/type/size_tests.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include -#include -#include - -using namespace graphite; - -// MARK: - Test Data - -static constexpr std::uint8_t size_test_data[] = { - 0x00, 0x80, 0x00, 0x20 -}; - -// MARK: - Construction Tests - -TEST(size_constructUsingEqualDimensions) -{ - quickdraw::size size(10); - test::equal(size.width, 10); - test::equal(size.height, 10); -} - -TEST(size_constructUsingSeparateDimensions) -{ - quickdraw::size size(5, 7); - test::equal(size.width, 5); - test::equal(size.height, 7); -} - -TEST(size_constructUsingReader_quickdraw) -{ - data::block block(size_test_data, sizeof(size_test_data), false); - data::reader reader(&block); - - quickdraw::size size(reader, quickdraw::coding_type::quickdraw); - test::equal(size.width, 32); - test::equal(size.height, 128); -} - -TEST(size_constructUsingReader_macintosh) -{ - data::block block(size_test_data, sizeof(size_test_data), false); - data::reader reader(&block); - - quickdraw::size size(reader, quickdraw::coding_type::macintosh); - test::equal(size.width, 128); - test::equal(size.height, 32); -} - -// MARK: - Static Reader - -TEST(size_readsizeFromReader) -{ - data::block block(size_test_data, sizeof(size_test_data), false); - data::reader reader(&block); - - auto size = quickdraw::size::read(reader, quickdraw::coding_type::quickdraw); - test::equal(size.width, 32); - test::equal(size.height, 128); -} - -// MARK: - Encoding - -TEST(size_encodeInToWriter_quickdraw) -{ - data::writer writer(data::byte_order::msb); - - quickdraw::size size(32, 128); - size.encode(writer, quickdraw::coding_type::quickdraw); - - test::equal(writer.size(), sizeof(size_test_data)); - test::bytes_equal(writer.data()->get(), size_test_data, sizeof(size_test_data)); -} - -TEST(size_encodeInToWriter_macintosh) -{ - data::writer writer(data::byte_order::msb); - - quickdraw::size size(128, 32); - size.encode(writer, quickdraw::coding_type::macintosh); - - test::equal(writer.size(), sizeof(size_test_data)); - test::bytes_equal(writer.data()->get(), size_test_data, sizeof(size_test_data)); -} - -// MARK: - Operators - -TEST(size_assignmentOperator_copysize) -{ - quickdraw::size size(5); - test::equal(size.width, 5); - test::equal(size.height, 5); - - quickdraw::size newsize(10); - size = newsize; - test::equal(size.width, 10); - test::equal(size.height, 10); -} - -TEST(size_assignmentOperator_movesize) -{ - quickdraw::size size(5); - test::equal(size.width, 5); - test::equal(size.height, 5); - - size = quickdraw::size(10); - test::equal(size.width, 10); - test::equal(size.height, 10); -} - -TEST(size_equalsOperator_shouldBeEqual) -{ - test::is_true(quickdraw::size(5) == quickdraw::size(5)); -} - -TEST(size_equalsOperator_shouldNotBeEqual) -{ - test::is_false(quickdraw::size(5) == quickdraw::size(7)); -} - -TEST(size_notEqualsOperator_shouldNotBeEqual) -{ - test::is_true(quickdraw::size(5) != quickdraw::size(7)); -} - -TEST(size_notEqualsOperator_shouldBeEqual) -{ - test::is_false(quickdraw::size(5) != quickdraw::size(5)); -} - -TEST(size_addsize_returnsExpectedsize) -{ - auto result = quickdraw::size(5) + quickdraw::size(3); - test::equal(result.width, 8); - test::equal(result.height, 8); -} - -TEST(size_subtractsize_returnsExpectedsize) -{ - auto result = quickdraw::size(5) - quickdraw::size(3); - test::equal(result.width, 2); - test::equal(result.height, 2); -} - -TEST(size_multiplysize_returnsExpectedsize) -{ - auto result = quickdraw::size(5) * 3; - test::equal(result.width, 15); - test::equal(result.height, 15); -} - -TEST(size_dividesize_returnsExpectedsize) -{ - auto result = quickdraw::size(9) / 3; - test::equal(result.width, 3); - test::equal(result.height, 3); -} - -// MARK: - Casting Tests - -TEST(size_castToDifferentType_retainsSameValue) -{ - quickdraw::size size(76); - auto new_size = size.cast(); - test::equal(new_size.width, 76); - test::equal(new_size.height, 76); -} \ No newline at end of file diff --git a/Tests/util/hashing_tests.cpp b/Tests/util/hashing_tests.cpp deleted file mode 100644 index afaa811..0000000 --- a/Tests/util/hashing_tests.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include -#include - -using namespace graphite; - -// MARK: - XXHash64 Verification Tests - -TEST(xxh64_verifyCorrectHashIsProduced) -{ - std::string str = "Giraffe"; - hashing::value expected = 0xC09228325DE7E875; - test::equal(hashing::xxh64(str.c_str(), str.size()), expected); -} \ No newline at end of file diff --git a/libs/libGraphite/util/concepts.hpp b/libs/libCommon/concepts.hpp similarity index 78% rename from libs/libGraphite/util/concepts.hpp rename to libs/libCommon/concepts.hpp index c84183f..b0f8cb8 100644 --- a/libs/libGraphite/util/concepts.hpp +++ b/libs/libCommon/concepts.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tom Hancocks +// Copyright (c) 2023 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -20,13 +20,11 @@ #pragma once -#include #include +#include +#include -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/data/data.hpp" - -namespace graphite +namespace common { template concept convertible_to = std::is_convertible_v && requires { @@ -38,11 +36,4 @@ namespace graphite template concept move_constructible = constructible_from && convertible_to; - - template - concept resource_type = requires(const T& resource) { - requires constructible_from; - requires move_constructible; - { T::type_code() } -> std::same_as; - }; } \ No newline at end of file diff --git a/libs/libGraphite/hints.hpp b/libs/libCommon/hints.hpp similarity index 100% rename from libs/libGraphite/hints.hpp rename to libs/libCommon/hints.hpp diff --git a/libs/libGraphite/memory/alignment.hpp b/libs/libCommon/memory/alignment.hpp similarity index 97% rename from libs/libGraphite/memory/alignment.hpp rename to libs/libCommon/memory/alignment.hpp index 94b2b0d..9f12579 100644 --- a/libs/libGraphite/memory/alignment.hpp +++ b/libs/libCommon/memory/alignment.hpp @@ -24,7 +24,7 @@ #include #include -namespace graphite::memory::alignment +namespace common::memory::alignment { static constexpr std::size_t width = sizeof(std::uintptr_t); static constexpr std::size_t mask = ~(width - 1); diff --git a/libs/libGraphite/sys/types.hpp b/libs/libCommon/sys/types.hpp similarity index 99% rename from libs/libGraphite/sys/types.hpp rename to libs/libCommon/sys/types.hpp index d194d61..589e2fb 100644 --- a/libs/libGraphite/sys/types.hpp +++ b/libs/libCommon/sys/types.hpp @@ -30,7 +30,7 @@ // MARK: - Classic Macintosh Integer types -namespace graphite +namespace common { typedef signed char GRAPHITE_SYMBOL(sint8, SInt8, int8_t); typedef unsigned char GRAPHITE_SYMBOL(uint8, UInt8, uint8_t); diff --git a/libs/libGraphite/compression/packbits.hpp b/libs/libCompression/packbits.hpp similarity index 97% rename from libs/libGraphite/compression/packbits.hpp rename to libs/libCompression/packbits.hpp index 2b5c5a3..a562278 100644 --- a/libs/libGraphite/compression/packbits.hpp +++ b/libs/libCompression/packbits.hpp @@ -21,11 +21,11 @@ #pragma once #include -#include "libGraphite/data/data.hpp" -#include "libGraphite/data/writer.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include +#include -namespace graphite::compression +namespace compression { template struct packbits diff --git a/libs/libGraphite/CMakeLists.txt b/libs/libData/CMakeLists.txt similarity index 90% rename from libs/libGraphite/CMakeLists.txt rename to libs/libData/CMakeLists.txt index ac68153..b0aef14 100644 --- a/libs/libGraphite/CMakeLists.txt +++ b/libs/libData/CMakeLists.txt @@ -27,12 +27,12 @@ set(CMAKE_CXX_STANDARD 20) ######################################################################################################################## ## libSIMD -file(GLOB_RECURSE libGraphite_Sources +file(GLOB_RECURSE libData_Sources *.cpp ) -add_library(Graphite ${libGraphite_Sources}) -target_link_libraries(Graphite SIMD) -target_include_directories(Graphite PUBLIC +add_library(Data ${libData_Sources}) +target_link_libraries(Data SIMD Encoding) +target_include_directories(Data PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libGraphite/data/data.cpp b/libs/libData/block.cpp similarity index 77% rename from libs/libGraphite/data/data.cpp rename to libs/libData/block.cpp index 3004b06..d67f719 100644 --- a/libs/libGraphite/data/data.cpp +++ b/libs/libData/block.cpp @@ -18,40 +18,41 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include #include -#include #include +#include +#include +#include #include #include -#include "libGraphite/memory/alignment.hpp" -#include "libGraphite/data/data.hpp" +#include +#include // MARK: - Construction -graphite::data::block::block(std::size_t capacity, enum byte_order order) - : m_raw_size(memory::alignment::expand_capacity(capacity)), +data::block::block(std::size_t capacity, enum byte_order order) + : m_raw_size(common::memory::alignment::expand_capacity(capacity)), m_data_size(capacity), m_raw(malloc(m_raw_size)), - m_data(memory::alignment::align(m_raw)), + m_data(common::memory::alignment::align(m_raw)), m_allocation_owner(nullptr), m_byte_order(order), m_has_ownership(true) { } -graphite::data::block::block(std::size_t capacity, std::size_t allocation_size, enum byte_order order) - : m_raw_size(memory::alignment::expand_capacity(allocation_size)), +data::block::block(std::size_t capacity, std::size_t allocation_size, enum byte_order order) + : m_raw_size(common::memory::alignment::expand_capacity(allocation_size)), m_data_size(capacity), m_raw(malloc(m_raw_size)), - m_data(memory::alignment::align(m_raw)), + m_data(common::memory::alignment::align(m_raw)), m_allocation_owner(nullptr), m_byte_order(order), m_has_ownership(true) { } -graphite::data::block::block(const std::string &path, enum byte_order order) +data::block::block(const std::string &path, enum byte_order order) : m_byte_order(order), m_allocation_owner(nullptr), m_has_ownership(true) @@ -66,23 +67,23 @@ graphite::data::block::block(const std::string &path, enum byte_order order) m_data_size = file.tellg(); file.seekg(0, std::ios::beg); - m_raw_size = memory::alignment::expand_capacity(m_data_size); + m_raw_size = common::memory::alignment::expand_capacity(m_data_size); m_raw = malloc(m_raw_size); - m_data = memory::alignment::align(m_raw); + m_data = common::memory::alignment::align(m_raw); file.read(reinterpret_cast(m_data), m_data_size); file.close(); } -graphite::data::block::block(const std::vector& bytes, enum byte_order order) +data::block::block(const std::vector& bytes, enum byte_order order) : m_byte_order(order), m_allocation_owner(nullptr), m_has_ownership(true) { m_data_size = bytes.size(); - m_raw_size = memory::alignment::expand_capacity(m_data_size); + m_raw_size = common::memory::alignment::expand_capacity(m_data_size); m_raw = malloc(m_raw_size); - m_data = memory::alignment::align(m_raw); + m_data = common::memory::alignment::align(m_raw); // TODO: This is slow, and should be speeded up in the future. auto ptr = static_cast(m_data); @@ -91,7 +92,7 @@ graphite::data::block::block(const std::vector& bytes, enum byte_order ord } } -graphite::data::block::block(const block &source, bool copy) +data::block::block(const block &source, bool copy) : m_raw_size(source.m_raw_size), m_data_size(source.m_data_size), m_start_position(source.m_start_position), @@ -104,7 +105,7 @@ graphite::data::block::block(const block &source, bool copy) clone_from(source); } -graphite::data::block::block(const block &source, block::position pos, std::size_t amount, bool copy) +data::block::block(const block &source, block::position pos, std::size_t amount, bool copy) : m_allocation_owner(copy ? nullptr : &source), m_byte_order(source.m_byte_order), m_extended(source.m_extended) @@ -121,17 +122,17 @@ graphite::data::block::block(const block &source, block::position pos, std::size const_cast(m_allocation_owner)->m_users++; } else { - m_raw_size = memory::alignment::expand_capacity(amount); + m_raw_size = common::memory::alignment::expand_capacity(amount); m_data_size = amount; m_raw = malloc(m_raw_size); - m_data = memory::alignment::align(m_raw); + m_data = common::memory::alignment::align(m_raw); m_start_position = 0; m_count = 0; m_has_ownership = true; } } -graphite::data::block::block(const void *data, std::size_t count, bool take_ownership, enum byte_order order) +data::block::block(const void *data, std::size_t count, bool take_ownership, enum byte_order order) : m_allocation_owner(nullptr), m_has_ownership(take_ownership), m_raw(const_cast(data)), @@ -144,7 +145,7 @@ graphite::data::block::block(const void *data, std::size_t count, bool take_owne { } -graphite::data::block::block(const block &data) +data::block::block(const block &data) : m_raw_size(data.m_raw_size), m_data_size(data.m_data_size), m_allocation_owner(nullptr), @@ -157,7 +158,7 @@ graphite::data::block::block(const block &data) { if (m_has_ownership) { m_raw = malloc(m_raw_size); - m_data = memory::alignment::align(m_raw); + m_data = common::memory::alignment::align(m_raw); copy_from(data); } else { @@ -166,7 +167,7 @@ graphite::data::block::block(const block &data) } } -graphite::data::block::block(block &&data) noexcept +data::block::block(block &&data) noexcept : m_raw_size(data.m_raw_size), m_data_size(data.m_data_size), m_raw(data.m_raw), @@ -187,7 +188,7 @@ graphite::data::block::block(block &&data) noexcept data.m_allocation_owner = nullptr; } -auto graphite::data::block::operator=(const block &data) -> struct block & +auto data::block::operator=(const block &data) -> struct block & { if (this == const_cast(&data)) { return *this; @@ -213,13 +214,13 @@ auto graphite::data::block::operator=(const block &data) -> struct block & m_extended = data.m_extended; m_raw = malloc(m_raw_size); - m_data = memory::alignment::align(m_raw); + m_data = common::memory::alignment::align(m_raw); copy_from(data); return *this; } -auto graphite::data::block::operator=(block &&data) noexcept -> struct block & +auto data::block::operator=(block &&data) noexcept -> struct block & { if (this != &data) { // Clean up the current data... @@ -255,7 +256,7 @@ auto graphite::data::block::operator=(block &&data) noexcept -> struct block & // MARK: - Destruction -graphite::data::block::~block() +data::block::~block() { if (m_allocation_owner) { const_cast(m_allocation_owner)->m_users--; @@ -268,7 +269,7 @@ graphite::data::block::~block() // MARK: - Copy/Clone -auto graphite::data::block::clone_from(const graphite::data::block &source) -> void +auto data::block::clone_from(const data::block &source) -> void { m_extended = source.m_extended; if (m_allocation_owner) { @@ -279,13 +280,13 @@ auto graphite::data::block::clone_from(const graphite::data::block &source) -> v } else { m_raw = malloc(m_raw_size); - m_data = memory::alignment::align(m_raw); + m_data = common::memory::alignment::align(m_raw); m_has_ownership = true; copy_from(source); } } -__attribute__((optnone)) auto graphite::data::block::copy_from(const block &source) -> void +__attribute__((optnone)) auto data::block::copy_from(const block &source) -> void { auto source_ptr = source.get(); auto dest_ptr = get(); @@ -294,7 +295,7 @@ __attribute__((optnone)) auto graphite::data::block::copy_from(const block &sour // MARK: - Operations -auto graphite::data::block::increase_size_to(std::size_t new_size) -> void +auto data::block::increase_size_to(std::size_t new_size) -> void { if (new_size > m_raw_size) { throw std::runtime_error("Attempted to increase size of data::block beyond allowed range."); @@ -302,29 +303,29 @@ auto graphite::data::block::increase_size_to(std::size_t new_size) -> void m_data_size = new_size; } -auto graphite::data::block::clear() -> void +auto data::block::clear() -> void { simd::memory::zero(get(), size()); } -auto graphite::data::block::set(uint8_t value, std::size_t bytes, block::position start) -> void +auto data::block::set(uint8_t value, std::size_t bytes, block::position start) -> void { simd::string::set(get(start), value, std::min(static_cast(size() - start), bytes)); } -auto graphite::data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void +auto data::block::set(uint16_t value, std::size_t bytes, block::position start) -> void { simd::string::setw(get(start), value, std::min(static_cast(size() - start), bytes)); } -auto graphite::data::block::set(uint32_t value, std::size_t bytes, block::position start) -> void +auto data::block::set(uint32_t value, std::size_t bytes, block::position start) -> void { simd::string::setl(get(start), value, std::min(static_cast(size() - start), bytes)); } // MARK: - Slicing -auto graphite::data::block::slice(block::position pos, std::size_t size, bool copy) const -> block +auto data::block::slice(block::position pos, std::size_t size, bool copy) const -> block { return std::move(block(*this, m_start_position + pos, size, copy)); } diff --git a/libs/libGraphite/data/data.hpp b/libs/libData/block.hpp similarity index 96% rename from libs/libGraphite/data/data.hpp rename to libs/libData/block.hpp index 04a39da..0987d60 100644 --- a/libs/libGraphite/data/data.hpp +++ b/libs/libData/block.hpp @@ -25,10 +25,9 @@ #include #include #include -#include "libGraphite/data/endianess.hpp" -//#include "libGraphite/data/simd.hpp" +#include -namespace graphite::data +namespace data { struct block; @@ -112,7 +111,7 @@ namespace graphite::data return reinterpret_cast(reinterpret_cast(m_data) + m_start_position + offset); } - auto clone_from(const graphite::data::block& source) -> void; + auto clone_from(const data::block& source) -> void; }; } diff --git a/libs/libGraphite/data/encoding.hpp b/libs/libData/encoding.hpp similarity index 89% rename from libs/libGraphite/data/encoding.hpp rename to libs/libData/encoding.hpp index dd31414..03552f9 100644 --- a/libs/libGraphite/data/encoding.hpp +++ b/libs/libData/encoding.hpp @@ -22,9 +22,9 @@ #include #include -#include "libGraphite/util/concepts.hpp" +#include -namespace graphite::data +namespace data { struct reader; struct writer; @@ -36,8 +36,8 @@ namespace graphite::data template concept decodable = requires(const T& object) { - requires constructible_from; - requires move_constructible; + requires common::constructible_from; + requires common::move_constructible; }; } \ No newline at end of file diff --git a/libs/libGraphite/data/endianess.hpp b/libs/libData/endianess.hpp similarity index 91% rename from libs/libGraphite/data/endianess.hpp rename to libs/libData/endianess.hpp index e5f8ded..5e34ebf 100644 --- a/libs/libGraphite/data/endianess.hpp +++ b/libs/libData/endianess.hpp @@ -20,7 +20,11 @@ #pragma once -namespace graphite::data +#include +#include +#include + +namespace data { // MARK: - Byte Order Enumeration @@ -30,9 +34,9 @@ namespace graphite::data // MARK: - Compile Time Constants #if __LITTLE_ENDIAN__ - static graphite::data::byte_order s_native_byte_order = graphite::data::byte_order::lsb; + static data::byte_order s_native_byte_order = data::byte_order::lsb; #else - static graphite::data::byte_order s_native_byte_order = graphite::data::byte_order::msb; + static data::byte_order s_native_byte_order = data::byte_order::msb; #endif static auto native_byte_order() -> enum byte_order diff --git a/libs/libGraphite/data/internals/specialised_reader.hpp b/libs/libData/internals/specialised_reader.hpp similarity index 95% rename from libs/libGraphite/data/internals/specialised_reader.hpp rename to libs/libData/internals/specialised_reader.hpp index be4a311..a1fe307 100644 --- a/libs/libGraphite/data/internals/specialised_reader.hpp +++ b/libs/libData/internals/specialised_reader.hpp @@ -20,15 +20,16 @@ #pragma once -#include "libGraphite/data/endianess.hpp" +#include +#include +#include -namespace graphite::data::internals +namespace data::internals { class specialised_reader { public: - virtual auto swap(std::uint8_t value, std::size_t size = 1) -> std::uint8_t { return value; diff --git a/libs/libGraphite/data/internals/swap_reader.hpp b/libs/libData/internals/swap_reader.hpp similarity index 78% rename from libs/libGraphite/data/internals/swap_reader.hpp rename to libs/libData/internals/swap_reader.hpp index bd99909..c2c2898 100644 --- a/libs/libGraphite/data/internals/swap_reader.hpp +++ b/libs/libData/internals/swap_reader.hpp @@ -20,9 +20,11 @@ #pragma once -#include "libGraphite/data/internals/specialised_reader.hpp" +#include +#include +#include -namespace graphite::data::internals +namespace data::internals { class swap_reader: public specialised_reader @@ -31,42 +33,42 @@ namespace graphite::data::internals auto swap(std::uint8_t value, std::size_t size = 1) -> std::uint8_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; auto swap(std::uint16_t value, std::size_t size = 2) -> std::uint16_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; auto swap(std::uint32_t value, std::size_t size = 4) -> std::uint32_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; auto swap(std::uint64_t value, std::size_t size = 1) -> std::uint64_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; auto swap(std::int8_t value, std::size_t size = 1) -> std::int8_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; auto swap(std::int16_t value, std::size_t size = 2) -> std::int16_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; auto swap(std::int32_t value, std::size_t size = 4) -> std::int32_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; auto swap(std::int64_t value, std::size_t size = 8) -> std::int64_t override { - return graphite::data::fixed_swap(value, size); + return data::fixed_swap(value, size); }; }; diff --git a/libs/libGraphite/data/reader.cpp b/libs/libData/reader.cpp similarity index 59% rename from libs/libGraphite/data/reader.cpp rename to libs/libData/reader.cpp index 137f0c5..3c045d7 100644 --- a/libs/libGraphite/data/reader.cpp +++ b/libs/libData/reader.cpp @@ -23,13 +23,13 @@ #include #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/endianess.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" +#include +#include +#include // MARK: - Construction -graphite::data::reader::reader(const class block *data, block::position pos, bool owns) +data::reader::reader(const class block *data, block::position pos, bool owns) : m_data(data), m_owns_data(owns), m_position(pos) @@ -37,7 +37,7 @@ graphite::data::reader::reader(const class block *data, block::position pos, boo update_swap_wrapper(); } -auto graphite::data::reader::file(const std::string &path, block::position pos) -> reader +auto data::reader::file(const std::string &path, block::position pos) -> reader { auto data = new class block(path, byte_order::msb); return reader(data, pos, true); @@ -45,7 +45,7 @@ auto graphite::data::reader::file(const std::string &path, block::position pos) // MARK: - Destruction -graphite::data::reader::~reader() +data::reader::~reader() { if (m_owns_data) { delete m_data; @@ -54,22 +54,22 @@ graphite::data::reader::~reader() // MARK: - Position Management -auto graphite::data::reader::set_position(block::position pos) -> void +auto data::reader::set_position(block::position pos) -> void { m_position = static_cast(std::max(static_cast(0), std::min(static_cast(pos), size() + 1))); } -auto graphite::data::reader::move(block::position delta) -> void +auto data::reader::move(block::position delta) -> void { set_position(position() + delta); } -auto graphite::data::reader::save_position() -> void +auto data::reader::save_position() -> void { m_position_stack.emplace_back(m_position); } -auto graphite::data::reader::restore_position() -> void +auto data::reader::restore_position() -> void { if (m_position_stack.empty()) { throw std::runtime_error("Attempted to restore position of data reader, when no saved positions exist."); @@ -80,57 +80,57 @@ auto graphite::data::reader::restore_position() -> void // MARK: - Read Operations -auto graphite::data::reader::read_byte(block::position offset, mode mode) -> uint8_t +auto data::reader::read_byte(block::position offset, mode mode) -> std::uint8_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_byte(block::position offset, mode mode) -> int8_t +auto data::reader::read_signed_byte(block::position offset, mode mode) -> std::int8_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_short(block::position offset, mode mode) -> uint16_t +auto data::reader::read_short(block::position offset, mode mode) -> std::uint16_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_short(block::position offset, mode mode) -> int16_t +auto data::reader::read_signed_short(block::position offset, mode mode) -> std::int16_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_fixed_point(block::position offset, mode mode) -> double +auto data::reader::read_fixed_point(block::position offset, mode mode) -> double { return static_cast(read_signed_long(offset, mode)) / static_cast(1 << 16); } -auto graphite::data::reader::read_triple(block::position offset, mode mode) -> uint32_t +auto data::reader::read_triple(block::position offset, mode mode) -> std::uint32_t { - return read_integer(offset, mode, 3); + return read_integer(offset, mode, 3); } -auto graphite::data::reader::read_long(block::position offset, mode mode) -> uint32_t +auto data::reader::read_long(block::position offset, mode mode) -> std::uint32_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_long(block::position offset, mode mode) -> int32_t +auto data::reader::read_signed_long(block::position offset, mode mode) -> std::int32_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_quad(block::position offset, mode mode) -> uint64_t +auto data::reader::read_quad(block::position offset, mode mode) -> std::uint64_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_signed_quad(block::position offset, mode mode) -> int64_t +auto data::reader::read_signed_quad(block::position offset, mode mode) -> std::int64_t { - return read_integer(offset, mode); + return read_integer(offset, mode); } -auto graphite::data::reader::read_pstr(block::position offset, mode mode) -> std::string +auto data::reader::read_pstr(block::position offset, mode mode) -> std::string { switch (mode) { case mode::advance: { @@ -147,9 +147,9 @@ auto graphite::data::reader::read_pstr(block::position offset, mode mode) -> std } } -auto graphite::data::reader::read_cstr(std::size_t length, block::position offset, mode mode) -> std::string +auto data::reader::read_cstr(std::size_t length, block::position offset, mode mode) -> std::string { - std::vector bytes; + std::vector bytes; if (length == 0) { block::position i = 0; @@ -167,14 +167,14 @@ auto graphite::data::reader::read_cstr(std::size_t length, block::position offse if (byte == '\0') { break; } - bytes.emplace_back(static_cast(byte)); + bytes.emplace_back(static_cast(byte)); } } return encoding::mac_roman::to_utf8(bytes); } -auto graphite::data::reader::read_data(std::size_t length, block::position offset, mode mode) -> class block +auto data::reader::read_data(std::size_t length, block::position offset, mode mode) -> class block { auto sliced = std::move(m_data->slice(m_position + offset, length)); if (mode == mode::advance) { @@ -183,10 +183,9 @@ auto graphite::data::reader::read_data(std::size_t length, block::position offse return std::move(sliced); } -auto graphite::data::reader::read_bytes(std::size_t length, block::position offset, mode mode) -> std::vector +auto data::reader::read_bytes(std::size_t length, block::position offset, mode mode) -> std::vector { auto start = m_data->get(m_position + offset); - auto end = m_data->get(m_position + offset + length); move(offset + length); std::vector bytes(std::max(length, static_cast(28)), '\0'); diff --git a/libs/libGraphite/data/reader.hpp b/libs/libData/reader.hpp similarity index 94% rename from libs/libGraphite/data/reader.hpp rename to libs/libData/reader.hpp index aaab4da..f203dad 100644 --- a/libs/libGraphite/data/reader.hpp +++ b/libs/libData/reader.hpp @@ -22,19 +22,14 @@ #include #include -#include "libGraphite/data/data.hpp" -#include "libGraphite/util/concepts.hpp" -#include "libGraphite/data/encoding.hpp" -#include "libGraphite/data/internals/specialised_reader.hpp" -#include "libGraphite/data/internals/swap_reader.hpp" +#include +#include +#include +#include +#include -namespace graphite::data +namespace data { - class reader; - - template - concept readable_resource_type = resource_type && decodable; - class reader { public: @@ -136,7 +131,7 @@ namespace graphite::data } move(offset); - graphite::data::decodable auto object = T(*this); + data::decodable auto object = T(*this); if (mode == mode::peek) { restore_position(); diff --git a/libs/libGraphite/data/simd.hpp b/libs/libData/simd.hpp similarity index 97% rename from libs/libGraphite/data/simd.hpp rename to libs/libData/simd.hpp index 33699f6..0e18517 100644 --- a/libs/libGraphite/data/simd.hpp +++ b/libs/libData/simd.hpp @@ -21,13 +21,16 @@ #pragma once #include +#include +#include +#include -namespace graphite::data +namespace data { class block; } -namespace graphite::data::simd +namespace data::simd { #if __x86_64__ diff --git a/libs/libGraphite/data/writer.cpp b/libs/libData/writer.cpp similarity index 70% rename from libs/libGraphite/data/writer.cpp rename to libs/libData/writer.cpp index 62b1b27..4be77d3 100644 --- a/libs/libGraphite/data/writer.cpp +++ b/libs/libData/writer.cpp @@ -22,19 +22,19 @@ #include #include #include -#include "libGraphite/data/writer.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" +#include +#include // MARK: - Construction -graphite::data::writer::writer(enum byte_order order) +data::writer::writer(enum byte_order order) : m_owns_data(true), m_data(new class block(0, order)) { } -graphite::data::writer::writer(const class block *data) +data::writer::writer(const class block *data) : m_owns_data(false), m_data(data) { @@ -43,7 +43,7 @@ graphite::data::writer::writer(const class block *data) // MARK: - Destruction -graphite::data::writer::~writer() +data::writer::~writer() { if (m_owns_data) { delete m_data; @@ -52,7 +52,7 @@ graphite::data::writer::~writer() // MARK: - Storage Management -auto graphite::data::writer::expand_storage(std::size_t amount) -> void +auto data::writer::expand_storage(std::size_t amount) -> void { // NOTE: We only allow resizing of data objects that we own. assert(m_owns_data); @@ -75,7 +75,7 @@ auto graphite::data::writer::expand_storage(std::size_t amount) -> void } -auto graphite::data::writer::ensure_required_space(block::position position, std::size_t amount) -> void +auto data::writer::ensure_required_space(block::position position, std::size_t amount) -> void { auto remaining = static_cast(this->size()) - position; auto delta = 0; @@ -87,7 +87,7 @@ auto graphite::data::writer::ensure_required_space(block::position position, std // MARK: - Position Management -auto graphite::data::writer::set_position(block::position pos) -> void +auto data::writer::set_position(block::position pos) -> void { if (pos < 0 || pos > size()) { throw std::runtime_error("Attempted to set position of data reader out of bounds."); @@ -95,65 +95,65 @@ auto graphite::data::writer::set_position(block::position pos) -> void m_position = pos; } -auto graphite::data::writer::move(block::position delta) -> void +auto data::writer::move(block::position delta) -> void { set_position(m_position + delta); } // MARK: - Write Operations -auto graphite::data::writer::write_byte(uint8_t value, std::size_t count) -> void +auto data::writer::write_byte(uint8_t value, std::size_t count) -> void { write_integer(value, count); } -auto graphite::data::writer::write_signed_byte(int8_t value, std::size_t count) -> void +auto data::writer::write_signed_byte(int8_t value, std::size_t count) -> void { write_integer(static_cast(value), count); } -auto graphite::data::writer::write_short(uint16_t value, std::size_t count) -> void +auto data::writer::write_short(uint16_t value, std::size_t count) -> void { write_integer(value, count); } -auto graphite::data::writer::write_signed_short(int16_t value, std::size_t count) -> void +auto data::writer::write_signed_short(int16_t value, std::size_t count) -> void { write_integer(static_cast(value), count); }; -auto graphite::data::writer::write_fixed_point(double value, std::size_t count) -> void +auto data::writer::write_fixed_point(double value, std::size_t count) -> void { auto integral_value = static_cast(value * (1 << 16)); write_integer(integral_value, count); } -auto graphite::data::writer::write_triple(uint32_t value, std::size_t count) -> void +auto data::writer::write_triple(uint32_t value, std::size_t count) -> void { write_integer(value, count, 3); }; -auto graphite::data::writer::write_long(uint32_t value, std::size_t count) -> void +auto data::writer::write_long(uint32_t value, std::size_t count) -> void { write_integer(value, count); }; -auto graphite::data::writer::write_signed_long(int32_t value, std::size_t count) -> void +auto data::writer::write_signed_long(int32_t value, std::size_t count) -> void { write_integer(static_cast(value), count); }; -auto graphite::data::writer::write_quad(uint64_t value, std::size_t count) -> void +auto data::writer::write_quad(uint64_t value, std::size_t count) -> void { write_integer(value, count); }; -auto graphite::data::writer::write_signed_quad(int64_t value, std::size_t count) -> void +auto data::writer::write_signed_quad(int64_t value, std::size_t count) -> void { write_integer(static_cast(value), count); } -auto graphite::data::writer::write_pstr(const std::string &str) -> std::size_t +auto data::writer::write_pstr(const std::string &str) -> std::size_t { auto bytes = encoding::mac_roman::from_utf8(str); @@ -166,7 +166,7 @@ auto graphite::data::writer::write_pstr(const std::string &str) -> std::size_t return bytes.size(); } -auto graphite::data::writer::write_cstr(const std::string &str, std::size_t size) -> std::size_t +auto data::writer::write_cstr(const std::string &str, std::size_t size) -> std::size_t { std::vector bytes { encoding::mac_roman::from_utf8(str) }; @@ -183,7 +183,7 @@ auto graphite::data::writer::write_cstr(const std::string &str, std::size_t size return bytes.size(); } -auto graphite::data::writer::write_bytes(const std::vector &bytes) -> void +auto data::writer::write_bytes(const std::vector &bytes) -> void { ensure_required_space(position(), bytes.size()); auto ptr = m_data->template get(position()); @@ -194,12 +194,12 @@ auto graphite::data::writer::write_bytes(const std::vector &bytes) -> v } } -auto graphite::data::writer::write_bytes(const std::vector &bytes) -> void +auto data::writer::write_bytes(const std::vector &bytes) -> void { write_bytes(std::vector(bytes.begin(), bytes.end())); } -auto graphite::data::writer::write_data(const class block *data) -> void +auto data::writer::write_data(const class block *data) -> void { assert(data != m_data); @@ -215,7 +215,7 @@ auto graphite::data::writer::write_data(const class block *data) -> void // MARK: - Padding -auto graphite::data::writer::pad_to_size(std::size_t size) -> void +auto data::writer::pad_to_size(std::size_t size) -> void { if (this->size() >= size) { return; @@ -228,7 +228,7 @@ auto graphite::data::writer::pad_to_size(std::size_t size) -> void // MARK: - Saving / File Access -auto graphite::data::writer::save(const std::string &path, std::size_t size) const -> void +auto data::writer::save(const std::string &path, std::size_t size) const -> void { std::ofstream file { path, std::ios::out | std::ios::binary }; file.write(m_data->get(), size == 0 ? m_data->size() : size); diff --git a/libs/libGraphite/data/writer.hpp b/libs/libData/writer.hpp similarity index 98% rename from libs/libGraphite/data/writer.hpp rename to libs/libData/writer.hpp index 42d669d..9473957 100644 --- a/libs/libGraphite/data/writer.hpp +++ b/libs/libData/writer.hpp @@ -20,13 +20,14 @@ #pragma once +#include #include #include -#include "libGraphite/data/data.hpp" -#include "libGraphite/util/concepts.hpp" -#include "libGraphite/data/encoding.hpp" +#include +#include +#include -namespace graphite::data +namespace data { class writer { diff --git a/libs/libEncoding/CMakeLists.txt b/libs/libEncoding/CMakeLists.txt new file mode 100644 index 0000000..1f21de6 --- /dev/null +++ b/libs/libEncoding/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libEncoding_Sources + *.cpp +) + +add_library(Encoding ${libEncoding_Sources}) +target_include_directories(Encoding PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libGraphite/encoding/macroman/macroman.cpp b/libs/libEncoding/macroman/macroman.cpp similarity index 90% rename from libs/libGraphite/encoding/macroman/macroman.cpp rename to libs/libEncoding/macroman/macroman.cpp index fc1f11c..3882a0f 100644 --- a/libs/libGraphite/encoding/macroman/macroman.cpp +++ b/libs/libEncoding/macroman/macroman.cpp @@ -20,7 +20,7 @@ #include #include -#include "libGraphite/encoding/macroman/macroman.hpp" +#include // MARK: - Encoding Tables @@ -88,11 +88,11 @@ namespace unicode { static std::vector utf8; if (utf8.empty()) { - utf8.emplace_back(unicode::hint(0b00111111, 0b10000000, 0, 0, 6)); - utf8.emplace_back(unicode::hint(0b01111111, 0b00000000, 0000, 0177, 7)); - utf8.emplace_back(unicode::hint(0b00011111, 0b11000000, 0200, 03777, 5)); - utf8.emplace_back(unicode::hint(0b00001111, 0b11100000, 04000, 0177777, 4)); - utf8.emplace_back(unicode::hint(0b00000111, 0b11110000, 0200000, 04177777, 3)); + utf8.emplace_back(0b00111111, 0b10000000, 0, 0, 6); + utf8.emplace_back(0b01111111, 0b00000000, 0000, 0177, 7); + utf8.emplace_back(0b00011111, 0b11000000, 0200, 03777, 5); + utf8.emplace_back(0b00001111, 0b11100000, 04000, 0177777, 4); + utf8.emplace_back(0b00000111, 0b11110000, 0200000, 04177777, 3); } return utf8; } @@ -102,7 +102,7 @@ namespace unicode // MARK: - Conversion Functions -auto graphite::encoding::mac_roman::from_utf8(const std::string &str) -> std::vector +auto encoding::mac_roman::from_utf8(const std::string &str) -> std::vector { std::vector mac_roman_bytes; @@ -148,7 +148,7 @@ auto graphite::encoding::mac_roman::from_utf8(const std::string &str) -> std::ve return mac_roman_bytes; } -auto graphite::encoding::mac_roman::to_utf8(const std::vector& bytes) -> std::string +auto encoding::mac_roman::to_utf8(const std::vector& bytes) -> std::string { std::string result; diff --git a/libs/libGraphite/encoding/macroman/macroman.hpp b/libs/libEncoding/macroman/macroman.hpp similarity index 93% rename from libs/libGraphite/encoding/macroman/macroman.hpp rename to libs/libEncoding/macroman/macroman.hpp index b8bdc57..c745809 100644 --- a/libs/libGraphite/encoding/macroman/macroman.hpp +++ b/libs/libEncoding/macroman/macroman.hpp @@ -21,10 +21,10 @@ #include #include -#if !defined(GRAPHITE_MACROMAN) -#define GRAPHITE_MACROMAN +#if !defined(ENCODING_MACROMAN) +#define ENCODING_MACROMAN -namespace graphite::encoding::mac_roman { +namespace encoding::mac_roman { /** * Convert a sequence of bytes into a UTF-8 string, translating them from a diff --git a/libs/libGraphite/rsrc/resource.cpp b/libs/libGraphite/rsrc/resource.cpp deleted file mode 100644 index 35a9bf7..0000000 --- a/libs/libGraphite/rsrc/resource.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2022 Tom Hancocks -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/util/hashing.hpp" - -// MARK: - Construction - -graphite::rsrc::resource::resource(resource::identifier id, const std::string &name) - : m_id(id), m_name(name) -{ -} - -graphite::rsrc::resource::resource(struct type *type, resource::identifier id, const std::string &name, data::block data) - : m_type(type), m_id(id), m_name(name), m_data(std::move(data)) -{ -} - -graphite::rsrc::resource::resource(const resource &resource) - : m_type(resource.m_type), - m_id(resource.m_id), - m_name(resource.m_name), - m_data(data::block(resource.m_data, true)) -{ -} - -graphite::rsrc::resource::resource(resource &&resource) noexcept - : m_type(resource.m_type), - m_id(resource.m_id), - m_name(std::move(resource.m_name)), - m_data(std::move(resource.m_data)) -{ - resource.m_type = nullptr; -} - -// MARK: - Destruction - -graphite::rsrc::resource::~resource() -{ -} - -// MARK: - Operators - -auto graphite::rsrc::resource::operator=(const resource &resource) -> struct resource & -{ - if (this == const_cast(&resource)) { - return *this; - } - - m_id = resource.m_id; - m_type = resource.m_type; - m_name = resource.m_name; - m_data = resource.m_data; - m_data_offset = resource.m_data_offset; - - return *this; -} - -auto graphite::rsrc::resource::operator=(resource &&resource) noexcept -> struct resource & -{ - if (this != &resource) { - m_id = resource.m_id; - m_type = resource.m_type; - m_name = std::move(resource.m_name); - m_data = std::move(resource.m_data); - m_data_offset = resource.m_data_offset; - } - return *this; -} - -// MARK: - Accessors - -auto graphite::rsrc::resource::id() const -> resource::identifier -{ - return m_id; -} - -auto graphite::rsrc::resource::type() const -> struct type * -{ - return m_type; -} - -auto graphite::rsrc::resource::name() const -> const std::string& -{ - return m_name; -} - -auto graphite::rsrc::resource::type_code() const -> std::string -{ - if (m_type) { - return m_type->code(); - } - else { - return "????"; - } -} - -auto graphite::rsrc::resource::data() const -> const data::block& -{ - return m_data; -} - -auto graphite::rsrc::resource::set_id(resource::identifier id) -> void -{ - m_id = id; -} - -auto graphite::rsrc::resource::set_name(const std::string &name) -> void -{ - m_name = name; -} - -auto graphite::rsrc::resource::set_type(struct type *type) -> void -{ - m_type = type; -} - -auto graphite::rsrc::resource::set_data(graphite::data::block &data) -> void -{ - m_data = data; - m_data_offset = 0; -} - -// MARK: - Hashing - -auto graphite::rsrc::resource::hash(identifier id) -> identifier_hash -{ - return hashing::xxh64(&id, sizeof(id)); -} - -auto graphite::rsrc::resource::hash(const std::string &name) -> name_hash -{ - return hashing::xxh64(name.c_str(), name.size()); -} - -// MARK: - Data Offsets - -auto graphite::rsrc::resource::set_data_offset(std::size_t offset) -> void -{ - m_data_offset = offset; -} - -auto graphite::rsrc::resource::data_offset() const -> std::size_t -{ - return m_data_offset; -} diff --git a/libs/libHashing/CMakeLists.txt b/libs/libHashing/CMakeLists.txt new file mode 100644 index 0000000..2bc5af1 --- /dev/null +++ b/libs/libHashing/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libHashing_Sources + *.cpp +) + +add_library(Hashing ${libHashing_Sources}) +target_include_directories(Hashing PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libGraphite/util/hashing.cpp b/libs/libHashing/xxhash/xxhash.cpp similarity index 95% rename from libs/libGraphite/util/hashing.cpp rename to libs/libHashing/xxhash/xxhash.cpp index 8f07cc2..04ac179 100644 --- a/libs/libGraphite/util/hashing.cpp +++ b/libs/libHashing/xxhash/xxhash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tom Hancocks +// Copyright (c) 2023 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,8 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include "libGraphite/util/hashing.hpp" +#include // MARK: - Constants @@ -47,7 +46,7 @@ static std::uint32_t xxhash32_p5 = 374761393U; // MARK: - XXHash64 -auto graphite::hashing::xxh64(const void *src, std::size_t length) -> hashing::value64 +auto hashing::xxh64(const void *src, std::size_t length) -> hashing::value64 { uint64_t h64 { 0 }; auto ptr = const_cast(reinterpret_cast(src)); @@ -147,7 +146,7 @@ auto graphite::hashing::xxh64(const void *src, std::size_t length) -> hashing::v } -auto graphite::hashing::xxh32(const void *src, std::size_t length) -> value32 +auto hashing::xxh32(const void *src, std::size_t length) -> value32 { uint32_t h32 { 0 }; auto ptr = const_cast(reinterpret_cast(src)); diff --git a/libs/libGraphite/util/hashing.hpp b/libs/libHashing/xxhash/xxhash.hpp similarity index 95% rename from libs/libGraphite/util/hashing.hpp rename to libs/libHashing/xxhash/xxhash.hpp index 7378991..8fdf02d 100644 --- a/libs/libGraphite/util/hashing.hpp +++ b/libs/libHashing/xxhash/xxhash.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tom Hancocks +// Copyright (c) 2023 Tom Hancocks // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,10 @@ #pragma once -#include +#include +#include -namespace graphite::hashing +namespace hashing { /** * A 64-bit hash value. @@ -52,4 +53,3 @@ namespace graphite::hashing */ auto xxh32(const void *ptr, std::size_t length) -> hashing::value32; } - diff --git a/libs/libQuickdraw/CMakeLists.txt b/libs/libQuickdraw/CMakeLists.txt new file mode 100644 index 0000000..d3fa262 --- /dev/null +++ b/libs/libQuickdraw/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libQuickDraw_Sources + *.cpp +) + +add_library(QuickDraw ${libQuickDraw_Sources}) +target_link_libraries(QuickDraw SIMD Data Resource) +target_include_directories(QuickDraw PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libGraphite/quickdraw/type/color.cpp b/libs/libQuickdraw/color/color.cpp similarity index 86% rename from libs/libGraphite/quickdraw/type/color.cpp rename to libs/libQuickdraw/color/color.cpp index 40fcf9d..4f442fe 100644 --- a/libs/libGraphite/quickdraw/type/color.cpp +++ b/libs/libQuickdraw/color/color.cpp @@ -19,11 +19,11 @@ // SOFTWARE. #include -#include "libGraphite/quickdraw/type/color.hpp" +#include // MARK: - Construction -auto graphite::quickdraw::rgb(color_component r, color_component g, color_component b, color_component a) -> union color +auto quickdraw::rgb(color_component r, color_component g, color_component b, color_component a) -> union color { return { .components = { @@ -32,7 +32,7 @@ auto graphite::quickdraw::rgb(color_component r, color_component g, color_compon }; } -auto graphite::quickdraw::rgb(std::uint16_t rgb555) -> union color +auto quickdraw::rgb(std::uint16_t rgb555) -> union color { union color c = { .components = { @@ -52,24 +52,24 @@ auto graphite::quickdraw::rgb(std::uint16_t rgb555) -> union color // MARK: - Pre-defined Colors -auto graphite::quickdraw::colors::white() -> union color +auto quickdraw::colors::white() -> union color { return rgb(255, 255, 255); } -auto graphite::quickdraw::colors::black() -> union color +auto quickdraw::colors::black() -> union color { return rgb(0, 0, 0); } -auto graphite::quickdraw::colors::clear() -> union color +auto quickdraw::colors::clear() -> union color { return rgb(0, 0, 0, 0); } // MARK: - YCrCb Color -auto graphite::quickdraw::ycbcr(const union color& rgb) -> union ycbcr +auto quickdraw::ycbcr(const union color& rgb) -> union ycbcr { std::uint8_t r = rgb.components.red; std::uint8_t g = rgb.components.green; @@ -91,7 +91,7 @@ auto graphite::quickdraw::ycbcr(const union color& rgb) -> union ycbcr }; } -auto graphite::quickdraw::rgb(const union ycbcr& color) -> union color +auto quickdraw::rgb(const union ycbcr& color) -> union color { auto color_value = color.value & 0xFFFFFF; if (color.components.alpha < 0.05) { diff --git a/libs/libGraphite/quickdraw/type/color.hpp b/libs/libQuickdraw/color/color.hpp similarity index 98% rename from libs/libGraphite/quickdraw/type/color.hpp rename to libs/libQuickdraw/color/color.hpp index c269870..2f5d014 100644 --- a/libs/libGraphite/quickdraw/type/color.hpp +++ b/libs/libQuickdraw/color/color.hpp @@ -23,7 +23,7 @@ #include #include -namespace graphite::quickdraw +namespace quickdraw { typedef std::uint8_t color_component; diff --git a/libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp b/libs/libQuickdraw/colorspace/depth_2_bpp.cpp similarity index 85% rename from libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp rename to libs/libQuickdraw/colorspace/depth_2_bpp.cpp index f97446b..d185463 100644 --- a/libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.cpp +++ b/libs/libQuickdraw/colorspace/depth_2_bpp.cpp @@ -18,12 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp" -#include "libGraphite/data/data.hpp" +#include +#include // MARK: - Drawing -auto graphite::quickdraw::drawing::depth_2bpp::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::depth_2bpp::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { if (cfg.mask.data) { draw_masked(cfg, surface); @@ -44,7 +44,7 @@ auto graphite::quickdraw::drawing::depth_2bpp::pixmap::draw(const quickdraw::pix } } -auto graphite::quickdraw::drawing::depth_2bpp::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::depth_2bpp::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { auto y_offset = y * cfg.pixmap.row_bytes; diff --git a/libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp b/libs/libQuickdraw/colorspace/depth_2_bpp.hpp similarity index 87% rename from libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp rename to libs/libQuickdraw/colorspace/depth_2_bpp.hpp index a3d1fde..cacc337 100644 --- a/libs/libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp +++ b/libs/libQuickdraw/colorspace/depth_2_bpp.hpp @@ -21,11 +21,11 @@ #pragma once #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/support/pixmap.hpp" -#include "libGraphite/data/data.hpp" +#include +#include +#include -namespace graphite::quickdraw::drawing::depth_2bpp::pixmap +namespace quickdraw::colorspace::depth_2bpp { auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; diff --git a/libs/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp b/libs/libQuickdraw/colorspace/depth_4bpp.cpp similarity index 85% rename from libs/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp rename to libs/libQuickdraw/colorspace/depth_4bpp.cpp index cd4564a..903e765 100644 --- a/libs/libGraphite/quickdraw/support/drawing/depth_4bpp.cpp +++ b/libs/libQuickdraw/colorspace/depth_4bpp.cpp @@ -18,12 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/support/drawing/depth_4bpp.hpp" -#include "libGraphite/data/data.hpp" +#include +#include // MARK: - Drawing -auto graphite::quickdraw::drawing::depth_4bpp::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::depth_4bpp::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { if (cfg.mask.data) { draw_masked(cfg, surface); @@ -44,7 +44,7 @@ auto graphite::quickdraw::drawing::depth_4bpp::pixmap::draw(const quickdraw::pix } } -auto graphite::quickdraw::drawing::depth_4bpp::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::depth_4bpp::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { auto y_offset = y * cfg.pixmap.row_bytes; diff --git a/libs/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp b/libs/libQuickdraw/colorspace/depth_4bpp.hpp similarity index 87% rename from libs/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp rename to libs/libQuickdraw/colorspace/depth_4bpp.hpp index 92db50c..d2e6341 100644 --- a/libs/libGraphite/quickdraw/support/drawing/depth_4bpp.hpp +++ b/libs/libQuickdraw/colorspace/depth_4bpp.hpp @@ -21,11 +21,11 @@ #pragma once #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/support/pixmap.hpp" -#include "libGraphite/data/data.hpp" +#include +#include +#include -namespace graphite::quickdraw::drawing::depth_4bpp::pixmap +namespace quickdraw::colorspace::depth_4bpp { auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; diff --git a/libs/libGraphite/quickdraw/support/drawing/monochrome.cpp b/libs/libQuickdraw/colorspace/monochrome.cpp similarity index 86% rename from libs/libGraphite/quickdraw/support/drawing/monochrome.cpp rename to libs/libQuickdraw/colorspace/monochrome.cpp index 9fbf7a2..6b21634 100644 --- a/libs/libGraphite/quickdraw/support/drawing/monochrome.cpp +++ b/libs/libQuickdraw/colorspace/monochrome.cpp @@ -18,8 +18,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/support/drawing/monochrome.hpp" -#include "libGraphite/data/data.hpp" +#include +#include #if defined(CHAR_BIT) static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); @@ -29,7 +29,7 @@ // MARK: - Drawing -auto graphite::quickdraw::drawing::monochrome::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::monochrome::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { if (cfg.mask.data) { draw_masked(cfg, surface); @@ -47,7 +47,7 @@ auto graphite::quickdraw::drawing::monochrome::pixmap::draw(const quickdraw::pix } } -auto graphite::quickdraw::drawing::monochrome::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::monochrome::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { auto y_offset = y * cfg.pixmap.row_bytes; diff --git a/libs/libGraphite/quickdraw/support/drawing/monochrome.hpp b/libs/libQuickdraw/colorspace/monochrome.hpp similarity index 87% rename from libs/libGraphite/quickdraw/support/drawing/monochrome.hpp rename to libs/libQuickdraw/colorspace/monochrome.hpp index 95fbd63..dd05ee8 100644 --- a/libs/libGraphite/quickdraw/support/drawing/monochrome.hpp +++ b/libs/libQuickdraw/colorspace/monochrome.hpp @@ -21,11 +21,11 @@ #pragma once #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/support/pixmap.hpp" -#include "libGraphite/data/data.hpp" +#include +#include +#include -namespace graphite::quickdraw::drawing::monochrome::pixmap +namespace quickdraw::colorspace::monochrome { auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; diff --git a/libs/libGraphite/quickdraw/support/drawing/true_color.cpp b/libs/libQuickdraw/colorspace/true_color.cpp similarity index 85% rename from libs/libGraphite/quickdraw/support/drawing/true_color.cpp rename to libs/libQuickdraw/colorspace/true_color.cpp index 411161a..494bf6f 100644 --- a/libs/libGraphite/quickdraw/support/drawing/true_color.cpp +++ b/libs/libQuickdraw/colorspace/true_color.cpp @@ -19,8 +19,8 @@ // SOFTWARE. #include -#include "libGraphite/quickdraw/support/drawing/true_color.hpp" -#include "libGraphite/data/data.hpp" +#include +#include #if defined(CHAR_BIT) static_assert(CHAR_BIT == 8, "We require CHAR_BIT to be equal to 8 here."); @@ -30,7 +30,7 @@ // MARK: - Drawing -auto graphite::quickdraw::drawing::true_color::pixmap::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::true_color::draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { if (cfg.mask.data) { draw_masked(cfg, surface); @@ -47,7 +47,7 @@ auto graphite::quickdraw::drawing::true_color::pixmap::draw(const quickdraw::pix } } -auto graphite::quickdraw::drawing::true_color::pixmap::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void +auto quickdraw::colorspace::true_color::draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface &surface) -> void { for (std::int16_t y = 0; y < cfg.pixmap.bounds.size.height; ++y) { auto y_offset = y * cfg.pixmap.row_bytes; diff --git a/libs/libGraphite/quickdraw/support/drawing/true_color.hpp b/libs/libQuickdraw/colorspace/true_color.hpp similarity index 87% rename from libs/libGraphite/quickdraw/support/drawing/true_color.hpp rename to libs/libQuickdraw/colorspace/true_color.hpp index 5ca54f5..357e292 100644 --- a/libs/libGraphite/quickdraw/support/drawing/true_color.hpp +++ b/libs/libQuickdraw/colorspace/true_color.hpp @@ -21,11 +21,11 @@ #pragma once #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/support/pixmap.hpp" -#include "libGraphite/data/data.hpp" +#include +#include +#include -namespace graphite::quickdraw::drawing::true_color::pixmap +namespace quickdraw::colorspace::true_color { auto draw(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; auto draw_masked(const quickdraw::pixmap::draw_configuration& cfg, quickdraw::surface& surface) -> void; diff --git a/libs/libGraphite/quickdraw/format/cicn.cpp b/libs/libQuickdraw/format/color_icon.cpp similarity index 83% rename from libs/libGraphite/quickdraw/format/cicn.cpp rename to libs/libQuickdraw/format/color_icon.cpp index e670374..8ddae1f 100644 --- a/libs/libGraphite/quickdraw/format/cicn.cpp +++ b/libs/libQuickdraw/format/color_icon.cpp @@ -19,39 +19,38 @@ // SOFTWARE. #include -#include "libGraphite/quickdraw/format/cicn.hpp" -#include "libGraphite/quickdraw/support/drawing/monochrome.hpp" -#include "libGraphite/quickdraw/support/drawing/depth_2_bpp.hpp" -#include "libGraphite/quickdraw/support/drawing/depth_4bpp.hpp" -#include "libGraphite/quickdraw/support/drawing/true_color.hpp" +#include +#include +#include +#include +#include // MARK: - Construction -graphite::quickdraw::cicn::cicn(const data::block &data, rsrc::resource::identifier id, const std::string &name) +quickdraw::color_icon::color_icon(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::quickdraw::cicn::cicn(data::reader &reader) +quickdraw::color_icon::color_icon(data::reader &reader) { decode(reader); } -graphite::quickdraw::cicn::cicn(quickdraw::surface& surface) +quickdraw::color_icon::color_icon(quickdraw::surface& surface) : m_surface(std::move(surface)) -{ -} +{} // MARK: - Accessors -auto graphite::quickdraw::cicn::surface() -> quickdraw::surface& +auto quickdraw::color_icon::surface() -> quickdraw::surface& { return m_surface; } -auto graphite::quickdraw::cicn::data() -> data::block +auto quickdraw::color_icon::data() -> data::block { data::writer writer; encode(writer); @@ -60,7 +59,7 @@ auto graphite::quickdraw::cicn::data() -> data::block // MARK: - Coding -auto graphite::quickdraw::cicn::encode(data::writer &writer) -> void +auto quickdraw::color_icon::encode(data::writer &writer) -> void { auto width = m_surface.size().width; auto height = m_surface.size().height; @@ -143,7 +142,7 @@ auto graphite::quickdraw::cicn::encode(data::writer &writer) -> void writer.write_data(&pmap_data); } -auto graphite::quickdraw::cicn::decode(data::reader &reader) -> void +auto quickdraw::color_icon::decode(data::reader &reader) -> void { m_pixmap = reader.read(); @@ -159,7 +158,7 @@ auto graphite::quickdraw::cicn::decode(data::reader &reader) -> void auto mask_data = reader.read_data(cfg.mask.expected_data_size()); auto bmap_data = reader.read_data(cfg.bitmap.expected_data_size()); - cfg.color_table = &(m_clut = reader.read()); + cfg.color_table = &(m_clut = reader.read()); auto pmap_data = reader.read_data(cfg.pixmap.expected_data_size()); cfg.mask.data = &mask_data; @@ -169,16 +168,16 @@ auto graphite::quickdraw::cicn::decode(data::reader &reader) -> void m_surface = quickdraw::surface(cfg.pixmap.bounds.size); if (m_pixmap.total_component_width() == 1) { - drawing::monochrome::pixmap::draw(cfg, m_surface); + colorspace::monochrome::draw(cfg, m_surface); } else if (m_pixmap.total_component_width() == 2) { - drawing::depth_2bpp::pixmap::draw(cfg, m_surface); + colorspace::depth_2bpp::draw(cfg, m_surface); } else if (m_pixmap.total_component_width() == 4) { - drawing::depth_4bpp::pixmap::draw(cfg, m_surface); + colorspace::depth_4bpp::draw(cfg, m_surface); } else if (m_pixmap.total_component_width() == 8) { - drawing::true_color::pixmap::draw(cfg, m_surface); + colorspace::true_color::draw(cfg, m_surface); } else { throw std::runtime_error("Currently unsupported cicn configuration: cmp_size=" + diff --git a/libs/libGraphite/quickdraw/format/cicn.hpp b/libs/libQuickdraw/format/color_icon.hpp similarity index 77% rename from libs/libGraphite/quickdraw/format/cicn.hpp rename to libs/libQuickdraw/format/color_icon.hpp index b8e934b..1a2ef92 100644 --- a/libs/libGraphite/quickdraw/format/cicn.hpp +++ b/libs/libQuickdraw/format/color_icon.hpp @@ -21,23 +21,23 @@ #pragma once #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" -#include "libGraphite/quickdraw/support/pixmap.hpp" -#include "libGraphite/quickdraw/format/clut.hpp" +#include +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { - struct cicn + struct color_icon { public: static auto type_code() -> std::string { return "cicn"; } public: - cicn() = default; - explicit cicn(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); - explicit cicn(data::reader& reader); - explicit cicn(quickdraw::surface& surface); + color_icon() = default; + explicit color_icon(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit color_icon(data::reader& reader); + explicit color_icon(quickdraw::surface& surface); auto surface() -> surface&; @@ -45,7 +45,7 @@ namespace graphite::quickdraw auto data() -> data::block; private: - rsrc::resource::identifier m_id { INT64_MIN }; + resource::identifier m_id { resource::auto_resource_id }; std::string m_name; quickdraw::pixmap m_pixmap; std::uint32_t m_mask_base_address { 0 }; @@ -55,7 +55,7 @@ namespace graphite::quickdraw std::uint16_t m_bmap_row_bytes { 0 }; rect m_bmap_bounds; quickdraw::surface m_surface; - quickdraw::clut m_clut; + quickdraw::color_lookup_table m_clut; auto decode(data::reader& reader) -> void; }; diff --git a/libs/libGraphite/quickdraw/format/clut.cpp b/libs/libQuickdraw/format/color_lookup_table.cpp similarity index 71% rename from libs/libGraphite/quickdraw/format/clut.cpp rename to libs/libQuickdraw/format/color_lookup_table.cpp index 714ef4b..0106b26 100644 --- a/libs/libGraphite/quickdraw/format/clut.cpp +++ b/libs/libQuickdraw/format/color_lookup_table.cpp @@ -18,20 +18,20 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/format/clut.hpp" -#include "libGraphite/data/writer.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include +#include // MARK: - Construction -graphite::quickdraw::clut::clut(const data::block &data, rsrc::resource::identifier id, const std::string &name) +quickdraw::color_lookup_table::color_lookup_table(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::quickdraw::clut::clut(data::reader &reader) +quickdraw::color_lookup_table::color_lookup_table(data::reader &reader) : m_id(0), m_name("Embedded `clut` resource") { decode(reader); @@ -39,12 +39,12 @@ graphite::quickdraw::clut::clut(data::reader &reader) // MARK: - Accessors -auto graphite::quickdraw::clut::size() const -> size_type +auto quickdraw::color_lookup_table::size() const -> size_type { return m_entries.size(); } -auto graphite::quickdraw::clut::at(index_type index) const -> union color +auto quickdraw::color_lookup_table::at(index_type index) const -> union color { for (const auto& entry : m_entries) { if (entry.first == index) { @@ -54,7 +54,7 @@ auto graphite::quickdraw::clut::at(index_type index) const -> union color return colors::black(); } -auto graphite::quickdraw::clut::set(union color color) -> index_type +auto quickdraw::color_lookup_table::set(union color color) -> index_type { index_type value = 0; for (const auto& entry : m_entries) { @@ -65,12 +65,12 @@ auto graphite::quickdraw::clut::set(union color color) -> index_type value = std::max(value, entry.first); } } - m_entries.emplace_back(std::pair(value, color)); + m_entries.emplace_back(value, color); m_size = m_entries.size(); return value; } -auto graphite::quickdraw::clut::set(index_type index, union color color) -> void +auto quickdraw::color_lookup_table::set(index_type index, union color color) -> void { for (auto& entry : m_entries) { if (entry.first == index) { @@ -78,12 +78,12 @@ auto graphite::quickdraw::clut::set(index_type index, union color color) -> void return; } } - m_entries.emplace_back(std::pair(index, color)); + m_entries.emplace_back(index, color); } // MARK: - Coding -auto graphite::quickdraw::clut::encode(data::writer &writer) -> void +auto quickdraw::color_lookup_table::encode(data::writer &writer) -> void { writer.write_long(m_seed); writer.write_enum(m_flags); @@ -97,7 +97,7 @@ auto graphite::quickdraw::clut::encode(data::writer &writer) -> void } } -auto graphite::quickdraw::clut::decode(data::reader &reader) -> void +auto quickdraw::color_lookup_table::decode(data::reader &reader) -> void { m_seed = reader.read_long(); m_flags = reader.read_enum(); @@ -106,32 +106,32 @@ auto graphite::quickdraw::clut::decode(data::reader &reader) -> void for (std::uint16_t i = 0; i < m_size; ++i) { auto value = reader.read_short(); std::uint16_t index = m_flags == device ? i : value; - m_entries.emplace_back(std::pair(index, rgb( + m_entries.emplace_back(index, rgb( static_cast((reader.read_short() / 65535.0) * 255.0), static_cast((reader.read_short() / 65535.0) * 255.0), static_cast((reader.read_short() / 65535.0) * 255.0) - ))); + )); } } // MARK: - Iterators -auto graphite::quickdraw::clut::begin() -> iterator +auto quickdraw::color_lookup_table::begin() -> iterator { return { this, 0 }; } -auto graphite::quickdraw::clut::end() -> iterator +auto quickdraw::color_lookup_table::end() -> iterator { return { this, m_size }; } -auto graphite::quickdraw::clut::begin() const -> iterator +auto quickdraw::color_lookup_table::begin() const -> iterator { - return { const_cast(this), 0 }; + return { const_cast(this), 0 }; } -auto graphite::quickdraw::clut::end() const -> iterator +auto quickdraw::color_lookup_table::end() const -> iterator { - return { const_cast(this), m_size }; + return { const_cast(this), m_size }; } \ No newline at end of file diff --git a/libs/libGraphite/quickdraw/format/clut.hpp b/libs/libQuickdraw/format/color_lookup_table.hpp similarity index 84% rename from libs/libGraphite/quickdraw/format/clut.hpp rename to libs/libQuickdraw/format/color_lookup_table.hpp index b36357a..fd598f2 100644 --- a/libs/libGraphite/quickdraw/format/clut.hpp +++ b/libs/libQuickdraw/format/color_lookup_table.hpp @@ -20,13 +20,13 @@ #pragma once -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/quickdraw/type/color.hpp" +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { - struct clut + struct color_lookup_table { public: typedef std::uint16_t size_type; @@ -48,7 +48,7 @@ namespace graphite::quickdraw using pointer = value_type*; using reference = value_type&; - iterator(struct clut *clut, index_type idx) : m_clut(clut), m_idx(idx) {} + iterator(struct color_lookup_table *clut, index_type idx) : m_clut(clut), m_idx(idx) {} auto operator*() const -> reference { return m_clut->m_entries[m_idx].second; } auto operator->() -> pointer { return &m_clut->m_entries[m_idx].second; } @@ -58,14 +58,14 @@ namespace graphite::quickdraw friend auto operator!=(const iterator& a, const iterator& b) -> bool { return (a.m_clut != b.m_clut) && (a.m_idx == b.m_idx); } private: - struct clut *m_clut; + struct color_lookup_table *m_clut; index_type m_idx; }; public: - clut() = default; - explicit clut(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); - explicit clut(data::reader& reader); + color_lookup_table() = default; + explicit color_lookup_table(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit color_lookup_table(data::reader& reader); [[nodiscard]] auto size() const -> size_type; @@ -81,7 +81,7 @@ namespace graphite::quickdraw auto encode(data::writer& writer) -> void; private: - rsrc::resource::identifier m_id; + resource::identifier m_id; std::string m_name; std::uint32_t m_seed; enum flags m_flags { pixmap }; diff --git a/libs/libGraphite/quickdraw/format/pict.cpp b/libs/libQuickdraw/format/picture.cpp similarity index 89% rename from libs/libGraphite/quickdraw/format/pict.cpp rename to libs/libQuickdraw/format/picture.cpp index fd93888..318d2f0 100644 --- a/libs/libGraphite/quickdraw/format/pict.cpp +++ b/libs/libQuickdraw/format/picture.cpp @@ -18,35 +18,35 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/format/pict.hpp" -#include "libGraphite/quickdraw/support/pixmap.hpp" -#include "libGraphite/quickdraw/format/clut.hpp" -#include "libGraphite/compression/packbits.hpp" -#include "libGraphite/quicktime/image_description.hpp" +#include +#include +#include +#include +#include // MARK: - Constants -namespace graphite::quickdraw::constants +namespace quickdraw::constants { - static constexpr std::uint16_t pict_v1_magic = 0x1101; - static constexpr std::uint32_t pict_v2_magic = 0x001102ff; + static constexpr std::uint16_t v1_magic = 0x1101; + static constexpr std::uint32_t v2_magic = 0x001102ff; } // MARK: - Construction -graphite::quickdraw::pict::pict(const data::block &data, rsrc::resource::identifier id, const std::string &name) +quickdraw::picture::picture(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::quickdraw::pict::pict(data::reader &reader) +quickdraw::picture::picture(data::reader &reader) { decode(reader); } -graphite::quickdraw::pict::pict(quickdraw::surface &surface) +quickdraw::picture::picture(quickdraw::surface &surface) : m_surface(std::move(surface)), m_dpi(72, 72) { m_frame.size = m_surface.size(); @@ -54,12 +54,12 @@ graphite::quickdraw::pict::pict(quickdraw::surface &surface) // MARK: - Accessors -auto graphite::quickdraw::pict::surface() -> quickdraw::surface & +auto quickdraw::picture::surface() -> quickdraw::surface & { return m_surface; } -auto graphite::quickdraw::pict::data() -> data::block +auto quickdraw::picture::data() -> data::block { data::writer writer; encode(writer); @@ -68,19 +68,19 @@ auto graphite::quickdraw::pict::data() -> data::block // MARK: - Decoding -auto graphite::quickdraw::pict::decode(data::reader &reader) -> void +auto quickdraw::picture::decode(data::reader &reader) -> void { reader.move(2); m_frame = reader.read>(); bool v1 = false; - if (reader.read_short(0, data::reader::mode::peek) == constants::pict_v1_magic) { + if (reader.read_short(0, data::reader::mode::peek) == constants::v1_magic) { reader.move(2); v1 = true; } else { - if (reader.read_long() != constants::pict_v2_magic) { + if (reader.read_long() != constants::v2_magic) { throw std::runtime_error("Invalid PICT resource. Incorrect header: " + std::to_string(m_id) + ", " + m_name); } @@ -245,7 +245,7 @@ auto graphite::quickdraw::pict::decode(data::reader &reader) -> void // MARK: - Encoding -auto graphite::quickdraw::pict::encode(data::writer &writer) -> void +auto quickdraw::picture::encode(data::writer &writer) -> void { write_header(writer); write_def_hilite(writer); @@ -262,7 +262,7 @@ auto graphite::quickdraw::pict::encode(data::writer &writer) -> void // MARK: - Reading Functions -auto graphite::quickdraw::pict::read_region(data::reader &reader) const -> rect +auto quickdraw::picture::read_region(data::reader &reader) const -> rect { auto size = reader.read_short(); auto rect = reader.read>(); @@ -277,28 +277,28 @@ auto graphite::quickdraw::pict::read_region(data::reader &reader) const -> rect< return rect; } -auto graphite::quickdraw::pict::read_long_comment(data::reader &reader) const -> void +auto quickdraw::picture::read_long_comment(data::reader &reader) const -> void { reader.move(2); reader.move(reader.read_short()); } -auto graphite::quickdraw::pict::read_short_comment(data::reader &reader) const -> void +auto quickdraw::picture::read_short_comment(data::reader &reader) const -> void { reader.move(2); } -auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bool packed, bool region) -> void +auto quickdraw::picture::read_indirect_bits_rect(data::reader &reader, bool packed, bool region) -> void { quickdraw::pixmap pm; - quickdraw::clut color_table; + quickdraw::color_lookup_table color_table; // Determine if we're dealing with a PixMap or an old style BitMap. bool is_pixmap = reader.read_short(0, data::reader::mode::peek) & 0x8000; if (is_pixmap) { // The PixMap base address is omitted here, step back when reading. pm = reader.read(-4); - color_table = reader.read(); + color_table = reader.read(); } else { // Old style Bitmap @@ -348,7 +348,7 @@ auto graphite::quickdraw::pict::read_indirect_bits_rect(data::reader &reader, bo m_size += width * height; } -auto graphite::quickdraw::pict::read_direct_bits_rect(data::reader &reader, bool region) -> void +auto quickdraw::picture::read_direct_bits_rect(data::reader &reader, bool region) -> void { auto pm = reader.read(); m_format = pm.pixel_size() == 16 ? 16 : pm.component_size() * pm.component_count(); @@ -448,7 +448,7 @@ auto graphite::quickdraw::pict::read_direct_bits_rect(data::reader &reader, bool } } -auto graphite::quickdraw::pict::read_compressed_quicktime(data::reader &reader) -> void +auto quickdraw::picture::read_compressed_quicktime(data::reader &reader) -> void { auto length = reader.read_long(); reader.move(38); @@ -472,7 +472,7 @@ auto graphite::quickdraw::pict::read_compressed_quicktime(data::reader &reader) m_format = static_cast(image_description.compressor()); } -auto graphite::quickdraw::pict::read_uncompressed_quicktime(data::reader &reader) -> void +auto quickdraw::picture::read_uncompressed_quicktime(data::reader &reader) -> void { auto length = reader.read_long(); reader.move(38); @@ -484,7 +484,7 @@ auto graphite::quickdraw::pict::read_uncompressed_quicktime(data::reader &reader } } -auto graphite::quickdraw::pict::read_image_description(data::reader &reader) -> void +auto quickdraw::picture::read_image_description(data::reader &reader) -> void { auto length = reader.read_long(); if (length != 86) { @@ -502,7 +502,7 @@ auto graphite::quickdraw::pict::read_image_description(data::reader &reader) -> depth -= 32; // Grayscale } - auto color_table = reader.read(); + auto color_table = reader.read(); if (compressor == 'rle ') { // RLE is often garbage or redundant, skip over it and hope we find other image data later. @@ -526,7 +526,7 @@ auto graphite::quickdraw::pict::read_image_description(data::reader &reader) -> // MARK: - Writing Functions -auto graphite::quickdraw::pict::write_header(data::writer &writer) -> void +auto quickdraw::picture::write_header(data::writer &writer) -> void { // Write the size of zero. This seems to be fine. writer.write_short(0); @@ -535,7 +535,7 @@ auto graphite::quickdraw::pict::write_header(data::writer &writer) -> void writer.write>(m_frame); // We're only dealing with PICT version 2 currently. - writer.write_long(constants::pict_v2_magic); + writer.write_long(constants::v2_magic); writer.write_enum(opcode::ext_header); writer.write_long(0xFFFE0000); @@ -552,19 +552,19 @@ auto graphite::quickdraw::pict::write_header(data::writer &writer) -> void writer.write_long(0); } -auto graphite::quickdraw::pict::write_def_hilite(data::writer &writer) -> void +auto quickdraw::picture::write_def_hilite(data::writer &writer) -> void { writer.write_enum(opcode::def_hilite); } -auto graphite::quickdraw::pict::write_clip_region(data::writer &writer) -> void +auto quickdraw::picture::write_clip_region(data::writer &writer) -> void { writer.write_enum(opcode::clip_region); writer.write_short(10); writer.write>(m_frame); } -auto graphite::quickdraw::pict::write_direct_bits_rect(data::writer &writer) -> void +auto quickdraw::picture::write_direct_bits_rect(data::writer &writer) -> void { writer.write_enum(opcode::direct_bits_rect); diff --git a/libs/libGraphite/quickdraw/format/pict.hpp b/libs/libQuickdraw/format/picture.hpp similarity index 90% rename from libs/libGraphite/quickdraw/format/pict.hpp rename to libs/libQuickdraw/format/picture.hpp index 1432db3..efbb6dd 100644 --- a/libs/libGraphite/quickdraw/format/pict.hpp +++ b/libs/libQuickdraw/format/picture.hpp @@ -21,21 +21,22 @@ #pragma once #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { - struct pict + struct picture { public: static auto type_code() -> std::string { return "PICT"; } public: - pict() = default; - explicit pict(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); - explicit pict(data::reader& reader); - explicit pict(quickdraw::surface& surface); + picture() = default; + explicit picture(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit picture(data::reader& reader); + explicit picture(quickdraw::surface& surface); auto encode(data::writer& writer) -> void; auto data() -> data::block; @@ -91,7 +92,7 @@ namespace graphite::quickdraw }; private: - rsrc::resource::identifier m_id { 0 }; + resource::identifier m_id { 0 }; std::string m_name; quickdraw::surface m_surface; rect m_frame; diff --git a/libs/libGraphite/quickdraw/format/ppat.cpp b/libs/libQuickdraw/format/pixel_pattern.cpp similarity index 88% rename from libs/libGraphite/quickdraw/format/ppat.cpp rename to libs/libQuickdraw/format/pixel_pattern.cpp index ae760f7..19d47a4 100644 --- a/libs/libGraphite/quickdraw/format/ppat.cpp +++ b/libs/libQuickdraw/format/pixel_pattern.cpp @@ -19,36 +19,36 @@ // SOFTWARE. #include -#include "libGraphite/quickdraw/format/ppat.hpp" -#include "libGraphite/quickdraw/support/surface.hpp" +#include +#include // MARK: - Construction -graphite::quickdraw::ppat::ppat(const data::block &data, rsrc::resource::identifier id, const std::string& name) +quickdraw::pixel_pattern::pixel_pattern(const data::block &data, resource::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::quickdraw::ppat::ppat(data::reader &reader) +quickdraw::pixel_pattern::pixel_pattern(data::reader &reader) { decode(reader); } -graphite::quickdraw::ppat::ppat(graphite::quickdraw::surface& surface) +quickdraw::pixel_pattern::pixel_pattern(quickdraw::surface& surface) : m_surface(surface) { } // MARK: - Accessors -auto graphite::quickdraw::ppat::surface() -> struct surface & +auto quickdraw::pixel_pattern::surface() -> struct surface & { return m_surface; } -auto graphite::quickdraw::ppat::data() -> data::block +auto quickdraw::pixel_pattern::data() -> data::block { data::writer writer; encode(writer); @@ -57,7 +57,7 @@ auto graphite::quickdraw::ppat::data() -> data::block // MARK: - Coding -auto graphite::quickdraw::ppat::encode(data::writer &writer) -> void +auto quickdraw::pixel_pattern::encode(data::writer &writer) -> void { auto width = m_surface.size().width; auto height = m_surface.size().height; @@ -135,7 +135,7 @@ auto graphite::quickdraw::ppat::encode(data::writer &writer) -> void writer.write(m_clut); } -auto graphite::quickdraw::ppat::decode(data::reader &reader) -> void +auto quickdraw::pixel_pattern::decode(data::reader &reader) -> void { m_pat_type = reader.read_short(); if (m_pat_type != 1) { @@ -153,7 +153,7 @@ auto graphite::quickdraw::ppat::decode(data::reader &reader) -> void auto pmap_data = reader.read_data(pmap_data_size); reader.set_position(m_pixmap.pm_table()); - m_clut = reader.read(); + m_clut = reader.read(); auto surface_size = m_pixmap.bounds().size; m_surface = quickdraw::surface(surface_size); diff --git a/libs/libGraphite/quickdraw/format/ppat.hpp b/libs/libQuickdraw/format/pixel_pattern.hpp similarity index 74% rename from libs/libGraphite/quickdraw/format/ppat.hpp rename to libs/libQuickdraw/format/pixel_pattern.hpp index ff574ef..4de5ea4 100644 --- a/libs/libGraphite/quickdraw/format/ppat.hpp +++ b/libs/libQuickdraw/format/pixel_pattern.hpp @@ -21,23 +21,23 @@ #pragma once #include -#include "libGraphite/quickdraw/type/rect.hpp" -#include "libGraphite/quickdraw/format/clut.hpp" -#include "libGraphite/quickdraw/support/pixmap.hpp" -#include "libGraphite/quickdraw/support/surface.hpp" +#include +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { - struct ppat + struct pixel_pattern { public: static auto type_code() -> std::string { return "ppat"; } public: - ppat() = default; - explicit ppat(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); - explicit ppat(data::reader& reader); - explicit ppat(graphite::quickdraw::surface& surface); + pixel_pattern() = default; + explicit pixel_pattern(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit pixel_pattern(data::reader& reader); + explicit pixel_pattern(surface& surface); auto surface() -> quickdraw::surface&; @@ -45,14 +45,14 @@ namespace graphite::quickdraw auto data() -> data::block; private: - rsrc::resource::identifier m_id; + resource::identifier m_id; std::string m_name; std::uint16_t m_pat_type; std::uint32_t m_pmap_base_address; std::uint32_t m_pat_base_address; quickdraw::pixmap m_pixmap; quickdraw::surface m_surface; - quickdraw::clut m_clut; + quickdraw::color_lookup_table m_clut; auto decode(data::reader& reader) -> void; }; diff --git a/libs/libGraphite/quickdraw/support/pixmap.cpp b/libs/libQuickdraw/pixmap/pixmap.cpp similarity index 73% rename from libs/libGraphite/quickdraw/support/pixmap.cpp rename to libs/libQuickdraw/pixmap/pixmap.cpp index e2fcb0c..5ab600b 100644 --- a/libs/libGraphite/quickdraw/support/pixmap.cpp +++ b/libs/libQuickdraw/pixmap/pixmap.cpp @@ -18,11 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/support/pixmap.hpp" +#include +#include // MARK: - Construction -graphite::quickdraw::pixmap::pixmap(const rect& frame, bool rgb555) +quickdraw::pixmap::pixmap(const rect& frame, bool rgb555) : m_bounds(frame), m_row_bytes(frame.size.width * (rgb555 ? constants::rgb555_color_width : constants::color_width)), m_pack_type(rgb555 ? pack_type::packbits_word : pack_type::packbits_component), @@ -35,129 +36,129 @@ graphite::quickdraw::pixmap::pixmap(const rect& frame, bool rgb555 { } -graphite::quickdraw::pixmap::pixmap(const data::block &data, rsrc::resource::identifier id, const std::string &name) +quickdraw::pixmap::pixmap(const data::block &data, resource::identifier id, const std::string &name) { data::reader reader(&data); decode(reader); } -graphite::quickdraw::pixmap::pixmap(data::reader &reader) +quickdraw::pixmap::pixmap(data::reader &reader) { decode(reader); } // MARK: - Accessors -auto graphite::quickdraw::pixmap::bounds() const -> rect +auto quickdraw::pixmap::bounds() const -> rect { return m_bounds; } -auto graphite::quickdraw::pixmap::row_bytes() const -> std::int16_t +auto quickdraw::pixmap::row_bytes() const -> std::int16_t { return m_row_bytes; } -auto graphite::quickdraw::pixmap::pack_type() const -> enum pack_type +auto quickdraw::pixmap::pack_type() const -> enum pack_type { return m_pack_type; } -auto graphite::quickdraw::pixmap::pack_size() const -> std::int16_t +auto quickdraw::pixmap::pack_size() const -> std::int16_t { return m_pack_size; } -auto graphite::quickdraw::pixmap::pixel_type() const -> std::int16_t +auto quickdraw::pixmap::pixel_type() const -> std::int16_t { return m_pixel_type; } -auto graphite::quickdraw::pixmap::pixel_size() const -> std::int16_t +auto quickdraw::pixmap::pixel_size() const -> std::int16_t { return m_pixel_size; } -auto graphite::quickdraw::pixmap::component_count() const -> std::int16_t +auto quickdraw::pixmap::component_count() const -> std::int16_t { return m_component_count; } -auto graphite::quickdraw::pixmap::component_size() const -> std::int16_t +auto quickdraw::pixmap::component_size() const -> std::int16_t { return m_component_size; } -auto graphite::quickdraw::pixmap::pixel_format() const -> enum pixel_format +auto quickdraw::pixmap::pixel_format() const -> enum pixel_format { return m_pixel_format; } -auto graphite::quickdraw::pixmap::pm_table() const -> std::uint32_t +auto quickdraw::pixmap::pm_table() const -> std::uint32_t { return m_pm_table; } -auto graphite::quickdraw::pixmap::set_bounds(const rect& rect) -> void +auto quickdraw::pixmap::set_bounds(const rect& rect) -> void { m_bounds = rect; } -auto graphite::quickdraw::pixmap::set_row_bytes(std::int16_t row_bytes) -> void +auto quickdraw::pixmap::set_row_bytes(std::int16_t row_bytes) -> void { m_row_bytes = row_bytes; } -auto graphite::quickdraw::pixmap::set_pack_type(enum pack_type pack_type) -> void +auto quickdraw::pixmap::set_pack_type(enum pack_type pack_type) -> void { m_pack_type = pack_type; } -auto graphite::quickdraw::pixmap::set_pack_size(std::int16_t pack_size) -> void +auto quickdraw::pixmap::set_pack_size(std::int16_t pack_size) -> void { m_pack_size = pack_size; } -auto graphite::quickdraw::pixmap::set_pixel_type(std::int16_t pixel_type) -> void +auto quickdraw::pixmap::set_pixel_type(std::int16_t pixel_type) -> void { m_pixel_type = pixel_type; } -auto graphite::quickdraw::pixmap::set_pixel_size(std::int16_t pixel_size) -> void +auto quickdraw::pixmap::set_pixel_size(std::int16_t pixel_size) -> void { m_pixel_size = pixel_size; } -auto graphite::quickdraw::pixmap::set_component_count(std::int16_t component_count) -> void +auto quickdraw::pixmap::set_component_count(std::int16_t component_count) -> void { m_component_count = component_count; } -auto graphite::quickdraw::pixmap::set_component_size(std::int16_t component_size) -> void +auto quickdraw::pixmap::set_component_size(std::int16_t component_size) -> void { m_component_size = component_size; } -auto graphite::quickdraw::pixmap::set_pixel_format(enum pixel_format format) -> void +auto quickdraw::pixmap::set_pixel_format(enum pixel_format format) -> void { m_pixel_format = format; } -auto graphite::quickdraw::pixmap::set_pm_table(std::uint32_t table) -> void +auto quickdraw::pixmap::set_pm_table(std::uint32_t table) -> void { m_pm_table = table; } // MARK: - Calculations -auto graphite::quickdraw::pixmap::total_component_width() const -> std::size_t +auto quickdraw::pixmap::total_component_width() const -> std::size_t { return m_component_size * m_component_count; } // MARK: - Draw Configuration -auto graphite::quickdraw::pixmap::basic_draw_configuration() const -> struct draw_configuration +auto quickdraw::pixmap::basic_draw_configuration() const -> struct draw_configuration { struct draw_configuration cfg; cfg.pixmap.base_address = m_base_address; // Check that this is actually the correct value here? @@ -166,14 +167,14 @@ auto graphite::quickdraw::pixmap::basic_draw_configuration() const -> struct dra return std::move(cfg); } -auto graphite::quickdraw::pixmap::draw_configuration::aspect::expected_data_size() const -> std::size_t +auto quickdraw::pixmap::draw_configuration::aspect::expected_data_size() const -> std::size_t { return row_bytes * bounds.size.height; } // MARK: - Encoding / Decoding -auto graphite::quickdraw::pixmap::decode(data::reader &reader) -> void +auto quickdraw::pixmap::decode(data::reader &reader) -> void { m_base_address = reader.read_long(); m_row_bytes = static_cast(reader.read_short() & 0x7FFF); @@ -191,7 +192,7 @@ auto graphite::quickdraw::pixmap::decode(data::reader &reader) -> void m_pm_extension = reader.read_long(); } -auto graphite::quickdraw::pixmap::encode(data::writer &writer) -> void +auto quickdraw::pixmap::encode(data::writer &writer) -> void { writer.write_long(m_base_address); writer.write_short(0x8000 | m_row_bytes); @@ -211,7 +212,7 @@ auto graphite::quickdraw::pixmap::encode(data::writer &writer) -> void // MARK: - Surface / Image -auto graphite::quickdraw::pixmap::build_pixel_data(const data::block& color_data, std::uint16_t pixel_size) -> data::block +auto quickdraw::pixmap::build_pixel_data(const data::block& color_data, std::uint16_t pixel_size) -> data::block { data::block pixel_map_data; data::writer pmap(&pixel_map_data); @@ -253,7 +254,7 @@ auto graphite::quickdraw::pixmap::build_pixel_data(const data::block& color_data return std::move(pixel_map_data); } -auto graphite::quickdraw::pixmap::build_surface(surface &surface, const data::block &pixel_data, const clut &clut, const rect &destination) -> void +auto quickdraw::pixmap::build_surface(surface &surface, const data::block &pixel_data, const color_lookup_table &clut, const rect &destination) -> void { if (pixel_data.size() < destination.size.height * m_row_bytes) { throw std::runtime_error("Insufficient data to build surface from PixMap"); @@ -286,7 +287,7 @@ auto graphite::quickdraw::pixmap::build_surface(surface &surface, const data::bl } } -auto graphite::quickdraw::pixmap::draw(quickdraw::surface& surface) -> void +auto quickdraw::pixmap::draw(quickdraw::surface& surface) -> void { if (m_component_size == 1 && m_component_count == 1) { diff --git a/libs/libGraphite/quickdraw/support/pixmap.hpp b/libs/libQuickdraw/pixmap/pixmap.hpp similarity index 89% rename from libs/libGraphite/quickdraw/support/pixmap.hpp rename to libs/libQuickdraw/pixmap/pixmap.hpp index 6a8baec..2f45a12 100644 --- a/libs/libGraphite/quickdraw/support/pixmap.hpp +++ b/libs/libQuickdraw/pixmap/pixmap.hpp @@ -23,14 +23,15 @@ #include #include #include -#include "libGraphite/data/data.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/quickdraw/format/clut.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/type/pixel_format.hpp" - -namespace graphite::quickdraw + +#include +#include +#include +#include +#include +#include + +namespace quickdraw { struct pixmap { @@ -43,7 +44,6 @@ namespace graphite::quickdraw std::uint32_t base_address { 0 }; std::uint16_t row_bytes { 0 }; rect bounds; - [[nodiscard]] auto expected_data_size() const -> std::size_t; }; @@ -51,7 +51,7 @@ namespace graphite::quickdraw struct aspect bitmap; struct aspect mask; - struct clut *color_table { nullptr }; + struct color_lookup_table *color_table { nullptr }; }; enum pack_type : std::uint16_t @@ -68,7 +68,7 @@ namespace graphite::quickdraw pixmap() = default; explicit pixmap(const rect& frame, bool rgb555 = false); - explicit pixmap(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit pixmap(const data::block& data, resource::identifier id = 0, const std::string& name = ""); explicit pixmap(data::reader& reader); pixmap(const pixmap&) noexcept = default; @@ -103,7 +103,7 @@ namespace graphite::quickdraw auto draw(quickdraw::surface& surface) -> void; - auto build_surface(surface& surface, const data::block& pixel_data, const clut& clut, const rect& destination) -> void; + auto build_surface(surface& surface, const data::block& pixel_data, const color_lookup_table& clut, const rect& destination) -> void; auto build_pixel_data(const data::block& color_data, std::uint16_t pixel_size) -> data::block; auto encode(data::writer& writer) -> void; diff --git a/libs/libGraphite/quicktime/animation.cpp b/libs/libQuickdraw/quicktime/animation.cpp similarity index 96% rename from libs/libGraphite/quicktime/animation.cpp rename to libs/libQuickdraw/quicktime/animation.cpp index d8decbf..96c6567 100644 --- a/libs/libGraphite/quicktime/animation.cpp +++ b/libs/libQuickdraw/quicktime/animation.cpp @@ -18,9 +18,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quicktime/animation.hpp" +#include -auto graphite::quicktime::format::animation::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface +auto quicktime::format::animation::decode(const image_description &desc, data::reader &reader) -> quickdraw::surface { auto depth = desc.depth(); if (depth < 8) { diff --git a/libs/libGraphite/quicktime/animation.hpp b/libs/libQuickdraw/quicktime/animation.hpp similarity index 79% rename from libs/libGraphite/quicktime/animation.hpp rename to libs/libQuickdraw/quicktime/animation.hpp index f3e5230..8218098 100644 --- a/libs/libGraphite/quicktime/animation.hpp +++ b/libs/libQuickdraw/quicktime/animation.hpp @@ -20,13 +20,13 @@ #pragma once -#include "libGraphite/data/reader.hpp" -#include "libGraphite/quicktime/image_description.hpp" -#include "libGraphite/quickdraw/support/surface.hpp" +#include +#include +#include -namespace graphite::quicktime::format::animation +namespace quicktime::format::animation { - auto decode(const quicktime::image_description& desc, data::reader& reader) -> quickdraw::surface; + auto decode(const image_description& desc, data::reader& reader) -> quickdraw::surface; } diff --git a/libs/libGraphite/quicktime/image_description.cpp b/libs/libQuickdraw/quicktime/image_description.cpp similarity index 70% rename from libs/libGraphite/quicktime/image_description.cpp rename to libs/libQuickdraw/quicktime/image_description.cpp index f3137c7..2d7ce95 100644 --- a/libs/libGraphite/quicktime/image_description.cpp +++ b/libs/libQuickdraw/quicktime/image_description.cpp @@ -18,16 +18,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quicktime/image_description.hpp" -#include "libGraphite/quickdraw/format/pict.hpp" -#include "libGraphite/rsrc/manager.hpp" -#include "libGraphite/quicktime/raw.hpp" -#include "libGraphite/quicktime/animation.hpp" -#include "libGraphite/quicktime/planar.hpp" +#include +#include +#include +#include +#include +#include // MARK: - Construction -graphite::quicktime::image_description::image_description(data::reader &reader) +quicktime::image_description::image_description(data::reader &reader) { // http://mirror.informatimago.com/next/developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.17.htm auto start = reader.position(); @@ -51,10 +51,10 @@ graphite::quicktime::image_description::image_description(data::reader &reader) } auto clut = reader.read_signed_short(); if (clut == 0) { - m_clut = reader.read(); + m_clut = reader.read(); } else if (clut > 0) { - if (auto resource = rsrc::manager::shared_manager().find(clut)) { - m_clut = quickdraw::clut(resource->data()); + if (auto resource = resource::manager::shared_manager().find(clut)) { + m_clut = quickdraw::color_lookup_table(resource->data()); } else { throw std::runtime_error("Color table not found: clut " + std::to_string(clut)); @@ -68,59 +68,59 @@ graphite::quicktime::image_description::image_description(data::reader &reader) // MARK: - Accessors -auto graphite::quicktime::image_description::length() const -> std::int32_t +auto quicktime::image_description::length() const -> std::int32_t { return m_length; } -auto graphite::quicktime::image_description::compressor() const -> enum compression_type +auto quicktime::image_description::compressor() const -> enum compression_type { return m_compressor; } -auto graphite::quicktime::image_description::version() const -> std::uint32_t +auto quicktime::image_description::version() const -> std::uint32_t { return m_version; } -auto graphite::quicktime::image_description::width() const -> std::int16_t +auto quicktime::image_description::width() const -> std::int16_t { return m_width; } -auto graphite::quicktime::image_description::height() const -> std::int16_t +auto quicktime::image_description::height() const -> std::int16_t { return m_height; } -auto graphite::quicktime::image_description::data_size() const -> std::int32_t +auto quicktime::image_description::data_size() const -> std::int32_t { return m_data_size; } -auto graphite::quicktime::image_description::depth() const -> std::int16_t +auto quicktime::image_description::depth() const -> std::int16_t { return m_depth; } -auto graphite::quicktime::image_description::data_offset() const -> std::int32_t +auto quicktime::image_description::data_offset() const -> std::int32_t { return m_data_offset; } -auto graphite::quicktime::image_description::clut() const -> const quickdraw::clut& +auto quicktime::image_description::clut() const -> const quickdraw::color_lookup_table& { return m_clut; } -auto graphite::quicktime::image_description::surface() const -> const quickdraw::surface& +auto quicktime::image_description::surface() const -> const quickdraw::surface& { return m_surface; } // MARK: - Decoding -auto graphite::quicktime::image_description::decode(data::reader &reader) -> void +auto quicktime::image_description::decode(data::reader &reader) -> void { switch (m_compressor) { case compression_type::rle: { @@ -136,7 +136,7 @@ auto graphite::quicktime::image_description::decode(data::reader &reader) -> voi break; } case compression_type::quickdraw: { - auto pict = reader.read(m_data_size); + auto pict = reader.read(m_data_size); m_surface = pict.surface(); break; } diff --git a/libs/libGraphite/quicktime/image_description.hpp b/libs/libQuickdraw/quicktime/image_description.hpp similarity index 91% rename from libs/libGraphite/quicktime/image_description.hpp rename to libs/libQuickdraw/quicktime/image_description.hpp index 0331274..1b736a2 100644 --- a/libs/libGraphite/quicktime/image_description.hpp +++ b/libs/libQuickdraw/quicktime/image_description.hpp @@ -20,10 +20,10 @@ #pragma once -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/format/clut.hpp" +#include +#include -namespace graphite::quicktime +namespace quicktime { struct image_description { @@ -49,7 +49,7 @@ namespace graphite::quicktime [[nodiscard]] auto data_size() const -> std::int32_t; [[nodiscard]] auto depth() const -> std::int16_t; [[nodiscard]] auto data_offset() const -> std::int32_t; - [[nodiscard]] auto clut() const -> const quickdraw::clut&; + [[nodiscard]] auto clut() const -> const quickdraw::color_lookup_table&; [[nodiscard]] auto surface() const -> const quickdraw::surface&; private: @@ -61,7 +61,7 @@ namespace graphite::quicktime std::int32_t m_data_size { 0 }; std::int16_t m_depth { 0 }; std::int32_t m_data_offset { 0 }; - quickdraw::clut m_clut; + quickdraw::color_lookup_table m_clut; quickdraw::surface m_surface; auto decode(data::reader& reader) -> void; diff --git a/libs/libGraphite/quicktime/planar.cpp b/libs/libQuickdraw/quicktime/planar.cpp similarity index 94% rename from libs/libGraphite/quicktime/planar.cpp rename to libs/libQuickdraw/quicktime/planar.cpp index f29deb0..4af3633 100644 --- a/libs/libGraphite/quicktime/planar.cpp +++ b/libs/libQuickdraw/quicktime/planar.cpp @@ -18,12 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quicktime/planar.hpp" -#include "libGraphite/compression/packbits.hpp" +#include +#include // MARK: - Decoding -auto graphite::quicktime::format::planar::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface +auto quicktime::format::planar::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface { auto depth = desc.depth(); if (depth != 1 && depth != 8 && depth != 24 && depth != 32) { diff --git a/libs/libGraphite/quicktime/planar.hpp b/libs/libQuickdraw/quicktime/planar.hpp similarity index 86% rename from libs/libGraphite/quicktime/planar.hpp rename to libs/libQuickdraw/quicktime/planar.hpp index 9af75a3..ad2f6f5 100644 --- a/libs/libGraphite/quicktime/planar.hpp +++ b/libs/libQuickdraw/quicktime/planar.hpp @@ -20,11 +20,11 @@ #pragma once -#include "libGraphite/data/reader.hpp" -#include "libGraphite/quicktime/image_description.hpp" -#include "libGraphite/quickdraw/support/surface.hpp" +#include +#include +#include -namespace graphite::quicktime::format::planar +namespace quicktime::format::planar { auto decode(const quicktime::image_description& desc, data::reader& reader) -> quickdraw::surface; } diff --git a/libs/libGraphite/quicktime/raw.cpp b/libs/libQuickdraw/quicktime/raw.cpp similarity index 92% rename from libs/libGraphite/quicktime/raw.cpp rename to libs/libQuickdraw/quicktime/raw.cpp index fe1a152..d20575c 100644 --- a/libs/libGraphite/quicktime/raw.cpp +++ b/libs/libQuickdraw/quicktime/raw.cpp @@ -18,11 +18,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quicktime/raw.hpp" +#include // MARK: - Decoding -auto graphite::quicktime::format::raw::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface +auto quicktime::format::raw::decode(const quicktime::image_description &desc, data::reader &reader) -> quickdraw::surface { auto depth = desc.depth(); if (depth > 8) { diff --git a/libs/libGraphite/quicktime/raw.hpp b/libs/libQuickdraw/quicktime/raw.hpp similarity index 79% rename from libs/libGraphite/quicktime/raw.hpp rename to libs/libQuickdraw/quicktime/raw.hpp index 4359c15..f3a23b2 100644 --- a/libs/libGraphite/quicktime/raw.hpp +++ b/libs/libQuickdraw/quicktime/raw.hpp @@ -20,11 +20,11 @@ #pragma once -#include "libGraphite/data/reader.hpp" -#include "libGraphite/quicktime/image_description.hpp" -#include "libGraphite/quickdraw/support/surface.hpp" +#include +#include +#include -namespace graphite::quicktime::format::raw +namespace quicktime::format::raw { - auto decode(const quicktime::image_description& desc, data::reader& reader) -> quickdraw::surface; + auto decode(const image_description& desc, data::reader& reader) -> quickdraw::surface; } \ No newline at end of file diff --git a/libs/libGraphite/quickdraw/support/surface.cpp b/libs/libQuickdraw/surface/surface.cpp similarity index 69% rename from libs/libGraphite/quickdraw/support/surface.cpp rename to libs/libQuickdraw/surface/surface.cpp index 4769415..c7f100c 100644 --- a/libs/libGraphite/quickdraw/support/surface.cpp +++ b/libs/libQuickdraw/surface/surface.cpp @@ -18,11 +18,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/quickdraw/support/surface.hpp" +#include // MARK: - Construction -graphite::quickdraw::surface::surface(const quickdraw::size &size) +quickdraw::surface::surface(const quickdraw::size &size) : m_size(size), m_row_bytes(size.width * constants::color_width), m_data(new data::block(size.width * size.height * constants::color_width)) @@ -30,7 +30,7 @@ graphite::quickdraw::surface::surface(const quickdraw::size &size) m_data->set(static_cast(0), m_data->size()); } -graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) +quickdraw::surface::surface(std::int16_t width, std::int16_t height) : m_size(width, height), m_row_bytes(width * constants::color_width), m_data(new data::block(width * height * constants::color_width)) @@ -38,7 +38,7 @@ graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height) m_data->set(static_cast(0), m_data->size()); } -graphite::quickdraw::surface::surface(const quickdraw::size& size, union color color) +quickdraw::surface::surface(const quickdraw::size& size, union color color) : m_size(size), m_row_bytes(size.width * constants::color_width), m_data(new data::block(size.width * size.height * constants::color_width)) @@ -46,7 +46,7 @@ graphite::quickdraw::surface::surface(const quickdraw::size& size, m_data->set(color.value, m_data->size()); } -graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, union color color) +quickdraw::surface::surface(std::int16_t width, std::int16_t height, union color color) : m_size(width, height), m_row_bytes(width * constants::color_width), m_data(new data::block(width * height * constants::color_width)) @@ -54,14 +54,14 @@ graphite::quickdraw::surface::surface(std::int16_t width, std::int16_t height, u m_data->set(color.value, m_data->size()); } -graphite::quickdraw::surface::surface(const surface &surface) +quickdraw::surface::surface(const surface &surface) : m_size(surface.m_size), m_row_bytes(surface.m_row_bytes), m_data(new data::block(*surface.m_data)) { } -graphite::quickdraw::surface::surface(surface &&surface) noexcept +quickdraw::surface::surface(surface &&surface) noexcept : m_size(surface.m_size), m_row_bytes(surface.m_row_bytes), m_data(surface.m_data) @@ -71,7 +71,7 @@ graphite::quickdraw::surface::surface(surface &&surface) noexcept // MARK: - Destruction -graphite::quickdraw::surface::~surface() +quickdraw::surface::~surface() { if (!m_weak_data && m_data) { delete m_data; @@ -80,7 +80,7 @@ graphite::quickdraw::surface::~surface() // MARK: - Operators -auto graphite::quickdraw::surface::operator=(const surface& surface) -> class surface& +auto quickdraw::surface::operator=(const surface& surface) -> class surface& { if (this == const_cast(&surface)) { return *this; @@ -94,7 +94,7 @@ auto graphite::quickdraw::surface::operator=(const surface& surface) -> class su return *this; } -auto graphite::quickdraw::surface::operator=(class surface&& surface) noexcept -> class surface& +auto quickdraw::surface::operator=(class surface&& surface) noexcept -> class surface& { if (this != &surface) { delete m_data; @@ -111,51 +111,51 @@ auto graphite::quickdraw::surface::operator=(class surface&& surface) noexcept - // MARK: - Accessors -auto graphite::quickdraw::surface::raw() const -> const data::block& +auto quickdraw::surface::raw() const -> const data::block& { return *m_data; } -auto graphite::quickdraw::surface::size() const -> struct quickdraw::size +auto quickdraw::surface::size() const -> struct quickdraw::size { return m_size; } // MARK: - Pixel Access -auto graphite::quickdraw::surface::at(const point &p) const -> union color +auto quickdraw::surface::at(const point &p) const -> union color { return at(p.x, p.y); } -auto graphite::quickdraw::surface::at(std::int16_t x, std::int16_t y) const -> union color +auto quickdraw::surface::at(std::int16_t x, std::int16_t y) const -> union color { return at((y * m_size.width) + x); } -auto graphite::quickdraw::surface::at(std::uint32_t offset) const -> union color +auto quickdraw::surface::at(std::uint32_t offset) const -> union color { return m_data->get()[offset]; } -auto graphite::quickdraw::surface::set(const point& p, union color color) -> void +auto quickdraw::surface::set(const point& p, union color color) -> void { set(p.x, p.y, color); } -auto graphite::quickdraw::surface::set(std::int16_t x, std::int16_t y, union color color) -> void +auto quickdraw::surface::set(std::int16_t x, std::int16_t y, union color color) -> void { set((y * m_size.width) + x, color); } -auto graphite::quickdraw::surface::set(std::uint32_t offset, union color color) -> void +auto quickdraw::surface::set(std::uint32_t offset, union color color) -> void { m_data->set(color.value, constants::color_width, offset * constants::color_width); } // MARK: - Operations -auto graphite::quickdraw::surface::clear() -> void +auto quickdraw::surface::clear() -> void { m_data->set(colors::clear().value, m_data->size()); } \ No newline at end of file diff --git a/libs/libGraphite/quickdraw/support/surface.hpp b/libs/libQuickdraw/surface/surface.hpp similarity index 90% rename from libs/libGraphite/quickdraw/support/surface.hpp rename to libs/libQuickdraw/surface/surface.hpp index b89f64f..dada4cc 100644 --- a/libs/libGraphite/quickdraw/support/surface.hpp +++ b/libs/libQuickdraw/surface/surface.hpp @@ -20,12 +20,12 @@ #pragma once -#include "libGraphite/quickdraw/type/point.hpp" -#include "libGraphite/quickdraw/type/size.hpp" -#include "libGraphite/quickdraw/type/color.hpp" -#include "libGraphite/data/data.hpp" +#include +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { struct surface { @@ -57,7 +57,7 @@ namespace graphite::quickdraw auto clear() -> void; private: - std::uint32_t m_row_bytes; + std::uint32_t m_row_bytes { 0 }; quickdraw::size m_size; data::block *m_data { nullptr }; bool m_weak_data { false }; diff --git a/libs/libGraphite/quickdraw/type/coding_type.hpp b/libs/libQuickdraw/type/coding_type.hpp similarity index 97% rename from libs/libGraphite/quickdraw/type/coding_type.hpp rename to libs/libQuickdraw/type/coding_type.hpp index 353c815..1f1b44a 100644 --- a/libs/libGraphite/quickdraw/type/coding_type.hpp +++ b/libs/libQuickdraw/type/coding_type.hpp @@ -20,7 +20,7 @@ #pragma once -namespace graphite::quickdraw +namespace quickdraw { enum class coding_type { diff --git a/libs/libGraphite/quickdraw/type/pixel_format.hpp b/libs/libQuickdraw/type/pixel_format.hpp similarity index 97% rename from libs/libGraphite/quickdraw/type/pixel_format.hpp rename to libs/libQuickdraw/type/pixel_format.hpp index c872a3e..b3ce212 100644 --- a/libs/libGraphite/quickdraw/type/pixel_format.hpp +++ b/libs/libQuickdraw/type/pixel_format.hpp @@ -22,7 +22,7 @@ #include -namespace graphite::quickdraw +namespace quickdraw { enum pixel_format : std::uint32_t { diff --git a/libs/libGraphite/quickdraw/type/point.hpp b/libs/libQuickdraw/type/point.hpp similarity index 97% rename from libs/libGraphite/quickdraw/type/point.hpp rename to libs/libQuickdraw/type/point.hpp index c08616b..04dd2a2 100644 --- a/libs/libGraphite/quickdraw/type/point.hpp +++ b/libs/libQuickdraw/type/point.hpp @@ -22,12 +22,12 @@ #include #include -#include "libGraphite/data/encoding.hpp" -#include "libGraphite/quickdraw/type/coding_type.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" +#include +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { /** * Represents a 2D point on a surface. diff --git a/libs/libGraphite/quickdraw/type/rect.hpp b/libs/libQuickdraw/type/rect.hpp similarity index 95% rename from libs/libGraphite/quickdraw/type/rect.hpp rename to libs/libQuickdraw/type/rect.hpp index 5b142ff..be2d8a0 100644 --- a/libs/libGraphite/quickdraw/type/rect.hpp +++ b/libs/libQuickdraw/type/rect.hpp @@ -22,13 +22,13 @@ #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" -#include "libGraphite/quickdraw/type/coding_type.hpp" -#include "libGraphite/quickdraw/type/point.hpp" -#include "libGraphite/quickdraw/type/size.hpp" +#include +#include +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { /** * Represents a rectangle or frame within a surface. diff --git a/libs/libGraphite/quickdraw/type/size.hpp b/libs/libQuickdraw/type/size.hpp similarity index 97% rename from libs/libGraphite/quickdraw/type/size.hpp rename to libs/libQuickdraw/type/size.hpp index 1af405a..9ea4d3a 100644 --- a/libs/libGraphite/quickdraw/type/size.hpp +++ b/libs/libQuickdraw/type/size.hpp @@ -22,11 +22,11 @@ #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/data/writer.hpp" -#include "libGraphite/quickdraw/type/coding_type.hpp" +#include +#include +#include -namespace graphite::quickdraw +namespace quickdraw { /** * Represents a size of a 2D area on a surface. diff --git a/libs/libResource/CMakeLists.txt b/libs/libResource/CMakeLists.txt new file mode 100644 index 0000000..78a833b --- /dev/null +++ b/libs/libResource/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libResource_Sources + *.cpp +) + +add_library(Resource ${libResource_Sources}) +target_link_libraries(Resource SIMD Data Encoding) +target_include_directories(Resource PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libResource/concepts.hpp b/libs/libResource/concepts.hpp new file mode 100644 index 0000000..ff862b0 --- /dev/null +++ b/libs/libResource/concepts.hpp @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include + +namespace resource +{ + template + concept isa_resource_type = requires(const T& type) { + { T::type_code() } -> std::same_as; + }; +} \ No newline at end of file diff --git a/libs/libGraphite/rsrc/file.cpp b/libs/libResource/file.cpp similarity index 61% rename from libs/libGraphite/rsrc/file.cpp rename to libs/libResource/file.cpp index f2339b2..a7263ba 100644 --- a/libs/libGraphite/rsrc/file.cpp +++ b/libs/libResource/file.cpp @@ -18,25 +18,23 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/data/reader.hpp" - -#include "libGraphite/rsrc/classic/classic.hpp" -#include "libGraphite/rsrc/extended/extended.hpp" -#include "libGraphite/rsrc/rez/rez.hpp" - -#include "libGraphite/util/hashing.hpp" +#include +#include +#include +#include +#include +#include +#include +#include // MARK: - Construction -graphite::rsrc::file::file(const std::string &path) +resource::file::file(const std::string &path) { read(path); } -graphite::rsrc::file::file(const file &file) +resource::file::file(const file &file) : m_format(file.m_format), m_path(file.m_path), m_data(new data::block(*file.m_data)) @@ -47,7 +45,7 @@ graphite::rsrc::file::file(const file &file) } } -graphite::rsrc::file::file(file &&file) noexcept +resource::file::file(file &&file) noexcept : m_format(file.m_format), m_path(std::move(file.m_path)), m_data(file.m_data), @@ -59,7 +57,7 @@ graphite::rsrc::file::file(file &&file) noexcept // MARK: - Destruction -graphite::rsrc::file::~file() +resource::file::~file() { for (auto& it : m_types) { delete it.second; @@ -69,7 +67,7 @@ graphite::rsrc::file::~file() // MARK: - Operators -auto graphite::rsrc::file::operator=(const file &file) -> class file & +auto resource::file::operator=(const file &file) -> class file & { if (this == const_cast(&file)) { return *this; @@ -81,13 +79,13 @@ auto graphite::rsrc::file::operator=(const file &file) -> class file & // Copy the types. for (const auto& it : file.m_types) { - m_types.emplace(std::pair(it.first, new struct type(*it.second))); + m_types.emplace(it.first, new struct type(*it.second)); } return *this; } -auto graphite::rsrc::file::operator=(file &&file) noexcept -> class file & +auto resource::file::operator=(file &&file) noexcept -> class file & { if (this != &file) { m_path = std::move(file.m_path); @@ -103,30 +101,30 @@ auto graphite::rsrc::file::operator=(file &&file) noexcept -> class file & // MARK: - Hashing -auto graphite::rsrc::file::hash_for_path(const std::string &path) -> hash +auto resource::file::hash_for_path(const std::string &path) -> hash { return hashing::xxh64(path.c_str(), path.size()); } // MARK: - Accessors -auto graphite::rsrc::file::name() const -> std::string +auto resource::file::name() const -> std::string { auto pos = m_path.find_last_of('/'); return m_path.substr(pos + 1); } -auto graphite::rsrc::file::path() const -> const std::string& +auto resource::file::path() const -> const std::string& { return m_path; } -auto graphite::rsrc::file::type_count() const -> std::size_t +auto resource::file::type_count() const -> std::size_t { return m_types.size(); } -auto graphite::rsrc::file::types() const -> std::vector +auto resource::file::types() const -> std::vector { std::vector types; for (const auto& type : m_types) { @@ -135,7 +133,7 @@ auto graphite::rsrc::file::types() const -> std::vector return std::move(types); } -auto graphite::rsrc::file::type_codes() const -> std::vector +auto resource::file::type_codes() const -> std::vector { std::vector types; for (const auto& type : m_types) { @@ -144,12 +142,12 @@ auto graphite::rsrc::file::type_codes() const -> std::vector return std::move(types); } -auto graphite::rsrc::file::format() const -> enum format +auto resource::file::format() const -> enum format { return m_format; } -auto graphite::rsrc::file::hash_value() const -> hash +auto resource::file::hash_value() const -> hash { return hash_for_path(m_path); } @@ -157,13 +155,13 @@ auto graphite::rsrc::file::hash_value() const -> hash // MARK: - Type Management -auto graphite::rsrc::file::add_resource(const std::string &type_code, - rsrc::resource::identifier id, - const std::string &name, - const data::block &data, - const std::unordered_map &attributes) -> void +auto resource::file::add_resource(const std::string &type_code, + identifier id, + const std::string &name, + const data::block &data, + const std::unordered_map &attributes) -> void { - auto resource = new struct resource(nullptr, id, name, data); + auto resource = new struct instance(nullptr, id, name, data); std::unordered_map type_attributes; for (const auto& it : attributes) { @@ -171,7 +169,7 @@ auto graphite::rsrc::file::add_resource(const std::string &type_code, type_attributes.emplace(std::pair(attr.hash_value(), std::move(attr))); } - auto type_hash = rsrc::type::hash_for_type_code(type_code, type_attributes); + auto type_hash = type::hash_for_type_code(type_code, type_attributes); auto it = m_types.find(type_hash); if (it == m_types.end()) { // The type doesn't exist, so we need to create it. @@ -190,32 +188,32 @@ auto graphite::rsrc::file::add_resource(const std::string &type_code, } } -auto graphite::rsrc::file::add_type(struct type *type) -> void +auto resource::file::add_type(struct type *type) -> void { m_types.emplace(std::pair(type->hash_value(), type)); } -auto graphite::rsrc::file::add_types(const std::vector &types) -> void +auto resource::file::add_types(const std::vector &types) -> void { for (const auto type : types) { m_types.emplace(std::pair(type->hash_value(), type)); } } -auto graphite::rsrc::file::type(const std::string &code, const std::unordered_map& attributes) const -> const struct type * +auto resource::file::type(const std::string &code, const std::unordered_map& attributes) const -> const struct type * { // Convert the unordered map to what is required. std::unordered_map attributes_map; for (const auto& it : attributes) { - rsrc::attribute attr(it.first, it.second); - attributes_map.emplace(std::pair(attr.hash_value(), std::move(attr))); + attribute attr(it.first, it.second); + attributes_map.emplace(attr.hash_value(), std::move(attr)); } auto it = m_types.find(type::hash_for_type_code(code, attributes_map)); return (it == m_types.end()) ? nullptr : it->second; } -auto graphite::rsrc::file::type(const std::string& code, const std::vector& attributes) const -> const struct type * +auto resource::file::type(const std::string& code, const std::vector& attributes) const -> const struct type * { bool universal_namespace = false; std::unordered_map attributes_map; @@ -244,30 +242,30 @@ auto graphite::rsrc::file::type(const std::string& code, const std::vector const struct type * +auto resource::file::type(const std::string& code) const -> const struct type * { auto it = m_types.find(type::hash_for_type_code(code)); return (it == m_types.end()) ? nullptr : it->second; } -auto graphite::rsrc::file::type(type::hash hash) const -> const struct type * +auto resource::file::type(type::hash hash) const -> const struct type * { auto it = m_types.find(hash); return (it == m_types.end()) ? nullptr : it->second; } -auto graphite::rsrc::file::find(const std::string &type_code, resource::identifier id, const std::unordered_map& attributes) const -> const struct resource * +auto resource::file::find(const std::string &type_code, identifier id, const std::unordered_map& attributes) const -> const struct instance * { - if (auto type = const_cast(this->type(type_code, attributes))) { + if (auto type = const_cast<::resource::type *>(this->type(type_code, attributes))) { return type->resource_with_id(id); } return nullptr; } -auto graphite::rsrc::file::find(const std::string &type_code, resource::identifier id, const std::vector& attributes) const -> const struct resource * +auto resource::file::find(const std::string &type_code, identifier id, const std::vector& attributes) const -> const struct instance * { - if (auto type = const_cast(this->type(type_code, attributes))) { + if (auto type = const_cast<::resource::type *>(this->type(type_code, attributes))) { return type->resource_with_id(id); } return nullptr; @@ -275,19 +273,19 @@ auto graphite::rsrc::file::find(const std::string &type_code, resource::identifi // MARK: - File Access -auto graphite::rsrc::file::read(const std::string &path) -> void +auto resource::file::read(const std::string &path) -> void { m_path = path; - m_data = new graphite::data::block(m_path); - graphite::data::reader reader(m_data); + m_data = new data::block(m_path); + data::reader reader(m_data); - if (rsrc::format::extended::parse(reader, *this)) { + if (::resource::format::extended::parse(reader, *this)) { m_format = format::extended; } - else if (rsrc::format::rez::parse(reader, *this)) { + else if (::resource::format::rez::parse(reader, *this)) { m_format = format::rez; } - else if (rsrc::format::classic::parse(reader, *this)) { + else if (::resource::format::classic::parse(reader, *this)) { m_format = format::classic; } else { @@ -295,17 +293,17 @@ auto graphite::rsrc::file::read(const std::string &path) -> void } } -auto graphite::rsrc::file::write() -> bool +auto resource::file::write() -> bool { return write(m_path, m_format); } -auto graphite::rsrc::file::write(const std::string &path) -> bool +auto resource::file::write(const std::string &path) -> bool { return write(path, m_format); } -auto graphite::rsrc::file::write(const std::string &path, enum format format) -> bool +auto resource::file::write(const std::string &path, enum format format) -> bool { if (m_path != path) { m_path = path; @@ -314,13 +312,13 @@ auto graphite::rsrc::file::write(const std::string &path, enum format format) -> switch (m_format) { case format::extended: - return rsrc::format::extended::write(*this, m_path); + return ::resource::format::extended::write(*this, m_path); case format::rez: - return rsrc::format::rez::write(*this, m_path); + return ::resource::format::rez::write(*this, m_path); case format::classic: - return rsrc::format::classic::write(*this, m_path); + return ::resource::format::classic::write(*this, m_path); default: return false; diff --git a/libs/libGraphite/rsrc/file.hpp b/libs/libResource/file.hpp similarity index 84% rename from libs/libGraphite/rsrc/file.hpp rename to libs/libResource/file.hpp index cfe807a..bc0e3bb 100644 --- a/libs/libGraphite/rsrc/file.hpp +++ b/libs/libResource/file.hpp @@ -23,11 +23,12 @@ #include #include #include -#include "libGraphite/data/data.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/util/concepts.hpp" +#include +#include +#include +#include -namespace graphite::rsrc +namespace resource { class file { @@ -69,22 +70,22 @@ namespace graphite::rsrc [[nodiscard]] auto type(type::hash hash) const -> const struct type *; auto add_resource(const std::string& type_code, - rsrc::resource::identifier id, + identifier id, const std::string& name, const data::block& data, const std::unordered_map& attributes = {}) -> void; - template + template [[nodiscard]] auto find(resource::identifier id, const std::unordered_map& attributes = {}) const -> const struct resource * { return find(T::type_code(), id, attributes); } - [[nodiscard]] auto find(const std::string& type_code, resource::identifier id, const std::unordered_map& attributes = {}) const -> const struct resource *; - [[nodiscard]] auto find(const std::string& type_code, resource::identifier id, const std::vector& attributes) const -> const struct resource *; + [[nodiscard]] auto find(const std::string& type_code, identifier id, const std::unordered_map& attributes = {}) const -> const struct instance *; + [[nodiscard]] auto find(const std::string& type_code, identifier id, const std::vector& attributes) const -> const struct instance *; - template - [[nodiscard]] auto load(resource::identifier id) const -> T + template + [[nodiscard]] auto load(identifier id) const -> T { if (const auto resource = find(id)) { return std::move(T(resource->data(), resource->id(), resource->name())); diff --git a/libs/libGraphite/rsrc/classic/classic.hpp b/libs/libResource/format/classic/classic.hpp similarity index 92% rename from libs/libGraphite/rsrc/classic/classic.hpp rename to libs/libResource/format/classic/classic.hpp index 3b663cc..d0324da 100644 --- a/libs/libGraphite/rsrc/classic/classic.hpp +++ b/libs/libResource/format/classic/classic.hpp @@ -20,5 +20,5 @@ #pragma once -#include "libGraphite/rsrc/classic/parser.hpp" -#include "libGraphite/rsrc/classic/writer.hpp" \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/libs/libGraphite/rsrc/classic/parser.cpp b/libs/libResource/format/classic/parser.cpp similarity index 87% rename from libs/libGraphite/rsrc/classic/parser.cpp rename to libs/libResource/format/classic/parser.cpp index 353e3d0..a585818 100644 --- a/libs/libGraphite/rsrc/classic/parser.cpp +++ b/libs/libResource/format/classic/parser.cpp @@ -18,18 +18,17 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/classic/parser.hpp" - #include #include -#include "libGraphite/hints.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include +#include +#include +#include // MARK: - Parsing -auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> bool +auto resource::format::classic::parse(data::reader &reader, file& file) -> bool { std::vector types; @@ -91,8 +90,8 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> // fork. GRAPHITE_UNUSED auto flags = reader.read_short(); - auto type_list_offset = static_cast(reader.read_short()); - auto name_list_offset = static_cast(reader.read_short()); + auto type_list_offset = static_cast(reader.read_short()); + auto name_list_offset = static_cast(reader.read_short()); // 3. Parse the list of Resource Types. reader.set_position(map_offset + type_list_offset); @@ -101,7 +100,7 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> for (auto type_idx = 0; type_idx < type_count; ++type_idx) { auto code = reader.read_cstr(4); auto count = reader.read_short() + 1; - auto first_resource_offset = static_cast(reader.read_short()); + auto first_resource_offset = static_cast(reader.read_short()); auto type = new struct type(code); @@ -110,7 +109,7 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> reader.set_position(map_offset + type_list_offset + first_resource_offset); for (auto res_idx = 0; res_idx < count; ++res_idx) { - auto id = static_cast(reader.read_signed_short()); + auto id = static_cast(reader.read_signed_short()); auto name_offset = reader.read_short(); GRAPHITE_UNUSED auto flags = reader.read_byte(); auto resource_data_offset = reader.read_triple(); @@ -131,7 +130,7 @@ auto graphite::rsrc::format::classic::parse(data::reader &reader, file& file) -> reader.restore_position(); // 7. Construct a new resource instance and add it to the type. - auto resource = new struct resource(type, id, name, std::move(slice)); + auto resource = new struct instance(type, id, name, std::move(slice)); type->add_resource(resource); } diff --git a/libs/libGraphite/rsrc/classic/parser.hpp b/libs/libResource/format/classic/parser.hpp similarity index 90% rename from libs/libGraphite/rsrc/classic/parser.hpp rename to libs/libResource/format/classic/parser.hpp index 2157d06..20ba7b4 100644 --- a/libs/libGraphite/rsrc/classic/parser.hpp +++ b/libs/libResource/format/classic/parser.hpp @@ -20,10 +20,10 @@ #pragma once -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include -namespace graphite::rsrc::format::classic +namespace resource::format::classic { auto parse(data::reader& reader, file& file) -> bool; } diff --git a/libs/libGraphite/rsrc/classic/writer.cpp b/libs/libResource/format/classic/writer.cpp similarity index 82% rename from libs/libGraphite/rsrc/classic/writer.cpp rename to libs/libResource/format/classic/writer.cpp index 872522e..14355ba 100644 --- a/libs/libGraphite/rsrc/classic/writer.cpp +++ b/libs/libResource/format/classic/writer.cpp @@ -18,42 +18,40 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/classic/writer.hpp" - #include #include -#include "libGraphite/encoding/macroman/macroman.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include +#include +#include // MARK: - Constants -namespace graphite::rsrc::format::classic::constants::defaults +namespace resource::format::classic::constants::defaults { - constexpr uint32_t data_offset = 256; - constexpr uint32_t map_offset = 0; - constexpr uint32_t data_length = 0; - constexpr uint32_t map_length = 0; + constexpr std::uint32_t data_offset = 256; + constexpr std::uint32_t map_offset = 0; + constexpr std::uint32_t data_length = 0; + constexpr std::uint32_t map_length = 0; } -namespace graphite::rsrc::format::classic::constants +namespace resource::format::classic::constants { - - constexpr uint16_t resource_type_length = 8; - constexpr uint16_t resource_length = 12; - constexpr uint16_t type_list_offset = 28; + constexpr std::uint16_t resource_type_length = 8; + constexpr std::uint16_t resource_length = 12; + constexpr std::uint16_t type_list_offset = 28; } // MARK: - Writing -auto graphite::rsrc::format::classic::write(file &file) -> bool +auto resource::format::classic::write(file &file) -> bool { return write(file, file.path()); } -auto graphite::rsrc::format::classic::write(file &file, const std::string &path) -> bool +auto resource::format::classic::write(file &file, const std::string &path) -> bool { - graphite::data::writer writer(data::byte_order::msb); + data::writer writer(data::byte_order::msb); // 1. Begin setting up the preamble auto data_offset = constants::defaults::data_offset; @@ -69,7 +67,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) // 2. Iterate through all of the resources and write their data blobs to the file data. // When doing this we need to record the starting points of each resources data. - uint16_t resource_count = 0; + std::uint16_t resource_count = 0; std::vector types(file.type_count()); auto type_ptr = types.begin(); @@ -87,7 +85,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) auto data = resource->data(); auto size = data.size(); resource->set_data_offset(writer.size() - data_offset); - writer.write_long(static_cast(size)); + writer.write_long(static_cast(size)); writer.write_data(&data); } @@ -97,7 +95,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) // 3. Start writing the ResourceMap. This consists of several characteristics, the first of which is a secondary // preamble. We can now calculate the map offset and data length, but we're still waiting on the map length. For // now, write these values as zero. - map_offset = static_cast(writer.size()); + map_offset = static_cast(writer.size()); data_length = map_offset - data_offset; writer.write_long(data_offset); writer.write_long(map_offset); @@ -110,14 +108,14 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) // 4. We're now writing the primary map information, which includes flags, and offsets for the type list and the // name list. We can calculate where each of these will be. auto name_list_offset = constants::type_list_offset + (file.type_count() * constants::resource_type_length); - name_list_offset += (resource_count * constants::resource_length) + sizeof(uint16_t); + name_list_offset += (resource_count * constants::resource_length) + sizeof(std::uint16_t); writer.write_short(0x0000); writer.write_short(constants::type_list_offset); writer.write_short(name_list_offset); // Now moving on to actually write each of the type descriptors into the data. - auto resource_offset = sizeof(uint16_t) + (file.type_count() * constants::resource_type_length); + auto resource_offset = sizeof(std::uint16_t) + (file.type_count() * constants::resource_type_length); writer.write_short(file.type_count() - 1); for (const auto type : types) { // We need to ensure that the type code is 4 characters -- otherwise this file will be massively corrupt @@ -134,16 +132,16 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) } // 5. Now we're writing the actual resource headers. - uint16_t name_offset = 0; - uint16_t name_len = 0; + std::uint16_t name_offset = 0; + std::uint16_t name_len = 0; for (const auto type : types) { for (const auto& resource : *type) { auto id = resource->id(); - if (id < std::numeric_limits::min() || id > std::numeric_limits::max()) { + if (id < std::numeric_limits::min() || id > std::numeric_limits::max()) { return false; } - writer.write_signed_short(static_cast(id)); + writer.write_signed_short(static_cast(id)); // The name is actually stored in the name list, and the resource stores and offset to that name. // If no name is assigned to the resource then the offset is encoded as 0xFFFF @@ -170,7 +168,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) // The data offset is a 3 byte (24-bit) value. This means the hi-byte needs discarding and then a swap // performing. - auto offset = static_cast(resource->data_offset()); + auto offset = static_cast(resource->data_offset()); if (offset > 0xFFFFFF) { return false; } @@ -201,7 +199,7 @@ auto graphite::rsrc::format::classic::write(file &file, const std::string &path) if (writer.size() > 0xFFFFFF) { return false; } - map_length = static_cast(writer.size() - map_offset); + map_length = static_cast(writer.size() - map_offset); // 7. Fix the preamble values. writer.set_position(0); diff --git a/libs/libGraphite/rsrc/classic/writer.hpp b/libs/libResource/format/classic/writer.hpp similarity index 91% rename from libs/libGraphite/rsrc/classic/writer.hpp rename to libs/libResource/format/classic/writer.hpp index 86f18c9..981a9cd 100644 --- a/libs/libGraphite/rsrc/classic/writer.hpp +++ b/libs/libResource/format/classic/writer.hpp @@ -20,10 +20,11 @@ #pragma once -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/writer.hpp" +#include +#include +#include -namespace graphite::rsrc::format::classic +namespace resource::format::classic { auto write(file& file) -> bool; auto write(file& file, const std::string& path) -> bool; diff --git a/libs/libGraphite/rsrc/extended/extended.hpp b/libs/libResource/format/extended/extended.hpp similarity index 91% rename from libs/libGraphite/rsrc/extended/extended.hpp rename to libs/libResource/format/extended/extended.hpp index a4ced1e..35e3195 100644 --- a/libs/libGraphite/rsrc/extended/extended.hpp +++ b/libs/libResource/format/extended/extended.hpp @@ -20,5 +20,5 @@ #pragma once -#include "libGraphite/rsrc/extended/parser.hpp" -#include "libGraphite/rsrc/extended/writer.hpp" \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/libs/libGraphite/rsrc/extended/parser.cpp b/libs/libResource/format/extended/parser.cpp similarity index 87% rename from libs/libGraphite/rsrc/extended/parser.cpp rename to libs/libResource/format/extended/parser.cpp index e9f36f7..083595e 100644 --- a/libs/libGraphite/rsrc/extended/parser.cpp +++ b/libs/libResource/format/extended/parser.cpp @@ -18,18 +18,17 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/extended/parser.hpp" - #include #include -#include "libGraphite/hints.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include +#include +#include +#include // MARK: - Parsing -auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) -> bool +auto resource::format::extended::parse(data::reader &reader, file &file) -> bool { std::vector types; @@ -38,7 +37,7 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - return false; } - reader.move(sizeof(uint64_t)); + reader.move(sizeof(std::uint64_t)); auto data_offset = reader.read_quad(); auto map_offset = reader.read_quad(); auto data_length = reader.read_quad(); @@ -95,9 +94,9 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - GRAPHITE_UNUSED auto flags = reader.read_short(); // The next fields are the offsets of the type list and the name list. - auto type_list_offset = static_cast(reader.read_quad()); - auto name_list_offset = static_cast(reader.read_quad()); - auto attribute_list_offset = static_cast(reader.read_quad()); + auto type_list_offset = static_cast(reader.read_quad()); + auto name_list_offset = static_cast(reader.read_quad()); + auto attribute_list_offset = static_cast(reader.read_quad()); // 3. Parse the list of Resource Types. reader.set_position(map_offset + type_list_offset); @@ -126,7 +125,7 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - reader.set_position(map_offset + type_list_offset + first_resource_offset); for (auto res_idx = 0; res_idx < count; ++res_idx) { - auto id = static_cast(reader.read_signed_quad()); + auto id = static_cast(reader.read_signed_quad()); auto name_offset = reader.read_quad(); GRAPHITE_UNUSED auto flags = reader.read_byte(); auto resource_data_offset = reader.read_quad(); @@ -135,7 +134,7 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - reader.save_position(); // 6. Parse the name out of the list of resource names. std::string name; - if (name_offset != std::numeric_limits::max()) { + if (name_offset != std::numeric_limits::max()) { reader.set_position(map_offset + name_list_offset + name_offset); name = std::move(reader.read_pstr()); } @@ -147,7 +146,7 @@ auto graphite::rsrc::format::extended::parse(data::reader &reader, file &file) - reader.restore_position(); // 7. Construct a new resource instance and add it to the type. - auto resource = new struct resource(type, id, name, std::move(slice)); + auto resource = new struct instance(type, id, name, std::move(slice)); type->add_resource(resource); } diff --git a/libs/libGraphite/rsrc/rez/parser.hpp b/libs/libResource/format/extended/parser.hpp similarity index 91% rename from libs/libGraphite/rsrc/rez/parser.hpp rename to libs/libResource/format/extended/parser.hpp index 2b38189..c7e0493 100644 --- a/libs/libGraphite/rsrc/rez/parser.hpp +++ b/libs/libResource/format/extended/parser.hpp @@ -20,10 +20,10 @@ #pragma once -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include -namespace graphite::rsrc::format::rez +namespace resource::format::extended { auto parse(data::reader& reader, file& file) -> bool; } \ No newline at end of file diff --git a/libs/libGraphite/rsrc/extended/writer.cpp b/libs/libResource/format/extended/writer.cpp similarity index 83% rename from libs/libGraphite/rsrc/extended/writer.cpp rename to libs/libResource/format/extended/writer.cpp index 5220c33..1c6e9d1 100644 --- a/libs/libGraphite/rsrc/extended/writer.cpp +++ b/libs/libResource/format/extended/writer.cpp @@ -18,43 +18,42 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/extended/writer.hpp" - #include #include -#include "libGraphite/encoding/macroman/macroman.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include +#include +#include +#include // MARK: - Constants -namespace graphite::rsrc::format::extended::constants::defaults +namespace resource::format::extended::constants::defaults { - constexpr uint64_t version = 1; - constexpr uint64_t data_offset = 256; - constexpr uint64_t map_offset = 0; - constexpr uint64_t data_length = 0; - constexpr uint64_t map_length = 0; + constexpr std::uint64_t version = 1; + constexpr std::uint64_t data_offset = 256; + constexpr std::uint64_t map_offset = 0; + constexpr std::uint64_t data_length = 0; + constexpr std::uint64_t map_length = 0; } -namespace graphite::rsrc::format::extended::constants +namespace resource::format::extended::constants { - - constexpr uint16_t resource_type_length = 36; - constexpr uint16_t resource_length = 29; - constexpr uint16_t type_list_offset = 64; + constexpr std::uint16_t resource_type_length = 36; + constexpr std::uint16_t resource_length = 29; + constexpr std::uint16_t type_list_offset = 64; } // MARK: - Writing -auto graphite::rsrc::format::extended::write(file &file) -> bool +auto resource::format::extended::write(file &file) -> bool { return write(file, file.path()); } -auto graphite::rsrc::format::extended::write(file &file, const std::string &path) -> bool +auto resource::format::extended::write(file &file, const std::string &path) -> bool { - graphite::data::writer writer(data::byte_order::msb); + data::writer writer(data::byte_order::msb); // 1. Begin setting up the preamble auto data_offset = constants::defaults::data_offset; @@ -71,7 +70,7 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path // 2. Iterate through all of the resources and write their data blobs to the file data. // When doing this we need to record the starting points of each resources data. - uint64_t resource_count = 0; + std::uint64_t resource_count = 0; std::vector types(file.type_count()); auto type_ptr = types.begin(); @@ -109,8 +108,8 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path // 4. We're now writing the primary map information, which includes flags and offsets for the // type list and the name list. We can calculate where each of these will be. auto name_list_offset = constants::type_list_offset + (types.size() * constants::resource_type_length); - name_list_offset += (resource_count * constants::resource_length) + sizeof(uint64_t); - uint64_t attribute_list_offset_position = 0; + name_list_offset += (resource_count * constants::resource_length) + sizeof(std::uint64_t); + std::uint64_t attribute_list_offset_position = 0; writer.write_short(0); writer.write_quad(constants::type_list_offset); @@ -120,8 +119,8 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path writer.write_quad(attribute_list_offset_position); // No moving on to actually writing each of the type descriptors into the data. - uint64_t attribute_offset = 0; - uint64_t resource_offset = sizeof(uint64_t) + (types.size() * constants::resource_type_length); + std::uint64_t attribute_offset = 0; + std::uint64_t resource_offset = sizeof(std::uint64_t) + (types.size() * constants::resource_type_length); writer.write_quad(types.size() - 1); for (const auto type : types) { // We need to ensure that the type code is 4 characters -- otherwise this file be massively corrupt @@ -144,7 +143,7 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path } // 5. Now we're writing the actual resource headers. - uint64_t name_offset = 0; + std::uint64_t name_offset = 0; for (const auto type : types) { for (const auto& resource : *type) { writer.write_signed_quad(resource->id()); @@ -152,7 +151,7 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path // The name is actually stored in the name list, and the resource stores an offset to that name. // If no name is assigned to the resource then the offset is encoded as 0xFFFFFFFFFFFFFFFF. if (resource->name().empty()) { - writer.write_quad(std::numeric_limits::max()); + writer.write_quad(std::numeric_limits::max()); } else { // Convert the name to MacRoman so that we can get the length of it when encoded. @@ -182,7 +181,7 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path mac_roman.resize(0xFF); } name_offset += mac_roman.size() + 1; - writer.write_byte(static_cast(mac_roman.size())); + writer.write_byte(static_cast(mac_roman.size())); writer.write_bytes(mac_roman); } } @@ -206,10 +205,10 @@ auto graphite::rsrc::format::extended::write(file &file, const std::string &path attribute_offset += (writer.position() - initial); } - map_length = static_cast(writer.size() - map_offset); + map_length = static_cast(writer.size() - map_offset); // 8. Fix the preamble sizes. - writer.set_position(sizeof(uint64_t)); + writer.set_position(sizeof(std::uint64_t)); writer.write_quad(data_offset); writer.write_quad(map_offset); writer.write_quad(data_length); diff --git a/libs/libGraphite/rsrc/extended/writer.hpp b/libs/libResource/format/extended/writer.hpp similarity index 91% rename from libs/libGraphite/rsrc/extended/writer.hpp rename to libs/libResource/format/extended/writer.hpp index 004567c..173e7ad 100644 --- a/libs/libGraphite/rsrc/extended/writer.hpp +++ b/libs/libResource/format/extended/writer.hpp @@ -20,10 +20,11 @@ #pragma once -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/writer.hpp" +#include +#include +#include -namespace graphite::rsrc::format::extended +namespace resource::format::extended { auto write(file& file) -> bool; auto write(file& file, const std::string& path) -> bool; diff --git a/libs/libGraphite/rsrc/rez/parser.cpp b/libs/libResource/format/rez/parser.cpp similarity index 77% rename from libs/libGraphite/rsrc/rez/parser.cpp rename to libs/libResource/format/rez/parser.cpp index e9132a7..b1f69fc 100644 --- a/libs/libGraphite/rsrc/rez/parser.cpp +++ b/libs/libResource/format/rez/parser.cpp @@ -18,31 +18,30 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/rez/parser.hpp" - #include #include -#include "libGraphite/hints.hpp" -#include "libGraphite/encoding/macroman/macroman.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include +#include +#include +#include // MARK: - Constants -namespace graphite::rsrc::format::rez::constants +namespace resource::format::rez::constants { const std::string map_name = "resource.map"; - constexpr uint32_t signature = 'BRGR'; - constexpr uint32_t version = 1; - constexpr uint32_t resource_offset_length = 12; - constexpr uint32_t map_header_length = 8; - constexpr uint32_t type_info_length = 12; - constexpr uint32_t resource_info_length = 266; + constexpr std::uint32_t signature = 'BRGR'; + constexpr std::uint32_t version = 1; + constexpr std::uint32_t resource_offset_length = 12; + constexpr std::uint32_t map_header_length = 8; + constexpr std::uint32_t type_info_length = 12; + constexpr std::uint32_t resource_info_length = 266; }; // MARK: - Parsing -auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> bool +auto resource::format::rez::parse(data::reader &reader, file &file) -> bool { std::vector types; @@ -71,11 +70,11 @@ auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> boo } // 3. Record the offsets - std::vector offsets; - std::vector sizes; + std::vector offsets; + std::vector sizes; for (auto res_idx = 0; res_idx < count; ++res_idx) { - offsets.emplace_back(static_cast(reader.read_long())); - sizes.push_back(static_cast(reader.read_long())); + offsets.emplace_back(static_cast(reader.read_long())); + sizes.push_back(static_cast(reader.read_long())); reader.move(4); // Skip over an unknown value. } @@ -94,7 +93,7 @@ auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> boo // 5. Read the resource types. for (auto type_idx = 0; type_idx < type_count; ++type_idx) { auto code = reader.read_cstr(4); - auto type_offset = static_cast(reader.read_long()); + auto type_offset = static_cast(reader.read_long()); auto count = reader.read_long(); auto type = new struct type(code); @@ -109,7 +108,7 @@ auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> boo return false; } - auto id = static_cast(reader.read_signed_short()); + auto id = static_cast(reader.read_signed_short()); auto next_offset = reader.position() + 256; auto name = reader.read_cstr(); @@ -118,7 +117,7 @@ auto graphite::rsrc::format::rez::parse(data::reader &reader, file &file) -> boo reader.set_position(next_offset); // 7. Construct a new resource instance and add it to the type. - auto resource = new struct resource(type, id, name, std::move(slice)); + auto resource = new struct instance(type, id, name, std::move(slice)); type->add_resource(resource); } diff --git a/libs/libGraphite/rsrc/extended/parser.hpp b/libs/libResource/format/rez/parser.hpp similarity index 90% rename from libs/libGraphite/rsrc/extended/parser.hpp rename to libs/libResource/format/rez/parser.hpp index cbca92e..a62dd66 100644 --- a/libs/libGraphite/rsrc/extended/parser.hpp +++ b/libs/libResource/format/rez/parser.hpp @@ -20,10 +20,10 @@ #pragma once -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include -namespace graphite::rsrc::format::extended +namespace resource::format::rez { auto parse(data::reader& reader, file& file) -> bool; } \ No newline at end of file diff --git a/libs/libGraphite/rsrc/rez/rez.hpp b/libs/libResource/format/rez/rez.hpp similarity index 92% rename from libs/libGraphite/rsrc/rez/rez.hpp rename to libs/libResource/format/rez/rez.hpp index b0a458d..7dd8f7c 100644 --- a/libs/libGraphite/rsrc/rez/rez.hpp +++ b/libs/libResource/format/rez/rez.hpp @@ -20,5 +20,5 @@ #pragma once -#include "libGraphite/rsrc/rez/parser.hpp" -#include "libGraphite/rsrc/rez/writer.hpp" \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/libs/libGraphite/rsrc/rez/writer.cpp b/libs/libResource/format/rez/writer.cpp similarity index 72% rename from libs/libGraphite/rsrc/rez/writer.cpp rename to libs/libResource/format/rez/writer.cpp index 9bdf87d..ef4cbc2 100644 --- a/libs/libGraphite/rsrc/rez/writer.cpp +++ b/libs/libResource/format/rez/writer.cpp @@ -18,51 +18,50 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/rez/writer.hpp" - #include #include -#include "libGraphite/encoding/macroman/macroman.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include +#include +#include // MARK: - Constants -namespace graphite::rsrc::format::rez::constants +namespace resource::format::rez::constants { const std::string map_name = "resource.map"; - constexpr uint32_t signature = 'BRGR'; - constexpr uint32_t version = 1; - constexpr uint32_t header_length = 12; - constexpr uint32_t resource_offset_length = 12; - constexpr uint32_t map_header_length = 8; - constexpr uint32_t type_info_length = 12; - constexpr uint32_t resource_info_length = 266; + constexpr std::uint32_t signature = 'BRGR'; + constexpr std::uint32_t version = 1; + constexpr std::uint32_t header_length = 12; + constexpr std::uint32_t resource_offset_length = 12; + constexpr std::uint32_t map_header_length = 8; + constexpr std::uint32_t type_info_length = 12; + constexpr std::uint32_t resource_info_length = 266; } // MARK: - Writing -auto graphite::rsrc::format::rez::write(file &file) -> bool +auto resource::format::rez::write(file &file) -> bool { return write(file, file.path()); } -auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> bool +auto resource::format::rez::write(file &file, const std::string &path) -> bool { - graphite::data::writer writer(data::byte_order::msb); + data::writer writer(data::byte_order::msb); // Count up the total number of resources - uint32_t resource_count = 0; + std::uint32_t resource_count = 0; for (const auto type_hash : file.types()) { auto type = file.type(type_hash); resource_count += type->count(); } // The resource map itself is considered an entry for the offsets in the header. - uint32_t entry_count = resource_count + 1; + std::uint32_t entry_count = resource_count + 1; // Calculate header length - this is from the end of the preamble to the start of the resource data - uint32_t header_length = constants::header_length + (entry_count * constants::resource_offset_length) + constants::map_name.size() + 1; + std::uint32_t header_length = constants::header_length + (entry_count * constants::resource_offset_length) + constants::map_name.size() + 1; // Write the preamble writer.write_long(constants::signature); @@ -71,10 +70,10 @@ auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> writer.write_long(header_length); // Calculate the offset to the first resource data - uint32_t resource_offset = writer.size() + header_length; + std::uint32_t resource_offset = writer.size() + header_length; // Write the header - uint32_t index = 1; // Index of the first resource, starting at 1. + std::uint32_t index = 1; // Index of the first resource, starting at 1. writer.write_long(1); // Unknown value writer.write_long(index); writer.write_long(entry_count); @@ -90,17 +89,17 @@ auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> // Get the data for the resource and determine its size. auto size = resource->data().size(); writer.write_long(resource_offset); - writer.write_long(static_cast(size)); + writer.write_long(static_cast(size)); writer.write_long(0); resource_offset += size; } } - uint32_t type_count = file.type_count(); + std::uint32_t type_count = file.type_count(); // Calculate the offset within map to start of resource info - uint32_t type_offset = constants::map_header_length + (type_count * constants::type_info_length); - uint32_t map_length = type_offset + (resource_count & constants::resource_info_length); + std::uint32_t type_offset = constants::map_header_length + (type_count * constants::type_info_length); + std::uint32_t map_length = type_offset + (resource_count & constants::resource_info_length); // Write the offset and size of the resource map writer.write_long(resource_offset); @@ -135,7 +134,7 @@ auto graphite::rsrc::format::rez::write(file &file, const std::string &path) -> for (const auto& resource : *type) { writer.write_long(index++); writer.write_cstr(type->code(), 4); - writer.write_signed_short(static_cast(resource->id())); + writer.write_signed_short(static_cast(resource->id())); writer.write_cstr(resource->name(), 256); } } diff --git a/libs/libGraphite/rsrc/rez/writer.hpp b/libs/libResource/format/rez/writer.hpp similarity index 91% rename from libs/libGraphite/rsrc/rez/writer.hpp rename to libs/libResource/format/rez/writer.hpp index 1a52cca..9012291 100644 --- a/libs/libGraphite/rsrc/rez/writer.hpp +++ b/libs/libResource/format/rez/writer.hpp @@ -20,10 +20,11 @@ #pragma once -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/data/writer.hpp" +#include +#include +#include -namespace graphite::rsrc::format::rez +namespace resource::format::rez { auto write(file& file) -> bool; auto write(file& file, const std::string& path) -> bool; diff --git a/libs/libResource/identifier.hpp b/libs/libResource/identifier.hpp new file mode 100644 index 0000000..13f28da --- /dev/null +++ b/libs/libResource/identifier.hpp @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace resource +{ + typedef std::int64_t identifier; + constexpr identifier auto_resource_id = std::numeric_limits::min(); + constexpr identifier default_resource_id = 128; +} \ No newline at end of file diff --git a/libs/libGraphite/rsrc/manager.cpp b/libs/libResource/manager.cpp similarity index 61% rename from libs/libGraphite/rsrc/manager.cpp rename to libs/libResource/manager.cpp index e4878bf..4d3e717 100644 --- a/libs/libGraphite/rsrc/manager.cpp +++ b/libs/libResource/manager.cpp @@ -18,43 +18,32 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/manager.hpp" -#include "libGraphite/font/manager.hpp" -#include "libGraphite/font/sfnt.hpp" +#include // MARK: - Singleton / Construction -auto graphite::rsrc::manager::shared_manager() -> manager & +auto resource::manager::shared_manager() -> manager & { - static rsrc::manager manager; + static ::resource::manager manager; return manager; } // MARK: - File Management -auto graphite::rsrc::manager::import_file(class file *file) -> class file * +auto resource::manager::import_file(class file *file) -> class file * { - m_files.emplace(std::pair(file->hash_value(), file)); + m_files.emplace(file->hash_value(), file); m_file_load_order.insert(m_file_load_order.begin(), file->hash_value()); - - if ( - file->type(font::outline_font::type_code()) || - file->type(font::descriptor::type_code()) || - file->type(font::bitmapped_font::type_code()) - ) { - font::manager::shared_manager().update_font_table(); - } - return file; } -auto graphite::rsrc::manager::import_file(const std::string &path) -> class file * +auto resource::manager::import_file(const std::string &path) -> class file * { - auto file = new graphite::rsrc::file(path); + auto file = new ::resource::file(path); return import_file(file); } -auto graphite::rsrc::manager::unload_file(file::hash file) -> void +auto resource::manager::unload_file(file::hash file) -> void { auto it = m_files.find(file); if (it != m_files.end()) { @@ -63,19 +52,19 @@ auto graphite::rsrc::manager::unload_file(file::hash file) -> void } } -auto graphite::rsrc::manager::unload_file(class file *file) -> void +auto resource::manager::unload_file(class file *file) -> void { if (file) { unload_file(file->hash_value()); } } -auto graphite::rsrc::manager::unload_file(const std::string &path) -> void +auto resource::manager::unload_file(const std::string &path) -> void { unload_file(file::hash_for_path(path)); } -auto graphite::rsrc::manager::file(file::hash file) -> class file * +auto resource::manager::file(file::hash file) -> class file * { auto it = m_files.find(file); if (it != m_files.end()) { @@ -84,7 +73,7 @@ auto graphite::rsrc::manager::file(file::hash file) -> class file * return nullptr; } -auto graphite::rsrc::manager::file(file::hash file) const -> class file * +auto resource::manager::file(file::hash file) const -> class file * { auto it = m_files.find(file); if (it != m_files.end()) { @@ -93,17 +82,17 @@ auto graphite::rsrc::manager::file(file::hash file) const -> class file * return nullptr; } -auto graphite::rsrc::manager::file(const std::string &path) -> class file * +auto resource::manager::file(const std::string &path) -> class file * { return file(file::hash_for_path(path)); } -auto graphite::rsrc::manager::files() const -> const std::vector& +auto resource::manager::files() const -> const std::vector& { return m_file_load_order; } -auto graphite::rsrc::manager::file_references() const -> std::vector +auto resource::manager::file_references() const -> std::vector { std::vector files; for (auto hash : this->files()) { @@ -114,7 +103,7 @@ auto graphite::rsrc::manager::file_references() const -> std::vector &attributes) const -> std::vector +auto resource::manager::all_types(const std::string &type_code, const std::vector &attributes) const -> std::vector { std::vector types; for (const auto& it : m_files) { @@ -126,10 +115,10 @@ auto graphite::rsrc::manager::all_types(const std::string &type_code, const std: return types; } -auto graphite::rsrc::manager::find(const std::string &type_code, const std::vector &attributes) const -> resource_result +auto resource::manager::find(const std::string &type_code, const std::vector &attributes) const -> result { - std::unordered_map resources; - resource_result result; + std::unordered_map resources; + result result; // Gather all of the resources for the type into a single location to draw upon. const auto& types = all_types(type_code, attributes); @@ -142,16 +131,16 @@ auto graphite::rsrc::manager::find(const std::string &type_code, const std::vect return std::move(result); } -auto graphite::rsrc::manager::find(const std::string &type_code, resource::identifier id, const std::vector &attributes) const -> struct resource * +auto resource::manager::find(const std::string &type_code, identifier id, const std::vector &attributes) const -> struct instance * { auto resources = std::move(find(type_code, attributes)); return resources.resource(type_code, id); } -auto graphite::rsrc::manager::find(const std::string &type_code, const std::string &name_prefix, const std::vector &attributes) const -> resource_result +auto resource::manager::find(const std::string &type_code, const std::string &name_prefix, const std::vector &attributes) const -> result { auto resources = std::move(find(type_code, attributes)); - return std::move(resources.filter([&] (struct resource *subject) -> bool { + return std::move(resources.filter([&] (struct instance *subject) -> bool { const auto& name = subject->name(); if (name.length() == name_prefix.length() && name == name_prefix) { return true; @@ -167,7 +156,7 @@ auto graphite::rsrc::manager::find(const std::string &type_code, const std::stri // MARK: - Tear Down -auto graphite::rsrc::manager::tear_down() -> void +auto resource::manager::tear_down() -> void { for (const auto& file : m_files) { delete file.second; diff --git a/libs/libGraphite/rsrc/manager.hpp b/libs/libResource/manager.hpp similarity index 76% rename from libs/libGraphite/rsrc/manager.hpp rename to libs/libResource/manager.hpp index cbc38b5..3581144 100644 --- a/libs/libGraphite/rsrc/manager.hpp +++ b/libs/libResource/manager.hpp @@ -22,14 +22,14 @@ #include #include -#include "libGraphite/rsrc/file.hpp" -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/rsrc/attribute.hpp" -#include "libGraphite/rsrc/result.hpp" -#include "libGraphite/util/concepts.hpp" - -namespace graphite::rsrc +#include +#include +#include +#include +#include +#include + +namespace resource { class manager { @@ -57,38 +57,38 @@ namespace graphite::rsrc [[nodiscard]] auto files() const -> const std::vector&; [[nodiscard]] auto file_references() const -> std::vector; - [[nodiscard]] auto find(const std::string& type_code, const std::vector& attributes = {}) const -> resource_result; - [[nodiscard]] auto find(const std::string& type_code, resource::identifier id, const std::vector& attributes = {}) const -> struct resource *; - [[nodiscard]] auto find(const std::string& type_code, const std::string& name_prefix, const std::vector& attributes = {}) const -> resource_result; + [[nodiscard]] auto find(const std::string& type_code, const std::vector& attributes = {}) const -> result; + [[nodiscard]] auto find(const std::string& type_code, identifier id, const std::vector& attributes = {}) const -> struct instance *; + [[nodiscard]] auto find(const std::string& type_code, const std::string& name_prefix, const std::vector& attributes = {}) const -> result; - template - [[nodiscard]] auto find(const std::vector& attributes = {}) const -> resource_result + template + [[nodiscard]] auto find(const std::vector& attributes = {}) const -> result { return find(T::type_code(), attributes); } - template - [[nodiscard]] auto find(resource::identifier id, const std::vector& attributes = {}) const -> struct resource * + template + [[nodiscard]] auto find(identifier id, const std::vector& attributes = {}) const -> struct instance * { return find(T::type_code(), id, attributes); } - template - [[nodiscard]] auto find(const std::string& name_prefix, const std::vector& attributes = {}) const -> resource_result + template + [[nodiscard]] auto find(const std::string& name_prefix, const std::vector& attributes = {}) const -> result { return find(T::type_code(), name_prefix, attributes); } [[nodiscard]] auto all_types(const std::string& type_code, const std::vector& attributes = {}) const -> std::vector; - template + template [[nodiscard]] auto all_types(const std::vector& attributes = {}) const -> std::vector { return all_types(T::type_code(), attributes); } - template - [[nodiscard]] auto load(resource::identifier id, const std::vector& attributes = {}) const -> T + template + [[nodiscard]] auto load(identifier id, const std::vector& attributes = {}) const -> T { if (const auto resource = find(id, attributes)) { return std::move(T(resource->data(), resource->id(), resource->name())); diff --git a/libs/libGraphite/rsrc/result.cpp b/libs/libResource/result.cpp similarity index 65% rename from libs/libGraphite/rsrc/result.cpp rename to libs/libResource/result.cpp index 0546ba1..bbaa953 100644 --- a/libs/libGraphite/rsrc/result.cpp +++ b/libs/libResource/result.cpp @@ -19,28 +19,28 @@ // SOFTWARE. #include -#include "libGraphite/rsrc/result.hpp" -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/util/hashing.hpp" +#include +#include +#include // MARK: - Hashing -auto graphite::rsrc::resource_result::sort_key(struct resource *resource) -> hash +auto resource::result::sort_key(struct instance *resource) -> hash { return sort_key(resource->type_code(), resource->id()); } -auto graphite::rsrc::resource_result::sort_key(const std::string& type_code, resource::identifier id) -> hash +auto resource::result::sort_key(const std::string& type_code, identifier id) -> hash { - std::string key { type_code + "." + std::to_string(id) }; + std::string key = type_code + "." + std::to_string(id); return hashing::xxh64(key.c_str(), key.size()); } // MARK: - Item Management -auto graphite::rsrc::resource_result::add(struct resource *resource) -> void +auto resource::result::add(struct instance *instance) -> void { - if (!resource) { + if (!instance) { return; } @@ -49,25 +49,25 @@ auto graphite::rsrc::resource_result::add(struct resource *resource) -> void return; } - auto key = resource_result::sort_key(resource); - m_resources.emplace(std::pair(key, resource)); + auto key = sort_key(instance); + m_resources.emplace(key, instance); m_sorted_keys.emplace_back(key); } -auto graphite::rsrc::resource_result::finalize() -> void +auto resource::result::finalize() -> void { m_finalized = true; sort(); } -auto graphite::rsrc::resource_result::size() const -> std::size_t +auto resource::result::size() const -> std::size_t { return m_resources.size(); } // MARK: - Sorting -auto graphite::rsrc::resource_result::sort() -> void +auto resource::result::sort() -> void { if (!m_finalized) { // TODO: Issue a warning @@ -84,23 +84,23 @@ auto graphite::rsrc::resource_result::sort() -> void // MARK: - Look up -auto graphite::rsrc::resource_result::begin() -> iterator +auto resource::result::begin() -> iterator { return { this, 0 }; } -auto graphite::rsrc::resource_result::end() -> iterator +auto resource::result::end() -> iterator { return { this, std::numeric_limits::max() }; } -auto graphite::rsrc::resource_result::at(std::uint64_t idx) const -> struct resource * +auto resource::result::at(std::uint64_t idx) const -> struct instance * { auto it = m_resources.find(m_sorted_keys.at(idx)); return (it != m_resources.end()) ? it->second : nullptr; } -auto graphite::rsrc::resource_result::id(resource::identifier id) const -> struct resource * +auto resource::result::id(identifier id) const -> struct instance * { for (const auto resource : m_resources) { if (resource.second->id() == id) { @@ -110,16 +110,16 @@ auto graphite::rsrc::resource_result::id(resource::identifier id) const -> struc return nullptr; } -auto graphite::rsrc::resource_result::resource(const std::string &type_code, resource::identifier id) const -> struct resource * +auto resource::result::resource(const std::string &type_code, identifier id) const -> struct instance * { - auto key = resource_result::sort_key(type_code, id); + auto key = sort_key(type_code, id); auto it = m_resources.find(key); return (it != m_resources.end()) ? it->second : nullptr; } -auto graphite::rsrc::resource_result::filter(const std::functionbool>& fn) const -> resource_result +auto resource::result::filter(const std::functionbool>& fn) const -> result { - resource_result result; + result result; for (const auto resource : m_resources) { if (fn(resource.second)) { diff --git a/libs/libGraphite/rsrc/result.hpp b/libs/libResource/result.hpp similarity index 81% rename from libs/libGraphite/rsrc/result.hpp rename to libs/libResource/result.hpp index 044b6cf..f1a66e2 100644 --- a/libs/libGraphite/rsrc/result.hpp +++ b/libs/libResource/result.hpp @@ -25,11 +25,11 @@ #include #include #include -#include "libGraphite/rsrc/resource.hpp" +#include -namespace graphite::rsrc +namespace resource { - struct resource_result + struct result { public: typedef std::uint64_t hash; @@ -38,11 +38,11 @@ namespace graphite::rsrc { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; - using value_type = struct resource; + using value_type = struct instance; using pointer = value_type*; using reference = value_type&; - iterator(resource_result *ptr, std::uint64_t index) : m_ptr(ptr), m_index(index) {}; + iterator(result *ptr, std::uint64_t index) : m_ptr(ptr), m_index(index) {}; auto operator*() const -> reference { return *get(); } auto operator->() -> pointer { return const_cast(get()); } @@ -67,7 +67,7 @@ namespace graphite::rsrc } private: - resource_result *m_ptr { nullptr }; + result *m_ptr { nullptr }; std::uint64_t m_index { 0 }; [[nodiscard]] auto get() const -> pointer @@ -82,12 +82,12 @@ namespace graphite::rsrc }; public: - resource_result() = default; + result() = default; - static auto sort_key(struct resource *resource) -> hash; - static auto sort_key(const std::string& type_code, resource::identifier id) -> hash; + static auto sort_key(struct instance *instance) -> hash; + static auto sort_key(const std::string& type_code, identifier id) -> hash; - auto add(struct resource *resource) -> void; + auto add(struct instance *instance) -> void; auto finalize() -> void; auto sort() -> void; @@ -95,17 +95,17 @@ namespace graphite::rsrc auto begin() -> iterator; auto end() -> iterator; - [[nodiscard]] auto filter(const std::functionbool>& fn) const -> resource_result; + [[nodiscard]] auto filter(const std::functionbool>& fn) const -> result; [[nodiscard]] auto size() const -> std::size_t; - [[nodiscard]] auto at(std::uint64_t idx) const -> struct resource *; - [[nodiscard]] auto id(resource::identifier id) const -> struct resource *; - [[nodiscard]] auto resource(const std::string& type_code, resource::identifier id) const -> struct resource *; + [[nodiscard]] auto at(std::uint64_t idx) const -> struct instance *; + [[nodiscard]] auto id(identifier id) const -> struct instance *; + [[nodiscard]] auto resource(const std::string& type_code, identifier id) const -> struct instance *; private: typedef std::uint64_t resource_sort_key; bool m_finalized { false }; - std::unordered_map m_resources; + std::unordered_map m_resources; std::vector m_sorted_keys; }; diff --git a/libs/libGraphite/rsrc/attribute.cpp b/libs/libResource/structure/attribute.cpp similarity index 75% rename from libs/libGraphite/rsrc/attribute.cpp rename to libs/libResource/structure/attribute.cpp index 01ac965..322a2b3 100644 --- a/libs/libGraphite/rsrc/attribute.cpp +++ b/libs/libResource/structure/attribute.cpp @@ -18,36 +18,36 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/attribute.hpp" -#include "libGraphite/util/hashing.hpp" +#include +#include // MARK: - Construction -graphite::rsrc::attribute::attribute(const std::string &name, const std::string &value) +resource::attribute::attribute(const std::string &name, const std::string &value) : m_name(name), m_value(value) { } // MARK: - Accessors -auto graphite::rsrc::attribute::hash_value() const -> hash +auto resource::attribute::hash_value() const -> hash { return hash_for_name(m_name); } -auto graphite::rsrc::attribute::name() const -> const std::string& +auto resource::attribute::name() const -> const std::string& { return m_name; } -auto graphite::rsrc::attribute::string_value() const -> const std::string& +auto resource::attribute::string_value() const -> const std::string& { return m_value; } // MARK: - Helpers -auto graphite::rsrc::attribute::hash_for_name(const std::string& name) -> hash +auto resource::attribute::hash_for_name(const std::string& name) -> hash { return hashing::xxh64(name.c_str(), name.size()); } diff --git a/libs/libGraphite/rsrc/attribute.hpp b/libs/libResource/structure/attribute.hpp similarity index 98% rename from libs/libGraphite/rsrc/attribute.hpp rename to libs/libResource/structure/attribute.hpp index cd553d8..ff43c1c 100644 --- a/libs/libGraphite/rsrc/attribute.hpp +++ b/libs/libResource/structure/attribute.hpp @@ -23,7 +23,7 @@ #include #include -namespace graphite::rsrc +namespace resource { struct attribute { diff --git a/libs/libResource/structure/instance.cpp b/libs/libResource/structure/instance.cpp new file mode 100644 index 0000000..15e614b --- /dev/null +++ b/libs/libResource/structure/instance.cpp @@ -0,0 +1,157 @@ +// Copyright (c) 2022 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include + +// MARK: - Construction + +resource::instance::instance(identifier id, const std::string &name) + : m_id(id), m_name(name) +{} + +resource::instance::instance(struct type *type, resource::identifier id, const std::string &name, data::block data) + : m_type(type), m_id(id), m_name(name), m_data(std::move(data)) +{ +} + +resource::instance::instance(const instance &instance) + : m_type(instance.m_type), + m_id(instance.m_id), + m_name(instance.m_name), + m_data(data::block(instance.m_data, true)) +{ +} + +resource::instance::instance(instance &&instance) noexcept + : m_type(instance.m_type), + m_id(instance.m_id), + m_name(std::move(instance.m_name)), + m_data(std::move(instance.m_data)) +{ + instance.m_type = nullptr; +} + +// MARK: - Operators + +auto resource::instance::operator=(const instance &instance) -> struct instance& +{ + if (this == const_cast(&instance)) { + return *this; + } + + m_id = instance.m_id; + m_type = instance.m_type; + m_name = instance.m_name; + m_data = instance.m_data; + m_data_offset = instance.m_data_offset; + + return *this; +} + +auto resource::instance::operator=(instance &&instance) noexcept -> struct instance& +{ + if (this != &instance) { + m_id = instance.m_id; + m_type = instance.m_type; + m_name = std::move(instance.m_name); + m_data = std::move(instance.m_data); + m_data_offset = instance.m_data_offset; + } + return *this; +} + +// MARK: - Accessors + +auto resource::instance::id() const -> identifier +{ + return m_id; +} + +auto resource::instance::type() const -> struct type * +{ + return m_type; +} + +auto resource::instance::name() const -> const std::string& +{ + return m_name; +} + +auto resource::instance::type_code() const -> std::string +{ + if (m_type) { + return m_type->code(); + } + else { + return type::unknown_type_code; + } +} + +auto resource::instance::data() const -> const data::block& +{ + return m_data; +} + +auto resource::instance::set_id(identifier id) -> void +{ + m_id = id; +} + +auto resource::instance::set_name(const std::string &name) -> void +{ + m_name = name; +} + +auto resource::instance::set_type(struct type *type) -> void +{ + m_type = type; +} + +auto resource::instance::set_data(data::block& data) -> void +{ + m_data = data; + m_data_offset = 0; +} + +// MARK: - Hashing + +auto resource::instance::hash(identifier id) -> identifier_hash +{ + return hashing::xxh64(&id, sizeof(id)); +} + +auto resource::instance::hash(const std::string &name) -> name_hash +{ + return hashing::xxh64(name.c_str(), name.size()); +} + +// MARK: - Data Offsets + +auto resource::instance::set_data_offset(std::size_t offset) -> void +{ + m_data_offset = offset; +} + +auto resource::instance::data_offset() const -> std::size_t +{ + return m_data_offset; +} diff --git a/libs/libGraphite/rsrc/resource.hpp b/libs/libResource/structure/instance.hpp similarity index 70% rename from libs/libGraphite/rsrc/resource.hpp rename to libs/libResource/structure/instance.hpp index b2e939c..648428e 100644 --- a/libs/libGraphite/rsrc/resource.hpp +++ b/libs/libResource/structure/instance.hpp @@ -22,39 +22,35 @@ #include #include -#include "libGraphite/data/data.hpp" +#include +#include -namespace graphite::rsrc +namespace resource { struct type; - struct resource + struct instance { public: - typedef std::int64_t identifier; typedef std::uint64_t identifier_hash; typedef std::uint64_t name_hash; - static constexpr resource::identifier default_resource_id { 128 }; - public: - explicit resource(resource::identifier id = default_resource_id, const std::string& name = ""); - explicit resource(struct type *type, resource::identifier id = default_resource_id, const std::string& name = "", data::block data = {}); - resource(const resource& resource); - resource(resource&& resource) noexcept; - - ~resource(); + explicit instance(identifier id = default_resource_id, const std::string& name = ""); + explicit instance(struct type *type, identifier id = default_resource_id, const std::string& name = "", data::block data = {}); + instance(const instance& resource); + instance(instance&& resource) noexcept; - auto operator=(const resource& resource) -> struct resource&; - auto operator=(resource&& resource) noexcept -> struct resource&; + auto operator=(const instance& resource) -> struct instance&; + auto operator=(instance&& resource) noexcept -> struct instance&; - [[nodiscard]] auto id() const -> resource::identifier; + [[nodiscard]] auto id() const -> identifier; [[nodiscard]] auto type() const -> struct type *; [[nodiscard]] auto name() const -> const std::string&; [[nodiscard]] auto type_code() const -> std::string; [[nodiscard]] auto data() const -> const data::block&; - auto set_id(resource::identifier id) -> void; + auto set_id(identifier id) -> void; auto set_name(const std::string& name) -> void; auto set_type(struct type *type) -> void; auto set_data(data::block& data) -> void; @@ -66,7 +62,7 @@ namespace graphite::rsrc [[nodiscard]] auto data_offset() const -> std::size_t; private: - resource::identifier m_id { default_resource_id }; + identifier m_id { default_resource_id }; struct type *m_type { nullptr }; std::string m_name; data::block m_data; diff --git a/libs/libGraphite/rsrc/type.cpp b/libs/libResource/structure/type.cpp similarity index 65% rename from libs/libGraphite/rsrc/type.cpp rename to libs/libResource/structure/type.cpp index ef2b6d5..914c566 100644 --- a/libs/libGraphite/rsrc/type.cpp +++ b/libs/libResource/structure/type.cpp @@ -18,27 +18,27 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/rsrc/type.hpp" -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/util/hashing.hpp" +#include +#include +#include // MARK: - Construction -graphite::rsrc::type::type(const std::string &code) +resource::type::type(const std::string &code) : m_code(code) { } -graphite::rsrc::type::type(const type &type) +resource::type::type(const type &type) : m_code(type.m_code), m_attributes(type.m_attributes) { for (const auto& resource : type.m_resources) { - add_resource(new rsrc::resource(*resource)); + add_resource(new instance(*resource)); } } -graphite::rsrc::type::type(type &&type) noexcept +resource::type::type(type &&type) noexcept : m_code(std::move(type.m_code)), m_resources(std::move(type.m_resources)), m_resource_id_map(std::move(type.m_resource_id_map)), @@ -52,7 +52,7 @@ graphite::rsrc::type::type(type &&type) noexcept // MARK: - Destruction -graphite::rsrc::type::~type() +resource::type::~type() { for (auto it : m_resources) { delete it; @@ -61,7 +61,7 @@ graphite::rsrc::type::~type() // MARK: - Operators -auto graphite::rsrc::type::operator=(const type &type) -> struct type& +auto resource::type::operator=(const type &type) -> struct type& { if (this == const_cast(&type)) { return *this; @@ -71,13 +71,13 @@ auto graphite::rsrc::type::operator=(const type &type) -> struct type& m_attributes = type.m_attributes; for (const auto& resource : type.m_resources) { - add_resource(new rsrc::resource(*resource)); + add_resource(new instance(*resource)); } return *this; } -auto graphite::rsrc::type::operator=(type &&type) noexcept -> struct type& +auto resource::type::operator=(type &&type) noexcept -> struct type& { if (this != &type) { m_code = std::move(type.m_code); @@ -95,7 +95,7 @@ auto graphite::rsrc::type::operator=(type &&type) noexcept -> struct type& // MARK: - Accessors -auto graphite::rsrc::type::attribute_string(const std::unordered_map &attributes) -> std::string +auto resource::type::attribute_string(const std::unordered_map &attributes) -> std::string { std::string descriptor; for (const auto& attribute : attributes) { @@ -104,12 +104,12 @@ auto graphite::rsrc::type::attribute_string(const std::unordered_map hash +auto resource::type::hash_for_type_code(const std::string &code) -> hash { return hashing::xxh64(code.c_str(), code.size()); } -auto graphite::rsrc::type::hash_for_type_code(const std::string &code, const std::unordered_map &attributes) -> graphite::rsrc::type::hash +auto resource::type::hash_for_type_code(const std::string &code, const std::unordered_map &attributes) -> resource::type::hash { std::string assembled_code { code }; if (!attributes.empty()) { @@ -118,7 +118,7 @@ auto graphite::rsrc::type::hash_for_type_code(const std::string &code, const std return hash_for_type_code(assembled_code); } -auto graphite::rsrc::type::hash_value() const -> hash +auto resource::type::hash_value() const -> hash { std::string code { m_code }; if (!m_attributes.empty()) { @@ -127,36 +127,36 @@ auto graphite::rsrc::type::hash_value() const -> hash return hash_for_type_code(code); } -auto graphite::rsrc::type::code() const -> const std::string& +auto resource::type::code() const -> const std::string& { return m_code; } -auto graphite::rsrc::type::attributes() const -> const std::unordered_map& +auto resource::type::attributes() const -> const std::unordered_map& { return m_attributes; } -auto graphite::rsrc::type::count() const -> std::size_t +auto resource::type::count() const -> std::size_t { return m_resources.size(); } -auto graphite::rsrc::type::attribute_descriptor_string() const -> std::string +auto resource::type::attribute_descriptor_string() const -> std::string { return std::move(attribute_string(m_attributes)); } // MARK: - Attribute Management -auto graphite::rsrc::type::add_attribute(const std::string& name, const std::string& value) -> void +auto resource::type::add_attribute(const std::string& name, const std::string& value) -> void { attribute attr { name, value }; m_attributes.emplace(std::pair(attr.hash_value(), std::move(attr))); } template::value>::type*> -auto graphite::rsrc::type::add_attribute(const std::string &name, T value) -> void +auto resource::type::add_attribute(const std::string &name, T value) -> void { attribute attr { name, value }; m_attributes.template emplace(std::pair(attr.hash_value(), std::move(attr))); @@ -164,36 +164,36 @@ auto graphite::rsrc::type::add_attribute(const std::string &name, T value) -> vo // MARK: - Resource Management -auto graphite::rsrc::type::has_resource(resource::identifier id) const -> bool +auto resource::type::has_resource(resource::identifier id) const -> bool { auto hash = hashing::xxh64(&id, sizeof(id)); return (m_resource_id_map.find(hash) != m_resource_id_map.end()); } -auto graphite::rsrc::type::has_resource(const std::string &name) const -> bool +auto resource::type::has_resource(const std::string &name) const -> bool { auto hash = hashing::xxh64(name.c_str(), name.size()); return (m_resource_name_map.find(hash) != m_resource_name_map.end()); } -auto graphite::rsrc::type::add_resource(resource *resource) -> void +auto resource::type::add_resource(instance *resource) -> void { m_resources.emplace_back(resource); resource->set_type(this); - auto id_hash = resource::hash(resource->id()); - auto name_hash = resource::hash(resource->name()); + auto id_hash = instance::hash(resource->id()); + auto name_hash = instance::hash(resource->name()); m_resource_id_map.emplace(std::pair(id_hash, resource)); m_resource_name_map.emplace(std::pair(name_hash, resource)); } -auto graphite::rsrc::type::remove_resource(resource::identifier id) -> void +auto resource::type::remove_resource(identifier id) -> void { // TODO: } -auto graphite::rsrc::type::resource_with_id(resource::identifier id) const -> resource * +auto resource::type::resource_with_id(resource::identifier id) const -> instance * { for (const auto& it : m_resources) { if (it->id() == id) { @@ -203,7 +203,7 @@ auto graphite::rsrc::type::resource_with_id(resource::identifier id) const -> re return nullptr; } -auto graphite::rsrc::type::resource_with_name(const std::string &name) const -> resource * +auto resource::type::resource_with_name(const std::string &name) const -> instance * { for (const auto& it : m_resources) { if (it->name() == name) { @@ -213,31 +213,30 @@ auto graphite::rsrc::type::resource_with_name(const std::string &name) const -> return nullptr; } -auto graphite::rsrc::type::begin() -> std::vector::iterator +auto resource::type::begin() -> std::vector::iterator { return m_resources.begin(); } -auto graphite::rsrc::type::end() -> std::vector::iterator +auto resource::type::end() -> std::vector::iterator { return m_resources.end(); } -auto graphite::rsrc::type::begin() const -> std::vector::const_iterator +auto resource::type::begin() const -> std::vector::const_iterator { return m_resources.cbegin(); } -auto graphite::rsrc::type::end() const -> std::vector::const_iterator +auto resource::type::end() const -> std::vector::const_iterator { return m_resources.end(); } -auto graphite::rsrc::type::at(int64_t idx) -> resource * +auto resource::type::at(int64_t idx) -> instance * { if (idx < 0 || idx >= m_resources.size()) { return nullptr; } return m_resources.at(idx); } - diff --git a/libs/libGraphite/rsrc/type.hpp b/libs/libResource/structure/type.hpp similarity index 76% rename from libs/libGraphite/rsrc/type.hpp rename to libs/libResource/structure/type.hpp index 9ab30b5..0d36e1b 100644 --- a/libs/libGraphite/rsrc/type.hpp +++ b/libs/libResource/structure/type.hpp @@ -23,16 +23,18 @@ #include #include #include -#include "libGraphite/rsrc/attribute.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include -namespace graphite::rsrc +namespace resource { struct type { public: typedef std::uint64_t hash; + static constexpr const char *unknown_type_code = "????"; + public: explicit type(const std::string& code); type(const type& type); @@ -58,26 +60,26 @@ namespace graphite::rsrc template::value>::type* = nullptr> auto add_attribute(const std::string& name, T value) -> void; - [[nodiscard]] auto has_resource(resource::identifier id) const -> bool; + [[nodiscard]] auto has_resource(identifier id) const -> bool; [[nodiscard]] auto has_resource(const std::string& name) const -> bool; - auto add_resource(resource *resource) -> void; - auto remove_resource(resource::identifier id) -> void; + auto add_resource(instance *resource) -> void; + auto remove_resource(identifier id) -> void; - [[nodiscard]] auto resource_with_id(resource::identifier id) const -> resource *; - [[nodiscard]] auto resource_with_name(const std::string& name) const -> resource *; + [[nodiscard]] auto resource_with_id(resource::identifier id) const -> instance *; + [[nodiscard]] auto resource_with_name(const std::string& name) const -> instance *; - auto begin() -> std::vector::iterator; - auto end() -> std::vector::iterator; - [[nodiscard]] auto begin() const -> std::vector::const_iterator; - [[nodiscard]] auto end() const-> std::vector::const_iterator; - auto at(int64_t idx) -> resource *; + auto begin() -> std::vector::iterator; + auto end() -> std::vector::iterator; + [[nodiscard]] auto begin() const -> std::vector::const_iterator; + [[nodiscard]] auto end() const-> std::vector::const_iterator; + auto at(std::int64_t idx) -> instance *; private: std::string m_code; - std::vector m_resources; - std::unordered_map m_resource_id_map {}; - std::unordered_map m_resource_name_map {}; + std::vector m_resources; + std::unordered_map m_resource_id_map {}; + std::unordered_map m_resource_name_map {}; std::unordered_map m_attributes {}; }; diff --git a/libs/libSound/CMakeLists.txt b/libs/libSound/CMakeLists.txt new file mode 100644 index 0000000..79ea053 --- /dev/null +++ b/libs/libSound/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libSound_Sources + *.cpp +) + +add_library(Sound ${libSound_Sources}) +target_link_libraries(Sound SIMD Data Resource) +target_include_directories(Sound PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libGraphite/sound/codec/descriptor.hpp b/libs/libSound/codec/descriptor.hpp similarity index 97% rename from libs/libGraphite/sound/codec/descriptor.hpp rename to libs/libSound/codec/descriptor.hpp index 72dc7c0..0fab2fb 100644 --- a/libs/libGraphite/sound/codec/descriptor.hpp +++ b/libs/libSound/codec/descriptor.hpp @@ -22,7 +22,7 @@ #include -namespace graphite::sound_manager::codec +namespace sound::codec { struct descriptor { diff --git a/libs/libGraphite/sound/codec/ima4.cpp b/libs/libSound/codec/ima4/ima4.cpp similarity index 89% rename from libs/libGraphite/sound/codec/ima4.cpp rename to libs/libSound/codec/ima4/ima4.cpp index 8eddee6..da36586 100644 --- a/libs/libGraphite/sound/codec/ima4.cpp +++ b/libs/libSound/codec/ima4/ima4.cpp @@ -19,12 +19,12 @@ // SOFTWARE. #include -#include "libGraphite/sound/codec/ima4.hpp" -#include "libGraphite/data/writer.hpp" +#include +#include // MARK: - Look Up Tables -namespace graphite::sound_manager::codec::ima4::lut +namespace sound::codec::ima4::lut { constexpr std::int8_t index_table[16] = { -1, -1, -1, -1, 2, 4, 6, 8, @@ -46,14 +46,14 @@ namespace graphite::sound_manager::codec::ima4::lut // MARK: - Construction -graphite::sound_manager::codec::ima4::sound::sound(const codec::descriptor &descriptor, data::reader &reader) +sound::codec::ima4::sound::sound(const codec::descriptor &descriptor, data::reader &reader) { decode(descriptor, reader); } // MARK: - Decoder -auto graphite::sound_manager::codec::ima4::sound::decode(const codec::descriptor &descriptor, data::reader &reader) -> void +auto sound::codec::ima4::sound::decode(const codec::descriptor &descriptor, data::reader &reader) -> void { // TODO: This is relying on hard-coded constants and really shouldn't. // Determine the best way to calculate these values in the future. @@ -122,12 +122,12 @@ auto graphite::sound_manager::codec::ima4::sound::decode(const codec::descriptor // MARK: - Accessors -auto graphite::sound_manager::codec::ima4::sound::samples() const -> const data::block& +auto sound::codec::ima4::sound::samples() const -> const data::block& { return m_samples; } -auto graphite::sound_manager::codec::ima4::sound::descriptor() const -> const codec::descriptor & +auto sound::codec::ima4::sound::descriptor() const -> const codec::descriptor & { return m_descriptor; } \ No newline at end of file diff --git a/libs/libGraphite/sound/codec/ima4.hpp b/libs/libSound/codec/ima4/ima4.hpp similarity index 91% rename from libs/libGraphite/sound/codec/ima4.hpp rename to libs/libSound/codec/ima4/ima4.hpp index 1b9f379..159c2a4 100644 --- a/libs/libGraphite/sound/codec/ima4.hpp +++ b/libs/libSound/codec/ima4/ima4.hpp @@ -20,10 +20,10 @@ #pragma once -#include "libGraphite/data/reader.hpp" -#include "libGraphite/sound/codec/descriptor.hpp" +#include +#include -namespace graphite::sound_manager::codec::ima4 +namespace sound::codec::ima4 { struct sound { diff --git a/libs/libGraphite/sound/sound.cpp b/libs/libSound/format/sound.cpp similarity index 87% rename from libs/libGraphite/sound/sound.cpp rename to libs/libSound/format/sound.cpp index 932d567..cb19928 100644 --- a/libs/libGraphite/sound/sound.cpp +++ b/libs/libSound/format/sound.cpp @@ -20,13 +20,13 @@ #include #include -#include "libGraphite/sound/sound.hpp" -#include "libGraphite/sound/codec/descriptor.hpp" -#include "libGraphite/sound/codec/ima4.hpp" +#include +#include +#include // MARK: - Constants / Enumerations -namespace graphite::sound_manager +namespace sound::format { enum bitrate : std::uint32_t { @@ -131,7 +131,7 @@ namespace graphite::sound_manager // MARK: - Internal Helper Types -namespace graphite::sound_manager +namespace sound::format { struct sound_command { @@ -204,25 +204,25 @@ namespace graphite::sound_manager // MARK: - Construction -graphite::sound_manager::sound::sound(const data::block &data, rsrc::resource::identifier id, const std::string &name) +sound::format::sound::sound(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::sound_manager::sound::sound(data::reader &reader, rsrc::resource::identifier id, const std::string &name) +sound::format::sound::sound(data::reader &reader, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { decode(reader); } -graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) +sound::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) { m_descriptor.sample_rate = sample_rate; m_descriptor.bit_width = sample_bits; - graphite::data::writer writer(data::byte_order::lsb); + data::writer writer(data::byte_order::lsb); if (sample_bits == 8) { for (auto& channel : sample_data) { for (auto& frame : channel) { @@ -238,10 +238,10 @@ graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sa } } - m_samples = std::move(*const_cast(writer.data())); + m_samples = std::move(*const_cast(writer.data())); } -graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const graphite::data::block& sample_data) +sound::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const data::block& sample_data) { m_descriptor.sample_rate = sample_rate; m_descriptor.bit_width = sample_bits; @@ -250,7 +250,7 @@ graphite::sound_manager::sound::sound(std::uint32_t sample_rate, std::uint8_t sa // MARK: - Decoding -auto graphite::sound_manager::sound::decode(data::reader &reader) -> void +auto sound::format::sound::decode(data::reader &reader) -> void { auto sound_format = reader.read_signed_short(); @@ -405,71 +405,71 @@ auto graphite::sound_manager::sound::decode(data::reader &reader) -> void // MARK: - Accessors -auto graphite::sound_manager::sound::samples() const -> const data::block& +auto sound::format::sound::samples() const -> const data::block& { return m_samples; } -auto graphite::sound_manager::sound::codec_descriptor() const -> const codec::descriptor& +auto sound::format::sound::codec_descriptor() const -> const codec::descriptor& { return m_descriptor; } -auto graphite::sound_manager::sound::sample_rate() const -> std::uint32_t +auto sound::format::sound::sample_rate() const -> std::uint32_t { return m_descriptor.sample_rate; } -auto graphite::sound_manager::sound::channels() const -> std::uint16_t +auto sound::format::sound::channels() const -> std::uint16_t { return m_descriptor.channels; } -auto graphite::sound_manager::sound::bit_width() const -> std::uint8_t +auto sound::format::sound::bit_width() const -> std::uint8_t { return m_descriptor.bit_width; } -auto graphite::sound_manager::sound::bytes_per_frame() const -> std::uint32_t +auto sound::format::sound::bytes_per_frame() const -> std::uint32_t { return m_descriptor.bytes_per_frame; } -auto graphite::sound_manager::sound::frames_per_packet() const -> std::uint32_t +auto sound::format::sound::frames_per_packet() const -> std::uint32_t { return m_descriptor.frames_per_packet; } -auto graphite::sound_manager::sound::bytes_per_packet() const -> std::uint32_t +auto sound::format::sound::bytes_per_packet() const -> std::uint32_t { return m_descriptor.bytes_per_packet; } -auto graphite::sound_manager::sound::packet_count() const -> std::uint32_t +auto sound::format::sound::packet_count() const -> std::uint32_t { return m_descriptor.packet_count; } -auto graphite::sound_manager::sound::format_id() const -> std::uint32_t +auto sound::format::sound::format_id() const -> std::uint32_t { return m_descriptor.format_id; } -auto graphite::sound_manager::sound::format_flags() const -> std::uint32_t +auto sound::format::sound::format_flags() const -> std::uint32_t { return m_descriptor.format_flags; } // MARK: - Decoding -auto graphite::sound_manager::sound::data() -> data::block +auto sound::format::sound::data() -> data::block { data::writer writer; encode(writer); return std::move(*const_cast(writer.data())); } -auto graphite::sound_manager::sound::encode(data::writer &writer) -> void +auto sound::format::sound::encode(data::writer &writer) -> void { // TODO: Implement this... } \ No newline at end of file diff --git a/libs/libGraphite/sound/sound.hpp b/libs/libSound/format/sound.hpp similarity index 81% rename from libs/libGraphite/sound/sound.hpp rename to libs/libSound/format/sound.hpp index e26c178..8701455 100644 --- a/libs/libGraphite/sound/sound.hpp +++ b/libs/libSound/format/sound.hpp @@ -21,13 +21,13 @@ #pragma once #include -#include "libGraphite/data/data.hpp" -#include "libGraphite/data/writer.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/sound/codec/descriptor.hpp" +#include +#include +#include +#include +#include -namespace graphite::sound_manager +namespace sound::format { struct sound { @@ -35,9 +35,9 @@ namespace graphite::sound_manager static auto type_code() -> std::string { return "snd "; } public: - explicit sound(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); - explicit sound(data::reader& reader, rsrc::resource::identifier id = 0, const std::string& name = ""); - explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const graphite::data::block& sample_data); + explicit sound(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit sound(data::reader& reader, resource::identifier id = 0, const std::string& name = ""); + explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const data::block& sample_data); explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector>& sample_data); auto data() -> data::block; @@ -57,7 +57,7 @@ namespace graphite::sound_manager [[nodiscard]] auto format_flags() const -> std::uint32_t; private: - rsrc::resource::identifier m_id {}; + resource::identifier m_id { resource::default_resource_id }; std::string m_name; codec::descriptor m_descriptor; data::block m_samples; diff --git a/libs/libSpriteWorld/CMakeLists.txt b/libs/libSpriteWorld/CMakeLists.txt new file mode 100644 index 0000000..f634c77 --- /dev/null +++ b/libs/libSpriteWorld/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libSpriteWorld_Sources + *.cpp +) + +add_library(SpriteWorld ${libSpriteWorld_Sources}) +target_link_libraries(SpriteWorld SIMD Data Resource QuickDraw) +target_include_directories(SpriteWorld PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libGraphite/spriteworld/rleD.cpp b/libs/libSpriteWorld/formats/rleD.cpp similarity index 90% rename from libs/libGraphite/spriteworld/rleD.cpp rename to libs/libSpriteWorld/formats/rleD.cpp index 16195d7..af16a92 100644 --- a/libs/libGraphite/spriteworld/rleD.cpp +++ b/libs/libSpriteWorld/formats/rleD.cpp @@ -18,12 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/spriteworld/rleD.hpp" #include +#include // MARK: - Constants -namespace graphite::spriteworld::constants +namespace spriteworld::constants { static constexpr std::uint16_t rle_grid_width = 6; static constexpr std::size_t advance = 2; @@ -31,12 +31,12 @@ namespace graphite::spriteworld::constants // MARK: - Construction -graphite::spriteworld::rleD::rleD(data::reader& reader) +spriteworld::rleD::rleD(data::reader& reader) { decode(reader); } -graphite::spriteworld::rleD::rleD(const quickdraw::size& size, std::uint16_t frame_count) +spriteworld::rleD::rleD(const quickdraw::size& size, std::uint16_t frame_count) : m_id(0), m_name(type_code()), m_frame_size(size), m_frame_count(frame_count), m_bpp(16), m_palette_id(0) { // Determine what the grid will be. We need to round up to the next whole number and have blank tiles @@ -48,7 +48,7 @@ graphite::spriteworld::rleD::rleD(const quickdraw::size& size, std m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); } -graphite::spriteworld::rleD::rleD(const data::block& data, rsrc::resource::identifier id, const std::string& name) +spriteworld::rleD::rleD(const data::block& data, resource::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); @@ -57,22 +57,22 @@ graphite::spriteworld::rleD::rleD(const data::block& data, rsrc::resource::ident // MARK: - Accessors -auto graphite::spriteworld::rleD::surface() -> quickdraw::surface& +auto spriteworld::rleD::surface() -> quickdraw::surface& { return m_surface; } -auto graphite::spriteworld::rleD::frames() const -> std::vector> +auto spriteworld::rleD::frames() const -> std::vector> { return m_frames; } -auto graphite::spriteworld::rleD::frame_count() const -> std::size_t +auto spriteworld::rleD::frame_count() const -> std::size_t { return m_frame_count; } -auto graphite::spriteworld::rleD::data() -> data::block +auto spriteworld::rleD::data() -> data::block { data::writer writer; encode(writer); @@ -81,7 +81,7 @@ auto graphite::spriteworld::rleD::data() -> data::block // MARK: - Operations -auto graphite::spriteworld::rleD::frame_rect(std::uint32_t frame) const -> quickdraw::rect +auto spriteworld::rleD::frame_rect(std::uint32_t frame) const -> quickdraw::rect { return { quickdraw::point( @@ -92,7 +92,7 @@ auto graphite::spriteworld::rleD::frame_rect(std::uint32_t frame) const -> quick }; } -auto graphite::spriteworld::rleD::frame_surface(std::uint32_t frame) const -> quickdraw::surface +auto spriteworld::rleD::frame_surface(std::uint32_t frame) const -> quickdraw::surface { quickdraw::surface surface(m_frame_size); quickdraw::rect src_rect(frame_rect(frame)); @@ -107,7 +107,7 @@ auto graphite::spriteworld::rleD::frame_surface(std::uint32_t frame) const -> qu return std::move(surface); } -auto graphite::spriteworld::rleD::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +auto spriteworld::rleD::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void { quickdraw::rect dst_rect = frame_rect(frame); quickdraw::size src_size = surface.size(); @@ -125,12 +125,12 @@ auto graphite::spriteworld::rleD::write_frame(std::uint32_t frame, const quickdr } } -auto graphite::spriteworld::rleD::write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void +auto spriteworld::rleD::write_pixel(std::uint32_t pixel, std::uint8_t mask, std::uint64_t offset) -> void { m_surface.set(offset, quickdraw::rgb(static_cast(pixel & 0xFFFF))); } -auto graphite::spriteworld::rleD::write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void +auto spriteworld::rleD::write_pixel(std::uint64_t pixel, std::uint8_t mask, std::uint64_t offset, enum pixel_type type) -> void { switch (type) { case pixel_type::type1: { @@ -142,7 +142,7 @@ auto graphite::spriteworld::rleD::write_pixel(std::uint64_t pixel, std::uint8_t } } -auto graphite::spriteworld::rleD::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t +auto spriteworld::rleD::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t { quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); @@ -151,7 +151,7 @@ auto graphite::spriteworld::rleD::surface_offset(std::int32_t frame, std::int32_ // MARK: - Decoding -auto graphite::spriteworld::rleD::decode(data::reader &reader) -> void +auto spriteworld::rleD::decode(data::reader &reader) -> void { // Read the header of the RLE information. This will tell us what we need to do in order to actually // decode the frames. @@ -257,7 +257,7 @@ auto graphite::spriteworld::rleD::decode(data::reader &reader) -> void // MARK: - Encoding -auto graphite::spriteworld::rleD::encode(data::writer &writer) -> void +auto spriteworld::rleD::encode(data::writer &writer) -> void { writer.change_byte_order(data::byte_order::msb); diff --git a/libs/libGraphite/spriteworld/rleD.hpp b/libs/libSpriteWorld/formats/rleD.hpp similarity index 91% rename from libs/libGraphite/spriteworld/rleD.hpp rename to libs/libSpriteWorld/formats/rleD.hpp index 0a37154..2d9c360 100644 --- a/libs/libGraphite/spriteworld/rleD.hpp +++ b/libs/libSpriteWorld/formats/rleD.hpp @@ -22,10 +22,11 @@ #include #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" +#include +#include +#include -namespace graphite::spriteworld +namespace spriteworld { struct rleD { @@ -35,7 +36,7 @@ namespace graphite::spriteworld public: rleD() = default; rleD(const quickdraw::size& size, std::uint16_t frame_count); - explicit rleD(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit rleD(const data::block& data, resource::identifier id = 0, const std::string& name = ""); explicit rleD(data::reader& reader); ~rleD() = default; @@ -63,7 +64,7 @@ namespace graphite::spriteworld pixel_run = 0x04, }; - rsrc::resource::identifier m_id { 0 }; + resource::identifier m_id { 0 }; std::string m_name; std::vector> m_frames; quickdraw::surface m_surface; diff --git a/libs/libGraphite/spriteworld/rleX.cpp b/libs/libSpriteWorld/formats/rleX.cpp similarity index 79% rename from libs/libGraphite/spriteworld/rleX.cpp rename to libs/libSpriteWorld/formats/rleX.cpp index d8b1cff..a3f758a 100644 --- a/libs/libGraphite/spriteworld/rleX.cpp +++ b/libs/libSpriteWorld/formats/rleX.cpp @@ -18,12 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/spriteworld/rleX.hpp" #include +#include // MARK: - Constants -namespace graphite::spriteworld::constants +namespace spriteworld::constants { static constexpr std::uint16_t rle_grid_width = 6; static constexpr std::size_t advance = 2; @@ -31,12 +31,12 @@ namespace graphite::spriteworld::constants // MARK: - Construction -graphite::spriteworld::rleX::rleX(data::reader& reader) +spriteworld::rleX::rleX(data::reader& reader) { decode(reader); } -graphite::spriteworld::rleX::rleX(const quickdraw::size &size, std::uint16_t frame_count) +spriteworld::rleX::rleX(const quickdraw::size &size, std::uint16_t frame_count) : m_id(0), m_name(type_code()), m_frame_size(size), m_frame_count(frame_count), m_bpp(32), m_palette_id(0) { // Determine what the grid will be. We need to round up to the next whole number and have blank tiles @@ -49,7 +49,7 @@ graphite::spriteworld::rleX::rleX(const quickdraw::size &size, std m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); } -graphite::spriteworld::rleX::rleX(const data::block& data, rsrc::resource::identifier id, const std::string& name) +spriteworld::rleX::rleX(const data::block& data, resource::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); @@ -58,22 +58,22 @@ graphite::spriteworld::rleX::rleX(const data::block& data, rsrc::resource::ident // MARK: - Accessors -auto graphite::spriteworld::rleX::surface() -> quickdraw::surface& +auto spriteworld::rleX::surface() -> quickdraw::surface& { return m_surface; } -auto graphite::spriteworld::rleX::frames() const -> std::vector> +auto spriteworld::rleX::frames() const -> std::vector> { return m_frames; } -auto graphite::spriteworld::rleX::frame_count() const -> std::size_t +auto spriteworld::rleX::frame_count() const -> std::size_t { return m_frame_count; } -auto graphite::spriteworld::rleX::data() -> data::block +auto spriteworld::rleX::data() -> data::block { data::writer writer; encode(writer); @@ -82,7 +82,7 @@ auto graphite::spriteworld::rleX::data() -> data::block // MARK: - Operations -auto graphite::spriteworld::rleX::frame_rect(std::uint32_t frame) const -> quickdraw::rect +auto spriteworld::rleX::frame_rect(std::uint32_t frame) const -> quickdraw::rect { return { quickdraw::point( @@ -93,7 +93,7 @@ auto graphite::spriteworld::rleX::frame_rect(std::uint32_t frame) const -> quick }; } -auto graphite::spriteworld::rleX::frame_surface(std::uint32_t frame) const -> quickdraw::surface +auto spriteworld::rleX::frame_surface(std::uint32_t frame) const -> quickdraw::surface { quickdraw::surface surface(m_frame_size); quickdraw::rect src_rect(frame_rect(frame)); @@ -108,7 +108,7 @@ auto graphite::spriteworld::rleX::frame_surface(std::uint32_t frame) const -> qu return std::move(surface); } -auto graphite::spriteworld::rleX::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void +auto spriteworld::rleX::write_frame(std::uint32_t frame, const quickdraw::surface &surface) -> void { quickdraw::rect dst_rect = frame_rect(frame); quickdraw::size src_size = surface.size(); @@ -126,7 +126,7 @@ auto graphite::spriteworld::rleX::write_frame(std::uint32_t frame, const quickdr } } -auto graphite::spriteworld::rleX::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t +auto spriteworld::rleX::surface_offset(std::int32_t frame, std::int32_t line) -> std::uint64_t { quickdraw::point fo(frame % constants::rle_grid_width, frame / constants::rle_grid_width); quickdraw::point p(fo.x * m_frame_size.width, (fo.y * m_frame_size.height) + line); @@ -136,9 +136,9 @@ auto graphite::spriteworld::rleX::surface_offset(std::int32_t frame, std::int32_ // MARK: - Decoding static inline auto rleX_calculate_sprite_geometry( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, @@ -151,15 +151,15 @@ static inline auto rleX_calculate_sprite_geometry( } static inline auto rleX_draw_color( - graphite::quickdraw::surface& surface, - union graphite::quickdraw::ycbcr& color, - graphite::quickdraw::rect& rect, + quickdraw::surface& surface, + union quickdraw::ycbcr& color, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t count ) -> void { - auto rgb = graphite::quickdraw::rgb(color); + auto rgb = quickdraw::rgb(color); for (auto i = 0; i < count; ++i) { surface.set(offset, rgb); if (++offset >= right_offset_bound) { @@ -170,17 +170,17 @@ static inline auto rleX_draw_color( } static auto rleX_opcode_handler_eof( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::data::reader& reader, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + data::reader& reader, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t& frame, std::uint16_t frame_count, bool& completed, - union graphite::quickdraw::ycbcr& color + union quickdraw::ycbcr& color ) -> void { if (++frame >= frame_count) { completed = true; @@ -190,118 +190,118 @@ static auto rleX_opcode_handler_eof( } static auto rleX_opcode_handler_set_luma( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::data::reader& reader, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + data::reader& reader, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t& frame, std::uint16_t frame_count, bool& completed, - union graphite::quickdraw::ycbcr& color + union quickdraw::ycbcr& color ) -> void { color.components.y = reader.read_byte(); } static auto rleX_opcode_handler_set_cr( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::data::reader& reader, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + data::reader& reader, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t& frame, std::uint16_t frame_count, bool& completed, - union graphite::quickdraw::ycbcr& color + union quickdraw::ycbcr& color ) -> void { color.components.cr = reader.read_byte(); } static auto rleX_opcode_handler_set_cb( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::data::reader& reader, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + data::reader& reader, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t& frame, std::uint16_t frame_count, bool& completed, - union graphite::quickdraw::ycbcr& color + union quickdraw::ycbcr& color ) -> void { color.components.cb = reader.read_byte(); } static auto rleX_opcode_handler_set_alpha( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::data::reader& reader, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + data::reader& reader, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t& frame, std::uint16_t frame_count, bool& completed, - union graphite::quickdraw::ycbcr& color + union quickdraw::ycbcr& color ) -> void { color.components.alpha = reader.read_byte(); } static auto rleX_opcode_handler_advance( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::data::reader& reader, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + data::reader& reader, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t& frame, std::uint16_t frame_count, bool& completed, - union graphite::quickdraw::ycbcr& color + union quickdraw::ycbcr& color ) -> void { auto count = reader.read_long(); rleX_draw_color(surface, color, rect, offset, right_offset_bound, pitch, count); } static auto rleX_opcode_handler_short_advance( - graphite::spriteworld::rleX *sprite, - graphite::quickdraw::surface& surface, - graphite::data::reader& reader, - graphite::quickdraw::rect& rect, + spriteworld::rleX *sprite, + quickdraw::surface& surface, + data::reader& reader, + quickdraw::rect& rect, std::uint32_t& offset, std::uint32_t& right_offset_bound, std::uint32_t& pitch, std::uint32_t& frame, std::uint16_t frame_count, bool& completed, - union graphite::quickdraw::ycbcr& color + union quickdraw::ycbcr& color ) -> void { auto count = reader.read_byte(); rleX_draw_color(surface, color, rect, offset, right_offset_bound, pitch, static_cast(count)); } typedef void(*rleX_opcode_handler)( - graphite::spriteworld::rleX*, - graphite::quickdraw::surface&, - graphite::data::reader&, - graphite::quickdraw::rect&, + spriteworld::rleX*, + quickdraw::surface&, + data::reader&, + quickdraw::rect&, std::uint32_t&, std::uint32_t&, std::uint32_t&, std::uint32_t&, std::uint16_t, bool&, - union graphite::quickdraw::ycbcr& + union quickdraw::ycbcr& ); -auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void +auto spriteworld::rleX::decode(data::reader &reader) -> void { reader.change_byte_order(data::byte_order::lsb); @@ -378,7 +378,7 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void // MARK: - Encoding -auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void +auto spriteworld::rleX::encode(data::writer &writer) -> void { writer.change_byte_order(data::byte_order::lsb); diff --git a/libs/libGraphite/spriteworld/rleX.hpp b/libs/libSpriteWorld/formats/rleX.hpp similarity index 90% rename from libs/libGraphite/spriteworld/rleX.hpp rename to libs/libSpriteWorld/formats/rleX.hpp index 7aeb0ac..ea19855 100644 --- a/libs/libGraphite/spriteworld/rleX.hpp +++ b/libs/libSpriteWorld/formats/rleX.hpp @@ -22,10 +22,11 @@ #include #include -#include "libGraphite/quickdraw/support/surface.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" +#include +#include +#include -namespace graphite::spriteworld +namespace spriteworld { /* * This 'rleX' variant of the 'rleD' format, is a custom type created for Graphite/Kestrel. @@ -39,7 +40,7 @@ namespace graphite::spriteworld public: rleX() = default; rleX(const quickdraw::size& size, std::uint16_t frame_count); - explicit rleX(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit rleX(const data::block& data, resource::identifier id = 0, const std::string& name = ""); explicit rleX(data::reader& reader); ~rleX() = default; @@ -67,7 +68,7 @@ namespace graphite::spriteworld short_advance = 0x06, }; - rsrc::resource::identifier m_id { 0 }; + resource::identifier m_id { 0 }; std::string m_name; std::vector> m_frames; quickdraw::surface m_surface; diff --git a/libs/libToolbox/CMakeLists.txt b/libs/libToolbox/CMakeLists.txt new file mode 100644 index 0000000..0d35720 --- /dev/null +++ b/libs/libToolbox/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +######################################################################################################################## +## Project +project(Graphite LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +######################################################################################################################## +## libSIMD +file(GLOB_RECURSE libToolbox_Sources + *.cpp +) + +add_library(ToolBox ${libToolbox_Sources}) +target_link_libraries(ToolBox SIMD Data Resource Graphite) +target_include_directories(ToolBox PUBLIC + ${PROJECT_LIBS_DIR} +) diff --git a/libs/libGraphite/font/fond.cpp b/libs/libToolbox/font/fond.cpp similarity index 95% rename from libs/libGraphite/font/fond.cpp rename to libs/libToolbox/font/fond.cpp index 76a1cd9..5cf5794 100644 --- a/libs/libGraphite/font/fond.cpp +++ b/libs/libToolbox/font/fond.cpp @@ -18,26 +18,26 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/font/fond.hpp" #include +#include // MARK: - Construction -graphite::font::descriptor::descriptor(const data::block &data, rsrc::resource::identifier id, const std::string &name) +toolbox::font::descriptor::descriptor(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::font::descriptor::descriptor(data::reader &reader) +toolbox::font::descriptor::descriptor(data::reader &reader) { decode(reader); } // MARK: - Decoding -auto graphite::font::descriptor::decode(data::reader &reader) -> void +auto toolbox::font::descriptor::decode(data::reader &reader) -> void { m_fixed = reader.read_short() & 0x8000 ? true : false; m_family_id = reader.read_short(); diff --git a/libs/libGraphite/font/fond.hpp b/libs/libToolbox/font/fond.hpp similarity index 91% rename from libs/libGraphite/font/fond.hpp rename to libs/libToolbox/font/fond.hpp index 2f133c4..5799624 100644 --- a/libs/libGraphite/font/fond.hpp +++ b/libs/libToolbox/font/fond.hpp @@ -24,10 +24,10 @@ #include #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include -namespace graphite::font +namespace toolbox::font { struct descriptor { @@ -36,7 +36,7 @@ namespace graphite::font public: descriptor() = default; - explicit descriptor(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); + explicit descriptor(const data::block& data, resource::identifier = 0, const std::string& name = ""); explicit descriptor(data::reader& reader); private: @@ -67,7 +67,7 @@ namespace graphite::font std::vector kerns; }; - rsrc::resource::identifier m_id { INT64_MIN }; + resource::identifier m_id { resource::auto_resource_id }; std::string m_name; bool m_fixed { false }; std::uint16_t m_family_id { 0 }; diff --git a/libs/libGraphite/font/manager.cpp b/libs/libToolbox/font/manager.cpp similarity index 74% rename from libs/libGraphite/font/manager.cpp rename to libs/libToolbox/font/manager.cpp index dd944f6..109d304 100644 --- a/libs/libGraphite/font/manager.cpp +++ b/libs/libToolbox/font/manager.cpp @@ -18,13 +18,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/font/manager.hpp" -#include "libGraphite/rsrc/manager.hpp" -#include "libGraphite/font/sfnt.hpp" +#include +#include +#include +#include +#include // MARK: - Singleton -auto graphite::font::manager::shared_manager() -> graphite::font::manager & +auto toolbox::font::manager::shared_manager() -> manager & { static manager instance; return instance; @@ -32,9 +34,9 @@ auto graphite::font::manager::shared_manager() -> graphite::font::manager & // MARK: - Font Management -auto graphite::font::manager::update_font_table() -> void +auto toolbox::font::manager::update_font_table() -> void { - auto sfnt_resources = rsrc::manager::shared_manager().find(); + auto sfnt_resources = ::resource::manager::shared_manager().find(); for (const auto& res : sfnt_resources) { auto font_name = res.name(); auto it = m_fonts.find(font_name); @@ -53,12 +55,12 @@ auto graphite::font::manager::update_font_table() -> void } } -auto graphite::font::manager::has_font_named(const std::string &name) const -> bool +auto toolbox::font::manager::has_font_named(const std::string &name) const -> bool { return m_fonts.find(name) != m_fonts.end(); } -auto graphite::font::manager::font_has_bitmap(const std::string &name) const -> bool +auto toolbox::font::manager::font_has_bitmap(const std::string &name) const -> bool { if (!has_font_named(name)) { return false; @@ -68,7 +70,7 @@ auto graphite::font::manager::font_has_bitmap(const std::string &name) const -> return !font.m_bitmaps.empty(); } -auto graphite::font::manager::font_has_truetype(const std::string &name) const -> bool +auto toolbox::font::manager::font_has_truetype(const std::string &name) const -> bool { if (!has_font_named(name)) { return false; @@ -78,7 +80,7 @@ auto graphite::font::manager::font_has_truetype(const std::string &name) const - return font.ttf.size() > 0; } -auto graphite::font::manager::ttf_font_named(const std::string &name) const -> const data::block * +auto toolbox::font::manager::ttf_font_named(const std::string &name) const -> const data::block * { auto it = m_fonts.find(name); if (it == m_fonts.end()) { diff --git a/libs/libGraphite/font/manager.hpp b/libs/libToolbox/font/manager.hpp similarity index 90% rename from libs/libGraphite/font/manager.hpp rename to libs/libToolbox/font/manager.hpp index 1afe162..3c16961 100644 --- a/libs/libGraphite/font/manager.hpp +++ b/libs/libToolbox/font/manager.hpp @@ -22,12 +22,11 @@ #include #include -#include "libGraphite/data/data.hpp" +#include +#include +#include -#include "libGraphite/font/fond.hpp" -#include "libGraphite/font/nfnt.hpp" - -namespace graphite::font +namespace toolbox::font { class manager { @@ -36,7 +35,7 @@ namespace graphite::font { std::string name; descriptor m_bitmap_descriptor; - std::unordered_map m_bitmaps; + std::unordered_map m_bitmaps; data::block ttf; }; diff --git a/libs/libGraphite/font/nfnt.cpp b/libs/libToolbox/font/nfnt.cpp similarity index 86% rename from libs/libGraphite/font/nfnt.cpp rename to libs/libToolbox/font/nfnt.cpp index 16c5b0e..8e70539 100644 --- a/libs/libGraphite/font/nfnt.cpp +++ b/libs/libToolbox/font/nfnt.cpp @@ -18,25 +18,25 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/font/nfnt.hpp" +#include // MARK: - Construction -graphite::font::bitmapped_font::bitmapped_font(const data::block &data, rsrc::resource::identifier id, const std::string &name) +toolbox::font::bitmapped_font::bitmapped_font(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::font::bitmapped_font::bitmapped_font(data::reader &reader) +toolbox::font::bitmapped_font::bitmapped_font(data::reader &reader) { decode(reader); } // MARK: - Decoding -auto graphite::font::bitmapped_font::decode(data::reader &reader) -> void +auto toolbox::font::bitmapped_font::decode(data::reader &reader) -> void { m_font_type = reader.read_signed_short(); m_first_char_code = reader.read_signed_short(); diff --git a/libs/libGraphite/font/nfnt.hpp b/libs/libToolbox/font/nfnt.hpp similarity index 86% rename from libs/libGraphite/font/nfnt.hpp rename to libs/libToolbox/font/nfnt.hpp index 0618783..094f1c2 100644 --- a/libs/libGraphite/font/nfnt.hpp +++ b/libs/libToolbox/font/nfnt.hpp @@ -20,11 +20,11 @@ #pragma once -#include "libGraphite/data/data.hpp" -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include +#include -namespace graphite::font +namespace toolbox::font { struct bitmapped_font { @@ -33,11 +33,11 @@ namespace graphite::font public: bitmapped_font() = default; - explicit bitmapped_font(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit bitmapped_font(const data::block& data, resource::identifier id = 0, const std::string& name = ""); explicit bitmapped_font(data::reader& reader); private: - rsrc::resource::identifier m_id { INT64_MIN }; + resource::identifier m_id { INT64_MIN }; std::string m_name; std::int16_t m_font_type { 0 }; diff --git a/libs/libGraphite/font/sfnt.cpp b/libs/libToolbox/font/sfnt.cpp similarity index 76% rename from libs/libGraphite/font/sfnt.cpp rename to libs/libToolbox/font/sfnt.cpp index 7cb2832..cf9c996 100644 --- a/libs/libGraphite/font/sfnt.cpp +++ b/libs/libToolbox/font/sfnt.cpp @@ -18,32 +18,32 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/font/sfnt.hpp" -#include "libGraphite/data/writer.hpp" +#include +#include // MARK: - Construction -graphite::font::outline_font::outline_font(const data::block &data, rsrc::resource::identifier id, const std::string &name) +toolbox::font::outline_font::outline_font(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { m_ttf = data; } -graphite::font::outline_font::outline_font(data::reader &reader) +toolbox::font::outline_font::outline_font(data::reader &reader) { decode(reader); } // MARK: - Decoding -auto graphite::font::outline_font::decode(data::reader &reader) -> void +auto toolbox::font::outline_font::decode(data::reader &reader) -> void { m_ttf = std::move(*const_cast(reader.data())); } // MARK: - Accessors -auto graphite::font::outline_font::ttf_data() const -> const data::block& +auto toolbox::font::outline_font::ttf_data() const -> const data::block& { return m_ttf; } \ No newline at end of file diff --git a/libs/libGraphite/font/sfnt.hpp b/libs/libToolbox/font/sfnt.hpp similarity index 85% rename from libs/libGraphite/font/sfnt.hpp rename to libs/libToolbox/font/sfnt.hpp index d7ee634..6a031fb 100644 --- a/libs/libGraphite/font/sfnt.hpp +++ b/libs/libToolbox/font/sfnt.hpp @@ -24,10 +24,10 @@ #include #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include -namespace graphite::font +namespace toolbox::font { struct outline_font { @@ -36,13 +36,13 @@ namespace graphite::font public: outline_font() = default; - explicit outline_font(const data::block& data, rsrc::resource::identifier = 0, const std::string& name = ""); + explicit outline_font(const data::block& data, resource::identifier = 0, const std::string& name = ""); explicit outline_font(data::reader& reader); [[nodiscard]] auto ttf_data() const -> const data::block&; private: - rsrc::resource::identifier m_id { INT64_MIN }; + resource::identifier m_id { resource::auto_resource_id }; std::string m_name; data::block m_ttf; diff --git a/libs/libGraphite/toolbox/string.cpp b/libs/libToolbox/strings/string.cpp similarity index 50% rename from libs/libGraphite/toolbox/string.cpp rename to libs/libToolbox/strings/string.cpp index f2af010..6784710 100644 --- a/libs/libGraphite/toolbox/string.cpp +++ b/libs/libToolbox/strings/string.cpp @@ -2,12 +2,12 @@ // Created by Tom Hancocks on 24/03/2020. // -#include "libGraphite/toolbox/string.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include // MARK: - Constructor -graphite::toolbox::string::string(const data::block& data, rsrc::resource::identifier id, const std::string& name) +toolbox::string::string(const data::block& data, resource::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); @@ -16,22 +16,21 @@ graphite::toolbox::string::string(const data::block& data, rsrc::resource::ident // MARK: - Accessor -auto graphite::toolbox::string::value() const -> const std::string& +auto toolbox::string::value() const -> const std::string& { return m_str; } -auto graphite::toolbox::string::data() const -> const data::block& +auto toolbox::string::data() const -> const data::block& { return m_data; } // MARK: - Decoder -auto graphite::toolbox::string::decode(data::reader &reader) -> void +auto toolbox::string::decode(data::reader &reader) -> void { m_str = reader.read_pstr(); - auto length = reader.size() - reader.position(); if (length > 0) { m_data = reader.read_data(length); diff --git a/libs/libGraphite/toolbox/string.hpp b/libs/libToolbox/strings/string.hpp similarity index 65% rename from libs/libGraphite/toolbox/string.hpp rename to libs/libToolbox/strings/string.hpp index d975551..5a0ce8e 100644 --- a/libs/libGraphite/toolbox/string.hpp +++ b/libs/libToolbox/strings/string.hpp @@ -5,12 +5,11 @@ #pragma once #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include -namespace graphite::toolbox +namespace toolbox { - struct string { public: @@ -18,18 +17,17 @@ namespace graphite::toolbox public: string() = default; - explicit string(const data::block &data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit string(const data::block &data, resource::identifier id = 0, const std::string& name = ""); [[nodiscard]] auto value() const -> const std::string&; [[nodiscard]] auto data() const -> const data::block&; private: - rsrc::resource::identifier m_id {}; + resource::identifier m_id {}; std::string m_name; std::string m_str; data::block m_data; auto decode(data::reader& reader) -> void; }; - } diff --git a/libs/libGraphite/toolbox/string_list.cpp b/libs/libToolbox/strings/string_list.cpp similarity index 74% rename from libs/libGraphite/toolbox/string_list.cpp rename to libs/libToolbox/strings/string_list.cpp index 2398a85..0b9100d 100644 --- a/libs/libGraphite/toolbox/string_list.cpp +++ b/libs/libToolbox/strings/string_list.cpp @@ -18,12 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/toolbox/string_list.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include // MARK: - Construction -graphite::toolbox::string_list::string_list(const data::block &data, rsrc::resource::identifier id, const std::string& name) +toolbox::string_list::string_list(const data::block &data, resource::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); @@ -32,7 +32,7 @@ graphite::toolbox::string_list::string_list(const data::block &data, rsrc::resou // MARK: - Decoder -auto graphite::toolbox::string_list::decode(data::reader &reader) -> void +auto toolbox::string_list::decode(data::reader &reader) -> void { auto count = static_cast(reader.read_signed_short()); m_strings = { count, "" }; @@ -44,24 +44,24 @@ auto graphite::toolbox::string_list::decode(data::reader &reader) -> void // MARK: - Access -auto graphite::toolbox::string_list::string_count() const -> std::size_t +auto toolbox::string_list::string_count() const -> std::size_t { return m_strings.size(); } -auto graphite::toolbox::string_list::at(std::uint32_t idx) const -> std::string +auto toolbox::string_list::at(std::uint32_t idx) const -> std::string { return m_strings.at(idx); } // MARK: - Iterator -auto graphite::toolbox::string_list::begin() noexcept -> iterator +auto toolbox::string_list::begin() noexcept -> iterator { return m_strings.begin(); } -auto graphite::toolbox::string_list::end() noexcept -> iterator +auto toolbox::string_list::end() noexcept -> iterator { return m_strings.end(); } \ No newline at end of file diff --git a/libs/libGraphite/toolbox/string_list.hpp b/libs/libToolbox/strings/string_list.hpp similarity index 86% rename from libs/libGraphite/toolbox/string_list.hpp rename to libs/libToolbox/strings/string_list.hpp index f52e332..e73ae31 100644 --- a/libs/libGraphite/toolbox/string_list.hpp +++ b/libs/libToolbox/strings/string_list.hpp @@ -22,10 +22,10 @@ #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" +#include +#include -namespace graphite::toolbox +namespace toolbox { struct string_list { @@ -36,7 +36,7 @@ namespace graphite::toolbox public: string_list() = default; - explicit string_list(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit string_list(const data::block& data, resource::identifier id = 0, const std::string& name = ""); [[nodiscard]] auto string_count() const -> std::size_t; [[nodiscard]] auto at(std::uint32_t idx) const -> std::string; @@ -45,7 +45,7 @@ namespace graphite::toolbox auto end() noexcept -> iterator; private: - rsrc::resource::identifier m_id { 0 }; + resource::identifier m_id { 0 }; std::string m_name; std::vector m_strings; diff --git a/libs/libGraphite/toolbox/dialog.cpp b/libs/libToolbox/ui/dialog.cpp similarity index 59% rename from libs/libGraphite/toolbox/dialog.cpp rename to libs/libToolbox/ui/dialog.cpp index 7ba2da8..3b7412a 100644 --- a/libs/libGraphite/toolbox/dialog.cpp +++ b/libs/libToolbox/ui/dialog.cpp @@ -18,108 +18,108 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/toolbox/dialog.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include // MARK: - Construction -graphite::toolbox::dialog::dialog(const data::block &data, rsrc::resource::identifier id, const std::string &name) +toolbox::dialog::dialog(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::toolbox::dialog::dialog(graphite::data::reader &reader) +toolbox::dialog::dialog(data::reader &reader) { decode(reader); } // MARK: - Accessors -auto graphite::toolbox::dialog::bounds() const -> quickdraw::rect +auto toolbox::dialog::bounds() const -> quickdraw::rect { return m_bounds; } -auto graphite::toolbox::dialog::proc_id() const -> std::int16_t +auto toolbox::dialog::proc_id() const -> std::int16_t { return m_proc_id; } -auto graphite::toolbox::dialog::visible() const -> bool +auto toolbox::dialog::visible() const -> bool { return m_visible; } -auto graphite::toolbox::dialog::go_away() const -> bool +auto toolbox::dialog::go_away() const -> bool { return m_go_away; } -auto graphite::toolbox::dialog::ref_con() const -> std::int32_t +auto toolbox::dialog::ref_con() const -> std::int32_t { return m_ref_con; } -auto graphite::toolbox::dialog::interface_list() const -> rsrc::resource::identifier +auto toolbox::dialog::interface_list() const -> resource::identifier { return m_ditl_id; } -auto graphite::toolbox::dialog::auto_position() const -> std::uint16_t +auto toolbox::dialog::auto_position() const -> std::uint16_t { return m_auto_position; } -auto graphite::toolbox::dialog::title() const -> std::string +auto toolbox::dialog::title() const -> std::string { return m_title; } -auto graphite::toolbox::dialog::set_bounds(const quickdraw::rect& bounds) -> void +auto toolbox::dialog::set_bounds(const quickdraw::rect& bounds) -> void { m_bounds = bounds; } -auto graphite::toolbox::dialog::set_proc_id(std::int16_t id) -> void +auto toolbox::dialog::set_proc_id(std::int16_t id) -> void { m_proc_id = id; } -auto graphite::toolbox::dialog::set_visible(bool visible) -> void +auto toolbox::dialog::set_visible(bool visible) -> void { m_visible = visible; } -auto graphite::toolbox::dialog::set_go_away(bool go_away) -> void +auto toolbox::dialog::set_go_away(bool go_away) -> void { m_go_away = go_away; } -auto graphite::toolbox::dialog::set_ref_con(std::int32_t ref_con) -> void +auto toolbox::dialog::set_ref_con(std::int32_t ref_con) -> void { m_ref_con = ref_con; } -auto graphite::toolbox::dialog::set_interface_list(rsrc::resource::identifier id) -> void +auto toolbox::dialog::set_interface_list(resource::identifier id) -> void { m_ditl_id = id; } -auto graphite::toolbox::dialog::set_auto_position(std::uint16_t position) -> void +auto toolbox::dialog::set_auto_position(std::uint16_t position) -> void { m_auto_position = position; } -auto graphite::toolbox::dialog::set_title(const std::string& title) -> void +auto toolbox::dialog::set_title(const std::string& title) -> void { m_title = title; } // MARK: - Decoder -auto graphite::toolbox::dialog::decode(data::reader &reader) -> void +auto toolbox::dialog::decode(data::reader &reader) -> void { m_bounds = quickdraw::rect::read(reader, quickdraw::coding_type::macintosh); @@ -139,12 +139,12 @@ auto graphite::toolbox::dialog::decode(data::reader &reader) -> void // MARK: - Encoder -auto graphite::toolbox::dialog::encode(data::writer &writer) -> void +auto toolbox::dialog::encode(data::writer &writer) -> void { } -auto graphite::toolbox::dialog::data() -> data::block +auto toolbox::dialog::data() -> data::block { data::writer writer; encode(writer); diff --git a/libs/libGraphite/toolbox/dialog.hpp b/libs/libToolbox/ui/dialog.hpp similarity index 83% rename from libs/libGraphite/toolbox/dialog.hpp rename to libs/libToolbox/ui/dialog.hpp index f026137..ae6fb9b 100644 --- a/libs/libGraphite/toolbox/dialog.hpp +++ b/libs/libToolbox/ui/dialog.hpp @@ -22,11 +22,11 @@ #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" +#include +#include +#include -namespace graphite::toolbox +namespace toolbox { struct dialog { @@ -35,7 +35,7 @@ namespace graphite::toolbox public: dialog() = default; - explicit dialog(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit dialog(const data::block& data, resource::identifier id = 0, const std::string& name = ""); explicit dialog(data::reader& reader); [[nodiscard]] auto bounds() const -> quickdraw::rect; @@ -43,7 +43,7 @@ namespace graphite::toolbox [[nodiscard]] auto visible() const -> bool; [[nodiscard]] auto go_away() const -> bool; [[nodiscard]] auto ref_con() const -> std::int32_t; - [[nodiscard]] auto interface_list() const -> rsrc::resource::identifier; + [[nodiscard]] auto interface_list() const -> resource::identifier; [[nodiscard]] auto auto_position() const -> std::uint16_t; [[nodiscard]] auto title() const -> std::string; @@ -52,7 +52,7 @@ namespace graphite::toolbox auto set_visible(bool visible) -> void; auto set_go_away(bool go_away) -> void; auto set_ref_con(std::int32_t ref_con) -> void; - auto set_interface_list(rsrc::resource::identifier id) -> void; + auto set_interface_list(resource::identifier id) -> void; auto set_auto_position(std::uint16_t position) -> void; auto set_title(const std::string& title) -> void; @@ -60,7 +60,7 @@ namespace graphite::toolbox auto data() -> data::block; private: - rsrc::resource::identifier m_id { INT64_MIN }; + resource::identifier m_id { resource::auto_resource_id }; std::string m_name; std::string m_title; quickdraw::rect m_bounds; @@ -68,7 +68,7 @@ namespace graphite::toolbox bool m_visible { true }; bool m_go_away { true }; std::int32_t m_ref_con { 0 }; - rsrc::resource::identifier m_ditl_id { 0 }; + resource::identifier m_ditl_id { 0 }; std::uint16_t m_auto_position { 0 }; auto decode(data::reader& reader) -> void; diff --git a/libs/libGraphite/toolbox/dialog_item_list.cpp b/libs/libToolbox/ui/dialog_item_list.cpp similarity index 81% rename from libs/libGraphite/toolbox/dialog_item_list.cpp rename to libs/libToolbox/ui/dialog_item_list.cpp index cad901a..d560780 100644 --- a/libs/libGraphite/toolbox/dialog_item_list.cpp +++ b/libs/libToolbox/ui/dialog_item_list.cpp @@ -18,26 +18,26 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "libGraphite/toolbox/dialog_item_list.hpp" -#include "libGraphite/data/reader.hpp" +#include +#include // MARK: - Construction -graphite::toolbox::dialog_item_list::dialog_item_list(const data::block &data, rsrc::resource::identifier id, const std::string &name) +toolbox::dialog_item_list::dialog_item_list(const data::block &data, resource::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -graphite::toolbox::dialog_item_list::dialog_item_list(data::reader &reader) +toolbox::dialog_item_list::dialog_item_list(data::reader &reader) { decode(reader); } // MARK: - Encoder -auto graphite::toolbox::dialog_item_list::encode(data::writer &writer) -> void +auto toolbox::dialog_item_list::encode(data::writer &writer) -> void { writer.write_short(m_items.size() - 1); @@ -56,7 +56,7 @@ auto graphite::toolbox::dialog_item_list::encode(data::writer &writer) -> void } } -auto graphite::toolbox::dialog_item_list::data() -> data::block +auto toolbox::dialog_item_list::data() -> data::block { data::writer writer; encode(writer); @@ -65,7 +65,7 @@ auto graphite::toolbox::dialog_item_list::data() -> data::block // MARK: - Decoder -auto graphite::toolbox::dialog_item_list::decode(data::reader &reader) -> void +auto toolbox::dialog_item_list::decode(data::reader &reader) -> void { auto count = reader.read_short(); diff --git a/libs/libGraphite/toolbox/dialog_item_list.hpp b/libs/libToolbox/ui/dialog_item_list.hpp similarity index 88% rename from libs/libGraphite/toolbox/dialog_item_list.hpp rename to libs/libToolbox/ui/dialog_item_list.hpp index 58bc010..d8eeabe 100644 --- a/libs/libGraphite/toolbox/dialog_item_list.hpp +++ b/libs/libToolbox/ui/dialog_item_list.hpp @@ -22,11 +22,11 @@ #include #include -#include "libGraphite/data/reader.hpp" -#include "libGraphite/rsrc/resource.hpp" -#include "libGraphite/quickdraw/type/rect.hpp" +#include +#include +#include -namespace graphite::toolbox +namespace toolbox { struct dialog_item_list { @@ -57,7 +57,7 @@ namespace graphite::toolbox public: dialog_item_list() = default; - explicit dialog_item_list(const data::block& data, rsrc::resource::identifier id = 0, const std::string& name = ""); + explicit dialog_item_list(const data::block& data, resource::identifier id = 0, const std::string& name = ""); explicit dialog_item_list(data::reader& reader); auto encode(data::writer& writer) -> void; @@ -70,7 +70,7 @@ namespace graphite::toolbox auto end() -> std::vector::iterator { return m_items.end(); } private: - rsrc::resource::identifier m_id { INT64_MIN }; + resource::identifier m_id { INT64_MIN }; std::string m_name; std::vector m_items; From cf65e2c22384080d2ce5de92d38b429c431ee236 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 09:11:54 +0100 Subject: [PATCH 097/113] Fix linux build due to case-sensitivity, and remove macOS 11 CI workflow --- .github/workflows/build.yml | 2 +- CMakeLists.txt | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc7df21..73e2839 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: name: Build on macOS strategy: matrix: - os: [ macos-11, macos-12 ] + os: [ macos-12 ] runs-on: ${{ matrix.os }} steps: - name: Checkout diff --git a/CMakeLists.txt b/CMakeLists.txt index 051a12e..83d9a83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,13 +37,6 @@ add_subdirectory(${PROJECT_LIBS_DIR}/libHashing) add_subdirectory(${PROJECT_LIBS_DIR}/libEncoding) add_subdirectory(${PROJECT_LIBS_DIR}/libData) add_subdirectory(${PROJECT_LIBS_DIR}/libResource) -add_subdirectory(${PROJECT_LIBS_DIR}/libQuickDraw) +add_subdirectory(${PROJECT_LIBS_DIR}/libQuickdraw) add_subdirectory(${PROJECT_LIBS_DIR}/libSound) add_subdirectory(${PROJECT_LIBS_DIR}/libToolbox) - -# Unit Tests -if (EXISTS ${PROJECT_LIBS_DIR}/libTesting/testing.cmake) - include(${PROJECT_LIBS_DIR}/libTesting/testing.cmake) -# add_testing_target(Graphite ${CMAKE_CURRENT_LIST_DIR}/Tests) -# include("GraphiteTests.cmake") -endif() \ No newline at end of file From 49aa59d2e530e24ff123331af7c1ae6ab32054ba Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 09:14:30 +0100 Subject: [PATCH 098/113] Add SSE compiler flags. --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 83d9a83..0286be3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,8 @@ if (APPLE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2 -mavx -msse4.1") + set(PROJECT_LIBS_DIR ${CMAKE_CURRENT_LIST_DIR}/libs) # Libraries From a262f5669741c5e4b83d9b1f764c6fb1d9f34522 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 09:25:43 +0100 Subject: [PATCH 099/113] Start rebuilding the groundwork for test targets. --- CMakeLists.txt | 6 +++++ tests/CMakeLists.txt | 31 +++++++++++++++++++++++++ tests/libs/libHashing/CMakeLists.txt | 25 ++++++++++++++++++++ tests/libs/libHashing/xxhash.cpp | 34 ++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/libs/libHashing/CMakeLists.txt create mode 100644 tests/libs/libHashing/xxhash.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0286be3..1571d0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,3 +42,9 @@ add_subdirectory(${PROJECT_LIBS_DIR}/libResource) add_subdirectory(${PROJECT_LIBS_DIR}/libQuickdraw) add_subdirectory(${PROJECT_LIBS_DIR}/libSound) add_subdirectory(${PROJECT_LIBS_DIR}/libToolbox) + +######################################################################################################################## + +enable_testing() +add_subdirectory(tests) + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..77563e0 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +######################################################################################################################## +## libTesting +include(${PROJECT_SOURCE_DIR}/libs/libTesting/testing.cmake) +build_testing_library() + +######################################################################################################################## +## Preparation + +set(TESTS ${PROJECT_SOURCE_DIR}/tests) +add_test_target(Hashing ${TESTS}/libs/libHashing) diff --git a/tests/libs/libHashing/CMakeLists.txt b/tests/libs/libHashing/CMakeLists.txt new file mode 100644 index 0000000..97c845a --- /dev/null +++ b/tests/libs/libHashing/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Tom Hancocks +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +test_suite(Hashing) + test_case(XXHash) + test(hashed_string_returnsCorrectValue) + end_test_case() +end_test_suite() diff --git a/tests/libs/libHashing/xxhash.cpp b/tests/libs/libHashing/xxhash.cpp new file mode 100644 index 0000000..1433ffc --- /dev/null +++ b/tests/libs/libHashing/xxhash.cpp @@ -0,0 +1,34 @@ +// Copyright (c) 2023 Tom Hancocks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +TEST(hashed_string_returnsCorrectValue) +{ + // Additional values could be added here to help ensure edge cases are correctly + // hashed. + // Any expected hash values should be generated by a third party hashing algorithm + // to ensure we aren't validating against our self. These were generated using + // https://asecuritysite.com/encryption/xxHash + test::equal(hashing::xxh64("apple", 5), 0x5889a1c15c94729f); + test::equal(hashing::xxh64("banana", 6), 0xcef162e1813c8ce2); + test::equal(hashing::xxh64("orange", 6), 0xc23e954aef3ce5a9); +} \ No newline at end of file From 90a6530409b1ff4a452a823d4f3beb9bbdb81083 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 09:44:50 +0100 Subject: [PATCH 100/113] Fix includes for Windows build --- libs/libEncoding/macroman/macroman.cpp | 28 +++++++++++++------------- libs/libEncoding/macroman/macroman.hpp | 6 ++++-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libs/libEncoding/macroman/macroman.cpp b/libs/libEncoding/macroman/macroman.cpp index 3882a0f..0a31022 100644 --- a/libs/libEncoding/macroman/macroman.cpp +++ b/libs/libEncoding/macroman/macroman.cpp @@ -24,7 +24,7 @@ // MARK: - Encoding Tables -static uint16_t cp_table[0x100] = +static std::uint16_t cp_table[0x100] = { // Standard ASCII 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, @@ -72,13 +72,13 @@ namespace unicode struct hint { public: - uint8_t m_mask; - uint8_t m_lead; - uint32_t m_beg; - uint32_t m_end; - size_t m_bits; + std::uint8_t m_mask; + std::uint8_t m_lead; + std::uint32_t m_beg; + std::uint32_t m_end; + std::size_t m_bits; - hint(uint8_t mask, uint8_t lead, uint32_t beg, uint32_t end, size_t bits) + hint(std::uint8_t mask, std::uint8_t lead, std::uint32_t beg, std::uint32_t end, std::size_t bits) : m_mask(mask), m_lead(lead), m_beg(beg), m_end(end), m_bits(bits) { @@ -102,9 +102,9 @@ namespace unicode // MARK: - Conversion Functions -auto encoding::mac_roman::from_utf8(const std::string &str) -> std::vector +auto encoding::mac_roman::from_utf8(const std::string &str) -> std::vector { - std::vector mac_roman_bytes; + std::vector mac_roman_bytes; // Convert back to a C-String for easier processing here... const char *s = str.c_str(); @@ -116,7 +116,7 @@ auto encoding::mac_roman::from_utf8(const std::string &str) -> std::vector(s[i]); + auto ch = static_cast(s[i]); for (auto hint : utf8) { if ((ch & ~hint.m_mask) == hint.m_lead) { break; @@ -130,7 +130,7 @@ auto encoding::mac_roman::from_utf8(const std::string &str) -> std::vector std::vector& bytes) -> std::string +auto encoding::mac_roman::to_utf8(const std::vector& bytes) -> std::string { std::string result; @@ -160,8 +160,8 @@ auto encoding::mac_roman::to_utf8(const std::vector& bytes) -> std::str // Get the codepoint and determine the length of the UTF8 scalar. auto cp = cp_table[c]; - - size_t n = 0; + + std::size_t n = 0; for (auto hint : utf8) { if ((cp >= hint.m_beg) && (cp <= hint.m_end)) { break; diff --git a/libs/libEncoding/macroman/macroman.hpp b/libs/libEncoding/macroman/macroman.hpp index c745809..0829c9d 100644 --- a/libs/libEncoding/macroman/macroman.hpp +++ b/libs/libEncoding/macroman/macroman.hpp @@ -20,6 +20,8 @@ #include #include +#include +#include #if !defined(ENCODING_MACROMAN) #define ENCODING_MACROMAN @@ -30,13 +32,13 @@ namespace encoding::mac_roman { * Convert a sequence of bytes into a UTF-8 string, translating them from a * Mac OS Roman encoding. */ - auto to_utf8(const std::vector& bytes) -> std::string; + auto to_utf8(const std::vector& bytes) -> std::string; /** * Convert a UTF-8 encoded string into a sequence of bytes containing a Mac OS * Roman encoded string. */ - auto from_utf8(const std::string& str) -> std::vector; + auto from_utf8(const std::string& str) -> std::vector; } From 4e971f3900583f4ba11af404d23ede6a26917228 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 13:37:00 +0100 Subject: [PATCH 101/113] Rename libResource to libResourceCore --- CMakeLists.txt | 2 +- libs/libQuickdraw/CMakeLists.txt | 2 +- libs/libQuickdraw/format/color_icon.cpp | 2 +- libs/libQuickdraw/format/color_icon.hpp | 4 +- .../format/color_lookup_table.cpp | 2 +- .../format/color_lookup_table.hpp | 6 +- libs/libQuickdraw/format/picture.cpp | 2 +- libs/libQuickdraw/format/picture.hpp | 6 +- libs/libQuickdraw/format/pixel_pattern.cpp | 2 +- libs/libQuickdraw/format/pixel_pattern.hpp | 4 +- libs/libQuickdraw/pixmap/pixmap.cpp | 2 +- libs/libQuickdraw/pixmap/pixmap.hpp | 2 +- .../quicktime/image_description.cpp | 4 +- .../CMakeLists.txt | 8 +- .../concepts.hpp | 4 +- .../{libResource => libResourceCore}/file.cpp | 82 +++++++++---------- .../{libResource => libResourceCore}/file.hpp | 10 +-- .../format/classic/classic.hpp | 4 +- .../format/classic/parser.cpp | 8 +- .../format/classic/parser.hpp | 4 +- .../format/classic/writer.cpp | 14 ++-- .../format/classic/writer.hpp | 4 +- .../format/extended/extended.hpp | 4 +- .../format/extended/parser.cpp | 8 +- .../format/extended/parser.hpp | 4 +- .../format/extended/writer.cpp | 14 ++-- .../format/extended/writer.hpp | 4 +- .../format/rez/parser.cpp | 12 +-- .../format/rez/parser.hpp | 4 +- .../format/rez/rez.hpp | 4 +- .../format/rez/writer.cpp | 12 +-- .../format/rez/writer.hpp | 4 +- .../identifier.hpp | 2 +- .../manager.cpp | 38 ++++----- .../manager.hpp | 16 ++-- .../result.cpp | 28 +++---- .../result.hpp | 4 +- .../structure/attribute.cpp | 12 +-- .../structure/attribute.hpp | 2 +- .../structure/instance.cpp | 42 +++++----- .../structure/instance.hpp | 4 +- .../structure/type.cpp | 58 ++++++------- .../structure/type.hpp | 8 +- libs/libSound/CMakeLists.txt | 2 +- libs/libSound/format/sound.cpp | 6 +- libs/libSound/format/sound.hpp | 8 +- libs/libSpriteWorld/CMakeLists.txt | 2 +- libs/libSpriteWorld/formats/rleD.cpp | 2 +- libs/libSpriteWorld/formats/rleD.hpp | 6 +- libs/libSpriteWorld/formats/rleX.cpp | 2 +- libs/libSpriteWorld/formats/rleX.hpp | 6 +- libs/libToolbox/CMakeLists.txt | 2 +- libs/libToolbox/font/fond.cpp | 2 +- libs/libToolbox/font/fond.hpp | 6 +- libs/libToolbox/font/manager.cpp | 8 +- libs/libToolbox/font/manager.hpp | 2 +- libs/libToolbox/font/nfnt.cpp | 2 +- libs/libToolbox/font/nfnt.hpp | 6 +- libs/libToolbox/font/sfnt.cpp | 2 +- libs/libToolbox/font/sfnt.hpp | 6 +- libs/libToolbox/strings/string.cpp | 2 +- libs/libToolbox/strings/string.hpp | 6 +- libs/libToolbox/strings/string_list.cpp | 2 +- libs/libToolbox/strings/string_list.hpp | 6 +- libs/libToolbox/ui/dialog.cpp | 6 +- libs/libToolbox/ui/dialog.hpp | 12 +-- libs/libToolbox/ui/dialog_item_list.cpp | 2 +- libs/libToolbox/ui/dialog_item_list.hpp | 6 +- 68 files changed, 287 insertions(+), 287 deletions(-) rename libs/{libResource => libResourceCore}/CMakeLists.txt (88%) rename libs/{libResource => libResourceCore}/concepts.hpp (95%) rename libs/{libResource => libResourceCore}/file.cpp (69%) rename libs/{libResource => libResourceCore}/file.hpp (93%) rename libs/{libResource => libResourceCore}/format/classic/classic.hpp (91%) rename libs/{libResource => libResourceCore}/format/classic/parser.cpp (95%) rename libs/{libResource => libResourceCore}/format/classic/parser.hpp (94%) rename libs/{libResource => libResourceCore}/format/classic/writer.cpp (95%) rename libs/{libResource => libResourceCore}/format/classic/writer.hpp (94%) rename libs/{libResource => libResourceCore}/format/extended/extended.hpp (91%) rename libs/{libResource => libResourceCore}/format/extended/parser.cpp (96%) rename libs/{libResource => libResourceCore}/format/extended/parser.hpp (93%) rename libs/{libResource => libResourceCore}/format/extended/writer.cpp (95%) rename libs/{libResource => libResourceCore}/format/extended/writer.hpp (94%) rename libs/{libResource => libResourceCore}/format/rez/parser.cpp (92%) rename libs/{libResource => libResourceCore}/format/rez/parser.hpp (94%) rename libs/{libResource => libResourceCore}/format/rez/rez.hpp (92%) rename libs/{libResource => libResourceCore}/format/rez/writer.cpp (94%) rename libs/{libResource => libResourceCore}/format/rez/writer.hpp (94%) rename libs/{libResource => libResourceCore}/identifier.hpp (98%) rename libs/{libResource => libResourceCore}/manager.cpp (69%) rename libs/{libResource => libResourceCore}/manager.hpp (93%) rename libs/{libResource => libResourceCore}/result.cpp (76%) rename libs/{libResource => libResourceCore}/result.hpp (98%) rename libs/{libResource => libResourceCore}/structure/attribute.cpp (77%) rename libs/{libResource => libResourceCore}/structure/attribute.hpp (98%) rename libs/{libResource => libResourceCore}/structure/instance.cpp (65%) rename libs/{libResource => libResourceCore}/structure/instance.hpp (97%) rename libs/{libResource => libResourceCore}/structure/type.cpp (69%) rename libs/{libResource => libResourceCore}/structure/type.hpp (94%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1571d0d..d479488 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ add_subdirectory(${PROJECT_LIBS_DIR}/libSIMD) add_subdirectory(${PROJECT_LIBS_DIR}/libHashing) add_subdirectory(${PROJECT_LIBS_DIR}/libEncoding) add_subdirectory(${PROJECT_LIBS_DIR}/libData) -add_subdirectory(${PROJECT_LIBS_DIR}/libResource) +add_subdirectory(${PROJECT_LIBS_DIR}/libResourceCore) add_subdirectory(${PROJECT_LIBS_DIR}/libQuickdraw) add_subdirectory(${PROJECT_LIBS_DIR}/libSound) add_subdirectory(${PROJECT_LIBS_DIR}/libToolbox) diff --git a/libs/libQuickdraw/CMakeLists.txt b/libs/libQuickdraw/CMakeLists.txt index d3fa262..9bab936 100644 --- a/libs/libQuickdraw/CMakeLists.txt +++ b/libs/libQuickdraw/CMakeLists.txt @@ -32,7 +32,7 @@ file(GLOB_RECURSE libQuickDraw_Sources ) add_library(QuickDraw ${libQuickDraw_Sources}) -target_link_libraries(QuickDraw SIMD Data Resource) +target_link_libraries(QuickDraw SIMD Data ResourceCore) target_include_directories(QuickDraw PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libQuickdraw/format/color_icon.cpp b/libs/libQuickdraw/format/color_icon.cpp index 8ddae1f..aa4b163 100644 --- a/libs/libQuickdraw/format/color_icon.cpp +++ b/libs/libQuickdraw/format/color_icon.cpp @@ -27,7 +27,7 @@ // MARK: - Construction -quickdraw::color_icon::color_icon(const data::block &data, resource::identifier id, const std::string &name) +quickdraw::color_icon::color_icon(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libQuickdraw/format/color_icon.hpp b/libs/libQuickdraw/format/color_icon.hpp index 1a2ef92..1217fc0 100644 --- a/libs/libQuickdraw/format/color_icon.hpp +++ b/libs/libQuickdraw/format/color_icon.hpp @@ -35,7 +35,7 @@ namespace quickdraw public: color_icon() = default; - explicit color_icon(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit color_icon(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit color_icon(data::reader& reader); explicit color_icon(quickdraw::surface& surface); @@ -45,7 +45,7 @@ namespace quickdraw auto data() -> data::block; private: - resource::identifier m_id { resource::auto_resource_id }; + resource_core::identifier m_id { resource_core::auto_resource_id }; std::string m_name; quickdraw::pixmap m_pixmap; std::uint32_t m_mask_base_address { 0 }; diff --git a/libs/libQuickdraw/format/color_lookup_table.cpp b/libs/libQuickdraw/format/color_lookup_table.cpp index 0106b26..600c4ee 100644 --- a/libs/libQuickdraw/format/color_lookup_table.cpp +++ b/libs/libQuickdraw/format/color_lookup_table.cpp @@ -24,7 +24,7 @@ // MARK: - Construction -quickdraw::color_lookup_table::color_lookup_table(const data::block &data, resource::identifier id, const std::string &name) +quickdraw::color_lookup_table::color_lookup_table(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libQuickdraw/format/color_lookup_table.hpp b/libs/libQuickdraw/format/color_lookup_table.hpp index fd598f2..f7f528b 100644 --- a/libs/libQuickdraw/format/color_lookup_table.hpp +++ b/libs/libQuickdraw/format/color_lookup_table.hpp @@ -20,7 +20,7 @@ #pragma once -#include +#include #include #include @@ -64,7 +64,7 @@ namespace quickdraw public: color_lookup_table() = default; - explicit color_lookup_table(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit color_lookup_table(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit color_lookup_table(data::reader& reader); [[nodiscard]] auto size() const -> size_type; @@ -81,7 +81,7 @@ namespace quickdraw auto encode(data::writer& writer) -> void; private: - resource::identifier m_id; + resource_core::identifier m_id; std::string m_name; std::uint32_t m_seed; enum flags m_flags { pixmap }; diff --git a/libs/libQuickdraw/format/picture.cpp b/libs/libQuickdraw/format/picture.cpp index 318d2f0..58633d3 100644 --- a/libs/libQuickdraw/format/picture.cpp +++ b/libs/libQuickdraw/format/picture.cpp @@ -34,7 +34,7 @@ namespace quickdraw::constants // MARK: - Construction -quickdraw::picture::picture(const data::block &data, resource::identifier id, const std::string &name) +quickdraw::picture::picture(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libQuickdraw/format/picture.hpp b/libs/libQuickdraw/format/picture.hpp index efbb6dd..3165607 100644 --- a/libs/libQuickdraw/format/picture.hpp +++ b/libs/libQuickdraw/format/picture.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace quickdraw { @@ -34,7 +34,7 @@ namespace quickdraw public: picture() = default; - explicit picture(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit picture(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit picture(data::reader& reader); explicit picture(quickdraw::surface& surface); @@ -92,7 +92,7 @@ namespace quickdraw }; private: - resource::identifier m_id { 0 }; + resource_core::identifier m_id { 0 }; std::string m_name; quickdraw::surface m_surface; rect m_frame; diff --git a/libs/libQuickdraw/format/pixel_pattern.cpp b/libs/libQuickdraw/format/pixel_pattern.cpp index 19d47a4..8a01dd9 100644 --- a/libs/libQuickdraw/format/pixel_pattern.cpp +++ b/libs/libQuickdraw/format/pixel_pattern.cpp @@ -24,7 +24,7 @@ // MARK: - Construction -quickdraw::pixel_pattern::pixel_pattern(const data::block &data, resource::identifier id, const std::string& name) +quickdraw::pixel_pattern::pixel_pattern(const data::block &data, resource_core::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libQuickdraw/format/pixel_pattern.hpp b/libs/libQuickdraw/format/pixel_pattern.hpp index 4de5ea4..2e32a11 100644 --- a/libs/libQuickdraw/format/pixel_pattern.hpp +++ b/libs/libQuickdraw/format/pixel_pattern.hpp @@ -35,7 +35,7 @@ namespace quickdraw public: pixel_pattern() = default; - explicit pixel_pattern(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit pixel_pattern(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit pixel_pattern(data::reader& reader); explicit pixel_pattern(surface& surface); @@ -45,7 +45,7 @@ namespace quickdraw auto data() -> data::block; private: - resource::identifier m_id; + resource_core::identifier m_id; std::string m_name; std::uint16_t m_pat_type; std::uint32_t m_pmap_base_address; diff --git a/libs/libQuickdraw/pixmap/pixmap.cpp b/libs/libQuickdraw/pixmap/pixmap.cpp index 5ab600b..fdf1e94 100644 --- a/libs/libQuickdraw/pixmap/pixmap.cpp +++ b/libs/libQuickdraw/pixmap/pixmap.cpp @@ -36,7 +36,7 @@ quickdraw::pixmap::pixmap(const rect& frame, bool rgb555) { } -quickdraw::pixmap::pixmap(const data::block &data, resource::identifier id, const std::string &name) +quickdraw::pixmap::pixmap(const data::block &data, resource_core::identifier id, const std::string &name) { data::reader reader(&data); decode(reader); diff --git a/libs/libQuickdraw/pixmap/pixmap.hpp b/libs/libQuickdraw/pixmap/pixmap.hpp index 2f45a12..e1aac1f 100644 --- a/libs/libQuickdraw/pixmap/pixmap.hpp +++ b/libs/libQuickdraw/pixmap/pixmap.hpp @@ -68,7 +68,7 @@ namespace quickdraw pixmap() = default; explicit pixmap(const rect& frame, bool rgb555 = false); - explicit pixmap(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit pixmap(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit pixmap(data::reader& reader); pixmap(const pixmap&) noexcept = default; diff --git a/libs/libQuickdraw/quicktime/image_description.cpp b/libs/libQuickdraw/quicktime/image_description.cpp index 2d7ce95..37495eb 100644 --- a/libs/libQuickdraw/quicktime/image_description.cpp +++ b/libs/libQuickdraw/quicktime/image_description.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include @@ -53,7 +53,7 @@ quicktime::image_description::image_description(data::reader &reader) if (clut == 0) { m_clut = reader.read(); } else if (clut > 0) { - if (auto resource = resource::manager::shared_manager().find(clut)) { + if (auto resource = resource_core::manager::shared_manager().find(clut)) { m_clut = quickdraw::color_lookup_table(resource->data()); } else { diff --git a/libs/libResource/CMakeLists.txt b/libs/libResourceCore/CMakeLists.txt similarity index 88% rename from libs/libResource/CMakeLists.txt rename to libs/libResourceCore/CMakeLists.txt index 78a833b..e8545dc 100644 --- a/libs/libResource/CMakeLists.txt +++ b/libs/libResourceCore/CMakeLists.txt @@ -27,12 +27,12 @@ set(CMAKE_CXX_STANDARD 20) ######################################################################################################################## ## libSIMD -file(GLOB_RECURSE libResource_Sources +file(GLOB_RECURSE libResourceCore_Sources *.cpp ) -add_library(Resource ${libResource_Sources}) -target_link_libraries(Resource SIMD Data Encoding) -target_include_directories(Resource PUBLIC +add_library(ResourceCore ${libResourceCore_Sources}) +target_link_libraries(ResourceCore SIMD Data Encoding) +target_include_directories(ResourceCore PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libResource/concepts.hpp b/libs/libResourceCore/concepts.hpp similarity index 95% rename from libs/libResource/concepts.hpp rename to libs/libResourceCore/concepts.hpp index ff862b0..b04aa29 100644 --- a/libs/libResource/concepts.hpp +++ b/libs/libResourceCore/concepts.hpp @@ -24,9 +24,9 @@ #include #include #include -#include +#include -namespace resource +namespace resource_core { template concept isa_resource_type = requires(const T& type) { diff --git a/libs/libResource/file.cpp b/libs/libResourceCore/file.cpp similarity index 69% rename from libs/libResource/file.cpp rename to libs/libResourceCore/file.cpp index a7263ba..de18e64 100644 --- a/libs/libResource/file.cpp +++ b/libs/libResourceCore/file.cpp @@ -20,21 +20,21 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include // MARK: - Construction -resource::file::file(const std::string &path) +resource_core::file::file(const std::string &path) { read(path); } -resource::file::file(const file &file) +resource_core::file::file(const file &file) : m_format(file.m_format), m_path(file.m_path), m_data(new data::block(*file.m_data)) @@ -45,7 +45,7 @@ resource::file::file(const file &file) } } -resource::file::file(file &&file) noexcept +resource_core::file::file(file &&file) noexcept : m_format(file.m_format), m_path(std::move(file.m_path)), m_data(file.m_data), @@ -57,7 +57,7 @@ resource::file::file(file &&file) noexcept // MARK: - Destruction -resource::file::~file() +resource_core::file::~file() { for (auto& it : m_types) { delete it.second; @@ -67,7 +67,7 @@ resource::file::~file() // MARK: - Operators -auto resource::file::operator=(const file &file) -> class file & +auto resource_core::file::operator=(const file &file) -> class file & { if (this == const_cast(&file)) { return *this; @@ -85,7 +85,7 @@ auto resource::file::operator=(const file &file) -> class file & return *this; } -auto resource::file::operator=(file &&file) noexcept -> class file & +auto resource_core::file::operator=(file &&file) noexcept -> class file & { if (this != &file) { m_path = std::move(file.m_path); @@ -101,30 +101,30 @@ auto resource::file::operator=(file &&file) noexcept -> class file & // MARK: - Hashing -auto resource::file::hash_for_path(const std::string &path) -> hash +auto resource_core::file::hash_for_path(const std::string &path) -> hash { return hashing::xxh64(path.c_str(), path.size()); } // MARK: - Accessors -auto resource::file::name() const -> std::string +auto resource_core::file::name() const -> std::string { auto pos = m_path.find_last_of('/'); return m_path.substr(pos + 1); } -auto resource::file::path() const -> const std::string& +auto resource_core::file::path() const -> const std::string& { return m_path; } -auto resource::file::type_count() const -> std::size_t +auto resource_core::file::type_count() const -> std::size_t { return m_types.size(); } -auto resource::file::types() const -> std::vector +auto resource_core::file::types() const -> std::vector { std::vector types; for (const auto& type : m_types) { @@ -133,7 +133,7 @@ auto resource::file::types() const -> std::vector return std::move(types); } -auto resource::file::type_codes() const -> std::vector +auto resource_core::file::type_codes() const -> std::vector { std::vector types; for (const auto& type : m_types) { @@ -142,12 +142,12 @@ auto resource::file::type_codes() const -> std::vector return std::move(types); } -auto resource::file::format() const -> enum format +auto resource_core::file::format() const -> enum format { return m_format; } -auto resource::file::hash_value() const -> hash +auto resource_core::file::hash_value() const -> hash { return hash_for_path(m_path); } @@ -155,7 +155,7 @@ auto resource::file::hash_value() const -> hash // MARK: - Type Management -auto resource::file::add_resource(const std::string &type_code, +auto resource_core::file::add_resource(const std::string &type_code, identifier id, const std::string &name, const data::block &data, @@ -188,19 +188,19 @@ auto resource::file::add_resource(const std::string &type_code, } } -auto resource::file::add_type(struct type *type) -> void +auto resource_core::file::add_type(struct type *type) -> void { m_types.emplace(std::pair(type->hash_value(), type)); } -auto resource::file::add_types(const std::vector &types) -> void +auto resource_core::file::add_types(const std::vector &types) -> void { for (const auto type : types) { m_types.emplace(std::pair(type->hash_value(), type)); } } -auto resource::file::type(const std::string &code, const std::unordered_map& attributes) const -> const struct type * +auto resource_core::file::type(const std::string &code, const std::unordered_map& attributes) const -> const struct type * { // Convert the unordered map to what is required. std::unordered_map attributes_map; @@ -213,7 +213,7 @@ auto resource::file::type(const std::string &code, const std::unordered_mapsecond; } -auto resource::file::type(const std::string& code, const std::vector& attributes) const -> const struct type * +auto resource_core::file::type(const std::string& code, const std::vector& attributes) const -> const struct type * { bool universal_namespace = false; std::unordered_map attributes_map; @@ -242,30 +242,30 @@ auto resource::file::type(const std::string& code, const std::vector& return nullptr; } -auto resource::file::type(const std::string& code) const -> const struct type * +auto resource_core::file::type(const std::string& code) const -> const struct type * { auto it = m_types.find(type::hash_for_type_code(code)); return (it == m_types.end()) ? nullptr : it->second; } -auto resource::file::type(type::hash hash) const -> const struct type * +auto resource_core::file::type(type::hash hash) const -> const struct type * { auto it = m_types.find(hash); return (it == m_types.end()) ? nullptr : it->second; } -auto resource::file::find(const std::string &type_code, identifier id, const std::unordered_map& attributes) const -> const struct instance * +auto resource_core::file::find(const std::string &type_code, identifier id, const std::unordered_map& attributes) const -> const struct instance * { - if (auto type = const_cast<::resource::type *>(this->type(type_code, attributes))) { + if (auto type = const_cast<::resource_core::type *>(this->type(type_code, attributes))) { return type->resource_with_id(id); } return nullptr; } -auto resource::file::find(const std::string &type_code, identifier id, const std::vector& attributes) const -> const struct instance * +auto resource_core::file::find(const std::string &type_code, identifier id, const std::vector& attributes) const -> const struct instance * { - if (auto type = const_cast<::resource::type *>(this->type(type_code, attributes))) { + if (auto type = const_cast<::resource_core::type *>(this->type(type_code, attributes))) { return type->resource_with_id(id); } return nullptr; @@ -273,19 +273,19 @@ auto resource::file::find(const std::string &type_code, identifier id, const std // MARK: - File Access -auto resource::file::read(const std::string &path) -> void +auto resource_core::file::read(const std::string &path) -> void { m_path = path; m_data = new data::block(m_path); data::reader reader(m_data); - if (::resource::format::extended::parse(reader, *this)) { + if (::resource_core::format::extended::parse(reader, *this)) { m_format = format::extended; } - else if (::resource::format::rez::parse(reader, *this)) { + else if (::resource_core::format::rez::parse(reader, *this)) { m_format = format::rez; } - else if (::resource::format::classic::parse(reader, *this)) { + else if (::resource_core::format::classic::parse(reader, *this)) { m_format = format::classic; } else { @@ -293,17 +293,17 @@ auto resource::file::read(const std::string &path) -> void } } -auto resource::file::write() -> bool +auto resource_core::file::write() -> bool { return write(m_path, m_format); } -auto resource::file::write(const std::string &path) -> bool +auto resource_core::file::write(const std::string &path) -> bool { return write(path, m_format); } -auto resource::file::write(const std::string &path, enum format format) -> bool +auto resource_core::file::write(const std::string &path, enum format format) -> bool { if (m_path != path) { m_path = path; @@ -312,13 +312,13 @@ auto resource::file::write(const std::string &path, enum format format) -> bool switch (m_format) { case format::extended: - return ::resource::format::extended::write(*this, m_path); + return ::resource_core::format::extended::write(*this, m_path); case format::rez: - return ::resource::format::rez::write(*this, m_path); + return ::resource_core::format::rez::write(*this, m_path); case format::classic: - return ::resource::format::classic::write(*this, m_path); + return ::resource_core::format::classic::write(*this, m_path); default: return false; diff --git a/libs/libResource/file.hpp b/libs/libResourceCore/file.hpp similarity index 93% rename from libs/libResource/file.hpp rename to libs/libResourceCore/file.hpp index bc0e3bb..2ed7785 100644 --- a/libs/libResource/file.hpp +++ b/libs/libResourceCore/file.hpp @@ -24,11 +24,11 @@ #include #include #include -#include -#include -#include +#include +#include +#include -namespace resource +namespace resource_core { class file { @@ -76,7 +76,7 @@ namespace resource const std::unordered_map& attributes = {}) -> void; template - [[nodiscard]] auto find(resource::identifier id, const std::unordered_map& attributes = {}) const -> const struct resource * + [[nodiscard]] auto find(resource_core::identifier id, const std::unordered_map& attributes = {}) const -> const struct resource * { return find(T::type_code(), id, attributes); } diff --git a/libs/libResource/format/classic/classic.hpp b/libs/libResourceCore/format/classic/classic.hpp similarity index 91% rename from libs/libResource/format/classic/classic.hpp rename to libs/libResourceCore/format/classic/classic.hpp index d0324da..f20c599 100644 --- a/libs/libResource/format/classic/classic.hpp +++ b/libs/libResourceCore/format/classic/classic.hpp @@ -20,5 +20,5 @@ #pragma once -#include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/libs/libResource/format/classic/parser.cpp b/libs/libResourceCore/format/classic/parser.cpp similarity index 95% rename from libs/libResource/format/classic/parser.cpp rename to libs/libResourceCore/format/classic/parser.cpp index a585818..5063b22 100644 --- a/libs/libResource/format/classic/parser.cpp +++ b/libs/libResourceCore/format/classic/parser.cpp @@ -22,13 +22,13 @@ #include #include #include -#include -#include -#include +#include +#include +#include // MARK: - Parsing -auto resource::format::classic::parse(data::reader &reader, file& file) -> bool +auto resource_core::format::classic::parse(data::reader &reader, file& file) -> bool { std::vector types; diff --git a/libs/libResource/format/classic/parser.hpp b/libs/libResourceCore/format/classic/parser.hpp similarity index 94% rename from libs/libResource/format/classic/parser.hpp rename to libs/libResourceCore/format/classic/parser.hpp index 20ba7b4..7788f09 100644 --- a/libs/libResource/format/classic/parser.hpp +++ b/libs/libResourceCore/format/classic/parser.hpp @@ -20,10 +20,10 @@ #pragma once -#include +#include #include -namespace resource::format::classic +namespace resource_core::format::classic { auto parse(data::reader& reader, file& file) -> bool; } diff --git a/libs/libResource/format/classic/writer.cpp b/libs/libResourceCore/format/classic/writer.cpp similarity index 95% rename from libs/libResource/format/classic/writer.cpp rename to libs/libResourceCore/format/classic/writer.cpp index 14355ba..6a825b5 100644 --- a/libs/libResource/format/classic/writer.cpp +++ b/libs/libResourceCore/format/classic/writer.cpp @@ -21,13 +21,13 @@ #include #include #include -#include -#include -#include +#include +#include +#include // MARK: - Constants -namespace resource::format::classic::constants::defaults +namespace resource_core::format::classic::constants::defaults { constexpr std::uint32_t data_offset = 256; constexpr std::uint32_t map_offset = 0; @@ -35,7 +35,7 @@ namespace resource::format::classic::constants::defaults constexpr std::uint32_t map_length = 0; } -namespace resource::format::classic::constants +namespace resource_core::format::classic::constants { constexpr std::uint16_t resource_type_length = 8; constexpr std::uint16_t resource_length = 12; @@ -44,12 +44,12 @@ namespace resource::format::classic::constants // MARK: - Writing -auto resource::format::classic::write(file &file) -> bool +auto resource_core::format::classic::write(file &file) -> bool { return write(file, file.path()); } -auto resource::format::classic::write(file &file, const std::string &path) -> bool +auto resource_core::format::classic::write(file &file, const std::string &path) -> bool { data::writer writer(data::byte_order::msb); diff --git a/libs/libResource/format/classic/writer.hpp b/libs/libResourceCore/format/classic/writer.hpp similarity index 94% rename from libs/libResource/format/classic/writer.hpp rename to libs/libResourceCore/format/classic/writer.hpp index 981a9cd..4f7a095 100644 --- a/libs/libResource/format/classic/writer.hpp +++ b/libs/libResourceCore/format/classic/writer.hpp @@ -21,10 +21,10 @@ #pragma once #include -#include +#include #include -namespace resource::format::classic +namespace resource_core::format::classic { auto write(file& file) -> bool; auto write(file& file, const std::string& path) -> bool; diff --git a/libs/libResource/format/extended/extended.hpp b/libs/libResourceCore/format/extended/extended.hpp similarity index 91% rename from libs/libResource/format/extended/extended.hpp rename to libs/libResourceCore/format/extended/extended.hpp index 35e3195..f8f32b5 100644 --- a/libs/libResource/format/extended/extended.hpp +++ b/libs/libResourceCore/format/extended/extended.hpp @@ -20,5 +20,5 @@ #pragma once -#include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/libs/libResource/format/extended/parser.cpp b/libs/libResourceCore/format/extended/parser.cpp similarity index 96% rename from libs/libResource/format/extended/parser.cpp rename to libs/libResourceCore/format/extended/parser.cpp index 083595e..16bad69 100644 --- a/libs/libResource/format/extended/parser.cpp +++ b/libs/libResourceCore/format/extended/parser.cpp @@ -20,15 +20,15 @@ #include #include -#include +#include #include #include -#include -#include +#include +#include // MARK: - Parsing -auto resource::format::extended::parse(data::reader &reader, file &file) -> bool +auto resource_core::format::extended::parse(data::reader &reader, file &file) -> bool { std::vector types; diff --git a/libs/libResource/format/extended/parser.hpp b/libs/libResourceCore/format/extended/parser.hpp similarity index 93% rename from libs/libResource/format/extended/parser.hpp rename to libs/libResourceCore/format/extended/parser.hpp index c7e0493..4d2eb5c 100644 --- a/libs/libResource/format/extended/parser.hpp +++ b/libs/libResourceCore/format/extended/parser.hpp @@ -20,10 +20,10 @@ #pragma once -#include +#include #include -namespace resource::format::extended +namespace resource_core::format::extended { auto parse(data::reader& reader, file& file) -> bool; } \ No newline at end of file diff --git a/libs/libResource/format/extended/writer.cpp b/libs/libResourceCore/format/extended/writer.cpp similarity index 95% rename from libs/libResource/format/extended/writer.cpp rename to libs/libResourceCore/format/extended/writer.cpp index 1c6e9d1..ff9110e 100644 --- a/libs/libResource/format/extended/writer.cpp +++ b/libs/libResourceCore/format/extended/writer.cpp @@ -21,14 +21,14 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include // MARK: - Constants -namespace resource::format::extended::constants::defaults +namespace resource_core::format::extended::constants::defaults { constexpr std::uint64_t version = 1; constexpr std::uint64_t data_offset = 256; @@ -37,7 +37,7 @@ namespace resource::format::extended::constants::defaults constexpr std::uint64_t map_length = 0; } -namespace resource::format::extended::constants +namespace resource_core::format::extended::constants { constexpr std::uint16_t resource_type_length = 36; constexpr std::uint16_t resource_length = 29; @@ -46,12 +46,12 @@ namespace resource::format::extended::constants // MARK: - Writing -auto resource::format::extended::write(file &file) -> bool +auto resource_core::format::extended::write(file &file) -> bool { return write(file, file.path()); } -auto resource::format::extended::write(file &file, const std::string &path) -> bool +auto resource_core::format::extended::write(file &file, const std::string &path) -> bool { data::writer writer(data::byte_order::msb); diff --git a/libs/libResource/format/extended/writer.hpp b/libs/libResourceCore/format/extended/writer.hpp similarity index 94% rename from libs/libResource/format/extended/writer.hpp rename to libs/libResourceCore/format/extended/writer.hpp index 173e7ad..8189a87 100644 --- a/libs/libResource/format/extended/writer.hpp +++ b/libs/libResourceCore/format/extended/writer.hpp @@ -21,10 +21,10 @@ #pragma once #include -#include +#include #include -namespace resource::format::extended +namespace resource_core::format::extended { auto write(file& file) -> bool; auto write(file& file, const std::string& path) -> bool; diff --git a/libs/libResource/format/rez/parser.cpp b/libs/libResourceCore/format/rez/parser.cpp similarity index 92% rename from libs/libResource/format/rez/parser.cpp rename to libs/libResourceCore/format/rez/parser.cpp index b1f69fc..0faea2b 100644 --- a/libs/libResource/format/rez/parser.cpp +++ b/libs/libResourceCore/format/rez/parser.cpp @@ -20,15 +20,15 @@ #include #include -#include +#include #include #include -#include -#include +#include +#include // MARK: - Constants -namespace resource::format::rez::constants +namespace resource_core::format::rez::constants { const std::string map_name = "resource.map"; constexpr std::uint32_t signature = 'BRGR'; @@ -41,7 +41,7 @@ namespace resource::format::rez::constants // MARK: - Parsing -auto resource::format::rez::parse(data::reader &reader, file &file) -> bool +auto resource_core::format::rez::parse(data::reader &reader, file &file) -> bool { std::vector types; @@ -108,7 +108,7 @@ auto resource::format::rez::parse(data::reader &reader, file &file) -> bool return false; } - auto id = static_cast(reader.read_signed_short()); + auto id = static_cast(reader.read_signed_short()); auto next_offset = reader.position() + 256; auto name = reader.read_cstr(); diff --git a/libs/libResource/format/rez/parser.hpp b/libs/libResourceCore/format/rez/parser.hpp similarity index 94% rename from libs/libResource/format/rez/parser.hpp rename to libs/libResourceCore/format/rez/parser.hpp index a62dd66..d285054 100644 --- a/libs/libResource/format/rez/parser.hpp +++ b/libs/libResourceCore/format/rez/parser.hpp @@ -20,10 +20,10 @@ #pragma once -#include +#include #include -namespace resource::format::rez +namespace resource_core::format::rez { auto parse(data::reader& reader, file& file) -> bool; } \ No newline at end of file diff --git a/libs/libResource/format/rez/rez.hpp b/libs/libResourceCore/format/rez/rez.hpp similarity index 92% rename from libs/libResource/format/rez/rez.hpp rename to libs/libResourceCore/format/rez/rez.hpp index 7dd8f7c..9890e57 100644 --- a/libs/libResource/format/rez/rez.hpp +++ b/libs/libResourceCore/format/rez/rez.hpp @@ -20,5 +20,5 @@ #pragma once -#include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/libs/libResource/format/rez/writer.cpp b/libs/libResourceCore/format/rez/writer.cpp similarity index 94% rename from libs/libResource/format/rez/writer.cpp rename to libs/libResourceCore/format/rez/writer.cpp index ef4cbc2..1f065b2 100644 --- a/libs/libResource/format/rez/writer.cpp +++ b/libs/libResourceCore/format/rez/writer.cpp @@ -20,14 +20,14 @@ #include #include -#include +#include #include -#include -#include +#include +#include // MARK: - Constants -namespace resource::format::rez::constants +namespace resource_core::format::rez::constants { const std::string map_name = "resource.map"; constexpr std::uint32_t signature = 'BRGR'; @@ -41,12 +41,12 @@ namespace resource::format::rez::constants // MARK: - Writing -auto resource::format::rez::write(file &file) -> bool +auto resource_core::format::rez::write(file &file) -> bool { return write(file, file.path()); } -auto resource::format::rez::write(file &file, const std::string &path) -> bool +auto resource_core::format::rez::write(file &file, const std::string &path) -> bool { data::writer writer(data::byte_order::msb); diff --git a/libs/libResource/format/rez/writer.hpp b/libs/libResourceCore/format/rez/writer.hpp similarity index 94% rename from libs/libResource/format/rez/writer.hpp rename to libs/libResourceCore/format/rez/writer.hpp index 9012291..71c8dac 100644 --- a/libs/libResource/format/rez/writer.hpp +++ b/libs/libResourceCore/format/rez/writer.hpp @@ -21,10 +21,10 @@ #pragma once #include -#include +#include #include -namespace resource::format::rez +namespace resource_core::format::rez { auto write(file& file) -> bool; auto write(file& file, const std::string& path) -> bool; diff --git a/libs/libResource/identifier.hpp b/libs/libResourceCore/identifier.hpp similarity index 98% rename from libs/libResource/identifier.hpp rename to libs/libResourceCore/identifier.hpp index 13f28da..031cbfd 100644 --- a/libs/libResource/identifier.hpp +++ b/libs/libResourceCore/identifier.hpp @@ -23,7 +23,7 @@ #include #include -namespace resource +namespace resource_core { typedef std::int64_t identifier; constexpr identifier auto_resource_id = std::numeric_limits::min(); diff --git a/libs/libResource/manager.cpp b/libs/libResourceCore/manager.cpp similarity index 69% rename from libs/libResource/manager.cpp rename to libs/libResourceCore/manager.cpp index 4d3e717..3416d7b 100644 --- a/libs/libResource/manager.cpp +++ b/libs/libResourceCore/manager.cpp @@ -18,32 +18,32 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include +#include // MARK: - Singleton / Construction -auto resource::manager::shared_manager() -> manager & +auto resource_core::manager::shared_manager() -> manager & { - static ::resource::manager manager; + static ::resource_core::manager manager; return manager; } // MARK: - File Management -auto resource::manager::import_file(class file *file) -> class file * +auto resource_core::manager::import_file(class file *file) -> class file * { m_files.emplace(file->hash_value(), file); m_file_load_order.insert(m_file_load_order.begin(), file->hash_value()); return file; } -auto resource::manager::import_file(const std::string &path) -> class file * +auto resource_core::manager::import_file(const std::string &path) -> class file * { - auto file = new ::resource::file(path); + auto file = new ::resource_core::file(path); return import_file(file); } -auto resource::manager::unload_file(file::hash file) -> void +auto resource_core::manager::unload_file(file::hash file) -> void { auto it = m_files.find(file); if (it != m_files.end()) { @@ -52,19 +52,19 @@ auto resource::manager::unload_file(file::hash file) -> void } } -auto resource::manager::unload_file(class file *file) -> void +auto resource_core::manager::unload_file(class file *file) -> void { if (file) { unload_file(file->hash_value()); } } -auto resource::manager::unload_file(const std::string &path) -> void +auto resource_core::manager::unload_file(const std::string &path) -> void { unload_file(file::hash_for_path(path)); } -auto resource::manager::file(file::hash file) -> class file * +auto resource_core::manager::file(file::hash file) -> class file * { auto it = m_files.find(file); if (it != m_files.end()) { @@ -73,7 +73,7 @@ auto resource::manager::file(file::hash file) -> class file * return nullptr; } -auto resource::manager::file(file::hash file) const -> class file * +auto resource_core::manager::file(file::hash file) const -> class file * { auto it = m_files.find(file); if (it != m_files.end()) { @@ -82,17 +82,17 @@ auto resource::manager::file(file::hash file) const -> class file * return nullptr; } -auto resource::manager::file(const std::string &path) -> class file * +auto resource_core::manager::file(const std::string &path) -> class file * { return file(file::hash_for_path(path)); } -auto resource::manager::files() const -> const std::vector& +auto resource_core::manager::files() const -> const std::vector& { return m_file_load_order; } -auto resource::manager::file_references() const -> std::vector +auto resource_core::manager::file_references() const -> std::vector { std::vector files; for (auto hash : this->files()) { @@ -103,7 +103,7 @@ auto resource::manager::file_references() const -> std::vector // MARK: - Searching -auto resource::manager::all_types(const std::string &type_code, const std::vector &attributes) const -> std::vector +auto resource_core::manager::all_types(const std::string &type_code, const std::vector &attributes) const -> std::vector { std::vector types; for (const auto& it : m_files) { @@ -115,7 +115,7 @@ auto resource::manager::all_types(const std::string &type_code, const std::vecto return types; } -auto resource::manager::find(const std::string &type_code, const std::vector &attributes) const -> result +auto resource_core::manager::find(const std::string &type_code, const std::vector &attributes) const -> result { std::unordered_map resources; result result; @@ -131,13 +131,13 @@ auto resource::manager::find(const std::string &type_code, const std::vector &attributes) const -> struct instance * +auto resource_core::manager::find(const std::string &type_code, identifier id, const std::vector &attributes) const -> struct instance * { auto resources = std::move(find(type_code, attributes)); return resources.resource(type_code, id); } -auto resource::manager::find(const std::string &type_code, const std::string &name_prefix, const std::vector &attributes) const -> result +auto resource_core::manager::find(const std::string &type_code, const std::string &name_prefix, const std::vector &attributes) const -> result { auto resources = std::move(find(type_code, attributes)); return std::move(resources.filter([&] (struct instance *subject) -> bool { @@ -156,7 +156,7 @@ auto resource::manager::find(const std::string &type_code, const std::string &na // MARK: - Tear Down -auto resource::manager::tear_down() -> void +auto resource_core::manager::tear_down() -> void { for (const auto& file : m_files) { delete file.second; diff --git a/libs/libResource/manager.hpp b/libs/libResourceCore/manager.hpp similarity index 93% rename from libs/libResource/manager.hpp rename to libs/libResourceCore/manager.hpp index 3581144..f4e6d0e 100644 --- a/libs/libResource/manager.hpp +++ b/libs/libResourceCore/manager.hpp @@ -22,14 +22,14 @@ #include #include -#include -#include -#include -#include -#include -#include - -namespace resource +#include +#include +#include +#include +#include +#include + +namespace resource_core { class manager { diff --git a/libs/libResource/result.cpp b/libs/libResourceCore/result.cpp similarity index 76% rename from libs/libResource/result.cpp rename to libs/libResourceCore/result.cpp index bbaa953..ba4a5dc 100644 --- a/libs/libResource/result.cpp +++ b/libs/libResourceCore/result.cpp @@ -19,18 +19,18 @@ // SOFTWARE. #include -#include -#include +#include +#include #include // MARK: - Hashing -auto resource::result::sort_key(struct instance *resource) -> hash +auto resource_core::result::sort_key(struct instance *resource) -> hash { return sort_key(resource->type_code(), resource->id()); } -auto resource::result::sort_key(const std::string& type_code, identifier id) -> hash +auto resource_core::result::sort_key(const std::string& type_code, identifier id) -> hash { std::string key = type_code + "." + std::to_string(id); return hashing::xxh64(key.c_str(), key.size()); @@ -38,7 +38,7 @@ auto resource::result::sort_key(const std::string& type_code, identifier id) -> // MARK: - Item Management -auto resource::result::add(struct instance *instance) -> void +auto resource_core::result::add(struct instance *instance) -> void { if (!instance) { return; @@ -54,20 +54,20 @@ auto resource::result::add(struct instance *instance) -> void m_sorted_keys.emplace_back(key); } -auto resource::result::finalize() -> void +auto resource_core::result::finalize() -> void { m_finalized = true; sort(); } -auto resource::result::size() const -> std::size_t +auto resource_core::result::size() const -> std::size_t { return m_resources.size(); } // MARK: - Sorting -auto resource::result::sort() -> void +auto resource_core::result::sort() -> void { if (!m_finalized) { // TODO: Issue a warning @@ -84,23 +84,23 @@ auto resource::result::sort() -> void // MARK: - Look up -auto resource::result::begin() -> iterator +auto resource_core::result::begin() -> iterator { return { this, 0 }; } -auto resource::result::end() -> iterator +auto resource_core::result::end() -> iterator { return { this, std::numeric_limits::max() }; } -auto resource::result::at(std::uint64_t idx) const -> struct instance * +auto resource_core::result::at(std::uint64_t idx) const -> struct instance * { auto it = m_resources.find(m_sorted_keys.at(idx)); return (it != m_resources.end()) ? it->second : nullptr; } -auto resource::result::id(identifier id) const -> struct instance * +auto resource_core::result::id(identifier id) const -> struct instance * { for (const auto resource : m_resources) { if (resource.second->id() == id) { @@ -110,14 +110,14 @@ auto resource::result::id(identifier id) const -> struct instance * return nullptr; } -auto resource::result::resource(const std::string &type_code, identifier id) const -> struct instance * +auto resource_core::result::resource(const std::string &type_code, identifier id) const -> struct instance * { auto key = sort_key(type_code, id); auto it = m_resources.find(key); return (it != m_resources.end()) ? it->second : nullptr; } -auto resource::result::filter(const std::functionbool>& fn) const -> result +auto resource_core::result::filter(const std::functionbool>& fn) const -> result { result result; diff --git a/libs/libResource/result.hpp b/libs/libResourceCore/result.hpp similarity index 98% rename from libs/libResource/result.hpp rename to libs/libResourceCore/result.hpp index f1a66e2..4626cc4 100644 --- a/libs/libResource/result.hpp +++ b/libs/libResourceCore/result.hpp @@ -25,9 +25,9 @@ #include #include #include -#include +#include -namespace resource +namespace resource_core { struct result { diff --git a/libs/libResource/structure/attribute.cpp b/libs/libResourceCore/structure/attribute.cpp similarity index 77% rename from libs/libResource/structure/attribute.cpp rename to libs/libResourceCore/structure/attribute.cpp index 322a2b3..26f789f 100644 --- a/libs/libResource/structure/attribute.cpp +++ b/libs/libResourceCore/structure/attribute.cpp @@ -18,36 +18,36 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include +#include #include // MARK: - Construction -resource::attribute::attribute(const std::string &name, const std::string &value) +resource_core::attribute::attribute(const std::string &name, const std::string &value) : m_name(name), m_value(value) { } // MARK: - Accessors -auto resource::attribute::hash_value() const -> hash +auto resource_core::attribute::hash_value() const -> hash { return hash_for_name(m_name); } -auto resource::attribute::name() const -> const std::string& +auto resource_core::attribute::name() const -> const std::string& { return m_name; } -auto resource::attribute::string_value() const -> const std::string& +auto resource_core::attribute::string_value() const -> const std::string& { return m_value; } // MARK: - Helpers -auto resource::attribute::hash_for_name(const std::string& name) -> hash +auto resource_core::attribute::hash_for_name(const std::string& name) -> hash { return hashing::xxh64(name.c_str(), name.size()); } diff --git a/libs/libResource/structure/attribute.hpp b/libs/libResourceCore/structure/attribute.hpp similarity index 98% rename from libs/libResource/structure/attribute.hpp rename to libs/libResourceCore/structure/attribute.hpp index ff43c1c..415d764 100644 --- a/libs/libResource/structure/attribute.hpp +++ b/libs/libResourceCore/structure/attribute.hpp @@ -23,7 +23,7 @@ #include #include -namespace resource +namespace resource_core { struct attribute { diff --git a/libs/libResource/structure/instance.cpp b/libs/libResourceCore/structure/instance.cpp similarity index 65% rename from libs/libResource/structure/instance.cpp rename to libs/libResourceCore/structure/instance.cpp index 15e614b..4296bda 100644 --- a/libs/libResource/structure/instance.cpp +++ b/libs/libResourceCore/structure/instance.cpp @@ -18,22 +18,22 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include +#include +#include #include // MARK: - Construction -resource::instance::instance(identifier id, const std::string &name) +resource_core::instance::instance(resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) {} -resource::instance::instance(struct type *type, resource::identifier id, const std::string &name, data::block data) +resource_core::instance::instance(struct type *type, resource_core::identifier id, const std::string &name, data::block data) : m_type(type), m_id(id), m_name(name), m_data(std::move(data)) { } -resource::instance::instance(const instance &instance) +resource_core::instance::instance(const instance &instance) : m_type(instance.m_type), m_id(instance.m_id), m_name(instance.m_name), @@ -41,7 +41,7 @@ resource::instance::instance(const instance &instance) { } -resource::instance::instance(instance &&instance) noexcept +resource_core::instance::instance(instance &&instance) noexcept : m_type(instance.m_type), m_id(instance.m_id), m_name(std::move(instance.m_name)), @@ -52,7 +52,7 @@ resource::instance::instance(instance &&instance) noexcept // MARK: - Operators -auto resource::instance::operator=(const instance &instance) -> struct instance& +auto resource_core::instance::operator=(const instance &instance) -> struct instance& { if (this == const_cast(&instance)) { return *this; @@ -67,7 +67,7 @@ auto resource::instance::operator=(const instance &instance) -> struct instance& return *this; } -auto resource::instance::operator=(instance &&instance) noexcept -> struct instance& +auto resource_core::instance::operator=(instance &&instance) noexcept -> struct instance& { if (this != &instance) { m_id = instance.m_id; @@ -81,22 +81,22 @@ auto resource::instance::operator=(instance &&instance) noexcept -> struct insta // MARK: - Accessors -auto resource::instance::id() const -> identifier +auto resource_core::instance::id() const -> identifier { return m_id; } -auto resource::instance::type() const -> struct type * +auto resource_core::instance::type() const -> struct type * { return m_type; } -auto resource::instance::name() const -> const std::string& +auto resource_core::instance::name() const -> const std::string& { return m_name; } -auto resource::instance::type_code() const -> std::string +auto resource_core::instance::type_code() const -> std::string { if (m_type) { return m_type->code(); @@ -106,27 +106,27 @@ auto resource::instance::type_code() const -> std::string } } -auto resource::instance::data() const -> const data::block& +auto resource_core::instance::data() const -> const data::block& { return m_data; } -auto resource::instance::set_id(identifier id) -> void +auto resource_core::instance::set_id(identifier id) -> void { m_id = id; } -auto resource::instance::set_name(const std::string &name) -> void +auto resource_core::instance::set_name(const std::string &name) -> void { m_name = name; } -auto resource::instance::set_type(struct type *type) -> void +auto resource_core::instance::set_type(struct type *type) -> void { m_type = type; } -auto resource::instance::set_data(data::block& data) -> void +auto resource_core::instance::set_data(data::block& data) -> void { m_data = data; m_data_offset = 0; @@ -134,24 +134,24 @@ auto resource::instance::set_data(data::block& data) -> void // MARK: - Hashing -auto resource::instance::hash(identifier id) -> identifier_hash +auto resource_core::instance::hash(identifier id) -> identifier_hash { return hashing::xxh64(&id, sizeof(id)); } -auto resource::instance::hash(const std::string &name) -> name_hash +auto resource_core::instance::hash(const std::string &name) -> name_hash { return hashing::xxh64(name.c_str(), name.size()); } // MARK: - Data Offsets -auto resource::instance::set_data_offset(std::size_t offset) -> void +auto resource_core::instance::set_data_offset(std::size_t offset) -> void { m_data_offset = offset; } -auto resource::instance::data_offset() const -> std::size_t +auto resource_core::instance::data_offset() const -> std::size_t { return m_data_offset; } diff --git a/libs/libResource/structure/instance.hpp b/libs/libResourceCore/structure/instance.hpp similarity index 97% rename from libs/libResource/structure/instance.hpp rename to libs/libResourceCore/structure/instance.hpp index 648428e..903a502 100644 --- a/libs/libResource/structure/instance.hpp +++ b/libs/libResourceCore/structure/instance.hpp @@ -23,9 +23,9 @@ #include #include #include -#include +#include -namespace resource +namespace resource_core { struct type; diff --git a/libs/libResource/structure/type.cpp b/libs/libResourceCore/structure/type.cpp similarity index 69% rename from libs/libResource/structure/type.cpp rename to libs/libResourceCore/structure/type.cpp index 914c566..fa8258f 100644 --- a/libs/libResource/structure/type.cpp +++ b/libs/libResourceCore/structure/type.cpp @@ -18,18 +18,18 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include +#include +#include #include // MARK: - Construction -resource::type::type(const std::string &code) +resource_core::type::type(const std::string &code) : m_code(code) { } -resource::type::type(const type &type) +resource_core::type::type(const type &type) : m_code(type.m_code), m_attributes(type.m_attributes) { @@ -38,7 +38,7 @@ resource::type::type(const type &type) } } -resource::type::type(type &&type) noexcept +resource_core::type::type(type &&type) noexcept : m_code(std::move(type.m_code)), m_resources(std::move(type.m_resources)), m_resource_id_map(std::move(type.m_resource_id_map)), @@ -52,7 +52,7 @@ resource::type::type(type &&type) noexcept // MARK: - Destruction -resource::type::~type() +resource_core::type::~type() { for (auto it : m_resources) { delete it; @@ -61,7 +61,7 @@ resource::type::~type() // MARK: - Operators -auto resource::type::operator=(const type &type) -> struct type& +auto resource_core::type::operator=(const type &type) -> struct type& { if (this == const_cast(&type)) { return *this; @@ -77,7 +77,7 @@ auto resource::type::operator=(const type &type) -> struct type& return *this; } -auto resource::type::operator=(type &&type) noexcept -> struct type& +auto resource_core::type::operator=(type &&type) noexcept -> struct type& { if (this != &type) { m_code = std::move(type.m_code); @@ -95,7 +95,7 @@ auto resource::type::operator=(type &&type) noexcept -> struct type& // MARK: - Accessors -auto resource::type::attribute_string(const std::unordered_map &attributes) -> std::string +auto resource_core::type::attribute_string(const std::unordered_map &attributes) -> std::string { std::string descriptor; for (const auto& attribute : attributes) { @@ -104,12 +104,12 @@ auto resource::type::attribute_string(const std::unordered_map hash +auto resource_core::type::hash_for_type_code(const std::string &code) -> hash { return hashing::xxh64(code.c_str(), code.size()); } -auto resource::type::hash_for_type_code(const std::string &code, const std::unordered_map &attributes) -> resource::type::hash +auto resource_core::type::hash_for_type_code(const std::string &code, const std::unordered_map &attributes) -> resource_core::type::hash { std::string assembled_code { code }; if (!attributes.empty()) { @@ -118,7 +118,7 @@ auto resource::type::hash_for_type_code(const std::string &code, const std::unor return hash_for_type_code(assembled_code); } -auto resource::type::hash_value() const -> hash +auto resource_core::type::hash_value() const -> hash { std::string code { m_code }; if (!m_attributes.empty()) { @@ -127,36 +127,36 @@ auto resource::type::hash_value() const -> hash return hash_for_type_code(code); } -auto resource::type::code() const -> const std::string& +auto resource_core::type::code() const -> const std::string& { return m_code; } -auto resource::type::attributes() const -> const std::unordered_map& +auto resource_core::type::attributes() const -> const std::unordered_map& { return m_attributes; } -auto resource::type::count() const -> std::size_t +auto resource_core::type::count() const -> std::size_t { return m_resources.size(); } -auto resource::type::attribute_descriptor_string() const -> std::string +auto resource_core::type::attribute_descriptor_string() const -> std::string { return std::move(attribute_string(m_attributes)); } // MARK: - Attribute Management -auto resource::type::add_attribute(const std::string& name, const std::string& value) -> void +auto resource_core::type::add_attribute(const std::string& name, const std::string& value) -> void { attribute attr { name, value }; m_attributes.emplace(std::pair(attr.hash_value(), std::move(attr))); } template::value>::type*> -auto resource::type::add_attribute(const std::string &name, T value) -> void +auto resource_core::type::add_attribute(const std::string &name, T value) -> void { attribute attr { name, value }; m_attributes.template emplace(std::pair(attr.hash_value(), std::move(attr))); @@ -164,19 +164,19 @@ auto resource::type::add_attribute(const std::string &name, T value) -> void // MARK: - Resource Management -auto resource::type::has_resource(resource::identifier id) const -> bool +auto resource_core::type::has_resource(resource_core::identifier id) const -> bool { auto hash = hashing::xxh64(&id, sizeof(id)); return (m_resource_id_map.find(hash) != m_resource_id_map.end()); } -auto resource::type::has_resource(const std::string &name) const -> bool +auto resource_core::type::has_resource(const std::string &name) const -> bool { auto hash = hashing::xxh64(name.c_str(), name.size()); return (m_resource_name_map.find(hash) != m_resource_name_map.end()); } -auto resource::type::add_resource(instance *resource) -> void +auto resource_core::type::add_resource(instance *resource) -> void { m_resources.emplace_back(resource); resource->set_type(this); @@ -188,12 +188,12 @@ auto resource::type::add_resource(instance *resource) -> void m_resource_name_map.emplace(std::pair(name_hash, resource)); } -auto resource::type::remove_resource(identifier id) -> void +auto resource_core::type::remove_resource(resource_core::identifier id) -> void { // TODO: } -auto resource::type::resource_with_id(resource::identifier id) const -> instance * +auto resource_core::type::resource_with_id(resource_core::identifier id) const -> instance * { for (const auto& it : m_resources) { if (it->id() == id) { @@ -203,7 +203,7 @@ auto resource::type::resource_with_id(resource::identifier id) const -> instance return nullptr; } -auto resource::type::resource_with_name(const std::string &name) const -> instance * +auto resource_core::type::resource_with_name(const std::string &name) const -> instance * { for (const auto& it : m_resources) { if (it->name() == name) { @@ -213,27 +213,27 @@ auto resource::type::resource_with_name(const std::string &name) const -> instan return nullptr; } -auto resource::type::begin() -> std::vector::iterator +auto resource_core::type::begin() -> std::vector::iterator { return m_resources.begin(); } -auto resource::type::end() -> std::vector::iterator +auto resource_core::type::end() -> std::vector::iterator { return m_resources.end(); } -auto resource::type::begin() const -> std::vector::const_iterator +auto resource_core::type::begin() const -> std::vector::const_iterator { return m_resources.cbegin(); } -auto resource::type::end() const -> std::vector::const_iterator +auto resource_core::type::end() const -> std::vector::const_iterator { return m_resources.end(); } -auto resource::type::at(int64_t idx) -> instance * +auto resource_core::type::at(int64_t idx) -> instance * { if (idx < 0 || idx >= m_resources.size()) { return nullptr; diff --git a/libs/libResource/structure/type.hpp b/libs/libResourceCore/structure/type.hpp similarity index 94% rename from libs/libResource/structure/type.hpp rename to libs/libResourceCore/structure/type.hpp index 0d36e1b..f44a12e 100644 --- a/libs/libResource/structure/type.hpp +++ b/libs/libResourceCore/structure/type.hpp @@ -23,10 +23,10 @@ #include #include #include -#include -#include +#include +#include -namespace resource +namespace resource_core { struct type { @@ -66,7 +66,7 @@ namespace resource auto add_resource(instance *resource) -> void; auto remove_resource(identifier id) -> void; - [[nodiscard]] auto resource_with_id(resource::identifier id) const -> instance *; + [[nodiscard]] auto resource_with_id(identifier id) const -> instance *; [[nodiscard]] auto resource_with_name(const std::string& name) const -> instance *; auto begin() -> std::vector::iterator; diff --git a/libs/libSound/CMakeLists.txt b/libs/libSound/CMakeLists.txt index 79ea053..0792dc8 100644 --- a/libs/libSound/CMakeLists.txt +++ b/libs/libSound/CMakeLists.txt @@ -32,7 +32,7 @@ file(GLOB_RECURSE libSound_Sources ) add_library(Sound ${libSound_Sources}) -target_link_libraries(Sound SIMD Data Resource) +target_link_libraries(Sound SIMD Data ResourceCore) target_include_directories(Sound PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libSound/format/sound.cpp b/libs/libSound/format/sound.cpp index cb19928..ca6a37a 100644 --- a/libs/libSound/format/sound.cpp +++ b/libs/libSound/format/sound.cpp @@ -204,20 +204,20 @@ namespace sound::format // MARK: - Construction -sound::format::sound::sound(const data::block &data, resource::identifier id, const std::string &name) +resource_core::format::sound::sound(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -sound::format::sound::sound(data::reader &reader, resource::identifier id, const std::string &name) +resource_core::format::sound::sound(data::reader &reader, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { decode(reader); } -sound::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) +resource_core::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) { m_descriptor.sample_rate = sample_rate; m_descriptor.bit_width = sample_bits; diff --git a/libs/libSound/format/sound.hpp b/libs/libSound/format/sound.hpp index 8701455..3b2d716 100644 --- a/libs/libSound/format/sound.hpp +++ b/libs/libSound/format/sound.hpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include namespace sound::format @@ -35,8 +35,8 @@ namespace sound::format static auto type_code() -> std::string { return "snd "; } public: - explicit sound(const data::block& data, resource::identifier id = 0, const std::string& name = ""); - explicit sound(data::reader& reader, resource::identifier id = 0, const std::string& name = ""); + explicit sound(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); + explicit sound(data::reader& reader, resource_core::identifier id = 0, const std::string& name = ""); explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const data::block& sample_data); explicit sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector>& sample_data); @@ -57,7 +57,7 @@ namespace sound::format [[nodiscard]] auto format_flags() const -> std::uint32_t; private: - resource::identifier m_id { resource::default_resource_id }; + resource_core::identifier m_id { resource_core::default_resource_id }; std::string m_name; codec::descriptor m_descriptor; data::block m_samples; diff --git a/libs/libSpriteWorld/CMakeLists.txt b/libs/libSpriteWorld/CMakeLists.txt index f634c77..8bfe5f2 100644 --- a/libs/libSpriteWorld/CMakeLists.txt +++ b/libs/libSpriteWorld/CMakeLists.txt @@ -32,7 +32,7 @@ file(GLOB_RECURSE libSpriteWorld_Sources ) add_library(SpriteWorld ${libSpriteWorld_Sources}) -target_link_libraries(SpriteWorld SIMD Data Resource QuickDraw) +target_link_libraries(SpriteWorld SIMD Data ResourceCore QuickDraw) target_include_directories(SpriteWorld PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libSpriteWorld/formats/rleD.cpp b/libs/libSpriteWorld/formats/rleD.cpp index af16a92..5eaabf9 100644 --- a/libs/libSpriteWorld/formats/rleD.cpp +++ b/libs/libSpriteWorld/formats/rleD.cpp @@ -48,7 +48,7 @@ spriteworld::rleD::rleD(const quickdraw::size& size, std::uint16_t m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); } -spriteworld::rleD::rleD(const data::block& data, resource::identifier id, const std::string& name) +spriteworld::rleD::rleD(const data::block& data, resource_core::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libSpriteWorld/formats/rleD.hpp b/libs/libSpriteWorld/formats/rleD.hpp index 2d9c360..879e240 100644 --- a/libs/libSpriteWorld/formats/rleD.hpp +++ b/libs/libSpriteWorld/formats/rleD.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -36,7 +36,7 @@ namespace spriteworld public: rleD() = default; rleD(const quickdraw::size& size, std::uint16_t frame_count); - explicit rleD(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit rleD(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit rleD(data::reader& reader); ~rleD() = default; @@ -64,7 +64,7 @@ namespace spriteworld pixel_run = 0x04, }; - resource::identifier m_id { 0 }; + resource_core::identifier m_id { 0 }; std::string m_name; std::vector> m_frames; quickdraw::surface m_surface; diff --git a/libs/libSpriteWorld/formats/rleX.cpp b/libs/libSpriteWorld/formats/rleX.cpp index a3f758a..dc80a48 100644 --- a/libs/libSpriteWorld/formats/rleX.cpp +++ b/libs/libSpriteWorld/formats/rleX.cpp @@ -49,7 +49,7 @@ spriteworld::rleX::rleX(const quickdraw::size &size, std::uint16_t m_surface = quickdraw::surface(m_grid_size.width * m_frame_size.width, m_grid_size.height * m_frame_size.height); } -spriteworld::rleX::rleX(const data::block& data, resource::identifier id, const std::string& name) +spriteworld::rleX::rleX(const data::block& data, resource_core::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libSpriteWorld/formats/rleX.hpp b/libs/libSpriteWorld/formats/rleX.hpp index ea19855..8738a69 100644 --- a/libs/libSpriteWorld/formats/rleX.hpp +++ b/libs/libSpriteWorld/formats/rleX.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -40,7 +40,7 @@ namespace spriteworld public: rleX() = default; rleX(const quickdraw::size& size, std::uint16_t frame_count); - explicit rleX(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit rleX(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit rleX(data::reader& reader); ~rleX() = default; @@ -68,7 +68,7 @@ namespace spriteworld short_advance = 0x06, }; - resource::identifier m_id { 0 }; + resource_core::identifier m_id { 0 }; std::string m_name; std::vector> m_frames; quickdraw::surface m_surface; diff --git a/libs/libToolbox/CMakeLists.txt b/libs/libToolbox/CMakeLists.txt index 0d35720..cc823e0 100644 --- a/libs/libToolbox/CMakeLists.txt +++ b/libs/libToolbox/CMakeLists.txt @@ -32,7 +32,7 @@ file(GLOB_RECURSE libToolbox_Sources ) add_library(ToolBox ${libToolbox_Sources}) -target_link_libraries(ToolBox SIMD Data Resource Graphite) +target_link_libraries(ToolBox SIMD Data ResourceCore Graphite) target_include_directories(ToolBox PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libToolbox/font/fond.cpp b/libs/libToolbox/font/fond.cpp index 5cf5794..d83704f 100644 --- a/libs/libToolbox/font/fond.cpp +++ b/libs/libToolbox/font/fond.cpp @@ -23,7 +23,7 @@ // MARK: - Construction -toolbox::font::descriptor::descriptor(const data::block &data, resource::identifier id, const std::string &name) +toolbox::font::descriptor::descriptor(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libToolbox/font/fond.hpp b/libs/libToolbox/font/fond.hpp index 5799624..89297ec 100644 --- a/libs/libToolbox/font/fond.hpp +++ b/libs/libToolbox/font/fond.hpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include namespace toolbox::font { @@ -36,7 +36,7 @@ namespace toolbox::font public: descriptor() = default; - explicit descriptor(const data::block& data, resource::identifier = 0, const std::string& name = ""); + explicit descriptor(const data::block& data, resource_core::identifier = 0, const std::string& name = ""); explicit descriptor(data::reader& reader); private: @@ -67,7 +67,7 @@ namespace toolbox::font std::vector kerns; }; - resource::identifier m_id { resource::auto_resource_id }; + resource_core::identifier m_id { resource_core::auto_resource_id }; std::string m_name; bool m_fixed { false }; std::uint16_t m_family_id { 0 }; diff --git a/libs/libToolbox/font/manager.cpp b/libs/libToolbox/font/manager.cpp index 109d304..0ee2e39 100644 --- a/libs/libToolbox/font/manager.cpp +++ b/libs/libToolbox/font/manager.cpp @@ -20,9 +20,9 @@ #include #include -#include -#include -#include +#include +#include +#include // MARK: - Singleton @@ -36,7 +36,7 @@ auto toolbox::font::manager::shared_manager() -> manager & auto toolbox::font::manager::update_font_table() -> void { - auto sfnt_resources = ::resource::manager::shared_manager().find(); + auto sfnt_resources = ::resource_core::manager::shared_manager().find(); for (const auto& res : sfnt_resources) { auto font_name = res.name(); auto it = m_fonts.find(font_name); diff --git a/libs/libToolbox/font/manager.hpp b/libs/libToolbox/font/manager.hpp index 3c16961..e0149ae 100644 --- a/libs/libToolbox/font/manager.hpp +++ b/libs/libToolbox/font/manager.hpp @@ -35,7 +35,7 @@ namespace toolbox::font { std::string name; descriptor m_bitmap_descriptor; - std::unordered_map m_bitmaps; + std::unordered_map m_bitmaps; data::block ttf; }; diff --git a/libs/libToolbox/font/nfnt.cpp b/libs/libToolbox/font/nfnt.cpp index 8e70539..9b1f6a8 100644 --- a/libs/libToolbox/font/nfnt.cpp +++ b/libs/libToolbox/font/nfnt.cpp @@ -22,7 +22,7 @@ // MARK: - Construction -toolbox::font::bitmapped_font::bitmapped_font(const data::block &data, resource::identifier id, const std::string &name) +toolbox::font::bitmapped_font::bitmapped_font(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libToolbox/font/nfnt.hpp b/libs/libToolbox/font/nfnt.hpp index 094f1c2..18b37aa 100644 --- a/libs/libToolbox/font/nfnt.hpp +++ b/libs/libToolbox/font/nfnt.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include namespace toolbox::font { @@ -33,11 +33,11 @@ namespace toolbox::font public: bitmapped_font() = default; - explicit bitmapped_font(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit bitmapped_font(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit bitmapped_font(data::reader& reader); private: - resource::identifier m_id { INT64_MIN }; + resource_core::identifier m_id { resource_core::auto_resource_id }; std::string m_name; std::int16_t m_font_type { 0 }; diff --git a/libs/libToolbox/font/sfnt.cpp b/libs/libToolbox/font/sfnt.cpp index cf9c996..db0e217 100644 --- a/libs/libToolbox/font/sfnt.cpp +++ b/libs/libToolbox/font/sfnt.cpp @@ -23,7 +23,7 @@ // MARK: - Construction -toolbox::font::outline_font::outline_font(const data::block &data, resource::identifier id, const std::string &name) +toolbox::font::outline_font::outline_font(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { m_ttf = data; diff --git a/libs/libToolbox/font/sfnt.hpp b/libs/libToolbox/font/sfnt.hpp index 6a031fb..d75a56e 100644 --- a/libs/libToolbox/font/sfnt.hpp +++ b/libs/libToolbox/font/sfnt.hpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include namespace toolbox::font { @@ -36,13 +36,13 @@ namespace toolbox::font public: outline_font() = default; - explicit outline_font(const data::block& data, resource::identifier = 0, const std::string& name = ""); + explicit outline_font(const data::block& data, resource_core::identifier = 0, const std::string& name = ""); explicit outline_font(data::reader& reader); [[nodiscard]] auto ttf_data() const -> const data::block&; private: - resource::identifier m_id { resource::auto_resource_id }; + resource_core::identifier m_id { resource_core::auto_resource_id }; std::string m_name; data::block m_ttf; diff --git a/libs/libToolbox/strings/string.cpp b/libs/libToolbox/strings/string.cpp index 6784710..718c2f4 100644 --- a/libs/libToolbox/strings/string.cpp +++ b/libs/libToolbox/strings/string.cpp @@ -7,7 +7,7 @@ // MARK: - Constructor -toolbox::string::string(const data::block& data, resource::identifier id, const std::string& name) +toolbox::string::string(const data::block& data, resource_core::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libToolbox/strings/string.hpp b/libs/libToolbox/strings/string.hpp index 5a0ce8e..c61afa0 100644 --- a/libs/libToolbox/strings/string.hpp +++ b/libs/libToolbox/strings/string.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace toolbox { @@ -17,13 +17,13 @@ namespace toolbox public: string() = default; - explicit string(const data::block &data, resource::identifier id = 0, const std::string& name = ""); + explicit string(const data::block &data, resource_core::identifier id = 0, const std::string& name = ""); [[nodiscard]] auto value() const -> const std::string&; [[nodiscard]] auto data() const -> const data::block&; private: - resource::identifier m_id {}; + resource_core::identifier m_id { resource_core::auto_resource_id }; std::string m_name; std::string m_str; data::block m_data; diff --git a/libs/libToolbox/strings/string_list.cpp b/libs/libToolbox/strings/string_list.cpp index 0b9100d..47f564e 100644 --- a/libs/libToolbox/strings/string_list.cpp +++ b/libs/libToolbox/strings/string_list.cpp @@ -23,7 +23,7 @@ // MARK: - Construction -toolbox::string_list::string_list(const data::block &data, resource::identifier id, const std::string& name) +toolbox::string_list::string_list(const data::block &data, resource_core::identifier id, const std::string& name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libToolbox/strings/string_list.hpp b/libs/libToolbox/strings/string_list.hpp index e73ae31..ab9155b 100644 --- a/libs/libToolbox/strings/string_list.hpp +++ b/libs/libToolbox/strings/string_list.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace toolbox { @@ -36,7 +36,7 @@ namespace toolbox public: string_list() = default; - explicit string_list(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit string_list(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); [[nodiscard]] auto string_count() const -> std::size_t; [[nodiscard]] auto at(std::uint32_t idx) const -> std::string; @@ -45,7 +45,7 @@ namespace toolbox auto end() noexcept -> iterator; private: - resource::identifier m_id { 0 }; + resource_core::identifier m_id { 0 }; std::string m_name; std::vector m_strings; diff --git a/libs/libToolbox/ui/dialog.cpp b/libs/libToolbox/ui/dialog.cpp index 3b7412a..46e26f9 100644 --- a/libs/libToolbox/ui/dialog.cpp +++ b/libs/libToolbox/ui/dialog.cpp @@ -23,7 +23,7 @@ // MARK: - Construction -toolbox::dialog::dialog(const data::block &data, resource::identifier id, const std::string &name) +toolbox::dialog::dialog(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); @@ -62,7 +62,7 @@ auto toolbox::dialog::ref_con() const -> std::int32_t return m_ref_con; } -auto toolbox::dialog::interface_list() const -> resource::identifier +auto toolbox::dialog::interface_list() const -> resource_core::identifier { return m_ditl_id; } @@ -102,7 +102,7 @@ auto toolbox::dialog::set_ref_con(std::int32_t ref_con) -> void m_ref_con = ref_con; } -auto toolbox::dialog::set_interface_list(resource::identifier id) -> void +auto toolbox::dialog::set_interface_list(resource_core::identifier id) -> void { m_ditl_id = id; } diff --git a/libs/libToolbox/ui/dialog.hpp b/libs/libToolbox/ui/dialog.hpp index ae6fb9b..c5c1e01 100644 --- a/libs/libToolbox/ui/dialog.hpp +++ b/libs/libToolbox/ui/dialog.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include namespace toolbox @@ -35,7 +35,7 @@ namespace toolbox public: dialog() = default; - explicit dialog(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit dialog(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit dialog(data::reader& reader); [[nodiscard]] auto bounds() const -> quickdraw::rect; @@ -43,7 +43,7 @@ namespace toolbox [[nodiscard]] auto visible() const -> bool; [[nodiscard]] auto go_away() const -> bool; [[nodiscard]] auto ref_con() const -> std::int32_t; - [[nodiscard]] auto interface_list() const -> resource::identifier; + [[nodiscard]] auto interface_list() const -> resource_core::identifier; [[nodiscard]] auto auto_position() const -> std::uint16_t; [[nodiscard]] auto title() const -> std::string; @@ -52,7 +52,7 @@ namespace toolbox auto set_visible(bool visible) -> void; auto set_go_away(bool go_away) -> void; auto set_ref_con(std::int32_t ref_con) -> void; - auto set_interface_list(resource::identifier id) -> void; + auto set_interface_list(resource_core::identifier id) -> void; auto set_auto_position(std::uint16_t position) -> void; auto set_title(const std::string& title) -> void; @@ -60,7 +60,7 @@ namespace toolbox auto data() -> data::block; private: - resource::identifier m_id { resource::auto_resource_id }; + resource_core::identifier m_id { resource_core::auto_resource_id }; std::string m_name; std::string m_title; quickdraw::rect m_bounds; @@ -68,7 +68,7 @@ namespace toolbox bool m_visible { true }; bool m_go_away { true }; std::int32_t m_ref_con { 0 }; - resource::identifier m_ditl_id { 0 }; + resource_core::identifier m_ditl_id { 0 }; std::uint16_t m_auto_position { 0 }; auto decode(data::reader& reader) -> void; diff --git a/libs/libToolbox/ui/dialog_item_list.cpp b/libs/libToolbox/ui/dialog_item_list.cpp index d560780..00a56e0 100644 --- a/libs/libToolbox/ui/dialog_item_list.cpp +++ b/libs/libToolbox/ui/dialog_item_list.cpp @@ -23,7 +23,7 @@ // MARK: - Construction -toolbox::dialog_item_list::dialog_item_list(const data::block &data, resource::identifier id, const std::string &name) +toolbox::dialog_item_list::dialog_item_list(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); diff --git a/libs/libToolbox/ui/dialog_item_list.hpp b/libs/libToolbox/ui/dialog_item_list.hpp index d8eeabe..37414af 100644 --- a/libs/libToolbox/ui/dialog_item_list.hpp +++ b/libs/libToolbox/ui/dialog_item_list.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include namespace toolbox @@ -57,7 +57,7 @@ namespace toolbox public: dialog_item_list() = default; - explicit dialog_item_list(const data::block& data, resource::identifier id = 0, const std::string& name = ""); + explicit dialog_item_list(const data::block& data, resource_core::identifier id = 0, const std::string& name = ""); explicit dialog_item_list(data::reader& reader); auto encode(data::writer& writer) -> void; @@ -70,7 +70,7 @@ namespace toolbox auto end() -> std::vector::iterator { return m_items.end(); } private: - resource::identifier m_id { INT64_MIN }; + resource_core::identifier m_id { resource_core::auto_resource_id }; std::string m_name; std::vector m_items; From 9bb096195a66a481ec9959f2e27f3d07c7ab983c Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 13:41:09 +0100 Subject: [PATCH 102/113] Rename libSound to libSoundCore --- CMakeLists.txt | 2 +- .../{libSound => libSoundCore}/CMakeLists.txt | 8 ++-- .../codec/descriptor.hpp | 2 +- .../codec/ima4/ima4.cpp | 12 ++--- .../codec/ima4/ima4.hpp | 4 +- .../format/sound.cpp | 46 +++++++++---------- .../format/sound.hpp | 4 +- 7 files changed, 39 insertions(+), 39 deletions(-) rename libs/{libSound => libSoundCore}/CMakeLists.txt (89%) rename libs/{libSound => libSoundCore}/codec/descriptor.hpp (98%) rename libs/{libSound => libSoundCore}/codec/ima4/ima4.cpp (91%) rename libs/{libSound => libSoundCore}/codec/ima4/ima4.hpp (95%) rename libs/{libSound => libSoundCore}/format/sound.cpp (89%) rename libs/{libSound => libSoundCore}/format/sound.hpp (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d479488..732b157 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ add_subdirectory(${PROJECT_LIBS_DIR}/libEncoding) add_subdirectory(${PROJECT_LIBS_DIR}/libData) add_subdirectory(${PROJECT_LIBS_DIR}/libResourceCore) add_subdirectory(${PROJECT_LIBS_DIR}/libQuickdraw) -add_subdirectory(${PROJECT_LIBS_DIR}/libSound) +add_subdirectory(${PROJECT_LIBS_DIR}/libSoundCore) add_subdirectory(${PROJECT_LIBS_DIR}/libToolbox) ######################################################################################################################## diff --git a/libs/libSound/CMakeLists.txt b/libs/libSoundCore/CMakeLists.txt similarity index 89% rename from libs/libSound/CMakeLists.txt rename to libs/libSoundCore/CMakeLists.txt index 0792dc8..58e6957 100644 --- a/libs/libSound/CMakeLists.txt +++ b/libs/libSoundCore/CMakeLists.txt @@ -27,12 +27,12 @@ set(CMAKE_CXX_STANDARD 20) ######################################################################################################################## ## libSIMD -file(GLOB_RECURSE libSound_Sources +file(GLOB_RECURSE libSoundCore_Sources *.cpp ) -add_library(Sound ${libSound_Sources}) -target_link_libraries(Sound SIMD Data ResourceCore) -target_include_directories(Sound PUBLIC +add_library(SoundCore ${libSoundCore_Sources}) +target_link_libraries(SoundCore SIMD Data ResourceCore) +target_include_directories(SoundCore PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libSound/codec/descriptor.hpp b/libs/libSoundCore/codec/descriptor.hpp similarity index 98% rename from libs/libSound/codec/descriptor.hpp rename to libs/libSoundCore/codec/descriptor.hpp index 0fab2fb..3d6e9b0 100644 --- a/libs/libSound/codec/descriptor.hpp +++ b/libs/libSoundCore/codec/descriptor.hpp @@ -22,7 +22,7 @@ #include -namespace sound::codec +namespace sound_core::codec { struct descriptor { diff --git a/libs/libSound/codec/ima4/ima4.cpp b/libs/libSoundCore/codec/ima4/ima4.cpp similarity index 91% rename from libs/libSound/codec/ima4/ima4.cpp rename to libs/libSoundCore/codec/ima4/ima4.cpp index da36586..4eab87e 100644 --- a/libs/libSound/codec/ima4/ima4.cpp +++ b/libs/libSoundCore/codec/ima4/ima4.cpp @@ -19,12 +19,12 @@ // SOFTWARE. #include -#include +#include #include // MARK: - Look Up Tables -namespace sound::codec::ima4::lut +namespace sound_core::codec::ima4::lut { constexpr std::int8_t index_table[16] = { -1, -1, -1, -1, 2, 4, 6, 8, @@ -46,14 +46,14 @@ namespace sound::codec::ima4::lut // MARK: - Construction -sound::codec::ima4::sound::sound(const codec::descriptor &descriptor, data::reader &reader) +sound_core::codec::ima4::sound::sound(const codec::descriptor &descriptor, data::reader &reader) { decode(descriptor, reader); } // MARK: - Decoder -auto sound::codec::ima4::sound::decode(const codec::descriptor &descriptor, data::reader &reader) -> void +auto sound_core::codec::ima4::sound::decode(const codec::descriptor &descriptor, data::reader &reader) -> void { // TODO: This is relying on hard-coded constants and really shouldn't. // Determine the best way to calculate these values in the future. @@ -122,12 +122,12 @@ auto sound::codec::ima4::sound::decode(const codec::descriptor &descriptor, data // MARK: - Accessors -auto sound::codec::ima4::sound::samples() const -> const data::block& +auto sound_core::codec::ima4::sound::samples() const -> const data::block& { return m_samples; } -auto sound::codec::ima4::sound::descriptor() const -> const codec::descriptor & +auto sound_core::codec::ima4::sound::descriptor() const -> const codec::descriptor & { return m_descriptor; } \ No newline at end of file diff --git a/libs/libSound/codec/ima4/ima4.hpp b/libs/libSoundCore/codec/ima4/ima4.hpp similarity index 95% rename from libs/libSound/codec/ima4/ima4.hpp rename to libs/libSoundCore/codec/ima4/ima4.hpp index 159c2a4..1336cde 100644 --- a/libs/libSound/codec/ima4/ima4.hpp +++ b/libs/libSoundCore/codec/ima4/ima4.hpp @@ -21,9 +21,9 @@ #pragma once #include -#include +#include -namespace sound::codec::ima4 +namespace sound_core::codec::ima4 { struct sound { diff --git a/libs/libSound/format/sound.cpp b/libs/libSoundCore/format/sound.cpp similarity index 89% rename from libs/libSound/format/sound.cpp rename to libs/libSoundCore/format/sound.cpp index ca6a37a..0ec593f 100644 --- a/libs/libSound/format/sound.cpp +++ b/libs/libSoundCore/format/sound.cpp @@ -20,13 +20,13 @@ #include #include -#include -#include -#include +#include +#include +#include // MARK: - Constants / Enumerations -namespace sound::format +namespace sound_core::format { enum bitrate : std::uint32_t { @@ -131,7 +131,7 @@ namespace sound::format // MARK: - Internal Helper Types -namespace sound::format +namespace sound_core::format { struct sound_command { @@ -204,20 +204,20 @@ namespace sound::format // MARK: - Construction -resource_core::format::sound::sound(const data::block &data, resource_core::identifier id, const std::string &name) +sound_core::format::sound::sound(const data::block &data, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { data::reader reader(&data); decode(reader); } -resource_core::format::sound::sound(data::reader &reader, resource_core::identifier id, const std::string &name) +sound_core::format::sound::sound(data::reader &reader, resource_core::identifier id, const std::string &name) : m_id(id), m_name(name) { decode(reader); } -resource_core::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) +sound_core::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const std::vector> &sample_data) { m_descriptor.sample_rate = sample_rate; m_descriptor.bit_width = sample_bits; @@ -241,7 +241,7 @@ resource_core::format::sound::sound(std::uint32_t sample_rate, std::uint8_t samp m_samples = std::move(*const_cast(writer.data())); } -sound::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const data::block& sample_data) +sound_core::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, const data::block& sample_data) { m_descriptor.sample_rate = sample_rate; m_descriptor.bit_width = sample_bits; @@ -250,7 +250,7 @@ sound::format::sound::sound(std::uint32_t sample_rate, std::uint8_t sample_bits, // MARK: - Decoding -auto sound::format::sound::decode(data::reader &reader) -> void +auto sound_core::format::sound::decode(data::reader &reader) -> void { auto sound_format = reader.read_signed_short(); @@ -405,71 +405,71 @@ auto sound::format::sound::decode(data::reader &reader) -> void // MARK: - Accessors -auto sound::format::sound::samples() const -> const data::block& +auto sound_core::format::sound::samples() const -> const data::block& { return m_samples; } -auto sound::format::sound::codec_descriptor() const -> const codec::descriptor& +auto sound_core::format::sound::codec_descriptor() const -> const codec::descriptor& { return m_descriptor; } -auto sound::format::sound::sample_rate() const -> std::uint32_t +auto sound_core::format::sound::sample_rate() const -> std::uint32_t { return m_descriptor.sample_rate; } -auto sound::format::sound::channels() const -> std::uint16_t +auto sound_core::format::sound::channels() const -> std::uint16_t { return m_descriptor.channels; } -auto sound::format::sound::bit_width() const -> std::uint8_t +auto sound_core::format::sound::bit_width() const -> std::uint8_t { return m_descriptor.bit_width; } -auto sound::format::sound::bytes_per_frame() const -> std::uint32_t +auto sound_core::format::sound::bytes_per_frame() const -> std::uint32_t { return m_descriptor.bytes_per_frame; } -auto sound::format::sound::frames_per_packet() const -> std::uint32_t +auto sound_core::format::sound::frames_per_packet() const -> std::uint32_t { return m_descriptor.frames_per_packet; } -auto sound::format::sound::bytes_per_packet() const -> std::uint32_t +auto sound_core::format::sound::bytes_per_packet() const -> std::uint32_t { return m_descriptor.bytes_per_packet; } -auto sound::format::sound::packet_count() const -> std::uint32_t +auto sound_core::format::sound::packet_count() const -> std::uint32_t { return m_descriptor.packet_count; } -auto sound::format::sound::format_id() const -> std::uint32_t +auto sound_core::format::sound::format_id() const -> std::uint32_t { return m_descriptor.format_id; } -auto sound::format::sound::format_flags() const -> std::uint32_t +auto sound_core::format::sound::format_flags() const -> std::uint32_t { return m_descriptor.format_flags; } // MARK: - Decoding -auto sound::format::sound::data() -> data::block +auto sound_core::format::sound::data() -> data::block { data::writer writer; encode(writer); return std::move(*const_cast(writer.data())); } -auto sound::format::sound::encode(data::writer &writer) -> void +auto sound_core::format::sound::encode(data::writer &writer) -> void { // TODO: Implement this... } \ No newline at end of file diff --git a/libs/libSound/format/sound.hpp b/libs/libSoundCore/format/sound.hpp similarity index 97% rename from libs/libSound/format/sound.hpp rename to libs/libSoundCore/format/sound.hpp index 3b2d716..76ecad0 100644 --- a/libs/libSound/format/sound.hpp +++ b/libs/libSoundCore/format/sound.hpp @@ -25,9 +25,9 @@ #include #include #include -#include +#include -namespace sound::format +namespace sound_core::format { struct sound { From e185285cb9cb3cb6d1eddc33776c40c9dbb96799 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 14:04:52 +0100 Subject: [PATCH 103/113] Fix includes on Windows --- CMakeLists.txt | 5 +++-- libs/libResourceCore/structure/attribute.hpp | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 732b157..e4ff374 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,5 +46,6 @@ add_subdirectory(${PROJECT_LIBS_DIR}/libToolbox) ######################################################################################################################## enable_testing() -add_subdirectory(tests) - +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + add_subdirectory(tests) +endif() \ No newline at end of file diff --git a/libs/libResourceCore/structure/attribute.hpp b/libs/libResourceCore/structure/attribute.hpp index 415d764..6c65bf7 100644 --- a/libs/libResourceCore/structure/attribute.hpp +++ b/libs/libResourceCore/structure/attribute.hpp @@ -20,6 +20,8 @@ #pragma once +#include +#include #include #include From 5ad5878f2804b9f760416973ee0f787adcfa381f Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Fri, 2 Jun 2023 19:52:52 +0100 Subject: [PATCH 104/113] Fix several issues found when compiling Kestrel. --- CMakeLists.txt | 1 + libs/libSIMD/intel/intel_sse.hpp | 8 ++++---- libs/libToolbox/CMakeLists.txt | 2 +- libs/libToolbox/font/manager.cpp | 4 ++++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4ff374..6cfdc45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ add_subdirectory(${PROJECT_LIBS_DIR}/libData) add_subdirectory(${PROJECT_LIBS_DIR}/libResourceCore) add_subdirectory(${PROJECT_LIBS_DIR}/libQuickdraw) add_subdirectory(${PROJECT_LIBS_DIR}/libSoundCore) +add_subdirectory(${PROJECT_LIBS_DIR}/libSpriteWorld) add_subdirectory(${PROJECT_LIBS_DIR}/libToolbox) ######################################################################################################################## diff --git a/libs/libSIMD/intel/intel_sse.hpp b/libs/libSIMD/intel/intel_sse.hpp index 44a0728..0cc324a 100644 --- a/libs/libSIMD/intel/intel_sse.hpp +++ b/libs/libSIMD/intel/intel_sse.hpp @@ -22,6 +22,7 @@ #if (__x86_64__) #include +#include #include #include @@ -29,7 +30,6 @@ typedef __m128_u f32x4; // MARK: - Hints - namespace simd { @@ -126,7 +126,7 @@ namespace simd else { f32x4 v = a; for (auto i = 0; i < 4; ++i) { - v[i] = std::powf(v[i], exp); + v[i] = ::powf(v[i], exp); } return v; } @@ -146,7 +146,7 @@ namespace simd { f32x4 v = a; for (auto i = 0; i < 4; ++i) { - v[i] = std::sinf(v[i]); + v[i] = ::sinf(v[i]); } return v; } @@ -155,7 +155,7 @@ namespace simd { f32x4 v = a; for (auto i = 0; i < 4; ++i) { - v[i] = std::cosf(v[i]); + v[i] = ::cosf(v[i]); } return v; } diff --git a/libs/libToolbox/CMakeLists.txt b/libs/libToolbox/CMakeLists.txt index cc823e0..156c14a 100644 --- a/libs/libToolbox/CMakeLists.txt +++ b/libs/libToolbox/CMakeLists.txt @@ -32,7 +32,7 @@ file(GLOB_RECURSE libToolbox_Sources ) add_library(ToolBox ${libToolbox_Sources}) -target_link_libraries(ToolBox SIMD Data ResourceCore Graphite) +target_link_libraries(ToolBox SIMD Data ResourceCore) target_include_directories(ToolBox PUBLIC ${PROJECT_LIBS_DIR} ) diff --git a/libs/libToolbox/font/manager.cpp b/libs/libToolbox/font/manager.cpp index 0ee2e39..479b6b8 100644 --- a/libs/libToolbox/font/manager.cpp +++ b/libs/libToolbox/font/manager.cpp @@ -37,6 +37,10 @@ auto toolbox::font::manager::shared_manager() -> manager & auto toolbox::font::manager::update_font_table() -> void { auto sfnt_resources = ::resource_core::manager::shared_manager().find(); + if (sfnt_resources.size() == 0) { + return; + } + for (const auto& res : sfnt_resources) { auto font_name = res.name(); auto it = m_fonts.find(font_name); From f24f24c3fc3ee0b43c0a4c55f0fab4691efcc56c Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 16 Aug 2023 13:11:03 +1200 Subject: [PATCH 105/113] Add RSRX signature to extended format --- libs/libResourceCore/format/extended/parser.cpp | 13 ++++++++++++- libs/libResourceCore/format/extended/writer.cpp | 6 ++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/libs/libResourceCore/format/extended/parser.cpp b/libs/libResourceCore/format/extended/parser.cpp index 16bad69..d79b782 100644 --- a/libs/libResourceCore/format/extended/parser.cpp +++ b/libs/libResourceCore/format/extended/parser.cpp @@ -26,6 +26,14 @@ #include #include +// MARK: - Constants + +namespace resource_core::format::extended::constants::defaults +{ + constexpr std::uint32_t signature = 'RSRX'; + constexpr std::uint32_t version = 1; +} + // MARK: - Parsing auto resource_core::format::extended::parse(data::reader &reader, file &file) -> bool @@ -33,7 +41,10 @@ auto resource_core::format::extended::parse(data::reader &reader, file &file) -> std::vector types; // 1. Resource Preamble - if (reader.read_quad(0, data::reader::mode::peek) != 1) { + if (reader.read_long(0, data::reader::mode::peek) != constants::defaults::signature) { + return false; + } + if (reader.read_long(4, data::reader::mode::peek) != constants::defaults::version) { return false; } diff --git a/libs/libResourceCore/format/extended/writer.cpp b/libs/libResourceCore/format/extended/writer.cpp index ff9110e..2be4c3f 100644 --- a/libs/libResourceCore/format/extended/writer.cpp +++ b/libs/libResourceCore/format/extended/writer.cpp @@ -30,7 +30,8 @@ namespace resource_core::format::extended::constants::defaults { - constexpr std::uint64_t version = 1; + constexpr std::uint32_t signature = 'RSRX'; + constexpr std::uint32_t version = 1; constexpr std::uint64_t data_offset = 256; constexpr std::uint64_t map_offset = 0; constexpr std::uint64_t data_length = 0; @@ -61,7 +62,8 @@ auto resource_core::format::extended::write(file &file, const std::string &path) auto data_length = constants::defaults::data_length; auto map_length = constants::defaults::map_length; - writer.write_quad(constants::defaults::version); + writer.write_long(constants::defaults::signature); + writer.write_long(constants::defaults::version); writer.write_quad(data_offset); writer.write_quad(map_offset); writer.write_quad(data_length); From 3f4a6f166bc9baed495fb4a7ca426e4837a4d928 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 28 Aug 2023 09:25:30 +0100 Subject: [PATCH 106/113] Update CMakeLists minimum versions --- libs/libData/CMakeLists.txt | 2 +- libs/libEncoding/CMakeLists.txt | 2 +- libs/libHashing/CMakeLists.txt | 2 +- libs/libQuickdraw/CMakeLists.txt | 2 +- libs/libResourceCore/CMakeLists.txt | 2 +- libs/libSIMD/CMakeLists.txt | 2 +- libs/libSoundCore/CMakeLists.txt | 2 +- libs/libSpriteWorld/CMakeLists.txt | 2 +- libs/libToolbox/CMakeLists.txt | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/libData/CMakeLists.txt b/libs/libData/CMakeLists.txt index b0aef14..0f2c61d 100644 --- a/libs/libData/CMakeLists.txt +++ b/libs/libData/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libEncoding/CMakeLists.txt b/libs/libEncoding/CMakeLists.txt index 1f21de6..81298c5 100644 --- a/libs/libEncoding/CMakeLists.txt +++ b/libs/libEncoding/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libHashing/CMakeLists.txt b/libs/libHashing/CMakeLists.txt index 2bc5af1..78c2652 100644 --- a/libs/libHashing/CMakeLists.txt +++ b/libs/libHashing/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libQuickdraw/CMakeLists.txt b/libs/libQuickdraw/CMakeLists.txt index 9bab936..baa51d1 100644 --- a/libs/libQuickdraw/CMakeLists.txt +++ b/libs/libQuickdraw/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libResourceCore/CMakeLists.txt b/libs/libResourceCore/CMakeLists.txt index e8545dc..61506e8 100644 --- a/libs/libResourceCore/CMakeLists.txt +++ b/libs/libResourceCore/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libSIMD/CMakeLists.txt b/libs/libSIMD/CMakeLists.txt index 0aebbdd..084e705 100644 --- a/libs/libSIMD/CMakeLists.txt +++ b/libs/libSIMD/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libSoundCore/CMakeLists.txt b/libs/libSoundCore/CMakeLists.txt index 58e6957..26c1217 100644 --- a/libs/libSoundCore/CMakeLists.txt +++ b/libs/libSoundCore/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libSpriteWorld/CMakeLists.txt b/libs/libSpriteWorld/CMakeLists.txt index 8bfe5f2..9908e39 100644 --- a/libs/libSpriteWorld/CMakeLists.txt +++ b/libs/libSpriteWorld/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project diff --git a/libs/libToolbox/CMakeLists.txt b/libs/libToolbox/CMakeLists.txt index 156c14a..ced17e4 100644 --- a/libs/libToolbox/CMakeLists.txt +++ b/libs/libToolbox/CMakeLists.txt @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) ######################################################################################################################## ## Project From d4ee6cf9ede8d0308fe7d3283774d599a95fef0e Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 30 Aug 2023 19:57:31 +0100 Subject: [PATCH 107/113] Fixes for compiler warnings --- libs/libData/writer.hpp | 4 ++-- libs/libQuickdraw/color/color.cpp | 10 ++++++---- libs/libSIMD/string.hpp | 1 + libs/libSpriteWorld/formats/rleX.cpp | 20 ++++++++++++-------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/libs/libData/writer.hpp b/libs/libData/writer.hpp index 9473957..6a67bc1 100644 --- a/libs/libData/writer.hpp +++ b/libs/libData/writer.hpp @@ -124,7 +124,7 @@ namespace data template::value>::type* = nullptr> auto write_integer(T value, std::size_t count = 1, std::size_t size = sizeof(T)) -> void { - auto swapped = swap(value, native_byte_order(), m_data->byte_order()); + std::uint64_t swapped = swap(value, native_byte_order(), m_data->byte_order()); ensure_required_space(position(), size * count); auto ptr = m_data->template get(position()); @@ -148,7 +148,7 @@ namespace data } } - move(size * count); + move(static_cast(size * count)); } template::value>::type* = nullptr> diff --git a/libs/libQuickdraw/color/color.cpp b/libs/libQuickdraw/color/color.cpp index 4f442fe..fc6a1d0 100644 --- a/libs/libQuickdraw/color/color.cpp +++ b/libs/libQuickdraw/color/color.cpp @@ -84,10 +84,12 @@ auto quickdraw::ycbcr(const union color& rgb) -> union ycbcr std::uint8_t cr_clamped = std::clamp(cr, 0, 255); return (union ycbcr) { - .components.y = y_clamped, - .components.cb = cb_clamped, - .components.cr = cr_clamped, - .components.alpha = rgb.components.alpha + .components = { + .y = y_clamped, + .cb = cb_clamped, + .cr = cr_clamped, + .alpha = rgb.components.alpha + }, }; } diff --git a/libs/libSIMD/string.hpp b/libs/libSIMD/string.hpp index f6e6490..db729de 100644 --- a/libs/libSIMD/string.hpp +++ b/libs/libSIMD/string.hpp @@ -33,6 +33,7 @@ namespace simd::string { #if !USE_TARGET_MEMORY_FUNCTIONS // TODO: Implement + return src; #else return reinterpret_cast(::memcpy(dst, src, n)); #endif diff --git a/libs/libSpriteWorld/formats/rleX.cpp b/libs/libSpriteWorld/formats/rleX.cpp index dc80a48..06439cc 100644 --- a/libs/libSpriteWorld/formats/rleX.cpp +++ b/libs/libSpriteWorld/formats/rleX.cpp @@ -338,10 +338,12 @@ auto spriteworld::rleX::decode(data::reader &reader) -> void auto frame = frame_rect(0); union quickdraw::ycbcr yuv { - .components.y = 0, - .components.cb = 128, - .components.cr = 128, - .components.alpha = 255 + .components = { + .y = 0, + .cb = 128, + .cr = 128, + .alpha = 255 + }, }; // NOTE: This is a very _hot_ code path and thus we need to squeeze out as much performance as possible. @@ -396,10 +398,12 @@ auto spriteworld::rleX::encode(data::writer &writer) -> void auto frame = frame_rect(f); union quickdraw::ycbcr yuv { - .components.y = 0, - .components.cb = 128, - .components.cr = 128, - .components.alpha = 255 + .components = { + .y = 0, + .cb = 128, + .cr = 128, + .alpha = 255 + }, }; std::uint32_t count = 0; From c41ddf4568dc45e6b2646c8a5971e7d472903f1b Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Thu, 31 Aug 2023 20:48:42 +0100 Subject: [PATCH 108/113] ARM NEON fix --- libs/libSIMD/arm/arm_neon.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/libSIMD/arm/arm_neon.hpp b/libs/libSIMD/arm/arm_neon.hpp index a181b47..3feee68 100644 --- a/libs/libSIMD/arm/arm_neon.hpp +++ b/libs/libSIMD/arm/arm_neon.hpp @@ -145,7 +145,7 @@ namespace simd return vmulq_f32(a, a); } else { - vector_float4 v = a; + f32x4 v = a; for (auto i = 0; i < 4; ++i) { v[i] = std::powf(v[i], exp); } @@ -168,7 +168,7 @@ namespace simd SIMD_FUNCTION static inline auto sin(f32x4 a) -> f32x4 { - vector_float4 v = a; + f32x4 v = a; for (auto i = 0; i < 4; ++i) { v[i] = std::sinf(v[i]); } @@ -178,7 +178,7 @@ namespace simd SIMD_FUNCTION static inline auto cos(f32x4 a) -> f32x4 { - vector_float4 v = a; + f32x4 v = a; for (auto i = 0; i < 4; ++i) { v[i] = std::cosf(v[i]); } @@ -204,7 +204,6 @@ namespace simd { return vmaxq_f32(a, b); } - } #endif \ No newline at end of file From a037cde02e822624f7973316359f1a3807724dba Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 2 Sep 2023 20:31:51 +0100 Subject: [PATCH 109/113] Fix ARM NEON round function --- libs/libSIMD/arm/arm_neon.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/libSIMD/arm/arm_neon.hpp b/libs/libSIMD/arm/arm_neon.hpp index 3feee68..bef48e0 100644 --- a/libs/libSIMD/arm/arm_neon.hpp +++ b/libs/libSIMD/arm/arm_neon.hpp @@ -121,8 +121,10 @@ namespace simd SIMD_FUNCTION static inline auto round(f32x4 a) -> f32x4 { - auto r = vaddq_f32(a, vdupq_n_f32(0.5f)); - return vreinterpretq_f32_s32(vreinterpretq_s32_f32(r)); + auto r = vcvtq_n_s32_f32(a, 1); + r = vsraq_n_s32(r, r, 31); + r = vrshrq_n_s32(r, 1); + return vcvtq_f32_s32(r); } SIMD_FUNCTION From a617885118394849acd157b0822eb6bff3584650 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Mon, 25 Sep 2023 20:19:20 +0100 Subject: [PATCH 110/113] Fix issue with ARM NEON functions --- libs/libSIMD/arm/arm_neon.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/libSIMD/arm/arm_neon.hpp b/libs/libSIMD/arm/arm_neon.hpp index bef48e0..c679b60 100644 --- a/libs/libSIMD/arm/arm_neon.hpp +++ b/libs/libSIMD/arm/arm_neon.hpp @@ -67,13 +67,13 @@ namespace simd SIMD_FUNCTION static inline auto vector_slice_lower(f32x4 a) -> f32x4 { - return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_low_f32(a))); + return vcombine_f32(vget_low_f32(a), vget_low_f32(a)); } SIMD_FUNCTION static inline auto vector_slice_upper(f32x4 a) -> f32x4 { - return vcombine_f32(vrev64_f32(vget_high_f32(a)), vrev64_f32(vget_high_f32(a))); + return vcombine_f32(vget_high_f32(a), vget_high_f32(a)); } SIMD_FUNCTION From 3618f7edeca155881963a481789846475ee25043 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Wed, 27 Sep 2023 16:49:13 +0100 Subject: [PATCH 111/113] Fix type issue that causes incorrect writing of integers --- libs/libData/writer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libData/writer.hpp b/libs/libData/writer.hpp index 6a67bc1..3a4b7b5 100644 --- a/libs/libData/writer.hpp +++ b/libs/libData/writer.hpp @@ -124,7 +124,7 @@ namespace data template::value>::type* = nullptr> auto write_integer(T value, std::size_t count = 1, std::size_t size = sizeof(T)) -> void { - std::uint64_t swapped = swap(value, native_byte_order(), m_data->byte_order()); + T swapped = swap(value, native_byte_order(), m_data->byte_order()); ensure_required_space(position(), size * count); auto ptr = m_data->template get(position()); From 867399a52673483cbb39972e7bb6866a46d915c1 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Sat, 28 Oct 2023 19:00:53 +0100 Subject: [PATCH 112/113] Some small SIMD fixes --- libs/libSIMD/arm/arm_neon.hpp | 2 +- libs/libSIMD/float32.hpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/libSIMD/arm/arm_neon.hpp b/libs/libSIMD/arm/arm_neon.hpp index c679b60..538d567 100644 --- a/libs/libSIMD/arm/arm_neon.hpp +++ b/libs/libSIMD/arm/arm_neon.hpp @@ -130,7 +130,7 @@ namespace simd SIMD_FUNCTION static inline auto floor(f32x4 a) -> f32x4 { - return vreinterpretq_f32_s32(vreinterpretq_s32_f32(a)); + return vrndmq_f32(a); } SIMD_FUNCTION diff --git a/libs/libSIMD/float32.hpp b/libs/libSIMD/float32.hpp index f1f20a4..6696c80 100644 --- a/libs/libSIMD/float32.hpp +++ b/libs/libSIMD/float32.hpp @@ -65,6 +65,14 @@ namespace simd inline auto set(int i, float v) -> float32& { m_values[i] = v; return *this; } // MARK: - Operators + inline auto operator==(const float32& other) const -> bool + { + return (m_values[0] == other.m_values[0]) + && (m_values[1] == other.m_values[1]) + && (m_values[2] == other.m_values[2]) + && (m_values[3] == other.m_values[3]); + } + inline auto operator+ (const float32& other) const -> float32 { return float32(simd::add(m_values, other.m_values)); } inline auto operator+ (float f) const -> float32 { return float32(simd::add(m_values, simd::single_value_vector(f))); } inline auto operator+=(const float32& other) -> float32& { m_values = simd::add(m_values, other.m_values); return *this; } From db5c1a5acd4828604db864ef9269ce03a9d8adf0 Mon Sep 17 00:00:00 2001 From: Tom Hancocks Date: Tue, 31 Oct 2023 21:59:33 +0000 Subject: [PATCH 113/113] Fix issue in ARM NEON --- libs/libSIMD/arm/arm_neon.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libSIMD/arm/arm_neon.hpp b/libs/libSIMD/arm/arm_neon.hpp index 538d567..53f106d 100644 --- a/libs/libSIMD/arm/arm_neon.hpp +++ b/libs/libSIMD/arm/arm_neon.hpp @@ -61,7 +61,7 @@ namespace simd SIMD_FUNCTION static inline auto vector_shuffle_lower_higher(f32x4 a, f32x4 b) -> f32x4 { - return vcombine_f32(vget_high_f32(b), vget_low_f32(a)); + return vcombine_f32(vget_low_f32(a), vget_high_f32(b)); } SIMD_FUNCTION