added first selectable, and modyfiable assets to system, Mesh, Material, and Texture. Texture ist WIP, because no subassets are created jet, well technicaly everything is WIP bit nevermind XD
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,187 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <map> // map
|
||||
#include <memory> // allocator
|
||||
#include <string> // string
|
||||
#include <vector> // vector
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
// This file contains all macro definitions affecting or depending on the ABI
|
||||
|
||||
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0
|
||||
#warning "Already included a different version of the library!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum)
|
||||
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DIAGNOSTIC_POSITIONS
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTICS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
_v ## major ## _ ## minor ## _ ## patch
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
|
||||
|
||||
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION
|
||||
#else
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
|
||||
NLOHMANN_JSON_VERSION_MINOR, \
|
||||
NLOHMANN_JSON_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
// Combine namespace components
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE
|
||||
#define NLOHMANN_JSON_NAMESPACE \
|
||||
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION)
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
|
||||
namespace nlohmann \
|
||||
{ \
|
||||
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION) \
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_END
|
||||
#define NLOHMANN_JSON_NAMESPACE_END \
|
||||
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
|
||||
} // namespace nlohmann
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
@brief namespace for Niels Lohmann
|
||||
@see https://github.com/nlohmann
|
||||
@since version 1.0.0
|
||||
*/
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
/*!
|
||||
@brief default JSONSerializer template argument
|
||||
|
||||
This serializer ignores the template arguments and uses ADL
|
||||
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||
for serialization.
|
||||
*/
|
||||
template<typename T = void, typename SFINAE = void>
|
||||
struct adl_serializer;
|
||||
|
||||
/// a class to store JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/
|
||||
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||
std::map,
|
||||
template<typename U, typename... Args> class ArrayType = std::vector,
|
||||
class StringType = std::string, class BooleanType = bool,
|
||||
class NumberIntegerType = std::int64_t,
|
||||
class NumberUnsignedType = std::uint64_t,
|
||||
class NumberFloatType = double,
|
||||
template<typename U> class AllocatorType = std::allocator,
|
||||
template<typename T, typename SFINAE = void> class JSONSerializer =
|
||||
adl_serializer,
|
||||
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
|
||||
class CustomBaseClass = void>
|
||||
class basic_json;
|
||||
|
||||
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/
|
||||
template<typename RefStringType>
|
||||
class json_pointer;
|
||||
|
||||
/*!
|
||||
@brief default specialization
|
||||
@sa https://json.nlohmann.me/api/json/
|
||||
*/
|
||||
using json = basic_json<>;
|
||||
|
||||
/// @brief a minimal map-like container that preserves insertion order
|
||||
/// @sa https://json.nlohmann.me/api/ordered_map/
|
||||
template<class Key, class T, class IgnoredLess, class Allocator>
|
||||
struct ordered_map;
|
||||
|
||||
/// @brief specialization that maintains the insertion order of object keys
|
||||
/// @sa https://json.nlohmann.me/api/ordered_json/
|
||||
using ordered_json = basic_json<nlohmann::ordered_map>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
@@ -1,388 +0,0 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2017 okdshin
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifndef PICOSHA2_H
|
||||
#define PICOSHA2_H
|
||||
// picosha2:20140213
|
||||
|
||||
#ifndef PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR
|
||||
#define PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR \
|
||||
1048576 //=1024*1024: default is 1MB memory
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
namespace picosha2 {
|
||||
typedef unsigned long word_t;
|
||||
typedef unsigned char byte_t;
|
||||
|
||||
static const size_t k_digest_size = 32;
|
||||
|
||||
namespace detail {
|
||||
inline byte_t mask_8bit(byte_t x) { return x & 0xff; }
|
||||
|
||||
inline word_t mask_32bit(word_t x) { return x & 0xffffffff; }
|
||||
|
||||
const word_t add_constant[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
|
||||
|
||||
const word_t initial_message_digest[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372,
|
||||
0xa54ff53a, 0x510e527f, 0x9b05688c,
|
||||
0x1f83d9ab, 0x5be0cd19};
|
||||
|
||||
inline word_t ch(word_t x, word_t y, word_t z) { return (x & y) ^ ((~x) & z); }
|
||||
|
||||
inline word_t maj(word_t x, word_t y, word_t z) {
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
inline word_t rotr(word_t x, std::size_t n) {
|
||||
assert(n < 32);
|
||||
return mask_32bit((x >> n) | (x << (32 - n)));
|
||||
}
|
||||
|
||||
inline word_t bsig0(word_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); }
|
||||
|
||||
inline word_t bsig1(word_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); }
|
||||
|
||||
inline word_t shr(word_t x, std::size_t n) {
|
||||
assert(n < 32);
|
||||
return x >> n;
|
||||
}
|
||||
|
||||
inline word_t ssig0(word_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); }
|
||||
|
||||
inline word_t ssig1(word_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); }
|
||||
|
||||
template <typename RaIter1, typename RaIter2>
|
||||
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) {
|
||||
assert(first + 64 == last);
|
||||
static_cast<void>(last); // for avoiding unused-variable warning
|
||||
word_t w[64];
|
||||
std::fill(w, w + 64, word_t(0));
|
||||
for (std::size_t i = 0; i < 16; ++i) {
|
||||
w[i] = (static_cast<word_t>(mask_8bit(*(first + i * 4))) << 24) |
|
||||
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 1))) << 16) |
|
||||
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 2))) << 8) |
|
||||
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 3))));
|
||||
}
|
||||
for (std::size_t i = 16; i < 64; ++i) {
|
||||
w[i] = mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) +
|
||||
w[i - 16]);
|
||||
}
|
||||
|
||||
word_t a = *message_digest;
|
||||
word_t b = *(message_digest + 1);
|
||||
word_t c = *(message_digest + 2);
|
||||
word_t d = *(message_digest + 3);
|
||||
word_t e = *(message_digest + 4);
|
||||
word_t f = *(message_digest + 5);
|
||||
word_t g = *(message_digest + 6);
|
||||
word_t h = *(message_digest + 7);
|
||||
|
||||
for (std::size_t i = 0; i < 64; ++i) {
|
||||
word_t temp1 = h + bsig1(e) + ch(e, f, g) + add_constant[i] + w[i];
|
||||
word_t temp2 = bsig0(a) + maj(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = mask_32bit(d + temp1);
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = mask_32bit(temp1 + temp2);
|
||||
}
|
||||
*message_digest += a;
|
||||
*(message_digest + 1) += b;
|
||||
*(message_digest + 2) += c;
|
||||
*(message_digest + 3) += d;
|
||||
*(message_digest + 4) += e;
|
||||
*(message_digest + 5) += f;
|
||||
*(message_digest + 6) += g;
|
||||
*(message_digest + 7) += h;
|
||||
for (std::size_t i = 0; i < 8; ++i) {
|
||||
*(message_digest + i) = mask_32bit(*(message_digest + i));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename InIter>
|
||||
void output_hex(InIter first, InIter last, std::ostream& os) {
|
||||
os.setf(std::ios::hex, std::ios::basefield);
|
||||
while (first != last) {
|
||||
os.width(2);
|
||||
os.fill('0');
|
||||
os << static_cast<unsigned int>(*first);
|
||||
++first;
|
||||
}
|
||||
os.setf(std::ios::dec, std::ios::basefield);
|
||||
}
|
||||
|
||||
template <typename InIter>
|
||||
void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str) {
|
||||
std::ostringstream oss;
|
||||
output_hex(first, last, oss);
|
||||
hex_str.assign(oss.str());
|
||||
}
|
||||
|
||||
template <typename InContainer>
|
||||
void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str) {
|
||||
bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
|
||||
}
|
||||
|
||||
template <typename InIter>
|
||||
std::string bytes_to_hex_string(InIter first, InIter last) {
|
||||
std::string hex_str;
|
||||
bytes_to_hex_string(first, last, hex_str);
|
||||
return hex_str;
|
||||
}
|
||||
|
||||
template <typename InContainer>
|
||||
std::string bytes_to_hex_string(const InContainer& bytes) {
|
||||
std::string hex_str;
|
||||
bytes_to_hex_string(bytes, hex_str);
|
||||
return hex_str;
|
||||
}
|
||||
|
||||
class hash256_one_by_one {
|
||||
public:
|
||||
hash256_one_by_one() { init(); }
|
||||
|
||||
void init() {
|
||||
buffer_.clear();
|
||||
std::fill(data_length_digits_, data_length_digits_ + 4, word_t(0));
|
||||
std::copy(detail::initial_message_digest,
|
||||
detail::initial_message_digest + 8, h_);
|
||||
}
|
||||
|
||||
template <typename RaIter>
|
||||
void process(RaIter first, RaIter last) {
|
||||
add_to_data_length(static_cast<word_t>(std::distance(first, last)));
|
||||
std::copy(first, last, std::back_inserter(buffer_));
|
||||
std::size_t i = 0;
|
||||
for (; i + 64 <= buffer_.size(); i += 64) {
|
||||
detail::hash256_block(h_, buffer_.begin() + i,
|
||||
buffer_.begin() + i + 64);
|
||||
}
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin() + i);
|
||||
}
|
||||
|
||||
void finish() {
|
||||
byte_t temp[64];
|
||||
std::fill(temp, temp + 64, byte_t(0));
|
||||
std::size_t remains = buffer_.size();
|
||||
std::copy(buffer_.begin(), buffer_.end(), temp);
|
||||
assert(remains < 64);
|
||||
|
||||
// This branch is not executed actually (`remains` is always lower than 64),
|
||||
// but needed to avoid g++ false-positive warning.
|
||||
// See https://github.com/okdshin/PicoSHA2/issues/25
|
||||
// vvvvvvvvvvvvvvvv
|
||||
if(remains >= 64) {
|
||||
remains = 63;
|
||||
}
|
||||
// ^^^^^^^^^^^^^^^^
|
||||
|
||||
temp[remains] = 0x80;
|
||||
|
||||
if (remains > 55) {
|
||||
std::fill(temp + remains + 1, temp + 64, byte_t(0));
|
||||
detail::hash256_block(h_, temp, temp + 64);
|
||||
std::fill(temp, temp + 64 - 4, byte_t(0));
|
||||
} else {
|
||||
std::fill(temp + remains + 1, temp + 64 - 4, byte_t(0));
|
||||
}
|
||||
|
||||
write_data_bit_length(&(temp[56]));
|
||||
detail::hash256_block(h_, temp, temp + 64);
|
||||
}
|
||||
|
||||
template <typename OutIter>
|
||||
void get_hash_bytes(OutIter first, OutIter last) const {
|
||||
for (const word_t* iter = h_; iter != h_ + 8; ++iter) {
|
||||
for (std::size_t i = 0; i < 4 && first != last; ++i) {
|
||||
*(first++) = detail::mask_8bit(
|
||||
static_cast<byte_t>((*iter >> (24 - 8 * i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void add_to_data_length(word_t n) {
|
||||
word_t carry = 0;
|
||||
data_length_digits_[0] += n;
|
||||
for (std::size_t i = 0; i < 4; ++i) {
|
||||
data_length_digits_[i] += carry;
|
||||
if (data_length_digits_[i] >= 65536u) {
|
||||
carry = data_length_digits_[i] >> 16;
|
||||
data_length_digits_[i] &= 65535u;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void write_data_bit_length(byte_t* begin) {
|
||||
word_t data_bit_length_digits[4];
|
||||
std::copy(data_length_digits_, data_length_digits_ + 4,
|
||||
data_bit_length_digits);
|
||||
|
||||
// convert byte length to bit length (multiply 8 or shift 3 times left)
|
||||
word_t carry = 0;
|
||||
for (std::size_t i = 0; i < 4; ++i) {
|
||||
word_t before_val = data_bit_length_digits[i];
|
||||
data_bit_length_digits[i] <<= 3;
|
||||
data_bit_length_digits[i] |= carry;
|
||||
data_bit_length_digits[i] &= 65535u;
|
||||
carry = (before_val >> (16 - 3)) & 65535u;
|
||||
}
|
||||
|
||||
// write data_bit_length
|
||||
for (int i = 3; i >= 0; --i) {
|
||||
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i] >> 8);
|
||||
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i]);
|
||||
}
|
||||
}
|
||||
std::vector<byte_t> buffer_;
|
||||
word_t data_length_digits_[4]; // as 64bit integer (16bit x 4 integer)
|
||||
word_t h_[8];
|
||||
};
|
||||
|
||||
inline void get_hash_hex_string(const hash256_one_by_one& hasher,
|
||||
std::string& hex_str) {
|
||||
byte_t hash[k_digest_size];
|
||||
hasher.get_hash_bytes(hash, hash + k_digest_size);
|
||||
return bytes_to_hex_string(hash, hash + k_digest_size, hex_str);
|
||||
}
|
||||
|
||||
inline std::string get_hash_hex_string(const hash256_one_by_one& hasher) {
|
||||
std::string hex_str;
|
||||
get_hash_hex_string(hasher, hex_str);
|
||||
return hex_str;
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
template <typename RaIter, typename OutIter>
|
||||
void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int,
|
||||
std::random_access_iterator_tag) {
|
||||
hash256_one_by_one hasher;
|
||||
// hasher.init();
|
||||
hasher.process(first, last);
|
||||
hasher.finish();
|
||||
hasher.get_hash_bytes(first2, last2);
|
||||
}
|
||||
|
||||
template <typename InputIter, typename OutIter>
|
||||
void hash256_impl(InputIter first, InputIter last, OutIter first2,
|
||||
OutIter last2, int buffer_size, std::input_iterator_tag) {
|
||||
std::vector<byte_t> buffer(buffer_size);
|
||||
hash256_one_by_one hasher;
|
||||
// hasher.init();
|
||||
while (first != last) {
|
||||
int size = buffer_size;
|
||||
for (int i = 0; i != buffer_size; ++i, ++first) {
|
||||
if (first == last) {
|
||||
size = i;
|
||||
break;
|
||||
}
|
||||
buffer[i] = *first;
|
||||
}
|
||||
hasher.process(buffer.begin(), buffer.begin() + size);
|
||||
}
|
||||
hasher.finish();
|
||||
hasher.get_hash_bytes(first2, last2);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InIter, typename OutIter>
|
||||
void hash256(InIter first, InIter last, OutIter first2, OutIter last2,
|
||||
int buffer_size = PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR) {
|
||||
picosha2::impl::hash256_impl(
|
||||
first, last, first2, last2, buffer_size,
|
||||
typename std::iterator_traits<InIter>::iterator_category());
|
||||
}
|
||||
|
||||
template <typename InIter, typename OutContainer>
|
||||
void hash256(InIter first, InIter last, OutContainer& dst) {
|
||||
hash256(first, last, dst.begin(), dst.end());
|
||||
}
|
||||
|
||||
template <typename InContainer, typename OutIter>
|
||||
void hash256(const InContainer& src, OutIter first, OutIter last) {
|
||||
hash256(src.begin(), src.end(), first, last);
|
||||
}
|
||||
|
||||
template <typename InContainer, typename OutContainer>
|
||||
void hash256(const InContainer& src, OutContainer& dst) {
|
||||
hash256(src.begin(), src.end(), dst.begin(), dst.end());
|
||||
}
|
||||
|
||||
template <typename InIter>
|
||||
void hash256_hex_string(InIter first, InIter last, std::string& hex_str) {
|
||||
byte_t hashed[k_digest_size];
|
||||
hash256(first, last, hashed, hashed + k_digest_size);
|
||||
std::ostringstream oss;
|
||||
output_hex(hashed, hashed + k_digest_size, oss);
|
||||
hex_str.assign(oss.str());
|
||||
}
|
||||
|
||||
template <typename InIter>
|
||||
std::string hash256_hex_string(InIter first, InIter last) {
|
||||
std::string hex_str;
|
||||
hash256_hex_string(first, last, hex_str);
|
||||
return hex_str;
|
||||
}
|
||||
|
||||
inline void hash256_hex_string(const std::string& src, std::string& hex_str) {
|
||||
hash256_hex_string(src.begin(), src.end(), hex_str);
|
||||
}
|
||||
|
||||
template <typename InContainer>
|
||||
void hash256_hex_string(const InContainer& src, std::string& hex_str) {
|
||||
hash256_hex_string(src.begin(), src.end(), hex_str);
|
||||
}
|
||||
|
||||
template <typename InContainer>
|
||||
std::string hash256_hex_string(const InContainer& src) {
|
||||
return hash256_hex_string(src.begin(), src.end());
|
||||
}
|
||||
template<typename OutIter>void hash256(std::ifstream& f, OutIter first, OutIter last){
|
||||
hash256(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>(), first,last);
|
||||
|
||||
}
|
||||
}// namespace picosha2
|
||||
#endif // PICOSHA2_H
|
||||
@@ -14,3 +14,8 @@ TSE::Mesh *TSE::MeshContainer::GetMesh() const
|
||||
{
|
||||
return mesh;
|
||||
}
|
||||
|
||||
TSE::Mesh **TSE::MeshContainer::GetMeshRef()
|
||||
{
|
||||
return &mesh;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#define MESH_CONTAINER typeid(TSE::MeshContainer).name()
|
||||
|
||||
#include "Types.hpp"
|
||||
#include "Mesh.hpp"
|
||||
#include "elements/Mesh.hpp"
|
||||
#include "elements/BehaviourScript.hpp"
|
||||
|
||||
namespace TSE
|
||||
@@ -19,6 +19,7 @@ namespace TSE
|
||||
|
||||
void SetMesh(Mesh* mesh);
|
||||
Mesh* GetMesh() const;
|
||||
Mesh** GetMeshRef();
|
||||
|
||||
inline const char* GetName() override
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "elements/BehaviourScript.hpp"
|
||||
#include "Rect.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "Mesh.hpp"
|
||||
#include "elements/Mesh.hpp"
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace TSE
|
||||
return material;
|
||||
}
|
||||
|
||||
Material **Renderable::GetMaterialRef()
|
||||
{
|
||||
return &material;
|
||||
}
|
||||
|
||||
Mesh* Renderable::GetMeshContainer() const {
|
||||
if(baseObject->HasBehaviourScript(MESH_CONTAINER))
|
||||
return dynamic_cast<MeshContainer*>(baseObject->GetBehaviourScript(MESH_CONTAINER))->GetMesh();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "elements/Material.hpp"
|
||||
#include "interfaces/IRenderable.hpp"
|
||||
#include "elements/BehaviourScript.hpp"
|
||||
#include "Mesh.hpp"
|
||||
#include "elements/Mesh.hpp"
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
@@ -28,6 +28,7 @@ namespace TSE
|
||||
}
|
||||
void SetMaterial(Material* material);
|
||||
Material* GetMaterial();
|
||||
Material** GetMaterialRef();
|
||||
|
||||
private:
|
||||
Mesh* GetMeshContainer() const;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "AssetLibrary.hpp"
|
||||
#include "Material.hpp"
|
||||
#include "Mesh.hpp"
|
||||
#include "Texture.hpp"
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
@@ -10,6 +11,32 @@ std::unordered_map<uuids::uuid, std::tuple<std::any, TSE::string, uuids::uuid>>
|
||||
std::unordered_map<TSE::string, uuids::uuid> TSE::AssetLibrary::alreadyLoadedAssets;
|
||||
TSE::string TSE::AssetLibrary::currentAssetPath;
|
||||
|
||||
void TSE::AssetLibrary::LoadDefaultAssets()
|
||||
{
|
||||
Mesh* quad = new Mesh(Mesh::GetQuadMesh());
|
||||
quad->id = TSE_ID_MESH_QUAD;
|
||||
quad->IsVirtualAsset = true;
|
||||
|
||||
Mesh* circle = new Mesh(Mesh::GetCircleMesh());
|
||||
circle->id = TSE_ID_MESH_CIRCLE;
|
||||
circle->IsVirtualAsset = true;
|
||||
|
||||
SetValue(TSE_ID_MESH_QUAD, quad);
|
||||
SetValue(TSE_ID_MESH_CIRCLE, circle);
|
||||
}
|
||||
|
||||
void TSE::AssetLibrary::RemoveValue(const uuids::uuid &key, IAsset *asset)
|
||||
{
|
||||
if(HasValue(key))
|
||||
{
|
||||
if(!asset->IsVirtualAsset)
|
||||
{
|
||||
alreadyLoadedAssets.erase(asset->rawPath);
|
||||
}
|
||||
assets.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
bool TSE::AssetLibrary::HasValue(const uuids::uuid &key)
|
||||
{
|
||||
return assets.find(key) != assets.end();
|
||||
@@ -49,6 +76,12 @@ void TSE::AssetLibrary::SaveAllAssets()
|
||||
if(!value->IsVirtualAsset)
|
||||
value->SaveAsset();
|
||||
}
|
||||
if (type == typeid(Mesh*).name())
|
||||
{
|
||||
Mesh* value = GetValue<Mesh*>(name);
|
||||
if(!value->IsVirtualAsset)
|
||||
value->SaveAsset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +98,7 @@ std::string ToLower(std::string str)
|
||||
|
||||
void TSE::AssetLibrary::LoadAllAssets(string &path)
|
||||
{
|
||||
LoadDefaultAssets();
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
currentAssetPath = string(path);
|
||||
@@ -97,6 +131,13 @@ void TSE::AssetLibrary::LoadAllAssets(string &path)
|
||||
SetValue(tex->id, tex);
|
||||
alreadyLoadedAssets[path] = tex->id;
|
||||
}
|
||||
else if (ext == ".obj")
|
||||
{
|
||||
Mesh* mesh = new Mesh();
|
||||
mesh->LoadAsset(path);
|
||||
SetValue(mesh->id, mesh);
|
||||
alreadyLoadedAssets[path] = mesh->id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,8 +161,25 @@ void TSE::AssetLibrary::RescanAssets()
|
||||
if(!value->IsVirtualAsset)
|
||||
value->Rescan();
|
||||
}
|
||||
if (type == typeid(Mesh*).name())
|
||||
{
|
||||
Mesh* value = GetValue<Mesh*>(name);
|
||||
if(!value->IsVirtualAsset)
|
||||
value->Rescan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void TSE::AssetLibrary::SetValue<TSE::Material>(const uuids::uuid&, const TSE::Material*);
|
||||
template void TSE::AssetLibrary::SetValue<TSE::Texture>(const uuids::uuid&, const TSE::Texture*);
|
||||
TSE::string TSE::AssetLibrary::GetCurrentAssetPath()
|
||||
{
|
||||
return currentAssetPath;
|
||||
}
|
||||
|
||||
template void TSE::AssetLibrary::SetValue<TSE::Material>(const uuids::uuid&, TSE::Material*);
|
||||
template void TSE::AssetLibrary::SetValue<TSE::Texture>(const uuids::uuid&, TSE::Texture*);
|
||||
template void TSE::AssetLibrary::SetValue<TSE::Mesh>(const uuids::uuid&, TSE::Mesh*);
|
||||
|
||||
|
||||
template TSE::Texture* TSE::AssetLibrary::GetValue<TSE::Texture*>(const uuids::uuid&);
|
||||
template TSE::Material* TSE::AssetLibrary::GetValue<TSE::Material*>(const uuids::uuid&);
|
||||
template TSE::Mesh* TSE::AssetLibrary::GetValue<TSE::Mesh*>(const uuids::uuid&);
|
||||
|
||||
@@ -6,20 +6,27 @@
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
const uuids::uuid TSE_ID_MESH_QUAD = uuids::uuid::from_string("00000000-0000-0000-1000-000000000000").value();
|
||||
const uuids::uuid TSE_ID_MESH_CIRCLE = uuids::uuid::from_string("00000000-0000-0000-1001-000000000000").value();
|
||||
|
||||
class AssetLibrary
|
||||
{
|
||||
private:
|
||||
static std::unordered_map<uuids::uuid, std::tuple<std::any, string, uuids::uuid>> assets;
|
||||
static std::unordered_map<string, uuids::uuid> alreadyLoadedAssets;
|
||||
|
||||
|
||||
static string currentAssetPath;
|
||||
|
||||
static void LoadDefaultAssets();
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
static T GetValue(const uuids::uuid& key);
|
||||
|
||||
template<typename T>
|
||||
static void SetValue(const uuids::uuid& key, const T* value);
|
||||
static void SetValue(const uuids::uuid& key, T* value);
|
||||
static void RemoveValue(const uuids::uuid& key, IAsset* asset);
|
||||
|
||||
static bool HasValue(const uuids::uuid& key);
|
||||
static int GetValueCount();
|
||||
@@ -28,6 +35,8 @@ namespace TSE
|
||||
static void SaveAllAssets();
|
||||
static void LoadAllAssets(string& path);
|
||||
static void RescanAssets();
|
||||
|
||||
static string GetCurrentAssetPath();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -41,7 +50,7 @@ namespace TSE
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void AssetLibrary::SetValue(const uuids::uuid& key, const T* value) {
|
||||
void AssetLibrary::SetValue(const uuids::uuid& key, T* value) {
|
||||
assets[key] = std::make_tuple(value, typeid(T).name(), key);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "utils/JsonExports.hpp"
|
||||
#include "Debug.hpp"
|
||||
#include "ShaderRegistry.hpp"
|
||||
#include "AssetLibrary.hpp"
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
@@ -191,6 +192,7 @@ namespace TSE
|
||||
|
||||
void Material::SaveAsset()
|
||||
{
|
||||
if(IsVirtualAsset) return;
|
||||
using json = nlohmann::ordered_json;
|
||||
|
||||
json material = GenerateMaterialJson();
|
||||
@@ -289,6 +291,17 @@ namespace TSE
|
||||
hash = sha256(material.dump(-1));
|
||||
}
|
||||
|
||||
string Material::assetType()
|
||||
{
|
||||
return "material";
|
||||
}
|
||||
|
||||
void Material::UnloadAsset()
|
||||
{
|
||||
AssetLibrary::RemoveValue(id, static_cast<IAsset*>(this));
|
||||
delete(this);
|
||||
}
|
||||
|
||||
void Material::SaveMeta()
|
||||
{
|
||||
string metaPath = PathToMetaPath(rawPath);
|
||||
|
||||
@@ -46,6 +46,8 @@ namespace TSE
|
||||
void SaveAsset() override;
|
||||
nlohmann::ordered_json GenerateMaterialJson();
|
||||
void Hash() override;
|
||||
string assetType() override;
|
||||
void UnloadAsset() override;
|
||||
protected:
|
||||
void SaveMeta() override;
|
||||
};
|
||||
|
||||
564
TSE_Core/src/elements/Mesh.cpp
Normal file
564
TSE_Core/src/elements/Mesh.cpp
Normal file
@@ -0,0 +1,564 @@
|
||||
#include "Mesh.hpp"
|
||||
#include "MathF.hpp"
|
||||
#include <cmath>
|
||||
#include "json.hpp"
|
||||
#include "PathHelper.hpp"
|
||||
#include "IdGenerator.hpp"
|
||||
#include "Debug.hpp"
|
||||
#include "elements/AssetLibrary.hpp"
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ObjFaceVertex
|
||||
{
|
||||
int vertexIndex = -1;
|
||||
int uvIndex = -1;
|
||||
|
||||
bool operator==(const ObjFaceVertex& other) const
|
||||
{
|
||||
return vertexIndex == other.vertexIndex && uvIndex == other.uvIndex;
|
||||
}
|
||||
};
|
||||
|
||||
struct ObjFaceVertexHash
|
||||
{
|
||||
size_t operator()(const ObjFaceVertex& value) const
|
||||
{
|
||||
size_t h1 = std::hash<int>{}(value.vertexIndex);
|
||||
size_t h2 = std::hash<int>{}(value.uvIndex);
|
||||
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
|
||||
}
|
||||
};
|
||||
|
||||
struct ObjMeshData
|
||||
{
|
||||
TSE::string name;
|
||||
std::vector<TSE::Vector3> vertecies;
|
||||
std::vector<TSE::ushort> indecies;
|
||||
std::vector<TSE::Vector2> uvs;
|
||||
std::unordered_map<ObjFaceVertex, TSE::ushort, ObjFaceVertexHash> vertexLookup;
|
||||
};
|
||||
|
||||
int ResolveObjIndex(int index, size_t count)
|
||||
{
|
||||
if(index > 0)
|
||||
{
|
||||
return index - 1;
|
||||
}
|
||||
if(index < 0)
|
||||
{
|
||||
return static_cast<int>(count) + index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ObjFaceVertex ParseFaceVertex(const std::string& token, size_t vertexCount, size_t uvCount)
|
||||
{
|
||||
ObjFaceVertex result;
|
||||
std::stringstream stream(token);
|
||||
std::string part;
|
||||
|
||||
if(std::getline(stream, part, '/') && !part.empty())
|
||||
{
|
||||
result.vertexIndex = ResolveObjIndex(std::stoi(part), vertexCount);
|
||||
}
|
||||
|
||||
if(std::getline(stream, part, '/') && !part.empty())
|
||||
{
|
||||
result.uvIndex = ResolveObjIndex(std::stoi(part), uvCount);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AddObjFaceVertex(
|
||||
ObjMeshData& mesh,
|
||||
const ObjFaceVertex& faceVertex,
|
||||
const std::vector<TSE::Vector3>& sourceVertices,
|
||||
const std::vector<TSE::Vector2>& sourceUvs)
|
||||
{
|
||||
if(faceVertex.vertexIndex < 0 || faceVertex.vertexIndex >= static_cast<int>(sourceVertices.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto existing = mesh.vertexLookup.find(faceVertex);
|
||||
if(existing != mesh.vertexLookup.end())
|
||||
{
|
||||
mesh.indecies.push_back(existing->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(mesh.vertecies.size() > std::numeric_limits<TSE::ushort>::max())
|
||||
{
|
||||
TSE_WARNING("OBJ mesh has more vertices than ushort indices can address: " + mesh.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
TSE::ushort newIndex = static_cast<TSE::ushort>(mesh.vertecies.size());
|
||||
mesh.vertecies.push_back(sourceVertices[faceVertex.vertexIndex]);
|
||||
|
||||
if(faceVertex.uvIndex >= 0 && faceVertex.uvIndex < static_cast<int>(sourceUvs.size()))
|
||||
{
|
||||
mesh.uvs.push_back(sourceUvs[faceVertex.uvIndex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh.uvs.emplace_back(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
mesh.vertexLookup[faceVertex] = newIndex;
|
||||
mesh.indecies.push_back(newIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
TSE::string MeshGeometryHash(
|
||||
const std::vector<TSE::Vector3>& vertecies,
|
||||
const std::vector<TSE::ushort>& indecies,
|
||||
const std::vector<TSE::Vector2>& uvs)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
|
||||
|
||||
stream << "v:" << vertecies.size() << ";";
|
||||
for(const auto& vertex : vertecies)
|
||||
{
|
||||
stream << vertex.x << "," << vertex.y << "," << vertex.z << ";";
|
||||
}
|
||||
|
||||
stream << "i:" << indecies.size() << ";";
|
||||
for(TSE::ushort index : indecies)
|
||||
{
|
||||
stream << index << ";";
|
||||
}
|
||||
|
||||
stream << "uv:" << uvs.size() << ";";
|
||||
for(const auto& uv : uvs)
|
||||
{
|
||||
stream << uv.x << "," << uv.y << ";";
|
||||
}
|
||||
|
||||
return picosha2::hash256_hex_string(stream.str());
|
||||
}
|
||||
|
||||
TSE::string MeshGeometryHash(const TSE::Mesh& mesh)
|
||||
{
|
||||
return MeshGeometryHash(mesh.vertecies, mesh.indecies, mesh.uvs);
|
||||
}
|
||||
}
|
||||
|
||||
TSE::Mesh::Mesh()
|
||||
{
|
||||
id = GenerateRandomUUID();
|
||||
name = "";
|
||||
}
|
||||
|
||||
TSE::Mesh::Mesh(string _name, const std::vector<Vector3> &_vertecies, const std::vector<ushort> &_indecies, const std::vector<Vector2> &_uvs)
|
||||
{
|
||||
id = GenerateRandomUUID();
|
||||
name = _name;
|
||||
vertecies = std::move(_vertecies);
|
||||
indecies = std::move(_indecies);
|
||||
uvs = std::move(_uvs);
|
||||
}
|
||||
|
||||
size_t TSE::Mesh::IndeciesCount() const
|
||||
{
|
||||
return indecies.size();
|
||||
}
|
||||
|
||||
size_t TSE::Mesh::VerteciesCount() const
|
||||
{
|
||||
return vertecies.size();
|
||||
}
|
||||
|
||||
TSE::Mesh TSE::Mesh::GetCircleMesh(ushort segments)
|
||||
{
|
||||
std::vector<Vector3> verts;
|
||||
std::vector<ushort> indices;
|
||||
std::vector<Vector2> uvs;
|
||||
|
||||
verts.emplace_back(0.0f, 0.0f, 0.0f);
|
||||
uvs.emplace_back(0.5f, 0.5f);
|
||||
|
||||
float angleStep = 2.0f * TSE_PI / segments;
|
||||
|
||||
for (int i = 0; i <= segments; ++i) {
|
||||
float angle = i * angleStep;
|
||||
float x = std::cos(angle) * 0.5f;
|
||||
float y = std::sin(angle) * 0.5f;
|
||||
verts.emplace_back(x, y, 0);
|
||||
uvs.emplace_back(x + 0.5f, y + 0.5f);
|
||||
|
||||
if (i > 0) {
|
||||
indices.push_back(0);
|
||||
indices.push_back(i);
|
||||
indices.push_back(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return Mesh("Circle", verts, indices, uvs);
|
||||
}
|
||||
|
||||
TSE::Mesh TSE::Mesh::GetQuadMesh()
|
||||
{
|
||||
std::vector<Vector3> verts = {
|
||||
Vector3(-0.5f, -0.5f, 0),
|
||||
Vector3( 0.5f, -0.5f, 0),
|
||||
Vector3( 0.5f, 0.5f, 0),
|
||||
Vector3(-0.5f, 0.5f, 0)
|
||||
};
|
||||
|
||||
std::vector<Vector2> uvs = {
|
||||
Vector2(0.0f, 0.0f),
|
||||
Vector2(1.0f, 0.0f),
|
||||
Vector2(1.0f, 1.0f),
|
||||
Vector2(0.0f, 1.0f)
|
||||
};
|
||||
|
||||
std::vector<unsigned short> indices = {
|
||||
0, 1, 2,
|
||||
2, 3, 0
|
||||
};
|
||||
|
||||
return Mesh("Quad", verts, indices, uvs);
|
||||
}
|
||||
|
||||
void TSE::Mesh::LoadObj(const string &path)
|
||||
{
|
||||
|
||||
std::ifstream objStream;
|
||||
OpenFileReading(objStream, path);
|
||||
if(!objStream.is_open())
|
||||
{
|
||||
TSE_WARNING("Could not open OBJ file: " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
string fallbackName = fs::path(path).stem().string();
|
||||
std::vector<Vector3> sourceVertices;
|
||||
std::vector<Vector2> sourceUvs;
|
||||
std::vector<ObjMeshData> objects;
|
||||
ObjMeshData* currentObject = nullptr;
|
||||
|
||||
auto ensureObject = [&]() -> ObjMeshData&
|
||||
{
|
||||
if(currentObject == nullptr)
|
||||
{
|
||||
objects.emplace_back();
|
||||
objects.back().name = fallbackName;
|
||||
currentObject = &objects.back();
|
||||
}
|
||||
return *currentObject;
|
||||
};
|
||||
|
||||
std::string line;
|
||||
while(std::getline(objStream, line))
|
||||
{
|
||||
std::stringstream lineStream(line);
|
||||
std::string command;
|
||||
lineStream >> command;
|
||||
|
||||
if(command == "v")
|
||||
{
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
lineStream >> x >> y >> z;
|
||||
sourceVertices.emplace_back(x, y, z);
|
||||
}
|
||||
else if(command == "vt")
|
||||
{
|
||||
float u = 0.0f;
|
||||
float v = 0.0f;
|
||||
lineStream >> u >> v;
|
||||
sourceUvs.emplace_back(u, v);
|
||||
}
|
||||
else if(command == "o")
|
||||
{
|
||||
std::string objectName;
|
||||
std::getline(lineStream >> std::ws, objectName);
|
||||
objects.emplace_back();
|
||||
objects.back().name = objectName.empty() ? fallbackName : objectName;
|
||||
currentObject = &objects.back();
|
||||
}
|
||||
else if(command == "f")
|
||||
{
|
||||
ObjMeshData& mesh = ensureObject();
|
||||
std::vector<ObjFaceVertex> face;
|
||||
std::string token;
|
||||
while(lineStream >> token)
|
||||
{
|
||||
face.push_back(ParseFaceVertex(token, sourceVertices.size(), sourceUvs.size()));
|
||||
}
|
||||
|
||||
if(face.size() < 3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hasInvalidVertex = std::any_of(face.begin(), face.end(), [&sourceVertices](const ObjFaceVertex& faceVertex)
|
||||
{
|
||||
return faceVertex.vertexIndex < 0 || faceVertex.vertexIndex >= static_cast<int>(sourceVertices.size());
|
||||
});
|
||||
if(hasInvalidVertex)
|
||||
{
|
||||
TSE_WARNING("Skipping invalid OBJ face in: " + path);
|
||||
continue;
|
||||
}
|
||||
|
||||
for(size_t i = 1; i + 1 < face.size(); i++)
|
||||
{
|
||||
AddObjFaceVertex(mesh, face[0], sourceVertices, sourceUvs);
|
||||
AddObjFaceVertex(mesh, face[i], sourceVertices, sourceUvs);
|
||||
AddObjFaceVertex(mesh, face[i + 1], sourceVertices, sourceUvs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objects.erase(
|
||||
std::remove_if(objects.begin(), objects.end(), [](const ObjMeshData& object)
|
||||
{
|
||||
return object.vertecies.empty() || object.indecies.empty();
|
||||
}),
|
||||
objects.end());
|
||||
|
||||
if(objects.empty())
|
||||
{
|
||||
name = fallbackName;
|
||||
return;
|
||||
}
|
||||
|
||||
if(objects.size() == 1)
|
||||
{
|
||||
name = objects[0].name;
|
||||
vertecies = std::move(objects[0].vertecies);
|
||||
indecies = std::move(objects[0].indecies);
|
||||
uvs = std::move(objects[0].uvs);
|
||||
return;
|
||||
}
|
||||
|
||||
name = fallbackName;
|
||||
for(auto& object : objects)
|
||||
{
|
||||
if(vertecies.size() + object.vertecies.size() > std::numeric_limits<ushort>::max())
|
||||
{
|
||||
TSE_WARNING("Combined OBJ mesh has more vertices than ushort indices can address: " + path);
|
||||
continue;
|
||||
}
|
||||
|
||||
ushort indexOffset = static_cast<ushort>(vertecies.size());
|
||||
vertecies.insert(vertecies.end(), object.vertecies.begin(), object.vertecies.end());
|
||||
uvs.insert(uvs.end(), object.uvs.begin(), object.uvs.end());
|
||||
for(ushort index : object.indecies)
|
||||
{
|
||||
indecies.push_back(static_cast<ushort>(index + indexOffset));
|
||||
}
|
||||
|
||||
Mesh* submesh = new Mesh(object.name, object.vertecies, object.indecies, object.uvs);
|
||||
submesh->rawPath = path + "#" + object.name;
|
||||
submesh->hash = MeshGeometryHash(*submesh);
|
||||
submesh->IsVirtualAsset = true;
|
||||
derivedAssets.push_back(submesh);
|
||||
AssetLibrary::SetValue(submesh->id, submesh);
|
||||
}
|
||||
}
|
||||
|
||||
bool TSE::Mesh::LoadAsset(string &path)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
for(auto submesh : derivedAssets)
|
||||
{
|
||||
AssetLibrary::RemoveValue(submesh->id, submesh);
|
||||
delete(submesh);
|
||||
}
|
||||
derivedAssets.clear();
|
||||
|
||||
if(vertecies.size() != 0)
|
||||
{
|
||||
vertecies.clear();
|
||||
}
|
||||
if(indecies.size() != 0)
|
||||
{
|
||||
indecies.clear();
|
||||
}
|
||||
if(uvs.size() != 0)
|
||||
{
|
||||
uvs.clear();
|
||||
}
|
||||
rawPath = string(path);
|
||||
name = rawPath;
|
||||
string extension = fs::directory_entry(rawPath).path().extension().string();
|
||||
if(extension == ".obj")
|
||||
{
|
||||
LoadObj(rawPath);
|
||||
}
|
||||
|
||||
string metaPath = PathToMetaPath(rawPath);
|
||||
using json = nlohmann::ordered_json;
|
||||
|
||||
Hash();
|
||||
for(auto derivedAsset : derivedAssets)
|
||||
{
|
||||
Mesh* submesh = dynamic_cast<Mesh*>(derivedAsset);
|
||||
if(submesh != nullptr)
|
||||
{
|
||||
submesh->hash = MeshGeometryHash(*submesh);
|
||||
}
|
||||
}
|
||||
|
||||
if(FileExists(metaPath))
|
||||
{
|
||||
std::ifstream metaStream;
|
||||
OpenFileReading(metaStream, metaPath);
|
||||
json meta = json::parse(metaStream);
|
||||
if(meta["type"] != "metadata")
|
||||
{
|
||||
metaStream.close();
|
||||
TSE_WARNING("Rebuilding corrupted meta file (Texture): " + metaPath);
|
||||
SaveMeta();
|
||||
return true;
|
||||
}
|
||||
if(meta["version"] == 1)
|
||||
{
|
||||
if(meta["assetType"] == "mesh")
|
||||
{
|
||||
id = uuids::uuid::from_string((string)meta["id"]).value_or(id);
|
||||
|
||||
std::unordered_map<string, string> derivedAssetIds;
|
||||
if(meta.contains("derivedAssets") && meta["derivedAssets"].is_array())
|
||||
{
|
||||
for(const auto& derivedAssetMeta : meta["derivedAssets"])
|
||||
{
|
||||
if(derivedAssetMeta.contains("hash") && derivedAssetMeta.contains("id"))
|
||||
{
|
||||
derivedAssetIds[(string)derivedAssetMeta["hash"]] = (string)derivedAssetMeta["id"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto derivedAsset : derivedAssets)
|
||||
{
|
||||
Mesh* submesh = dynamic_cast<Mesh*>(derivedAsset);
|
||||
if(submesh == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
submesh->hash = MeshGeometryHash(*submesh);
|
||||
auto idIt = derivedAssetIds.find(submesh->hash);
|
||||
if(idIt == derivedAssetIds.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uuids::uuid oldId = submesh->id;
|
||||
submesh->id = uuids::uuid::from_string(idIt->second).value_or(submesh->id);
|
||||
if(oldId != submesh->id)
|
||||
{
|
||||
AssetLibrary::RemoveValue(oldId, submesh);
|
||||
AssetLibrary::SetValue(submesh->id, submesh);
|
||||
}
|
||||
}
|
||||
|
||||
metaStream.close();
|
||||
SaveMeta();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
metaStream.close();
|
||||
TSE_WARNING("Meta file incompatible with asset type. Please delete for auto regeneration or fix maualy (Mesh): " + metaPath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
metaStream.close();
|
||||
TSE_WARNING("Meta file incompatible. Please delete for auto regeneration or fix maualy (Mesh): " + metaPath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveMeta();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void TSE::Mesh::SaveAsset()
|
||||
{
|
||||
if(IsVirtualAsset) return;
|
||||
Hash();
|
||||
SaveMeta();
|
||||
}
|
||||
|
||||
void TSE::Mesh::Hash()
|
||||
{
|
||||
std::ifstream ifs(rawPath, std::ios::binary);
|
||||
std::vector<unsigned char> s(picosha2::k_digest_size);
|
||||
picosha2::hash256(ifs, s.begin(), s.end());
|
||||
hash = picosha2::hash256_hex_string(s);
|
||||
ifs.close();
|
||||
}
|
||||
|
||||
TSE::string TSE::Mesh::assetType()
|
||||
{
|
||||
return "mesh";
|
||||
}
|
||||
|
||||
void TSE::Mesh::UnloadAsset()
|
||||
{
|
||||
for(auto submesh : derivedAssets)
|
||||
{
|
||||
AssetLibrary::RemoveValue(submesh->id, submesh);
|
||||
delete(submesh);
|
||||
}
|
||||
AssetLibrary::RemoveValue(id, static_cast<IAsset*>(this));
|
||||
delete(this);
|
||||
}
|
||||
|
||||
void TSE::Mesh::SaveMeta()
|
||||
{
|
||||
string metaPath = PathToMetaPath(rawPath);
|
||||
using json = nlohmann::ordered_json;
|
||||
|
||||
json meta;
|
||||
meta["type"] = "metadata";
|
||||
meta["assetType"] = "mesh";
|
||||
meta["version"] = 1;
|
||||
meta["source"] = rawPath; //todo: clamp to assets root
|
||||
meta["id"] = uuids::to_string(id);
|
||||
meta["hash"] = hash;
|
||||
meta["derivedAssets"] = json::array();
|
||||
|
||||
for(auto derivedAsset : derivedAssets)
|
||||
{
|
||||
Mesh* submesh = dynamic_cast<Mesh*>(derivedAsset);
|
||||
if(submesh == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
submesh->hash = MeshGeometryHash(*submesh);
|
||||
|
||||
json derivedAssetMeta;
|
||||
derivedAssetMeta["name"] = submesh->name;
|
||||
derivedAssetMeta["id"] = uuids::to_string(submesh->id);
|
||||
derivedAssetMeta["hash"] = submesh->hash;
|
||||
meta["derivedAssets"].push_back(derivedAssetMeta);
|
||||
}
|
||||
|
||||
std::ofstream metaStream;
|
||||
CreateFileWriting(metaStream, metaPath);
|
||||
metaStream << meta.dump(4) << std::endl;
|
||||
metaStream.close();
|
||||
}
|
||||
57
TSE_Core/src/elements/Mesh.hpp
Normal file
57
TSE_Core/src/elements/Mesh.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Types.hpp"
|
||||
#include "Vector3.hpp"
|
||||
#include "Vector2.hpp"
|
||||
#include "interfaces/IAsset.hpp"
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
class Mesh : public IAsset
|
||||
{
|
||||
public:
|
||||
string name;
|
||||
|
||||
std::vector<Vector3> vertecies;
|
||||
std::vector<ushort> indecies;
|
||||
std::vector<Vector2> uvs;
|
||||
|
||||
/// @brief gives you an empty mesh with the name set to an empty string
|
||||
Mesh();
|
||||
/// @brief constructs a mesh with custom parameters
|
||||
/// @param _name name of the mesh
|
||||
/// @param _vertecies the vertecies
|
||||
/// @param _indecies the indecies
|
||||
/// @param _uvs the uvs
|
||||
Mesh(string _name,
|
||||
const std::vector<Vector3>& _vertecies,
|
||||
const std::vector<ushort>& _indecies,
|
||||
const std::vector<Vector2>& _uvs);
|
||||
/// @brief gives you the count of indecies in this mesh
|
||||
/// @return the indecie count
|
||||
size_t IndeciesCount() const;
|
||||
/// @brief gives you the count of vertecies in this mesh
|
||||
/// @return the vertex count
|
||||
size_t VerteciesCount() const;
|
||||
|
||||
/// @brief generates a circle mesh with the defined amounts of segments
|
||||
/// @param segments amount of "pizza slices" to make the mesh out of. default 16
|
||||
/// @return the resulting mesh
|
||||
static Mesh GetCircleMesh(ushort segments = 16);
|
||||
/// @brief gives you a basic unit quad with (-0.5, -0.5) -> (0.5, 0.5)
|
||||
/// @return the resulting mesh
|
||||
static Mesh GetQuadMesh();
|
||||
|
||||
void LoadObj(const string& path);
|
||||
|
||||
bool LoadAsset(string& path) override;
|
||||
void SaveAsset() override;
|
||||
void Hash() override;
|
||||
string assetType() override;
|
||||
void UnloadAsset() override;
|
||||
|
||||
protected:
|
||||
void SaveMeta() override;
|
||||
};
|
||||
} // namespace TSE
|
||||
@@ -7,10 +7,16 @@
|
||||
#include "PathHelper.hpp"
|
||||
#include "utils/JsonExports.hpp"
|
||||
#include "IdGenerator.hpp"
|
||||
#include "AssetLibrary.hpp"
|
||||
|
||||
TSE::Texture::Texture(const string &path)
|
||||
{
|
||||
id = GenerateRandomUUID();
|
||||
LoadImageFromFile(path);
|
||||
}
|
||||
|
||||
bool TSE::Texture::LoadImageFromFile(const string &path)
|
||||
{
|
||||
FREE_IMAGE_FORMAT fif = FREE_IMAGE_FORMAT::FIF_UNKNOWN;
|
||||
bmp = nullptr;
|
||||
imagePtr = nullptr;
|
||||
@@ -24,7 +30,7 @@ TSE::Texture::Texture(const string &path)
|
||||
TSE_ERROR(msg);
|
||||
Bpp = 24;
|
||||
makeError(*this);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
fif = FreeImage_GetFileType(name.c_str(), 0);
|
||||
@@ -35,12 +41,12 @@ TSE::Texture::Texture(const string &path)
|
||||
TSE_ERROR("Failed to load image. Unsupported Format.");
|
||||
Bpp = 24;
|
||||
makeError(*this);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if(FreeImage_FIFSupportsReading(fif))
|
||||
{
|
||||
bmp = FreeImage_Load(fif, path.c_str());
|
||||
if(FreeImage_GetBPP(bmp) != 32)
|
||||
bmp = FreeImage_Load(fif, name.c_str());
|
||||
if(bmp != nullptr && FreeImage_GetBPP(bmp) != 32)
|
||||
{
|
||||
auto tmpBmp = FreeImage_ConvertTo32Bits(bmp);
|
||||
FreeImage_Unload(bmp);
|
||||
@@ -52,7 +58,7 @@ TSE::Texture::Texture(const string &path)
|
||||
TSE_ERROR("Failed to load image. Bitmap was nullptr.");
|
||||
Bpp = 24;
|
||||
makeError(*this);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
Bpp = FreeImage_GetBPP(bmp);
|
||||
imagePtr = FreeImage_GetBits(bmp);
|
||||
@@ -70,6 +76,7 @@ TSE::Texture::Texture(const string &path)
|
||||
|
||||
Size = Vector2(FreeImage_GetWidth(bmp), FreeImage_GetHeight(bmp));
|
||||
regist();
|
||||
return true;
|
||||
}
|
||||
|
||||
TSE::Texture::Texture(const int &width, const int &height, int bpp)
|
||||
@@ -476,7 +483,19 @@ void TSE::Texture::PlatformDestroy()
|
||||
|
||||
bool TSE::Texture::LoadAsset(string &path)
|
||||
{
|
||||
*this = Texture(path);
|
||||
if(bmp != nullptr)
|
||||
{
|
||||
FreeImage_Unload(bmp);
|
||||
bmp = nullptr;
|
||||
}
|
||||
if(TextureID != 0)
|
||||
{
|
||||
PlatformDestroy();
|
||||
TextureID = 0;
|
||||
}
|
||||
imagePtr = nullptr;
|
||||
LoadImageFromFile(path);
|
||||
|
||||
rawPath = string(path);
|
||||
UpdateImportSettings(rawPath, 0, {1,1});
|
||||
string metaPath = PathToMetaPath(rawPath);
|
||||
@@ -542,6 +561,7 @@ bool TSE::Texture::LoadAsset(string &path)
|
||||
|
||||
void TSE::Texture::SaveAsset()
|
||||
{
|
||||
if(IsVirtualAsset) return;
|
||||
Hash();
|
||||
SaveMeta();
|
||||
}
|
||||
@@ -564,6 +584,22 @@ void TSE::Texture::UpdateImportSettings(string name, byte mode, Vector2 count)
|
||||
settings.chanels = chanels;
|
||||
}
|
||||
|
||||
TSE::string TSE::Texture::assetType()
|
||||
{
|
||||
return "texture";
|
||||
}
|
||||
|
||||
void TSE::Texture::UnloadAsset()
|
||||
{
|
||||
for(auto submesh : derivedAssets)
|
||||
{
|
||||
AssetLibrary::RemoveValue(submesh->id, submesh);
|
||||
delete(submesh);
|
||||
}
|
||||
AssetLibrary::RemoveValue(id, static_cast<IAsset*>(this));
|
||||
delete(this);
|
||||
}
|
||||
|
||||
void TSE::Texture::SaveMeta()
|
||||
{
|
||||
string metaPath = PathToMetaPath(rawPath);
|
||||
|
||||
@@ -79,9 +79,14 @@ namespace TSE
|
||||
bool LoadAsset(string& path) override;
|
||||
void SaveAsset() override;
|
||||
void Hash() override;
|
||||
TextureImportSettings& GetImportSettings() { return settings; }
|
||||
const TextureImportSettings& GetImportSettings() const { return settings; }
|
||||
void UpdateImportSettings(string name, byte mode, Vector2 count);
|
||||
string assetType() override;
|
||||
void UnloadAsset() override;
|
||||
|
||||
protected:
|
||||
bool LoadImageFromFile(const string& path);
|
||||
void SaveMeta() override;
|
||||
};
|
||||
} // namespace TSE
|
||||
|
||||
@@ -14,12 +14,15 @@ namespace TSE
|
||||
string rawPath;
|
||||
string hash;
|
||||
std::vector<IAsset*> dependecies;
|
||||
std::vector<IAsset*> derivedAssets;
|
||||
bool IsVirtualAsset = false;
|
||||
virtual ~IAsset() = default;
|
||||
|
||||
virtual bool LoadAsset(string& path) = 0;
|
||||
virtual void SaveAsset() = 0;
|
||||
virtual void Hash() = 0;
|
||||
virtual string assetType() = 0;
|
||||
virtual void UnloadAsset() = 0;
|
||||
inline void Rescan()
|
||||
{
|
||||
string oldHash = string(hash);
|
||||
|
||||
Reference in New Issue
Block a user