17 Commits

Author SHA256 Message Date
5e7c530e99 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 2026-05-16 23:43:52 +02:00
95bdb1c8bb Fist assetsystem implementations for textures and materials 2026-05-06 19:45:14 +02:00
1665569326 fixed flickering issue. problem was, that in the camera update of the render target the window was updatet agein, what internaly starts a new frame, so made the update function only affent non IWindow calsses, for IWindow it strictly is not neccecery anyway 2026-05-05 13:27:32 +02:00
4002030de8 fixed ordering problem, but have a wier flicker in non editor mode 2026-05-03 22:09:08 +02:00
4fce05a927 README.md aktualisiert 2026-04-11 07:53:19 +00:00
d98a70bb19 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-26 18:55:51 +01:00
1da99ca6c1 small fixes 2026-03-26 18:55:30 +01:00
f50b68c9ba Added 3D Textures to engine 2026-03-25 16:28:17 +01:00
6f5873e778 added sdl lib for windows 2026-03-25 10:36:52 +01:00
a596028ed9 implemented SDL3 as an option for window manager 2026-03-23 19:00:56 +01:00
226f60e9ae added render pipeline WIP 2026-03-15 17:46:11 +01:00
f859288689 added further fixes, and upgrades 2026-03-01 20:51:39 +01:00
769bbd4261 made a lot of changes, to get the render pipeline working 2026-02-21 13:52:07 +01:00
45501f153d started working with MRT 2026-02-20 15:58:51 +01:00
55dce5776a small fixes for windows 2026-02-09 15:25:01 +01:00
330d4b26dc added TileMaps to TSE 2026-02-08 18:09:46 +01:00
ea2dc4f6b5 implemented TileMap, still need Shader for it with billboarding and all that jizz XD 2026-02-02 20:52:28 +01:00
227 changed files with 91002 additions and 716 deletions

View File

@@ -1,2 +1,5 @@
# TSE
packages needed for building under linux:
build-essential llvm cmake ninja-build clang mesa-common-dev gdb

388
TSE_Base/include/picosha2.h Normal file
View File

@@ -0,0 +1,388 @@
/*
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

View File

@@ -1,9 +1,21 @@
#include "IdGenerator.hpp"
std::mt19937 rnd = std::mt19937();
bool init = false;
std::mt19937 rnd;
auto gen = uuids::uuid_random_generator(rnd);
uuids::uuid TSE::GenerateRandomUUID()
{
if(!init)
{
InitRandomIDs();
init = true;
}
return gen();
}
void TSE::InitRandomIDs()
{
rnd = std::mt19937();
gen = uuids::uuid_random_generator(rnd);
}

View File

@@ -5,4 +5,5 @@
namespace TSE
{
uuids::uuid GenerateRandomUUID();
void InitRandomIDs();
} // namespace TSE

View File

@@ -5,7 +5,7 @@ namespace TSE
{
#define TSE_VERSION_MAJOR 0
#define TSE_VERSION_MINOR 1
#define TSE_VERSION_BUILD 3
#define TSE_VERSION_BUILD 4
#define TSE_VERSION_STRING std::to_string(TSE_VERSION_MAJOR) + "." + std::to_string(TSE_VERSION_MINOR) + "." + std::to_string(TSE_VERSION_BUILD)

View File

@@ -1,6 +1,8 @@
#include "Camera.hpp"
#include "elements/Transformable.hpp"
#include "interfaces/IRenderer.hpp"
#include "interfaces/IWindow.hpp"
#include "uuid.h"
TSE::Camera* TSE::Camera::mainCamera = nullptr;
TSE::ICameraHelper* TSE::Camera::helper = nullptr;
@@ -30,6 +32,11 @@ float TSE::Camera::GetFov() const
return fov;
}
const TSE::Vector2 &TSE::Camera::GetRenderTargetSize() const
{
return lastRtSize;
}
TSE::Vector3 TSE::Camera::SceenPositionToGamePosition(Vector2 screenPos)
{
float x = 2.0f * screenPos.x / lastRtSize.x -1.0f;
@@ -95,7 +102,11 @@ void TSE::Camera::SetRenderTarget(IRenderTarget *target)
if(target != nullptr)
target->AddResizeNotifiable(this);
rt = target;
RecalculateProjMatrix();
if(lastRtSize != rt->GetRawIResizableSize())
{
lastRtSize = rt->GetRawIResizableSize();
RecalculateProjMatrix();
}
}
TSE::IRenderTarget *TSE::Camera::GetRenderTarget()
@@ -203,5 +214,8 @@ void TSE::Camera::Unbind()
void TSE::Camera::UpdateRenderTarget()
{
rt->Update();
if (dynamic_cast<IWindow*>(rt) == nullptr)
{
rt->Update();
}
}

View File

@@ -8,6 +8,7 @@
#include "Vector3.hpp"
#include "interfaces/IRenderTarget.hpp"
#include "elements/BehaviourScript.hpp"
#include "uuid.h"
namespace TSE
{
@@ -41,6 +42,7 @@ namespace TSE
Vector2 lastRtSize = {0, 0};
public:
std::vector<uuids::uuid> layersNotToRender;
static ICameraHelper* helper;
static Camera* mainCamera;
@@ -50,6 +52,7 @@ namespace TSE
float GetNearClippingPlane() const;
float GetFarClippingPlane() const;
float GetFov() const;
const Vector2& GetRenderTargetSize() const;
// Setter
Vector3 SceenPositionToGamePosition(Vector2 screenPos);

View File

@@ -14,3 +14,8 @@ TSE::Mesh *TSE::MeshContainer::GetMesh() const
{
return mesh;
}
TSE::Mesh **TSE::MeshContainer::GetMeshRef()
{
return &mesh;
}

View File

@@ -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
{

View File

@@ -0,0 +1,245 @@
#include "OrdererSpriteSet.hpp"
#include <algorithm>
#include <tuple>
#include <cmath>
#include "Debug.hpp"
TSE::OrdererSpriteSetChunk::OrdererSpriteSetChunk(int _chunksize, const Vector2 &_pos, SortingOrder _order)
{
chunksize = _chunksize;
pos = _pos;
order = _order;
}
void TSE::OrdererSpriteSetChunk::SetSprite(const Vector2 &p, const Vector2 &Spriteindex, const Vector2 &Normalindex, TileSet *set, float height, Vector2& scale)
{
int normalid = -1;
if(Normalindex != Vector2(-1,-1))
normalid = set->GetSpriteIdAt(Normalindex.x, Normalindex.y);
sprites[Vector3(p.x, p.y, height)] = {set->GetSpriteIdAt(Spriteindex.x, Spriteindex.y), normalid};
spriteScales[Vector3(p.x, p.y, height)] = scale;
dirtyPositions = true;
dirtySpriteIds = true;
dirtyScales = true;
}
void TSE::OrdererSpriteSetChunk::RemoveSprite(Vector2 p, float height)
{
sprites.erase(Vector3(p.x, p.y, height));
}
void TSE::OrdererSpriteSetChunk::SetOrdering(SortingOrder _order)
{
order = _order;
dirtyPositions = true;
dirtySpriteIds = true;
}
const std::vector<TSE::Vector3> *TSE::OrdererSpriteSetChunk::GetOrderedPositions()
{
if(dirtyPositions)
{
orderedPositions.clear();
for(auto pos : sprites)
{
orderedPositions.push_back(pos.first);
}
switch (order)
{
case TopLeft:
std::sort(orderedPositions.begin(), orderedPositions.end(), [](const Vector3& a, const Vector3& b)
{
return std::tie(a.y, a.x) > std::tie(b.y, b.x);
});
break;
case TopRight:
std::sort(orderedPositions.begin(), orderedPositions.end(), [](const Vector3& a, const Vector3& b)
{
if (a.y != b.y)
return a.y > b.y;
return a.x > b.x;
});
break;
case BottomLeft:
std::sort(orderedPositions.begin(), orderedPositions.end(), [](const Vector3& a, const Vector3& b)
{
return std::tie(a.y, a.x) < std::tie(b.y, b.x);
});
break;
case BottomRight:
std::sort(orderedPositions.begin(), orderedPositions.end(), [](const Vector3& a, const Vector3& b)
{
if (a.y != b.y)
return a.y < b.y;
return a.x > b.x;
});
break;
}
dirtyPositions = false;
}
return &orderedPositions;
}
const std::vector<TSE::Vector2i> *TSE::OrdererSpriteSetChunk::GetOrderedSpriteIds()
{
if(dirtySpriteIds)
{
orderedSpriteIDs.clear();
auto tmp = GetOrderedPositions();
for(auto& pos : *tmp)
{
auto v = sprites.find(pos);
if(v != sprites.end())
orderedSpriteIDs.push_back(v->second);
else
orderedSpriteIDs.push_back({0,0});
}
dirtySpriteIds = false;
}
return &orderedSpriteIDs;
}
const std::vector<TSE::Vector2> *TSE::OrdererSpriteSetChunk::GetOrderedScales()
{
if(dirtyScales)
{
orderedScales.clear();
auto tmp = GetOrderedPositions();
for(auto& pos : *tmp)
{
auto v = spriteScales.find(pos);
if(v != spriteScales.end())
orderedScales.push_back(v->second);
else
orderedScales.push_back({1,1});
}
dirtyScales = false;
}
return &orderedScales;
}
int TSE::OrdererSpriteSetChunk::GetChunksize()
{
return chunksize;
}
int TSE::OrdererSpriteSetChunk::GetSpriteCount()
{
return sprites.size();
}
void TSE::OrdererSpriteSet::RemoveSprite(Vector2 p, float height)
{
Vector2 chunkInnerPos = LocalToChunkPos(p);
Vector2 chunkIndex = p - chunkInnerPos;
if(chunks.contains(chunkIndex))
chunks[chunkIndex].RemoveSprite(chunkInnerPos, height);
}
void TSE::OrdererSpriteSet::SetSprite(Vector2 p, Vector2 Spriteindex, float height, Vector2 scale, Vector2 Normalindex)
{
Vector2 chunkInnerPos = LocalToChunkPos(p);
Vector2 chunkIndex = p - chunkInnerPos;
// Vector2 p2 = Vector2((int)p.x % chunkSize, (int)p.y % chunkSize);
// Vector2 chunkIndex = p - p2;
if(!chunks.contains(chunkIndex))
{
dirty = true;
chunks[chunkIndex] = OrdererSpriteSetChunk(chunkSize, chunkIndex, order);
}
chunks[chunkIndex].SetSprite(chunkInnerPos, Spriteindex, Normalindex, set, height, scale);
}
TSE::OrdererSpriteSetChunk *TSE::OrdererSpriteSet::GetChunk(const Vector2 &pos)
{
auto chunk = chunks.find(pos);
if(chunk == chunks.end())
return nullptr;
return &chunks[pos];
}
const std::vector<TSE::Vector2> *TSE::OrdererSpriteSet::GetChunkPositionsInOrder()
{
if(dirty)
{
orderedChunks.clear();
for(auto pos : chunks)
{
orderedChunks.push_back(pos.first);
}
switch (order)
{
case TopLeft:
std::sort(orderedChunks.begin(), orderedChunks.end(), [](const Vector2& a, const Vector2& b)
{
if (a.y != b.y)
return a.y > b.y;
return a.x < b.x;
});
break;
case TopRight:
std::sort(orderedChunks.begin(), orderedChunks.end(), [](const Vector2& a, const Vector2& b)
{
if (a.y != b.y)
return a.y > b.y;
return a.x > b.x;
});
break;
case BottomLeft:
std::sort(orderedChunks.begin(), orderedChunks.end(), [](const Vector2& a, const Vector2& b)
{
if (a.y != b.y)
return a.y < b.y;
return a.x < b.x;
});
break;
case BottomRight:
std::sort(orderedChunks.begin(), orderedChunks.end(), [](const Vector2& a, const Vector2& b)
{
if (a.y != b.y)
return a.y < b.y;
return a.x > b.x;
});
break;
}
dirty = false;
}
return &orderedChunks;
}
int TSE::OrdererSpriteSet::GetChunkCount()
{
return chunks.size();
}
TSE::TileSet *TSE::OrdererSpriteSet::GetTileSet()
{
return set;
}
void TSE::OrdererSpriteSet::DirtyAll()
{
dirty = true;
for(auto& chunk : chunks)
{
chunk.second.dirtyPositions = true;
chunk.second.dirtySpriteIds = true;
chunk.second.dirtyScales = true;
}
}
TSE::Vector2 TSE::OrdererSpriteSet::LocalToChunkPos(const Vector2 &v)
{
Vector2 p = Vector2(std::fmod(v.x, chunkSize), std::fmod(v.y, chunkSize));
if(p.x < 0) p.x += chunkSize;
if(p.y < 0) p.y += chunkSize;
return p;
}

View File

@@ -0,0 +1,74 @@
#pragma once
#define ORDERERSPRITESET typeid(OrdererSpriteSet).name()
#include "elements/BehaviourScript.hpp"
#include "elements/Transformable.hpp"
#include "Types.hpp"
#include "enums/SortingOrder.hpp"
#include "Vector2.hpp"
#include "Vector2i.hpp"
#include <unordered_map>
#include "elements/Sprite.hpp"
#include "elements/TileSet.hpp"
namespace TSE
{
struct OrdererSpriteSetChunk
{
private:
std::vector<Vector3> orderedPositions;
std::vector<Vector2i> orderedSpriteIDs;
std::vector<Vector2> orderedScales;
SortingOrder order;
int chunksize;
std::unordered_map<Vector3, Vector2i> sprites;
std::unordered_map<Vector3, Vector2> spriteScales;
public:
bool dirtyPositions = true;
bool dirtySpriteIds = true;
bool dirtyScales = true;
Vector2 pos;
OrdererSpriteSetChunk(int _chunksize = 16, const Vector2& _pos = {0,0}, SortingOrder _order = TopRight);
void SetSprite(const Vector2& p, const Vector2& Spriteindex, const Vector2& Normalindex, TileSet* set, float height, Vector2& scale);
void RemoveSprite(Vector2 p, float height);
void SetOrdering(SortingOrder _order);
const std::vector<Vector3>* GetOrderedPositions();
const std::vector<Vector2i>* GetOrderedSpriteIds();
const std::vector<Vector2>* GetOrderedScales();
int GetChunksize();
int GetSpriteCount();
};
class OrdererSpriteSet : public TSE::BehaviourScript
{
private:
bool dirty = true;
std::vector<Vector2> orderedChunks;
Rect bounds = Rect(0,0,0,0);
public:
float chunkSize = 16;
SortingOrder order = TopRight;
TileSet* set;
std::unordered_map<Vector2, OrdererSpriteSetChunk> chunks;
void RemoveSprite(Vector2 p, float height);
void SetSprite(Vector2 p, Vector2 Spriteindex, float height, Vector2 scale, Vector2 Normalindex = {-1,-1});
OrdererSpriteSetChunk* GetChunk(const Vector2& pos);
const std::vector<Vector2>* GetChunkPositionsInOrder();
int GetChunkCount();
TileSet* GetTileSet();
void DirtyAll();
inline const char* GetName() override
{
return "Orderer Sprite Set";
}
private:
Vector2 LocalToChunkPos(const Vector2& v);
};
} // namespace TSE

View File

@@ -5,7 +5,7 @@
#include "elements/BehaviourScript.hpp"
#include "Rect.hpp"
#include "Vector2.hpp"
#include "Mesh.hpp"
#include "elements/Mesh.hpp"
namespace TSE
{

View File

@@ -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();

View File

@@ -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;

View File

@@ -0,0 +1,327 @@
#include "TileMap.hpp"
TSE::TileMapChunk::TileMapChunk(int _chunksize, const Vector2 &_pos, SortingOrder _order)
{
chunksize = _chunksize;
pos = _pos;
order = _order;
}
void TSE::TileMapChunk::SetTile(const Vector2& p, const Vector2& Spriteindex, const Vector2& Normalindex, TileSet* set)
{
int normalid = -1;
if(Normalindex != Vector2(-1,-1))
normalid = set->GetSpriteIdAt(Normalindex.x, Normalindex.y);
sprites[p] = {set->GetSpriteIdAt(Spriteindex.x, Spriteindex.y), normalid};
dirtyPositions = true;
dirtySpriteIds = true;
}
void TSE::TileMapChunk::RemoveTile(Vector2 p)
{
sprites.erase(p);
}
void TSE::TileMapChunk::SetOrdering(SortingOrder _order)
{
order = _order;
dirtyPositions = true;
dirtySpriteIds = true;
}
const std::vector<TSE::Vector2>* TSE::TileMapChunk::GetOrderedPositions()
{
if(dirtyPositions)
{
orderedPositions.clear();
switch (order)
{
case TopLeft:
for (int y = 0; y < chunksize; y++)
{
Vector2 offset = nextLine * y;
for (int x = 0; x < chunksize; x++)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
}
}
break;
case TopRight:
for (int y = 0; y < chunksize; y++)
{
Vector2 offset = nextLine * y;
for (int x = chunksize - 1; x >= 0; x--)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
}
}
break;
case BottomLeft:
for (int y = chunksize - 1; y >= 0; y--)
{
Vector2 offset = nextLine * y;
for (int x = 0; x < chunksize; x++)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
}
}
break;
case BottomRight:
for (int y = chunksize - 1; y >= 0; y--)
{
Vector2 offset = nextLine * y;
for (int x = chunksize - 1; x >= 0; x--)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
}
}
break;
}
dirtyPositions = false;
}
return &orderedPositions;
}
const std::vector<TSE::Vector2i>* TSE::TileMapChunk::GetOrderedSpriteIds()
{
if(dirtySpriteIds)
{
orderedSpriteIDs.clear();
switch (order)
{
case TopLeft:
for (int y = 0; y < chunksize; y++)
{
for (int x = 0; x < chunksize; x++)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedSpriteIDs.push_back(v->second);
}
}
break;
case TopRight:
for (int y = 0; y < chunksize; y++)
{
for (int x = chunksize - 1; x >= 0; x--)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedSpriteIDs.push_back(v->second);
}
}
break;
case BottomLeft:
for (int y = chunksize - 1; y >= 0; y--)
{
for (int x = 0; x < chunksize; x++)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedSpriteIDs.push_back(v->second);
}
}
break;
case BottomRight:
for (int y = chunksize - 1; y >= 0; y--)
{
for (int x = chunksize - 1; x >= 0; x--)
{
Vector2 p(x,y);
auto v = sprites.find(p);
if(v != sprites.end())
orderedSpriteIDs.push_back(v->second);
}
}
break;
}
dirtySpriteIds = false;
}
return &orderedSpriteIDs;
}
int TSE::TileMapChunk::GetChunksize()
{
return chunksize;
}
int TSE::TileMapChunk::GetSpriteCount()
{
return sprites.size();
}
void TSE::TileMap::RemoveTile(Vector2 p)
{
Vector2 chunkInnerPos = LocalToChunkPos(p);
Vector2 chunkIndex = p - chunkInnerPos;
if(chunks.contains(chunkIndex))
chunks[chunkIndex].RemoveTile(chunkInnerPos);
}
void TSE::TileMap::SetTile(Vector2 p, Vector2 Spriteindex, Vector2 Normalindex)
{
Vector2 chunkInnerPos = LocalToChunkPos(p);
Vector2 chunkIndex = p - chunkInnerPos;
if(!chunks.contains(chunkIndex))
{
dirty = true;
chunks[chunkIndex] = TileMapChunk(chunkSize, chunkIndex, order);
chunks[chunkIndex].nextLine = nextLine;
CheckBounds(chunkIndex);
}
chunks[chunkIndex].SetTile(chunkInnerPos, Spriteindex, Normalindex, set);
}
TSE::TileMapChunk* TSE::TileMap::GetChunk(const Vector2 &pos)
{
auto chunk = chunks.find(pos);
if(chunk == chunks.end())
return nullptr;
return &chunks[pos];
}
const std::vector<TSE::Vector2>* TSE::TileMap::GetChunkPositionsInOrder()
{
if(dirty)
{
orderedChunks.clear();
switch (order)
{
case TopLeft:
for (int y = bounds.p1.y; y < bounds.p2.y + 1; y++)
{
for (int x = bounds.p1.x; x < bounds.p2.x + 1; x++)
{
Vector2 p(x,y);
auto v = chunks.find(p);
if(v != chunks.end())
orderedChunks.push_back(v->first);
}
}
break;
case TopRight:
for (int y = bounds.p1.y; y < bounds.p2.y + 1; y++)
{
for (int x = bounds.p2.x; x > bounds.p1.x - 1; x--)
{
Vector2 p(x,y);
auto v = chunks.find(p);
if(v != chunks.end())
orderedChunks.push_back(v->first);
}
}
break;
case BottomLeft:
for (int y = bounds.p2.y; y > bounds.p1.y - 1; y--)
{
for (int x = bounds.p1.x; x < bounds.p2.x + 1; x++)
{
Vector2 p(x,y);
auto v = chunks.find(p);
if(v != chunks.end())
orderedChunks.push_back(v->first);
}
}
break;
case BottomRight:
for (int y = bounds.p2.y; y > bounds.p1.y - 1; y--)
{
for (int x = bounds.p2.x; x > bounds.p1.x - 1; x--)
{
Vector2 p(x,y);
auto v = chunks.find(p);
if(v != chunks.end())
orderedChunks.push_back(v->first);
}
}
break;
}
dirty = false;
}
return &orderedChunks;
}
int TSE::TileMap::GetChunkCount()
{
return chunks.size();
}
TSE::TileSet *TSE::TileMap::GetTileSet()
{
return set;
}
void TSE::TileMap::SetNextLineOffset(const Vector2 &offset)
{
nextLine = offset;
for(auto& [_, chunk] : chunks)
{
chunk.nextLine = offset;
}
DirtyAll();
}
TSE::Vector2 TSE::TileMap::GetNextLineOffset()
{
return nextLine;
}
void TSE::TileMap::DirtyAll()
{
dirty = true;
for(auto& chunk : chunks)
{
chunk.second.dirtyPositions = true;
chunk.second.dirtySpriteIds = true;
}
}
void TSE::TileMap::CheckBounds(Vector2 pos)
{
if(pos.x > bounds.p2.x)
bounds.p2.x = pos.x;
if(pos.y > bounds.p2.y)
bounds.p2.y = pos.y;
if(pos.x < bounds.p1.x)
bounds.p1.x = pos.x;
if(pos.y < bounds.p1.y)
bounds.p1.y = pos.y;
}
TSE::Vector2 TSE::TileMap::LocalToChunkPos(const Vector2 &v)
{
Vector2 p = Vector2((int)v.x % chunkSize, (int)v.y % chunkSize);
if(p.x < 0) p.x += chunkSize;
if(p.y < 0) p.y += chunkSize;
return p;
}
TSE::Vector2 TSE::TileMap::ChunkToLocalPos(const Vector2 &v, const TileMapChunk &chunk)
{
return v + chunk.pos * chunkSize;
}
TSE::Vector2 TSE::TileMap::RealPosToTileMapPos(const Vector2 &v)
{
return v * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * v.y, nextLine.y * 0.5f * v.x);
}
TSE::Vector2 TSE::TileMap::TileMapToRealPos(const Vector2 &v)
{
return v * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * v.y, nextLine.y * 0.5f * v.x);
}

View File

@@ -0,0 +1,76 @@
#pragma once
#define TILE_MAP typeid(TSE::TileMap).name()
#include <unordered_map>
#include "elements/BehaviourScript.hpp"
#include "Vector2.hpp"
#include "Vector2i.hpp"
#include "elements/Sprite.hpp"
#include "elements/TileSet.hpp"
#include "enums/SortingOrder.hpp"
namespace TSE
{
struct TileMapChunk
{
private:
std::vector<Vector2> orderedPositions;
std::vector<Vector2i> orderedSpriteIDs;
SortingOrder order;
int chunksize;
std::unordered_map<Vector2, Vector2i> sprites;
public:
bool dirtyPositions = true;
bool dirtySpriteIds = true;
Vector2 nextLine;
Vector2 pos;
TileMapChunk(int _chunksize = 16, const Vector2& _pos = {0,0}, SortingOrder _order = TopRight);
void SetTile(const Vector2& p, const Vector2& Spriteindex, const Vector2& Normalindex, TileSet* set);
void RemoveTile(Vector2 p);
void SetOrdering(SortingOrder _order);
const std::vector<Vector2>* GetOrderedPositions();
const std::vector<Vector2i>* GetOrderedSpriteIds();
int GetChunksize();
int GetSpriteCount();
};
class TileMap : public BehaviourScript
{
private:
bool dirty = true;
std::vector<Vector2> orderedChunks;
Rect bounds = Rect(0,0,0,0);
Vector2 nextLine = Vector2(0.5f, 0.5f);
public:
int chunkSize = 16;
SortingOrder order = BottomRight;
Vector2 SpriteScale = Vector2(1,1);
TileSet* set;
std::unordered_map<Vector2, TileMapChunk> chunks;
void RemoveTile(Vector2 p);
void SetTile(Vector2 p, Vector2 Spriteindex, Vector2 Normalindex = {-1,-1});
TileMapChunk* GetChunk(const Vector2& pos);
const std::vector<Vector2>* GetChunkPositionsInOrder();
int GetChunkCount();
TileSet* GetTileSet();
const Rect& GetBounds() const { return bounds; }
void SetNextLineOffset(const Vector2& offset);
Vector2 GetNextLineOffset();
Vector2 RealPosToTileMapPos(const Vector2& v);
Vector2 TileMapToRealPos(const Vector2& v);
void DirtyAll();
inline const char* GetName() override
{
return "Tile Map";
}
private:
void CheckBounds(Vector2 pos);
Vector2 LocalToChunkPos(const Vector2& v);
Vector2 ChunkToLocalPos(const Vector2& v, const TileMapChunk& chunk);
};
} // namespace TSE

View File

@@ -0,0 +1,185 @@
#include "AssetLibrary.hpp"
#include "Material.hpp"
#include "Mesh.hpp"
#include "Texture.hpp"
#include <iostream>
#include <filesystem>
#include <algorithm>
#include "Debug.hpp"
std::unordered_map<uuids::uuid, std::tuple<std::any, TSE::string, uuids::uuid>> TSE::AssetLibrary::assets;
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();
}
int TSE::AssetLibrary::GetValueCount()
{
return assets.size();
}
std::tuple<std::any, TSE::string, uuids::uuid> &TSE::AssetLibrary::GetValueAt(int j)
{
auto it = assets.begin();
for (int i = 0; i < j; i++)
{
it++;
}
return it->second;
}
void TSE::AssetLibrary::SaveAllAssets()
{
int count = GetValueCount();
for(int i = 0; i < count; i++)
{
std::tuple<std::any, string, uuids::uuid> tupel = GetValueAt(i);
auto[ptr, type, name] = tupel;
if (type == typeid(Material*).name())
{
Material* value = GetValue<Material*>(name);
if(!value->IsVirtualAsset)
value->SaveAsset();
}
if (type == typeid(Texture*).name())
{
Texture* value = GetValue<Texture*>(name);
if(!value->IsVirtualAsset)
value->SaveAsset();
}
if (type == typeid(Mesh*).name())
{
Mesh* value = GetValue<Mesh*>(name);
if(!value->IsVirtualAsset)
value->SaveAsset();
}
}
}
std::string ToLower(std::string str)
{
std::transform(str.begin(), str.end(), str.begin(),
[](unsigned char c)
{
return static_cast<char>(std::tolower(c));
});
return str;
}
void TSE::AssetLibrary::LoadAllAssets(string &path)
{
LoadDefaultAssets();
namespace fs = std::filesystem;
currentAssetPath = string(path);
if (!fs::exists(currentAssetPath) || !fs::is_directory(currentAssetPath))
{
TSE_ERROR("Invalid Asset Path: " + currentAssetPath);
return;
}
for (const auto& entry : fs::recursive_directory_iterator(currentAssetPath))
{
if (!entry.is_regular_file())
continue;
string ext = ToLower(entry.path().extension().string());
string path = entry.path().string();
if(alreadyLoadedAssets.find(path) != alreadyLoadedAssets.end()) continue;
if (ext == ".material")
{
Material* mat = new Material();
mat->LoadAsset(path);
SetValue(mat->id, mat);
alreadyLoadedAssets[path] = mat->id;
}
else if (ext == ".png" || ext == ".jpeg" || ext == ".jpg")
{
Texture* tex = new Texture(0,0);
tex->LoadAsset(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;
}
}
}
void TSE::AssetLibrary::RescanAssets()
{
int count = GetValueCount();
for(int i = 0; i < count; i++)
{
std::tuple<std::any, string, uuids::uuid> tupel = GetValueAt(i);
auto[ptr, type, name] = tupel;
if (type == typeid(Material*).name())
{
Material* value = GetValue<Material*>(name);
if(!value->IsVirtualAsset)
value->Rescan();
}
if (type == typeid(Texture*).name())
{
Texture* value = GetValue<Texture*>(name);
if(!value->IsVirtualAsset)
value->Rescan();
}
if (type == typeid(Mesh*).name())
{
Mesh* value = GetValue<Mesh*>(name);
if(!value->IsVirtualAsset)
value->Rescan();
}
}
}
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&);

View File

@@ -0,0 +1,56 @@
#pragma once
#include "interfaces/IAsset.hpp"
#include <unordered_map>
#include <any>
#include "uuid.h"
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, T* value);
static void RemoveValue(const uuids::uuid& key, IAsset* asset);
static bool HasValue(const uuids::uuid& key);
static int GetValueCount();
static std::tuple<std::any, string, uuids::uuid>& GetValueAt(int i);
static void SaveAllAssets();
static void LoadAllAssets(string& path);
static void RescanAssets();
static string GetCurrentAssetPath();
};
template<typename T>
T AssetLibrary::GetValue(const uuids::uuid& key) {
auto it = assets.find(key);
if (it == assets.end()) {
throw std::runtime_error("AssetLibrary::GetValue - key '" + uuids::to_string(key) + "' not found");
}
auto [a,b,c] = it->second;
return std::any_cast<T>(a);
}
template<typename T>
void AssetLibrary::SetValue(const uuids::uuid& key, T* value) {
assets[key] = std::make_tuple(value, typeid(T).name(), key);
}
}

View File

@@ -1,6 +1,7 @@
#include "Layer.hpp"
#include "BehaviourScripts/Renderable.hpp"
#include "elements/BehaviourScript.hpp"
#include "IdGenerator.hpp"
void HandleObject(TSE::Transformable* trans, TSE::TransformationStack& stack, TSE::IRenderer& rnd)
{
@@ -24,6 +25,7 @@ void HandleObject(TSE::Transformable* trans, TSE::TransformationStack& stack, TS
TSE::Layer::Layer(const string &n)
{
ID = GenerateRandomUUID();
name = n;
}
@@ -94,3 +96,13 @@ void TSE::Layer::Update()
trans->Update();
}
}
void TSE::Layer::SetNonVisual(bool v)
{
nonVisual = v;
}
bool TSE::Layer::IsVisual()
{
return !nonVisual;
}

View File

@@ -4,14 +4,16 @@
#include "Types.hpp"
#include "interfaces/IRenderer.hpp"
#include <vector>
#include "interfaces/IIdentifyable.hpp"
namespace TSE
{
class Layer
class Layer : public IIdentifyable
{
private:
string name;
std::vector<Transformable*> objectsToRender;
bool nonVisual = false;
public:
Layer(const string& name);
@@ -27,5 +29,7 @@ namespace TSE
void SetName(const string& name);
std::vector<Transformable*>& GetAllObjects();
void Update();
void SetNonVisual(bool v);
bool IsVisual();
};
} // namespace TSE

View File

@@ -9,6 +9,11 @@
#include "Vector4.hpp"
#include "Color.hpp"
#include "Matrix4x4.hpp"
#include "PathHelper.hpp"
#include "utils/JsonExports.hpp"
#include "Debug.hpp"
#include "ShaderRegistry.hpp"
#include "AssetLibrary.hpp"
namespace TSE
{
@@ -18,7 +23,9 @@ namespace TSE
id = GenerateRandomUUID();
}
Material::Material(const string& name, IShader* shader, uuids::uuid id)
: name(name), shader(shader), id(id) {}
: name(name), shader(shader){
this->id = id;
}
Material::Material(const string &name, IShader *shader)
: name(name), shader(shader)
@@ -59,7 +66,268 @@ namespace TSE
return id;
}
bool Material::LoadAsset(string &path)
{
rawPath = string(path);
string metaPath = PathToMetaPath(rawPath);
using json = nlohmann::ordered_json;
std::ifstream rawStream;
OpenFileReading(rawStream, rawPath);
json material = json::parse(rawStream);
if(material["type"] != "material")
{
rawStream.close();
TSE_ERROR("Asset Loading Error (Material): not a material file = " + ((string)material["type"]));
return false;
}
if(material["version"] == 1)
{
name = material["name"];
shader = ShaderRegistry::GetShader(material["shader"]);
if (material.contains("properties"))
for (auto& [name, prop] : material["properties"].items())
{
std::string type = prop["type"];
auto& value = prop["value"];
if (type == "Int")
{
int v = value.get<int>();
SetValue(name, v);
}
else if (type == "Float")
{
float v = value.get<float>();
SetValue(name, v);
}
else if (type == "Vector2")
{
Vector2 v = ImportVector2(value);
SetValue(name, v);
}
else if (type == "Vector3")
{
Vector3 v = ImportVector3(value);
SetValue(name, v);
}
else if (type == "Vector4")
{
Vector4 v = ImportVector4(value);
SetValue(name, v);
}
else if (type == "Color")
{
Color v = ImportColor(value);
SetValue(name, v);
}
else if (type == "String")
{
string v = value.get<string>();
SetValue(name, v);
}
else if (type == "Uint")
{
uint v = value.get<uint>();
SetValue(name, v);
}
}
rawStream.close();
Hash();
rawStream.close();
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 (Material): " + metaPath);
SaveMeta();
return true;
}
if(meta["version"] == 1)
{
if(meta["assetType"] == "material")
{
id = uuids::uuid::from_string((string)meta["id"]).value_or(id);
//dependencies;
metaStream.close();
SaveMeta();
return true;
}
else
{
metaStream.close();
TSE_WARNING("Meta file incompatible with asset type. Please delete for auto regeneration or fix maualy (Material): " + metaPath);
return true;
}
}
else
{
metaStream.close();
TSE_WARNING("Meta file incompatible. Please delete for auto regeneration or fix maualy (Material): " + metaPath);
return true;
}
}
else
{
SaveMeta();
return true;
}
}
else
{
rawStream.close();
TSE_ERROR("Asset Loading Error (Material): incompatible asset version = " + std::to_string((int)material["version"]));
return false;
}
}
void Material::SaveAsset()
{
if(IsVirtualAsset) return;
using json = nlohmann::ordered_json;
json material = GenerateMaterialJson();
std::ofstream rawStream;
CreateFileWriting(rawStream, rawPath);
rawStream << material.dump(4) << std::endl;
rawStream.close();
Hash();
SaveMeta();
}
nlohmann::ordered_json Material::GenerateMaterialJson()
{
using json = nlohmann::ordered_json;
json material;
material["type"] = "material";
material["version"] = 1;
material["name"] = name;
material["shader"] = shader->GetName();
int count = GetValueCount();
for(int i = 0; i < count; i++)
{
std::tuple<std::any, std::string, std::string> tupel = GetValueAt(i);
auto[ptr, type, name] = tupel;
if (type == typeid(int).name())
{
int value = GetValue<int>(name);
material["properties"][name]["type"] = "Int";
material["properties"][name]["value"] = value;
}
else if (type == typeid(float).name())
{
float value = GetValue<float>(name);
material["properties"][name]["type"] = "Float";
material["properties"][name]["value"] = value;
}
else if (type == typeid(Vector2).name())
{
Vector2 value = GetValue<Vector2>(name);
material["properties"][name]["type"] = "Vector2";
material["properties"][name]["value"] = ExportVector2(value);
}
else if (type == typeid(Vector3).name())
{
Vector3 value = GetValue<Vector3>(name);
material["properties"][name]["type"] = "Vector3";
material["properties"][name]["value"] = ExportVector3(value);
}
else if (type == typeid(Vector4).name())
{
Vector4 value = GetValue<Vector4>(name);
material["properties"][name]["type"] = "Vector4";
material["properties"][name]["value"] = ExportVector4(value);
}
else if (type == typeid(Matrix4x4).name())
{
Matrix4x4 value = GetValue<Matrix4x4>(name);
//TODO: need to implement;
}
else if (type == typeid(Color).name())
{
Color value = GetValue<Color>(name);
material["properties"][name]["type"] = "Color";
material["properties"][name]["value"] = ExportColor(value);
}
else if (type == typeid(std::string).name())
{
std::string value = GetValue<std::string>(name);
material["properties"][name]["type"] = "String";
material["properties"][name]["value"] = value;
}
else if (type == typeid(Texture*).name())
{
Texture* value = GetValue<Texture*>(name);
//todo: implement
}
if (type == typeid(uint).name())
{
int value = GetValue<uint>(name);
material["properties"][name]["type"] = "Uint";
material["properties"][name]["value"] = value;
}
}
return material;
}
void Material::Hash()
{
using json = nlohmann::ordered_json;
json material = GenerateMaterialJson();
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);
using json = nlohmann::ordered_json;
json meta;
meta["type"] = "metadata";
meta["assetType"] = "material";
meta["version"] = 1;
meta["source"] = rawPath; //todo: clamp to assets root
meta["id"] = uuids::to_string(id);
meta["hash"] = hash;
for (int i = 0; i < dependecies.size(); i++)
{
meta["dependencies"][i]["id"] = uuids::to_string(dependecies[i]->id);
meta["dependencies"][i]["path"] = dependecies[i]->rawPath; //todo: clamp to assets root
}
std::ofstream metaStream;
CreateFileWriting(metaStream, metaPath);
metaStream << meta.dump(4) << std::endl;
metaStream.close();
}
template void Material::SetValue<int>(const string&, const int&);
template void Material::SetValue<uint>(const string&, const uint&);
template void Material::SetValue<float>(const string&, const float&);
template void Material::SetValue<Vector2>(const string&, const Vector2&);
template void Material::SetValue<Vector3>(const string&, const Vector3&);
@@ -70,6 +338,7 @@ namespace TSE
template void Material::SetValue<ITexture>(const string&, const ITexture*);
template int Material::GetValue<int>(const string&) const;
template uint Material::GetValue<uint>(const string&) const;
template float Material::GetValue<float>(const string&) const;
template Vector2 Material::GetValue<Vector2>(const string&) const;
template Vector3 Material::GetValue<Vector3>(const string&) const;

View File

@@ -6,14 +6,15 @@
#include <any>
#include <string>
#include <tuple>
#include "interfaces/IAsset.hpp"
#include "json.hpp"
namespace TSE
{
struct Material
struct Material : public IAsset
{
private:
string name;
uuids::uuid id;
IShader* shader;
std::unordered_map<string, std::tuple<std::any, string, string>> values;
@@ -40,6 +41,15 @@ namespace TSE
IShader* GetShader() const;
void SetShader(IShader* shader);
uuids::uuid GetID() const;
bool LoadAsset(string& path) override;
void SaveAsset() override;
nlohmann::ordered_json GenerateMaterialJson();
void Hash() override;
string assetType() override;
void UnloadAsset() override;
protected:
void SaveMeta() override;
};
template<typename T>

View 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();
}

View File

@@ -4,10 +4,11 @@
#include "Types.hpp"
#include "Vector3.hpp"
#include "Vector2.hpp"
#include "interfaces/IAsset.hpp"
namespace TSE
{
class Mesh
class Mesh : public IAsset
{
public:
string name;
@@ -41,5 +42,16 @@ namespace TSE
/// @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

View File

@@ -0,0 +1,40 @@
#include "RenderPipeline.hpp"
void TSE::RenderPipeline::AddRenderStep(const RenderStep &step)
{
steps.push_back(step);
}
void TSE::RenderPipeline::AddRenderStepAt(const RenderStep &step, int n)
{
steps.insert(steps.begin() + n, step);
}
void TSE::RenderPipeline::SetRenderStepAt(const RenderStep &step, int n)
{
steps[n] = step;
}
void TSE::RenderPipeline::RemoveRenderStepAt(int n)
{
auto i = steps.begin() += n;
steps.erase(i);
}
int TSE::RenderPipeline::GetRenderStepCount()
{
return steps.size();
}
const TSE::RenderStep &TSE::RenderPipeline::GetRenderStepAt(int n)
{
return steps[n];
}
TSE::RenderPipeline* TSE::RenderPipeline::CreateEmpty()
{
RenderPipeline* res = new RenderPipeline();
RenderStep step;
res->AddRenderStep(step);
return res;
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "RenderStep.hpp"
namespace TSE
{
class RenderPipeline
{
private:
std::vector<RenderStep> steps;
public:
void AddRenderStep(const RenderStep& step);
void AddRenderStepAt(const RenderStep& step, int n);
void SetRenderStepAt(const RenderStep& step, int n);
void RemoveRenderStepAt(int n);
int GetRenderStepCount();
const RenderStep& GetRenderStepAt(int n);
static RenderPipeline* CreateEmpty();
};
} // namespace TSE

View File

@@ -0,0 +1,18 @@
#pragma once
#include "Layer.hpp"
#include <vector>
#include "interfaces/IRenderTarget.hpp"
#include "Types.hpp"
namespace TSE
{
struct RenderStep
{
public:
std::vector<Layer*> layersToRender;
IRenderTarget* target;
bool EditorCamera = true;
};
} // namespace TSE

View File

@@ -1,24 +1,89 @@
#include "Scene.hpp"
#include "BehaviourScripts/Camera.hpp"
#include <algorithm>
#include "Debug.hpp"
#include "RenderPipeline.hpp"
void TSE::Scene::Render(IRenderer &rnd, const IWindow &wnd)
{
int counter = 1;
for(auto l : layers)
{
l.second->Render(rnd);
if(counter++ != layers.size())
{
rnd.End(); //OPTIMIZE:
//takes up 13,97% of function, but only needed, if there is more then one layer
//possible optimizations:
// -remove layers
// -make layer calculations, in shader
// -make an offset, that is calculated on cpu, and then commit everything at once
RenderPipeline* pipeline = IRenderer::pipeline;
auto camerasBackup = std::vector<Camera*>(IRenderer::camerasToRenderWith);
// now it is better because it is only done once per frame if only one shader is used, or textures are full, or more then one layers are used
rnd.Flush();
rnd.Begin();
wnd.ClearDepthBuffer();
if(pipeline != nullptr)
{
for(int i = 0; i < pipeline->GetRenderStepCount(); i++)
{
IRenderer::camerasToRenderWith = std::vector<Camera*>(camerasBackup);
const RenderStep& step = pipeline->GetRenderStepAt(i);
if(!step.EditorCamera)
{
for(int i = 0; i < IRenderer::camerasToRenderWith.size(); i++)
{
if(IRenderer::camerasToRenderWith[i]->baseObject->name == ".EditorCamera")
IRenderer::camerasToRenderWith.erase(IRenderer::camerasToRenderWith.begin() + i);
}
}
for(int i = 0; i < IRenderer::camerasToRenderWith.size(); i++)
{
if(IRenderer::camerasToRenderWith[i]->baseObject->name != ".EditorCamera")
IRenderer::camerasToRenderWith[i]->SetRenderTarget(step.target);
}
int counter = 1;
for(auto l : step.layersToRender)
{
if(!l->IsVisual()) continue;
l->Render(rnd);
if(counter++ != layers.size())
{
rnd.End(); //OPTIMIZE:
//takes up 13,97% of function, but only needed, if there is more then one layer
//possible optimizations:
// -remove layers
// -make layer calculations, in shader
// -make an offset, that is calculated on cpu, and then commit everything at once
// now it is better because it is only done once per frame if only one shader is used, or textures are full, or more then one layers are used
rnd.Flush();
rnd.Begin();
wnd.ClearDepthBuffer();
}
}
}
}
else
{
int counter = 1;
for(auto l : layers)
{
IRenderer::camerasToRenderWith.clear();
if(!l.second->IsVisual()) continue;
for(auto camera : camerasBackup)
{
auto it = std::find(camera->layersNotToRender.begin(), camera->layersNotToRender.end(), l.second->GetID());
if(it == camera->layersNotToRender.end())
{
IRenderer::camerasToRenderWith.push_back(camera);
}
}
l.second->Render(rnd);
if(counter++ != layers.size())
{
rnd.End(); //OPTIMIZE:
//takes up 13,97% of function, but only needed, if there is more then one layer
//possible optimizations:
// -remove layers
// -make layer calculations, in shader
// -make an offset, that is calculated on cpu, and then commit everything at once
// now it is better because it is only done once per frame if only one shader is used, or textures are full, or more then one layers are used
rnd.Flush();
rnd.Begin();
wnd.ClearDepthBuffer();
}
}
}
}

View File

@@ -12,9 +12,9 @@ namespace TSE
inline static std::unordered_map<string, IShader*> registeredShaders = {};
public:
inline static void SetShader(const string& name, IShader* shader)
inline static void SetShader(IShader* shader)
{
registeredShaders[name] = shader;
registeredShaders[shader->GetName()] = shader;
};
inline static IShader* GetShader(const string& name)
{

View File

@@ -2,28 +2,51 @@
#include "Debug.hpp"
#include "Color.hpp"
#include "ErrorTextureData.hpp"
#include <filesystem>
#include "json.hpp"
#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;
Size = Vector2(0,0);
fif = FreeImage_GetFileType(path.c_str(), 0);
string name = std::filesystem::absolute(path).string();
if(!std::filesystem::exists(name))
{
string msg = string("File dose not exist: ") + std::filesystem::absolute(path).string();
TSE_ERROR(msg);
Bpp = 24;
makeError(*this);
return false;
}
fif = FreeImage_GetFileType(name.c_str(), 0);
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN)
fif = FreeImage_GetFIFFromFilename(path.c_str());
fif = FreeImage_GetFIFFromFilename(name.c_str());
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN)
{
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);
@@ -35,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);
@@ -53,10 +76,12 @@ 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)
{
id = GenerateRandomUUID();
switch (bpp)
{
case 32:
@@ -76,6 +101,7 @@ TSE::Texture::Texture(const int &width, const int &height, int bpp)
TSE::Texture::Texture(const Vector2 &size, int bpp)
{
id = GenerateRandomUUID();
switch (bpp)
{
case 32:
@@ -108,6 +134,11 @@ TSE::Texture::~Texture()
}
}
TSE::string TSE::Texture::name() const
{
return settings.name;
}
TSE::uint TSE::Texture::bpp() const
{
return Bpp;
@@ -199,84 +230,6 @@ TSE::Texture TSE::Texture::CutOut(const Vector2 &pos, Vector2 &size) const
return out;
}
TSE::Texture TSE::Texture::Upscale(const Vector2 &size) const
{
Texture result = Texture(0,0);
if(bmp == nullptr)
{
TSE_ERROR("Failed to upscale texture. Source bitmap was nullptr.");
Texture::makeError(result);
return result;
}
const int width = static_cast<int>(size.x);
const int height = static_cast<int>(size.y);
if(width <= 0 || height <= 0)
{
TSE_ERROR("Failed to upscale texture. Size must be greater than 0.");
Texture::makeError(result);
return result;
}
FIBITMAP* scaled = FreeImage_Rescale(bmp, width, height, FILTER_NEAREST);
if(scaled == nullptr)
{
TSE_ERROR("Failed to upscale texture. FreeImage_Rescale returned nullptr.");
Texture::makeError(result);
return result;
}
Texture out = Texture(width, height, Bpp);
if(out.bmp != nullptr)
FreeImage_Unload(out.bmp);
out.bmp = scaled;
out.imagePtr = FreeImage_GetBits(scaled);
out.Bpp = Bpp;
out.chanels = chanels;
out.Size = Vector2(width, height);
out.Apply();
return out;
}
TSE::Texture TSE::Texture::Downscale(const Vector2 &size) const
{
Texture result = Texture(0,0);
if(bmp == nullptr)
{
TSE_ERROR("Failed to downscale texture. Source bitmap was nullptr.");
Texture::makeError(result);
return result;
}
const int width = static_cast<int>(size.x);
const int height = static_cast<int>(size.y);
if(width <= 0 || height <= 0)
{
TSE_ERROR("Failed to downscale texture. Size must be greater than 0.");
Texture::makeError(result);
return result;
}
FIBITMAP* scaled = FreeImage_Rescale(bmp, width, height, FILTER_NEAREST);
if(scaled == nullptr)
{
TSE_ERROR("Failed to downscale texture. FreeImage_Rescale returned nullptr.");
Texture::makeError(result);
return result;
}
Texture out = Texture(width, height, Bpp);
if(out.bmp != nullptr)
FreeImage_Unload(out.bmp);
out.bmp = scaled;
out.imagePtr = FreeImage_GetBits(scaled);
out.Bpp = Bpp;
out.chanels = chanels;
out.Size = Vector2(width, height);
out.Apply();
return out;
}
void TSE::Texture::PasteIn(const Vector2 &pos, Texture &t)
{
if(bmp == nullptr)
@@ -527,3 +480,154 @@ void TSE::Texture::PlatformDestroy()
{
helper->PlatromDestroy(this);
}
bool TSE::Texture::LoadAsset(string &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);
using json = nlohmann::ordered_json;
Hash();
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"] == "texture")
{
id = uuids::uuid::from_string((string)meta["id"]).value_or(id);
//dependencies;
settings.importMode = meta["importSettings"]["mode"];
settings.importCount = ImportVector2(meta["importSettings"]["count"]);
settings.bpp = meta["importSettings"]["bpp"];
settings.chanels = meta["importSettings"]["chanels"];
settings.name = meta["importSettings"]["name"];
Bpp = settings.bpp;
chanels = settings.chanels;
//create sub assets eg. sprites;
metaStream.close();
SaveMeta();
return true;
}
else
{
metaStream.close();
TSE_WARNING("Meta file incompatible with asset type. Please delete for auto regeneration or fix maualy (Texture): " + metaPath);
return true;
}
}
else
{
metaStream.close();
TSE_WARNING("Meta file incompatible. Please delete for auto regeneration or fix maualy (Texture): " + metaPath);
return true;
}
}
else
{
SaveMeta();
return true;
}
}
void TSE::Texture::SaveAsset()
{
if(IsVirtualAsset) return;
Hash();
SaveMeta();
}
void TSE::Texture::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();
}
void TSE::Texture::UpdateImportSettings(string name, byte mode, Vector2 count)
{
settings.importMode = mode;
settings.importCount = count;
settings.name = name;
settings.bpp = Bpp;
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);
using json = nlohmann::ordered_json;
json meta;
meta["type"] = "metadata";
meta["assetType"] = "texture";
meta["version"] = 1;
meta["source"] = rawPath; //todo: clamp to assets root
meta["id"] = uuids::to_string(id);
meta["hash"] = hash;
meta["importSettings"]["mode"] = settings.importMode;
meta["importSettings"]["count"] = ExportVector2(settings.importCount);
meta["importSettings"]["bpp"] = settings.bpp;
meta["importSettings"]["chanels"] = settings.chanels;
meta["importSettings"]["name"] = settings.name;
for (int i = 0; i < dependecies.size(); i++)
{
meta["dependencies"][i]["id"] = uuids::to_string(dependecies[i]->id);
meta["dependencies"][i]["path"] = dependecies[i]->rawPath; //todo: clamp to assets root
}
std::ofstream metaStream;
CreateFileWriting(metaStream, metaPath);
metaStream << meta.dump(4) << std::endl;
metaStream.close();
}

View File

@@ -5,15 +5,31 @@
#include "Types.hpp"
#include "Vector2.hpp"
#include "interfaces/ITextureHelper.hpp"
#include "interfaces/IAsset.hpp"
#define FREEIMAGE_LIB
#include "FI/FreeImage.h"
namespace TSE
{
class Texture : public ITexture
struct TextureImportSettings
{
//0 = rawTexture;
//1 = sprite;
//2 = spriteset; ==> need to set import count to sprite counts
//3 = ninetile;
byte importMode = 0;
Vector2 importCount = {1,1};
//bpp and chanels are set from import, but can be changed for custum effects, or memory layouts
uint bpp;
byte chanels;
string name = "Unnamed";
};
class Texture : public ITexture, public IAsset
{
protected:
TextureImportSettings settings;
uint TextureID = 0;
Vector2 Size;
uint Bpp;
@@ -22,14 +38,13 @@ namespace TSE
byte* imagePtr = nullptr;
public:
string name = "Unnamed";
inline static ITextureHelper* helper = nullptr;
Texture(const string& path);
Texture(const int& width, const int& height, int bpp = 32);
Texture(const Vector2& size, int bpp = 32);
~Texture();
string name() const;
uint bpp() const;
Vector2 size() const override;
float Width() const override;
@@ -39,8 +54,6 @@ namespace TSE
void SetPixel(const Vector2& pos, const Color& c);
void GetPixel(const Vector2& pos, Color& c) const;
Texture CutOut(const Vector2& pos, Vector2& size) const;
Texture Upscale(const Vector2& size) const;
Texture Downscale(const Vector2& size) const;
void PasteIn(const Vector2& pos, Texture& t);
void SetPixelNoApply(const Vector2& pos, const Color& c);
void ToSprite(Sprite& s);
@@ -62,5 +75,18 @@ namespace TSE
void Apply();
void regist();
void PlatformDestroy();
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

View File

@@ -1,5 +1,6 @@
#include "TileSet.hpp"
#include "Debug.hpp"
#include "Types.hpp"
#define PADDING 0.0f
@@ -33,3 +34,24 @@ void TSE::TileSet::GetSpriteAt(int x, int y, Sprite &s)
s = Sprite(tex, Rect(startpos, endpos));
}
int TSE::TileSet::GetSpriteIdAt(int x, int y)
{
if(x < 0 || x >= resx || y < 0 || y >= resy)
{
TSE_ERROR("The sprite you are trying to access is out of range");
return -1;
}
return y * resx + x;
}
TSE::uint TSE::TileSet::GetTextueID()
{
return tex->GetTextureId();
}
TSE::Vector2 TSE::TileSet::GetCount()
{
return Vector2(resx, resy);
}

View File

@@ -18,14 +18,18 @@ namespace TSE
void SetTexture(Texture* tex);
void GetSpriteAt(int x, int y, Sprite& s);
int GetSpriteIdAt(int x, int y);
uint GetTextueID();
Vector2 GetCount();
inline void SetCount(Vector2& v)
{
SetCount(v.x, v.y);
};
inline void GetSpriteAt(Vector2& v, Sprite& s)
inline void GetSpriteAt(const Vector2& v, Sprite& s)
{
GetSpriteAt(v.x, v.y, s);
};
};
} // namespace TSE

View File

@@ -110,7 +110,7 @@ namespace TSE
Matrix4x4 Transformable::GetLocalMatrix() const
{
return Matrix4x4::ToTranslationMatrix(position) * Matrix4x4::ToRotationMatrix(rotation) * Matrix4x4::ToScaleMatrix(scale);;
return Matrix4x4::ToTranslationMatrix(position) * Matrix4x4::ToRotationMatrix(rotation) * Matrix4x4::ToScaleMatrix(scale);
}
Matrix4x4 Transformable::GetGlobalMatrix() const

View File

@@ -0,0 +1,429 @@
#include "VolumeTexture3D.hpp"
#include "Debug.hpp"
#include <algorithm>
#include <cctype>
#include <filesystem>
#include <vector>
TSE::VolumeTexture3D::VolumeTexture3D(const string &path)
{
namespace fs = std::filesystem;
Size = Vector3(0, 0, 0);
Bpp = 0;
std::error_code ec;
const fs::path folderPath = fs::absolute(path, ec);
if(ec || !fs::exists(folderPath, ec))
{
TSE_WARNING("Can't create VolumeTexture3D because the given path is inaccessible: \n" + path);
return;
}
if(ec || !fs::is_directory(folderPath, ec))
{
TSE_WARNING("Can't create VolumeTexture3D because the given path is not a folder: \n" + folderPath.string());
return;
}
std::vector<fs::path> pngFiles;
for(fs::directory_iterator it(folderPath, ec); !ec && it != fs::directory_iterator(); it.increment(ec))
{
if(!it->is_regular_file(ec))
continue;
const fs::path &filePath = it->path();
auto extension = filePath.extension().string();
std::transform(extension.begin(), extension.end(), extension.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
if(extension == ".png")
pngFiles.push_back(filePath);
}
if(ec)
{
TSE_WARNING("Can't read VolumeTexture3D folder: \n" + folderPath.string());
return;
}
if(pngFiles.empty())
{
TSE_WARNING("Can't create VolumeTexture3D because the folder contains no png files: \n" + folderPath.string());
return;
}
std::sort(pngFiles.begin(), pngFiles.end());
std::vector<FIBITMAP*> loadedBitmaps;
loadedBitmaps.reserve(pngFiles.size());
uint width = 0;
uint height = 0;
for(const fs::path &filePath : pngFiles)
{
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filePath.string().c_str(), 0);
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN)
fif = FreeImage_GetFIFFromFilename(filePath.string().c_str());
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif))
{
TSE_WARNING("Failed to load png for VolumeTexture3D: \n" + filePath.string());
for(FIBITMAP* loadedBmp : loadedBitmaps)
FreeImage_Unload(loadedBmp);
return;
}
FIBITMAP* currentBmp = FreeImage_Load(fif, filePath.string().c_str());
if(currentBmp == nullptr)
{
TSE_WARNING("Failed to load png for VolumeTexture3D: \n" + filePath.string());
for(FIBITMAP* loadedBmp : loadedBitmaps)
FreeImage_Unload(loadedBmp);
return;
}
if(FreeImage_GetBPP(currentBmp) != 32)
{
FIBITMAP* convertedBmp = FreeImage_ConvertTo32Bits(currentBmp);
FreeImage_Unload(currentBmp);
currentBmp = convertedBmp;
}
if(currentBmp == nullptr)
{
TSE_WARNING("Failed to convert png for VolumeTexture3D: \n" + filePath.string());
for(FIBITMAP* loadedBmp : loadedBitmaps)
FreeImage_Unload(loadedBmp);
return;
}
const uint currentWidth = FreeImage_GetWidth(currentBmp);
const uint currentHeight = FreeImage_GetHeight(currentBmp);
if(loadedBitmaps.empty())
{
width = currentWidth;
height = currentHeight;
}
else if(currentWidth != width || currentHeight != height)
{
TSE_WARNING("Can't create VolumeTexture3D because all pngs must have the same dimensions: \n" + filePath.string());
FreeImage_Unload(currentBmp);
for(FIBITMAP* loadedBmp : loadedBitmaps)
FreeImage_Unload(loadedBmp);
return;
}
loadedBitmaps.push_back(currentBmp);
}
Bpp = 32;
chanels = 4;
Size = Vector3(width, height, static_cast<float>(loadedBitmaps.size()));
bmp = new FIBITMAP*[loadedBitmaps.size()];
imagePtr = new byte*[loadedBitmaps.size()];
for(size_t i = 0; i < loadedBitmaps.size(); ++i)
{
bmp[i] = loadedBitmaps[i];
imagePtr[i] = FreeImage_GetBits(bmp[i]);
}
regist();
}
TSE::VolumeTexture3D::VolumeTexture3D(const int &width, const int &height, const int &depth, int bpp)
{
switch (bpp)
{
case 32:
chanels = 4;
break;
case 24:
chanels = 3;
case 16:
chanels = 1;
case 8:
chanels = 4;
}
Bpp = bpp;
Size = Vector3(width, height, depth);
bmp = new FIBITMAP*[depth];
imagePtr = new byte*[depth];
for(int i = 0; i < Depth(); i++)
{
bmp[i] = FreeImage_Allocate(width, height, bpp);
imagePtr[i] = FreeImage_GetBits(bmp[i]);
}
regist();
}
TSE::VolumeTexture3D::VolumeTexture3D(const Vector3 &size, int bpp)
: VolumeTexture3D(size.x, size.y, size.z, bpp) { }
TSE::VolumeTexture3D::~VolumeTexture3D()
{
if(bmp != nullptr)
{
for(int i = 0; i < Depth(); i++)
{
if(bmp[i] != nullptr)
{
FreeImage_Unload(bmp[i]);
bmp[i] = nullptr;
}
}
delete [] bmp;
delete [] imagePtr;
}
if(TextureID != 0)
{
PlatformDestroy();
TextureID = 0;
}
}
TSE::uint TSE::VolumeTexture3D::bpp() const
{
return Bpp;
}
TSE::Vector2 TSE::VolumeTexture3D::size() const
{
return Vector2(Size.x, Size.y);
}
float TSE::VolumeTexture3D::Width() const
{
return Size.x;
}
float TSE::VolumeTexture3D::Height() const
{
return Size.y;
}
float TSE::VolumeTexture3D::Depth() const
{
return Size.z;
}
TSE::byte TSE::VolumeTexture3D::Chanels() const
{
return chanels;
}
TSE::byte *TSE::VolumeTexture3D::GetImagePtr(const int depth) const
{
return imagePtr[depth];
}
void TSE::VolumeTexture3D::SetPixel(const Vector3 &pos, const Color &c)
{
SetPixel(pos.x, pos.y, pos.z, c);
}
void TSE::VolumeTexture3D::GetPixel(const Vector3 &pos, Color &c) const
{
GetPixel(pos.x, pos.y, pos.z, c);
}
void TSE::VolumeTexture3D::SetPixelNoApply(const Vector3 &pos, const Color &c)
{
SetPixelNoApply(pos.x, pos.y, pos.z, c);
}
void TSE::VolumeTexture3D::SetChanels(const byte &ch)
{
chanels = ch;
}
TSE::uint TSE::VolumeTexture3D::GetTextureId() const
{
return TextureID;
}
void TSE::VolumeTexture3D::SetTextureId(uint id)
{
TextureID = id;
}
void TSE::VolumeTexture3D::SetPixel(const int &x, const int &y, const int &z, const Color &c)
{
SetPixelNoApply(x,y,z,c);
Apply();
}
void TSE::VolumeTexture3D::GetPixel(const int &x, const int &y, const int &z, Color &c) const
{
if(x >= Width() || x < 0 || y >= Height() || y < 0|| z >= Depth() || z < 0)
{
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ";" + std::to_string(z) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) + ";" + std::to_string(Depth()) );
return;
}
byte* pixel = getPixelPointer(x,y,z);
byte b = *pixel++;
byte g = *pixel++;
byte r = *pixel++;
byte a = *pixel++;
if(bpp() == 8)
c = Color(r,r,r);
else if(bpp() == 24)
c = Color(r,g,b,a);
else if(bpp() == 32)
c = Color(r,g,b);
}
void TSE::VolumeTexture3D::Fill(const Color &c)
{
for (int x = 0; x < Width(); x++)
{
for (int y = 0; y < Height(); y++)
{
for (int z = 0; z < Depth(); z++)
{
SetPixelNoApply(x,y,z,c);
}
}
}
Apply();
}
void TSE::VolumeTexture3D::SetPixelNoApply(const int &x, const int &y, const int &z, const Color &c)
{
if(x >= Width() || x < 0 || y >= Height() || y < 0 || z >= Depth() || z < 0)
{
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ";" + std::to_string(z) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) + ";" + std::to_string(Depth()) );
return;
}
byte* pixel = getPixelPointer(x,y,z);
if(chanels == 4 && bpp() == 8)
{
byte r2bit = static_cast<byte>(c.r * 3.0f);
byte g2bit = static_cast<byte>(c.g * 3.0f);
byte b2bit = static_cast<byte>(c.b * 3.0f);
byte a2bit = static_cast<byte>(c.a * 3.0f);
byte result = (r2bit << 6) | (g2bit << 4) | (b2bit << 2) | a2bit;
*pixel++ = result;
return;
}
*pixel++ = c.B();
if(bpp() > 8)
{
*pixel++ = c.G();
*pixel++ = c.R();
if(bpp() > 24)
*pixel++ = c.A();
}
}
void TSE::VolumeTexture3D::AddPixelNoApply(const int &x, const int &y, const int &z, const Color &c)
{
if(x >= Width() || x < 0 ||y >= Height() || y < 0 || z >= Depth() || z < 0)
{
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ";" + std::to_string(z) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) + ";" + std::to_string(Depth()) );
return;
}
byte* pixel = getPixelPointer(x,y,z);
if(chanels == 4 && bpp() == 8) //TODO add propper adding, becouse currently is only setting
{
byte r2bit = static_cast<byte>(c.r * 3.0f);
byte g2bit = static_cast<byte>(c.g * 3.0f);
byte b2bit = static_cast<byte>(c.b * 3.0f);
byte a2bit = static_cast<byte>(c.a * 3.0f);
byte result = (r2bit << 6) | (g2bit << 4) | (b2bit << 2) | a2bit;
*pixel++ = result;
return;
}
Color bc(pixel[2], pixel[1], pixel[0], pixel[3]);
bc = c + bc;
*pixel++ = bc.B();
if(bpp() > 8)
{
*pixel++ = bc.G();
*pixel++ = bc.R();
if(bpp() > 24)
*pixel++ = bc.A();
}
}
void TSE::VolumeTexture3D::Recreate(const int &x, const int &y, const int &z, const int &bpp, const int &chanels)
{
if(bmp != nullptr)
{
for(int i = 0; i < Depth(); i++)
{
if(bmp[i] != nullptr)
{
FreeImage_Unload(bmp[i]);
bmp[i] = nullptr;
}
}
delete [] bmp;
delete [] imagePtr;
}
if(TextureID != 0)
{
PlatformDestroy();
TextureID = 0;
}
this->chanels = chanels;
Bpp = bpp;
Size = Vector3(x, y, z);
bmp = new FIBITMAP*[z];
imagePtr = new byte*[z];
for(int i = 0; i < Depth(); i++)
{
bmp[i] = FreeImage_Allocate(x, y, bpp);
imagePtr[i] = FreeImage_GetBits(bmp[i]);
}
regist();
}
void TSE::VolumeTexture3D::SavePNG(const std::string &path) const
{
//TODO: implement save all images as PNG in the given path, if the given path is inaccaseable, or not a folder, ust TSE_WARNING with an apropriate message
}
TSE::byte *TSE::VolumeTexture3D::getPixelPointer(const int &x, const int &y, const int &z) const
{
int alphaoffset = y * 2;
if(bpp() > 24)
alphaoffset = 0;
int offset = ((y * Width() + x) * (bpp() / 8) + alphaoffset);
return imagePtr[z] + offset;
}
void TSE::VolumeTexture3D::bind() const
{
helper->Bind3D(this);
}
void TSE::VolumeTexture3D::unbind() const
{
helper->UnBind3D(this);
}
void TSE::VolumeTexture3D::Apply()
{
helper->Apply3D(this);
}
void TSE::VolumeTexture3D::regist()
{
helper->Regist3D(this);
}
void TSE::VolumeTexture3D::PlatformDestroy()
{
helper->PlatromDestroy3D(this);
}

View File

@@ -0,0 +1,61 @@
#pragma once
#include "interfaces/ITexture.hpp"
#include "Types.hpp"
#include "Vector3.hpp"
#include "Color.hpp"
#include "interfaces/ITextureHelper.hpp"
#define FREEIMAGE_LIB
#include "FI/FreeImage.h"
namespace TSE
{
class VolumeTexture3D : public ITexture
{
protected:
uint TextureID = 0;
Vector3 Size;
uint Bpp;
byte chanels = 0;
FIBITMAP** bmp = nullptr;
byte** imagePtr = nullptr;
public:
string name = "Unnamed";
VolumeTexture3D(const string& path);
VolumeTexture3D(const int& width, const int& height, const int& depth, int bpp = 32);
VolumeTexture3D(const Vector3& size, int bpp = 32);
~VolumeTexture3D();
uint bpp() const;
Vector2 size() const override;
float Width() const override;
float Height() const override;
float Depth() const;
byte Chanels() const;
byte* GetImagePtr(const int depth) const;
void SetPixel(const Vector3& pos, const Color& c);
void GetPixel(const Vector3& pos, Color& c) const;
void SetPixelNoApply(const Vector3& pos, const Color& c);
void SetChanels(const byte& ch);
uint GetTextureId() const override;
void SetTextureId(uint id);
void SetPixel(const int& x, const int& y, const int& z, const Color& c);
void GetPixel(const int& x, const int& y, const int& z, Color& c) const;
void Fill(const Color& c);
void SetPixelNoApply(const int& x, const int& y, const int& z, const Color& c);
void AddPixelNoApply(const int& x, const int& y, const int& z, const Color& c);
void Recreate(const int& x, const int& y, const int& z, const int& bpp, const int& chanels);
void SavePNG(const std::string& path) const;
byte* getPixelPointer(const int& x, const int& y, const int& z) const;
void bind() const;
void unbind() const;
void Apply();
void regist();
void PlatformDestroy();
};
} // namespace TSE

View File

@@ -19,6 +19,7 @@ namespace TSE
enum Modifier
{
None = 0x0000,
ShiftMod = 0x0001,
ControlMod = 0x0002,
AltMod = 0x0004,

View File

@@ -0,0 +1,12 @@
#pragma once
namespace TSE
{
enum SortingOrder
{
TopRight,
TopLeft,
BottomRight,
BottomLeft,
};
}

View File

@@ -0,0 +1,47 @@
#pragma once
#include "Types.hpp"
#include <filesystem>
#include "picosha2.h"
#include "uuid.h"
namespace TSE
{
class IAsset
{
public:
uuids::uuid id;
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);
Hash();
if(oldHash != hash)
{
LoadAsset(rawPath);
}
};
protected:
virtual void SaveMeta() = 0;
inline string PathToMetaPath(string path) const
{
return path + ".meta";
};
inline std::string sha256(const std::string& str) {
return picosha2::hash256_hex_string(str);
};
};
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "uuid.h"
namespace TSE
{
class IIdentifyable
{
protected:
uuids::uuid ID;
public:
inline const uuids::uuid& GetID() { return ID;};
};
} // namespace TSE

View File

@@ -0,0 +1,35 @@
#pragma once
#include "IObserver.hpp"
#include <vector>
#include <algorithm>
namespace TSE
{
class IObservable
{
private:
std::vector<IObserver*> objectsToNotify;
public:
inline void Observe(IObserver* observer)
{
objectsToNotify.push_back(observer);
};
inline void StopObserve(IObserver* observer)
{
auto it = std::find(objectsToNotify.begin(), objectsToNotify.end(), observer);
if(it != objectsToNotify.end())
objectsToNotify.erase(it);
};
protected:
inline void TriggerObserver(void* data)
{
for (auto &&observer : objectsToNotify)
{
observer->OnObserved(data);
}
};
};
} // namespace TSE

View File

@@ -0,0 +1,10 @@
#pragma once
namespace TSE
{
class IObserver
{
public:
virtual void OnObserved(void* data) = 0;
};
} // namespace TSE

View File

@@ -13,11 +13,12 @@ namespace TSE
public:
inline static IRenderTextureCreator* factory = nullptr;
virtual void SetSize(Vector2 v) = 0;
virtual uint GetTextureId(uint id) const = 0;
};
class IRenderTextureCreator
{
public:
virtual IRenderTexture* CreateTextureHeap(Vector2 v) = 0;
virtual IRenderTexture* CreateTextureHeap(Vector2 v, uint textureCount = 1) = 0;
};
} // namespace TSE

View File

@@ -7,11 +7,13 @@
namespace TSE
{
class Camera;
class RenderPipeline;
class IRenderer
{
public:
inline static TSE::RenderPipeline* pipeline = nullptr;
static std::vector<Camera*> camerasToRenderWith;
virtual void End() = 0;

View File

@@ -2,6 +2,7 @@
#include <list>
#include "IResizeNotifiable.hpp"
#include "Vector2.hpp"
namespace TSE
{
@@ -15,5 +16,9 @@ namespace TSE
public:
void AddResizeNotifiable(IResizeNotifiable* obj);
void RemoveResizeNotifiable(IResizeNotifiable* obj);
inline Vector2 GetRawIResizableSize()
{
return Vector2(width, height);
};
};
} // namespace TSE

View File

@@ -10,6 +10,9 @@ namespace TSE
{
class IShader
{
protected:
string name = "UnnamedShader";
public:
virtual void Bind() const = 0;
@@ -24,6 +27,8 @@ namespace TSE
virtual void SetUniform(const char* name, const Vector3* value) = 0;
virtual void SetUniform(const char* name, const Vector4* value) = 0;
inline string GetName() {return name;};
virtual ~IShader() = default;
};
} // namespace TSE

View File

@@ -1,12 +1,15 @@
#pragma once
#include "Vector2.hpp"
#include "interfaces/ITextureHelper.hpp"
namespace TSE
{
class ITexture
{
public:
inline static ITextureHelper* helper = nullptr;
virtual ~ITexture() = default;
virtual Vector2 size() const = 0;
virtual float Width() const = 0;

View File

@@ -3,6 +3,7 @@
namespace TSE
{
class Texture;
class VolumeTexture3D;
class ITextureHelper
{
@@ -12,5 +13,11 @@ namespace TSE
virtual void Apply(Texture* tex) = 0;
virtual void Regist(Texture* tex) = 0;
virtual void PlatromDestroy(Texture* tex) = 0;
virtual void Bind3D(const VolumeTexture3D* tex) = 0;
virtual void UnBind3D(const VolumeTexture3D* tex) = 0;
virtual void Apply3D(VolumeTexture3D* tex) = 0;
virtual void Regist3D(VolumeTexture3D* tex) = 0;
virtual void PlatromDestroy3D(VolumeTexture3D* tex) = 0;
};
} // namespace TSE

View File

@@ -5,6 +5,10 @@
#include "version.h"
#include "IInputManager.hpp"
#include "elements/AudioEngine.hpp"
#include "IdGenerator.hpp"
#define FREEIMAGE_LIB
#include "FI/FreeImage.h"
TSE::IWindow* TSE::IWindow::lastWindow = nullptr;
@@ -14,6 +18,7 @@ bool TSE::IWindow::BaseInit() const
Debug::Init();
Debug::Log("TSE:" + TSE_VERSION_STRING);
AudioEngine::Init();
FreeImage_Initialise(true);
return true;
}
@@ -29,6 +34,7 @@ TSE::Vector2 TSE::IWindow::GetSize() const
TSE::IWindow::~IWindow()
{
FreeImage_DeInitialise();
AudioEngine::Destroy();
IInputManager::instance()->Delete();
Time::Destroy();

View File

@@ -18,6 +18,7 @@ namespace TSE
virtual void Clear() const = 0;
virtual void ClearDepthBuffer() const = 0;
virtual bool ShouldClose() const = 0;
virtual void DoneSetup() = 0;
bool BaseInit() const;
void BaseUpdate() const;

View File

@@ -3,77 +3,60 @@
nlohmann::json TSE::ExportColor(Color &color)
{
using json = nlohmann::json;
json exp;
exp["r"] = color.r;
exp["g"] = color.g;
exp["b"] = color.b;
exp["a"] = color.a;
return exp;
return json::array({color.r, color.g, color.b, color.a});
}
nlohmann::json TSE::ExportVector2(Vector2 &vec2)
{
using json = nlohmann::json;
json exp;
exp["x"] = vec2.x;
exp["y"] = vec2.y;
return exp;
return json::array({vec2.x, vec2.y});
}
nlohmann::json TSE::ExportVector3(Vector3 &vec3)
{
using json = nlohmann::json;
json exp;
exp["x"] = vec3.x;
exp["y"] = vec3.y;
exp["z"] = vec3.z;
return exp;
return json::array({vec3.x, vec3.y, vec3.z});
}
nlohmann::json TSE::ExportVector4(Vector4 &vec4)
{
using json = nlohmann::json;
json exp;
exp["x"] = vec4.x;
exp["y"] = vec4.y;
exp["z"] = vec4.z;
exp["w"] = vec4.w;
return exp;
return json::array({vec4.x, vec4.y, vec4.z, vec4.w});
}
TSE::Color TSE::ImportColor(nlohmann::json json)
{
Color imp;
imp.r = json["r"];
imp.g = json["g"];
imp.b = json["b"];
imp.a = json["a"];
imp.r = json[0];
imp.g = json[1];
imp.b = json[2];
imp.a = json[3];
return imp;
}
TSE::Vector2 TSE::ImportVector2(nlohmann::json json)
{
Vector2 imp;
imp.x = json["x"];
imp.y = json["y"];
imp.x = json[0];
imp.y = json[1];
return imp;
}
TSE::Vector3 TSE::ImportVector3(nlohmann::json json)
{
Vector3 imp;
imp.x = json["x"];
imp.y = json["y"];
imp.z = json["z"];
imp.x = json[0];
imp.y = json[1];
imp.z = json[2];
return imp;
}
TSE::Vector4 TSE::ImportVector4(nlohmann::json json)
{
Vector4 imp;
imp.x = json["x"];
imp.y = json["y"];
imp.z = json["z"];
imp.w = json["w"];
imp.x = json[0];
imp.y = json[1];
imp.z = json[2];
imp.w = json[3];
return imp;
}

View File

@@ -3,19 +3,24 @@
#include "BehaviourScriptRegistry.hpp"
#include "BehaviourScripts/AudioListener.hpp"
#include "BehaviourScripts/AudioSource.hpp"
#include "BehaviourScripts/TileMap.hpp"
#include "BehaviourScripts/OrdererSpriteSet.hpp"
#include "BehaviourScripts/PhysicsObject.hpp"
#include "BehaviourScripts/basicEditorCamera.hpp"
TSE::EDITOR::EditorSubsystem::EditorSubsystem() : sv(nullptr), editorLayer("")
TSE::EDITOR::EditorSubsystem::EditorSubsystem(ConsolView* cvp) : sv(nullptr), editorLayer("")
{
rt = IRenderTexture::factory->CreateTextureHeap({100,100});
rt = IRenderTexture::factory->CreateTextureHeap({100,100}, 5);
sv = SceneView(rt);
cv = cvp;
controller.AddGuiElement("Scene", &sv);
controller.AddGuiElement("Consol", &cv);
controller.AddGuiElement("Consol", cv);
controller.AddGuiElement("Hirearchie", &hv);
controller.AddGuiElement("Properties", &pv);
controller.AddGuiElement("Debug", &dv);
controller.AddGuiElement("Camera", &camv);
controller.AddGuiElement("Assets", &av);
BehaviourScriptRegistry::RegisterBehaviourScript("Image", []() -> BehaviourScript* {return new Image();});
BehaviourScriptRegistry::RegisterBehaviourScript("Image Animation", []() -> BehaviourScript* {return new ImageAnimation();});
@@ -26,6 +31,9 @@ TSE::EDITOR::EditorSubsystem::EditorSubsystem() : sv(nullptr), editorLayer("")
BehaviourScriptRegistry::RegisterBehaviourScript("Camera", []() -> BehaviourScript* {return new Camera();});
BehaviourScriptRegistry::RegisterBehaviourScript("Audio Listener", []() -> BehaviourScript* {return new AudioListener();});
BehaviourScriptRegistry::RegisterBehaviourScript("Audio Source", []() -> BehaviourScript* {return new AudioSource();});
BehaviourScriptRegistry::RegisterBehaviourScript("Tile Map", []() -> BehaviourScript* {return new TileMap();});
BehaviourScriptRegistry::RegisterBehaviourScript("Orderer Sprite Set", []() -> BehaviourScript* {return new OrdererSpriteSet();});
BehaviourScriptRegistry::RegisterBehaviourScript("Physics Object", []() -> BehaviourScript* { return new PhysicsObject(BodyType::Dynamic, ColliderShape::Box, 1.0f, 0.3f, Vector3(1, 1, 0)); });
#pragma region camerastuff
@@ -40,6 +48,7 @@ TSE::EDITOR::EditorSubsystem::EditorSubsystem() : sv(nullptr), editorLayer("")
editorLayer = Layer(".editor");
editorLayer.AddTransformable(editorCamera);
editorLayer.SetNonVisual(true);
#pragma endregion
}

View File

@@ -7,6 +7,7 @@
#include "UI/windows/HirearchieView.hpp"
#include "UI/windows/PropertiesView.hpp"
#include "UI/windows/SceneView.hpp"
#include "UI/windows/AssetsView.hpp"
#include "interfaces/IRenderTexture.hpp"
namespace TSE::EDITOR
@@ -15,15 +16,16 @@ namespace TSE::EDITOR
{
public:
ViewportController controller;
ConsolView cv;
ConsolView* cv = nullptr;
DebugView dv;
HirearchieView hv = HirearchieView(nullptr);
PropertiesView pv;
CameraView camv;
TSE::IRenderTexture* rt;
SceneView sv;
AssetsView av;
Layer editorLayer;
EditorSubsystem();
EditorSubsystem(ConsolView* cvp);
};
} // namespace TSE::EDITOR

View File

@@ -1,11 +1,167 @@
#include "ElementDrawer.hpp"
#include "BehaviourScriptRegistry.hpp"
#include "elements/ShaderRegistry.hpp"
#include "elements/AssetLibrary.hpp"
#include "BehaviourScripts/Camera.hpp"
#include "windows/HirearchieView.hpp"
#include "windows/PropertiesView.hpp"
#include <algorithm>
#include <any>
#include <cctype>
namespace TSE::EDITOR
{
namespace
{
char assetPickerSearchBuffer[128] = "";
std::string ToLowerCopy(std::string value)
{
std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c)
{
return static_cast<char>(std::tolower(c));
});
return value;
}
template<typename T>
std::vector<T*> GetAssetsOfType()
{
std::vector<T*> result;
int count = AssetLibrary::GetValueCount();
for(int i = 0; i < count; i++)
{
auto [ptr, type, id] = AssetLibrary::GetValueAt(i);
if(type != typeid(T).name() && type != typeid(T*).name())
{
continue;
}
try
{
result.push_back(std::any_cast<T*>(ptr));
}
catch(const std::bad_any_cast&)
{
}
}
return result;
}
template<typename T, typename NameGetter>
T* DrawAssetPickerPopup(const char* popupId, const char* searchHint, const char* emptyText, NameGetter getName)
{
T* selectedAsset = nullptr;
ImGui::SetNextWindowSize({360.0f, 420.0f}, ImGuiCond_Appearing);
if(ImGui::BeginPopup(popupId))
{
ImGui::PushItemWidth(-1.0f);
ImGui::InputTextWithHint("##AssetPickerSearch", searchHint, assetPickerSearchBuffer, IM_ARRAYSIZE(assetPickerSearchBuffer));
ImGui::PopItemWidth();
ImGui::Separator();
std::string filterText = ToLowerCopy(assetPickerSearchBuffer);
std::vector<T*> assets = GetAssetsOfType<T>();
if(ImGui::BeginChild("##AssetPickerList", {0.0f, 0.0f}, ImGuiChildFlags_None, ImGuiWindowFlags_AlwaysVerticalScrollbar))
{
int shownCount = 0;
for(T* asset : assets)
{
if(asset == nullptr)
{
continue;
}
std::string assetName = getName(asset);
if(!filterText.empty() && ToLowerCopy(assetName).find(filterText) == std::string::npos)
{
continue;
}
ImGui::PushID(asset);
if(ImGui::Selectable(assetName.c_str()))
{
selectedAsset = asset;
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
shownCount++;
}
if(shownCount == 0)
{
ImGui::TextDisabled("%s", emptyText);
}
}
ImGui::EndChild();
ImGui::EndPopup();
}
return selectedAsset;
}
template<typename T>
bool BeginAssetField(T** element, const char* popupId)
{
if(element == nullptr)
{
ImGui::TextDisabled("No Asset Field");
return false;
}
ImGui::PushID(element);
float buttonWidth = ImGui::GetFrameHeight();
float fieldHeight = std::max(36.0f, ImGui::GetFrameHeightWithSpacing() + ImGui::GetStyle().WindowPadding.y * 2.0f);
ImGui::BeginChild("##AssetField", {0.0f, fieldHeight}, ImGuiChildFlags_Borders, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
if(ImGui::Button("+##SelectAsset", {buttonWidth, 0.0f}))
{
assetPickerSearchBuffer[0] = '\0';
ImGui::OpenPopup(popupId);
}
ImGui::SameLine();
ImGui::BeginChild("##AssetFieldValue", {0.0f, 0.0f}, ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
return true;
}
template<typename T>
void EndAssetField()
{
ImGui::EndChild();
}
template<typename T>
void OpenAssetPropertiesOnDoubleClick(T* asset)
{
if(asset == nullptr)
{
return;
}
if(ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{
PropertiesView::SetInspectorElement(InspectableType::IAsset, static_cast<IAsset*>(asset));
}
}
template<typename T, typename NameGetter>
void AssetSelector(T** element, const char* popupId, const char* searchHint, const char* emptyText, NameGetter getName)
{
T* selectedAsset = DrawAssetPickerPopup<T>(popupId, searchHint, emptyText, getName);
if(selectedAsset != nullptr)
{
*element = selectedAsset;
}
ImGui::EndChild();
ImGui::PopID();
}
}
#pragma region helper
bool InputText(const char* label, std::string& str, size_t bufferSize = 256) {
std::vector<char> buffer(bufferSize);
@@ -64,7 +220,7 @@ namespace TSE::EDITOR
// Suchfeld mit X Button
ImGui::PushItemWidth(-style.FramePadding.x * 4 - 24); // Platz für Clear Button
ImGui::InputTextWithHint("##SearchField", "Suchfeld", searchBuffer, IM_ARRAYSIZE(searchBuffer));
ImGui::InputTextWithHint("##SearchField", "Search", searchBuffer, IM_ARRAYSIZE(searchBuffer));
ImGui::PopItemWidth();
ImGui::SameLine();
@@ -203,6 +359,14 @@ namespace TSE::EDITOR
{
Draw((ParticleSystem*)element, debug);
}
else if (name == "Tile Map")
{
Draw((TileMap*)element, debug);
}
else if (name == "Orderer Sprite Set")
{
Draw((OrdererSpriteSet*)element, debug);
}
else
{
element->CustomDraw(debug);
@@ -213,15 +377,7 @@ namespace TSE::EDITOR
void ElementDrawer::Draw(Renderable *element, const bool &debug)
{
ImGui::SeparatorText("Material");
int height = 100;
if(element->GetMaterial() == nullptr)
{
height = 35;
}
ImVec2 size(0, height);
ImGui::BeginChild("MaterialViewer", size, ImGuiChildFlags_Borders);
Draw(element->GetMaterial(), debug);
ImGui::EndChild();
DrawMaterialField(element->GetMaterialRef());
}
void ElementDrawer::Draw(MeshContainer *element, const bool &debug)
{
@@ -231,7 +387,7 @@ namespace TSE::EDITOR
height = 35;
}
ImVec2 size(0, height);
Draw(element->GetMesh(), debug, "Mesh", true);
DrawMeshField(element->GetMeshRef());
}
void ElementDrawer::Draw(Image *element, const bool &debug)
{
@@ -435,6 +591,14 @@ namespace TSE::EDITOR
Texture* value = element->GetValue<Texture*>(name);
Draw(value, debug, name , true);
}
else if (type == typeid(uint).name())
{
int value = element->GetValue<uint>(name);
if(ImGui::InputInt(name.c_str(), &value))
{
element->SetValue(name, value);
}
}
else
{
ImGui::TextDisabled(("Not Implemented: " + type).c_str());
@@ -464,11 +628,6 @@ namespace TSE::EDITOR
}
void ElementDrawer::Draw(Mesh *element, const bool &debug, const std::string &label, const bool small)
{
if(element == nullptr)
{
ImGui::Text("No Mesh Set");
return;
}
if(small) DrawMeshCompact(element, debug, label);
else DrawMeshNormal(element, debug, label);
}
@@ -569,7 +728,7 @@ namespace TSE::EDITOR
ImGui::Text("Editor Camera can't be main camera");
}
ImGui::Separator();
ImGui::Separator();
// Render Scale
float renderScale = element->GetRenderScale();
if (ImGui::DragFloat("Render Scale", &renderScale, 0.1f))
@@ -600,6 +759,56 @@ namespace TSE::EDITOR
if (ImGui::DragFloat("Field of View (deg)", &fov, 0.1f))
element->SetFov(fov);
if (!isPerspective) ImGui::EndDisabled();
Scene* curScene = HirearchieView::currentScene;
ImGui::SeparatorText("Layers To Render");
if (curScene == nullptr)
{
ImGui::TextDisabled("No active scene available.");
return;
}
if (ImGui::BeginChild("LayersToRender", ImVec2(0, 170), ImGuiChildFlags_Borders))
{
const int layerCount = curScene->GetLayerCount();
if (layerCount <= 0)
{
ImGui::TextDisabled("Scene has no layers.");
}
else
{
for (int i = 0; i < layerCount; i++)
{
Layer* layer = curScene->GetLayerAt(i);
if (layer == nullptr) continue;
if (!layer->IsVisual()) continue;
const uuids::uuid& layerID = layer->GetID();
auto it = std::find(element->layersNotToRender.begin(), element->layersNotToRender.end(), layerID);
bool shouldRenderLayer = (it == element->layersNotToRender.end());
const std::string checkBoxLabel = layer->GetName() + "##layer_to_render_" + std::to_string(i);
if (ImGui::Checkbox(checkBoxLabel.c_str(), &shouldRenderLayer))
{
if (shouldRenderLayer)
{
auto removeIt = std::find(element->layersNotToRender.begin(), element->layersNotToRender.end(), layerID);
if (removeIt != element->layersNotToRender.end())
{
element->layersNotToRender.erase(removeIt);
}
}
else if (it == element->layersNotToRender.end())
{
element->layersNotToRender.push_back(layerID);
}
}
}
}
}
ImGui::EndChild();
}
void ElementDrawer::Draw(ParticleSystem *element, const bool &debug)
{
@@ -813,6 +1022,87 @@ namespace TSE::EDITOR
ImGui::Unindent(20.0f);
}
}
void ElementDrawer::Draw(TileMap *element, const bool &debug)
{
int orderIndex = static_cast<int>(element->order);
const char* orderItems[] = { "TopRight", "TopLeft", "BottomRight", "BottomLeft" };
if (ImGui::Combo("Order", &orderIndex, orderItems, IM_ARRAYSIZE(orderItems)))
{
element->order = static_cast<SortingOrder>(orderIndex);
for (auto& [_, chunk] : element->chunks)
{
chunk.SetOrdering(element->order);
}
element->DirtyAll();
}
ImGui::BeginDisabled();
ImGui::DragInt("Chunk Size", &element->chunkSize, 1.0f);
ImGui::EndDisabled();
Vector2 nextLine = element->GetNextLineOffset();
if (ImGui::DragFloat2("Next Line Offset", &nextLine.x, 0.01f))
{
element->SetNextLineOffset(nextLine);
}
ImGui::DragFloat2("Sprite Scale", &element->SpriteScale.x, 0.01f);
if (debug)
{
Rect bounds = element->GetBounds();
ImGui::Separator();
ImGui::TextDisabled("Bounds");
ImGui::BeginDisabled();
ImGui::InputFloat2("Min", &bounds.p1.x);
ImGui::InputFloat2("Max", &bounds.p2.x);
ImGui::EndDisabled();
ImGui::TextDisabled(("Chunk Count: " + std::to_string(element->GetChunkCount())).c_str());
}
}
void ElementDrawer::Draw(OrdererSpriteSet *element, const bool &debug)
{
int orderIndex = static_cast<int>(element->order);
const char* orderItems[] = { "TopRight", "TopLeft", "BottomRight", "BottomLeft" };
if (ImGui::Combo("Order", &orderIndex, orderItems, IM_ARRAYSIZE(orderItems)))
{
element->order = static_cast<SortingOrder>(orderIndex);
for (auto& [_, chunk] : element->chunks)
{
chunk.SetOrdering(element->order);
}
element->DirtyAll();
}
ImGui::BeginDisabled();
ImGui::DragFloat("Chunk Size", &element->chunkSize, 1.0f);
ImGui::EndDisabled();
if (debug)
{
ImGui::Separator();
ImGui::TextDisabled(("Chunk Count: " + std::to_string(element->GetChunkCount())).c_str());
}
}
void ElementDrawer::Draw(IAsset *element, const bool &debug)
{
if (element->assetType() == "material")
{
Draw((Material*)element, debug);
}
else if (element->assetType() == "texture")
{
Draw((Texture*)element, debug);
}
else if (element->assetType() == "mesh")
{
Draw((Mesh*)element, debug);
}
element->SaveAsset();
}
void ElementDrawer::DrawAudioClipCompact(AudioClip *element, const bool &debug, const std::string &label)
{
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
@@ -904,6 +1194,21 @@ namespace TSE::EDITOR
}
void ElementDrawer::DrawMeshCompact(Mesh *element, const bool &debug, const std::string &label)
{
if(element == nullptr)
{
ImGui::Text("No Mesh Set");
return;
}
ImGui::Text(element->name.c_str());
}
void ElementDrawer::DrawMeshNormal(Mesh *element, const bool &debug, const std::string &label)
{
if(element == nullptr)
{
ImGui::Text("No Mesh Set");
return;
}
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
ImVec2 label_size = ImGui::CalcTextSize(label.c_str());
@@ -930,54 +1235,6 @@ namespace TSE::EDITOR
cursorCurrent.y += 2;
ImGui::SetCursorPos(cursorCurrent);
ImGui::TextUnformatted(label.c_str());
}
void ElementDrawer::DrawMeshNormal(Mesh *element, const bool &debug, const std::string &label)
{
ImGui::Text(("Name: " + element->name).c_str());
if(debug)
{
//ImGui::TextDisabled(("ID: " + to_string(element->id)).c_str());
}
ImGui::Separator();
ImGui::Text(("Vectex Count: " + std::to_string(element->vertecies.size())).c_str());
ImGui::Text(("Index Count: " + std::to_string(element->indecies.size())).c_str());
ImGui::Text(("UV Count: " + std::to_string(element->uvs.size())).c_str());
ImGui::Indent(20.0f);
if(ImGui::CollapsingHeader("Vertecies"))
{
ImGui::PushID("Verts");
ImGui::BeginDisabled();
for (int i = 0; i < element->vertecies.size(); i++)
{
ImGui::InputFloat3(std::to_string(i).c_str(), &element->vertecies[i].x);
}
ImGui::EndDisabled();
ImGui::PopID();
}
if(ImGui::CollapsingHeader("Indecies"))
{
ImGui::PushID("Inds");
ImGui::BeginDisabled();
for (int i = 0; i < element->indecies.size(); i++)
{
int val = element->indecies[i];
ImGui::InputInt(std::to_string(i).c_str(), &val);
}
ImGui::EndDisabled();
ImGui::PopID();
}
if(ImGui::CollapsingHeader("UVs"))
{
ImGui::PushID("Uvs");
ImGui::BeginDisabled();
for (int i = 0; i < element->uvs.size(); i++)
{
ImGui::InputFloat2(std::to_string(i).c_str(), &element->uvs[i].x);
}
ImGui::EndDisabled();
ImGui::PopID();
}
ImGui::Unindent(20.0f);
}
void ElementDrawer::DrawSpriteCompact(Sprite *element, const bool &debug, const std::string &label)
@@ -1053,7 +1310,7 @@ namespace TSE::EDITOR
ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0});
ImGui::SameLine();
ImGui::SetCursorPos(ImVec2(field_size.y + 1,(60-label_size.y) / 2));
ImGui::TextUnformatted(element->name.c_str());
ImGui::TextUnformatted(element->name().c_str());
ImGui::EndChild();
@@ -1068,7 +1325,7 @@ namespace TSE::EDITOR
}
void ElementDrawer::DrawTextureNormal(Texture *element, const bool &debug, const std::string& label)
{
ImGui::TextUnformatted(element->name.c_str());
ImGui::TextUnformatted(element->name().c_str());
if(debug)
{
ImGui::Separator();
@@ -1085,6 +1342,98 @@ namespace TSE::EDITOR
ImVec2 texSize (available_width, (available_width) * ymultiplyer);
ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0});
ImGui::Separator();
ImGui::SeparatorText("Import Settings");
TextureImportSettings& settings = element->GetImportSettings();
bool importSettingsChanged = false;
int importMode = static_cast<int>(settings.importMode);
const char* importModes[] = { "Raw Texture", "Sprite", "Sprite Set", "Nine Tile" };
if (ImGui::Combo("Import Mode", &importMode, importModes, IM_ARRAYSIZE(importModes)))
{
settings.importMode = static_cast<byte>(std::clamp(importMode, 0, IM_ARRAYSIZE(importModes) - 1));
importSettingsChanged = true;
}
int importCount[2] = {
static_cast<int>(settings.importCount.x),
static_cast<int>(settings.importCount.y)
};
if (ImGui::InputInt2("Import Count", importCount))
{
settings.importCount.x = static_cast<float>(std::max(1, importCount[0]));
settings.importCount.y = static_cast<float>(std::max(1, importCount[1]));
importSettingsChanged = true;
}
int bpp = static_cast<int>(settings.bpp);
if (ImGui::InputInt("BPP", &bpp))
{
settings.bpp = static_cast<uint>(std::max(0, bpp));
importSettingsChanged = true;
}
int chanels = static_cast<int>(settings.chanels);
if (ImGui::InputInt("Chanels", &chanels))
{
settings.chanels = static_cast<byte>(std::clamp(chanels, 0, 255));
importSettingsChanged = true;
}
if (InputText("Import Name", settings.name))
{
importSettingsChanged = true;
}
if (importSettingsChanged)
{
element->SaveAsset();
}
}
void ElementDrawer::DrawMaterialCompact(Material *element, const bool &debug, const std::string &label)
{
if(element == nullptr)
{
ImGui::Text("No Mesh Set");
return;
}
ImGui::Text(element->GetName().c_str());
}
void ElementDrawer::DrawMeshField(Mesh **element)
{
if(!BeginAssetField<Mesh>(element, "MeshAssetPicker"))
{
return;
}
DrawMeshCompact(*element, false, "");
OpenAssetPropertiesOnDoubleClick(*element);
EndAssetField<Mesh>();
AssetSelector<Mesh>(element, "MeshAssetPicker", "Search Mesh", "No meshes found", [](Mesh* mesh)
{
return mesh->name.empty() ? std::string("Unnamed Mesh") : mesh->name;
});
}
void ElementDrawer::DrawMaterialField(Material **element)
{
if(!BeginAssetField<Material>(element, "MaterialAssetPicker"))
{
return;
}
DrawMaterialCompact(*element, false, "");
OpenAssetPropertiesOnDoubleClick(*element);
EndAssetField<Material>();
AssetSelector<Material>(element, "MaterialAssetPicker", "Search Material", "No materials found", [](Material* mat)
{
return mat->GetName().empty() ? std::string("Unnamed Material") : mat->GetName();
});
}
} // namespace TSE::EDITOR

View File

@@ -13,6 +13,8 @@
#include "BehaviourScripts/ParticleSystem.hpp"
#include "BehaviourScripts/AudioListener.hpp"
#include "BehaviourScripts/AudioSource.hpp"
#include "BehaviourScripts/TileMap.hpp"
#include "BehaviourScripts/OrdererSpriteSet.hpp"
namespace TSE::EDITOR
{
@@ -21,7 +23,8 @@ namespace TSE::EDITOR
None,
Transformable,
Scene,
Layer
Layer,
IAsset
};
struct Inspectable
@@ -52,6 +55,9 @@ namespace TSE::EDITOR
case InspectableType::Layer:
Draw(static_cast<Layer*>(element.ptr), debug);
break;
case InspectableType::IAsset:
Draw(static_cast<IAsset*>(element.ptr), debug);
break;
default:
TSE_WARNING("Draw not implemented for this type.");
break;
@@ -79,6 +85,9 @@ namespace TSE::EDITOR
static void Draw(AudioClip* element, const bool& debug, const std::string& label = "", const bool small = false);
static void Draw(Camera* element, const bool& debug);
static void Draw(ParticleSystem* element, const bool& debug);
static void Draw(TileMap* element, const bool& debug);
static void Draw(OrdererSpriteSet* element, const bool& debug);
static void Draw(IAsset* element, const bool& debug);
static void DrawAudioClipCompact(AudioClip* element, const bool& debug, const std::string& label);
static void DrawAudioClipNormal(AudioClip* element, const bool& debug, const std::string& label);
@@ -90,5 +99,9 @@ namespace TSE::EDITOR
static void DrawSpriteNormal(Sprite* element, const bool& debug, const std::string& label);
static void DrawTextureCompact(Texture* element, const bool& debug, const std::string& label);
static void DrawTextureNormal(Texture* element, const bool& debug, const std::string& label);
static void DrawMaterialCompact(Material* element, const bool& debug, const std::string& label);
static void DrawMeshField(Mesh** element);
static void DrawMaterialField(Material** element);
};
} // namespace TSE::EDITOR

View File

@@ -0,0 +1,751 @@
#include "AssetsView.hpp"
#include "elements/AssetLibrary.hpp"
#include "PathHelper.hpp"
#include "json.hpp"
#include "uuid.h"
#include "elements/Material.hpp"
#include "elements/Texture.hpp"
#include "PropertiesView.hpp"
#include <algorithm>
#include <cstdio>
#include <filesystem>
#include <vector>
namespace
{
std::vector<std::filesystem::directory_entry> GetDirectories(const std::filesystem::path& folderPath)
{
std::vector<std::filesystem::directory_entry> directories;
std::error_code errorCode;
for(const auto& entry : std::filesystem::directory_iterator(folderPath, errorCode))
{
std::error_code entryErrorCode;
if(entry.is_directory(entryErrorCode))
directories.push_back(entry);
}
std::sort(directories.begin(), directories.end(), [](const auto& a, const auto& b)
{
return a.path().filename().string() < b.path().filename().string();
});
return directories;
}
std::vector<std::filesystem::directory_entry> GetFiles(const std::filesystem::path& folderPath)
{
std::vector<std::filesystem::directory_entry> files;
std::error_code errorCode;
for(const auto& entry : std::filesystem::directory_iterator(folderPath, errorCode))
{
std::error_code entryErrorCode;
if(entry.is_regular_file(entryErrorCode) && entry.path().extension() != ".meta")
files.push_back(entry);
}
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b)
{
return a.path().filename().string() < b.path().filename().string();
});
return files;
}
bool IsPathInFolder(const std::filesystem::path& path, const std::filesystem::path& folderPath)
{
if(path.empty() || folderPath.empty())
return false;
const std::filesystem::path relativePath = path.lexically_relative(folderPath);
if(relativePath.empty() || relativePath == ".")
return true;
const auto firstPart = relativePath.begin();
return firstPart != relativePath.end() && firstPart->string() != "..";
}
bool IsSameOrChildPath(const std::filesystem::path& path, const std::filesystem::path& possibleParentPath)
{
return IsPathInFolder(path.lexically_normal(), possibleParentPath.lexically_normal());
}
std::string FitTextToWidth(const std::string& text, float maxWidth)
{
if(ImGui::CalcTextSize(text.c_str()).x <= maxWidth)
return text;
std::string result = text;
while(result.size() > 3)
{
result.pop_back();
const std::string truncated = result + "...";
if(ImGui::CalcTextSize(truncated.c_str()).x <= maxWidth)
return truncated;
}
return "...";
}
}
TSE::EDITOR::AssetsView::AssetsView() : GuiWindow("Assets", ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar)
{
}
void TSE::EDITOR::AssetsView::Define()
{
const float splitterWidth = 1.0f;
const float minPanelWidth = 100.0f;
const ImVec2 availableRegion = ImGui::GetContentRegionAvail();
if(availableRegion.x <= splitterWidth)
return;
if(leftPanelWidth < 0.0f)
leftPanelWidth = availableRegion.x / 3.0f;
float maxLeftPanelWidth = availableRegion.x - splitterWidth - minPanelWidth;
if(maxLeftPanelWidth < minPanelWidth)
maxLeftPanelWidth = (availableRegion.x - splitterWidth) * 0.5f;
if(leftPanelWidth < minPanelWidth)
leftPanelWidth = minPanelWidth;
if(leftPanelWidth > maxLeftPanelWidth)
leftPanelWidth = maxLeftPanelWidth;
if(leftPanelWidth < 1.0f)
leftPanelWidth = 1.0f;
auto clampLeftPanelWidth = [&]()
{
if(leftPanelWidth < minPanelWidth)
leftPanelWidth = minPanelWidth;
if(leftPanelWidth > maxLeftPanelWidth)
leftPanelWidth = maxLeftPanelWidth;
if(leftPanelWidth < 1.0f)
leftPanelWidth = 1.0f;
};
ImGuiWindowFlags childFlags = ImGuiWindowFlags_None;
if(ImGui::BeginChild("##AssetsTreeView", {leftPanelWidth, 0.0f}, ImGuiChildFlags_Borders, childFlags))
{
DefineTreeView();
}
ImGui::EndChild();
ImGui::SameLine(0.0f, 0.0f);
ImGui::InvisibleButton("##AssetsSplitter", {splitterWidth, availableRegion.y});
if(ImGui::IsItemActive())
{
leftPanelWidth += ImGui::GetIO().MouseDelta.x;
clampLeftPanelWidth();
}
if(ImGui::IsItemHovered() || ImGui::IsItemActive())
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
ImU32 splitterColor = ImGui::GetColorU32(ImGuiCol_Separator);
if(ImGui::IsItemHovered())
splitterColor = ImGui::GetColorU32(ImGuiCol_SeparatorHovered);
if(ImGui::IsItemActive())
splitterColor = ImGui::GetColorU32(ImGuiCol_SeparatorActive);
ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), splitterColor);
ImGui::SameLine(0.0f, 0.0f);
if(ImGui::BeginChild("##AssetsItemView", {0.0f, 0.0f}, ImGuiChildFlags_Borders, childFlags))
{
DefineItemView();
}
ImGui::EndChild();
}
void TSE::EDITOR::AssetsView::DefineTreeView()
{
const bool assetsOpen = ImGui::CollapsingHeader("Assets", ImGuiTreeNodeFlags_DefaultOpen);
const std::filesystem::path assetPath = TSE::AssetLibrary::GetCurrentAssetPath();
std::error_code errorCode;
if(assetPath.empty() || !std::filesystem::exists(assetPath, errorCode) || !std::filesystem::is_directory(assetPath, errorCode))
{
DefineFolderNamePopup();
return;
}
AcceptAssetDrop(assetPath);
if(assetsOpen)
{
DisplayDirectoryTree(assetPath);
ImVec2 remainingSpace = ImGui::GetContentRegionAvail();
if(remainingSpace.y > 0.0f)
{
if(remainingSpace.x < 1.0f)
remainingSpace.x = 1.0f;
ImGui::InvisibleButton("##AssetsRootDropArea", remainingSpace);
AcceptAssetDrop(assetPath);
if(ImGui::BeginPopupContextItem("##AssetsRootContext"))
{
DefineFolderBackgroundContextMenu(assetPath);
ImGui::EndPopup();
}
}
}
DefineFolderNamePopup();
}
void TSE::EDITOR::AssetsView::DefineItemView()
{
DefineItemViewToolbar();
const std::filesystem::path browserPath = GetCurrentBrowserPath();
std::error_code errorCode;
if(browserPath.empty() || !std::filesystem::exists(browserPath, errorCode) || !std::filesystem::is_directory(browserPath, errorCode))
return;
if(ImGui::BeginChild("##AssetsItemScroll", {0.0f, 0.0f}, ImGuiChildFlags_None, ImGuiWindowFlags_AlwaysVerticalScrollbar))
{
if(itemViewMode == ItemViewMode::List)
DefineItemListView(browserPath);
else
DefineItemTileView(browserPath);
ImVec2 remainingSpace = ImGui::GetContentRegionAvail();
if(remainingSpace.y > 0.0f)
{
if(remainingSpace.x < 1.0f)
remainingSpace.x = 1.0f;
ImGui::InvisibleButton("##AssetsItemRootDropArea", remainingSpace);
AcceptAssetDrop(browserPath);
if(ImGui::BeginPopupContextItem("##AssetsItemRootContext"))
{
DefineFolderBackgroundContextMenu(browserPath);
ImGui::EndPopup();
}
}
if(ImGui::BeginPopupContextWindow("##AssetsItemBackgroundContext", ImGuiPopupFlags_MouseButtonRight | ImGuiPopupFlags_NoOpenOverItems))
{
DefineFolderBackgroundContextMenu(browserPath);
ImGui::EndPopup();
}
}
ImGui::EndChild();
}
void TSE::EDITOR::AssetsView::DefineItemViewToolbar()
{
const float buttonWidth = 64.0f;
const float totalWidth = buttonWidth * 2.0f + ImGui::GetStyle().ItemSpacing.x;
const float startX = ImGui::GetContentRegionAvail().x - totalWidth;
if(startX > 0.0f)
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + startX);
if(ImGui::Selectable("List", itemViewMode == ItemViewMode::List, 0, {buttonWidth, 0.0f}))
itemViewMode = ItemViewMode::List;
ImGui::SameLine();
if(ImGui::Selectable("Tiles", itemViewMode == ItemViewMode::Tiles, 0, {buttonWidth, 0.0f}))
itemViewMode = ItemViewMode::Tiles;
}
void TSE::EDITOR::AssetsView::DefineItemListView(const std::filesystem::path& folderPath)
{
for(const auto& folderEntry : GetDirectories(folderPath))
DefineFolderListItem(folderEntry);
for(const auto& fileEntry : GetFiles(folderPath))
DefineFileListItem(fileEntry);
}
void TSE::EDITOR::AssetsView::DefineItemTileView(const std::filesystem::path& folderPath)
{
const float tileSize = 96.0f;
const float spacing = ImGui::GetStyle().ItemSpacing.x;
const float availableWidth = ImGui::GetContentRegionAvail().x;
int columns = static_cast<int>(availableWidth / (tileSize + spacing));
if(columns < 1)
columns = 1;
int index = 0;
auto nextTile = [&]()
{
index++;
if(index % columns != 0)
ImGui::SameLine();
};
for(const auto& folderEntry : GetDirectories(folderPath))
{
DefineFolderTileItem(folderEntry);
nextTile();
}
for(const auto& fileEntry : GetFiles(folderPath))
{
DefineFileTileItem(fileEntry);
nextTile();
}
}
void TSE::EDITOR::AssetsView::DefineFolderListItem(const std::filesystem::directory_entry& folderEntry)
{
const std::filesystem::path folderPath = folderEntry.path();
ImGui::PushID(folderPath.string().c_str());
ImGui::TextUnformatted("[D]");
ImGui::SameLine();
const bool selected = currentSelectedPath == folderPath;
ImGui::Selectable(folderPath.filename().string().c_str(), selected, 0, {ImGui::GetContentRegionAvail().x, 0.0f});
if(ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
currentSelectedPath = folderPath;
if(ImGui::BeginDragDropSource())
{
const std::string payloadPath = folderPath.string();
ImGui::SetDragDropPayload("ASSET_FOLDER_PATH", payloadPath.c_str(), payloadPath.size() + 1);
ImGui::Text("%s", folderPath.filename().string().c_str());
ImGui::EndDragDropSource();
}
AcceptAssetDrop(folderPath);
if(ImGui::BeginPopupContextItem())
{
DefineFolderContextMenu(folderPath);
ImGui::EndPopup();
}
ImGui::PopID();
}
void TSE::EDITOR::AssetsView::DefineFileListItem(const std::filesystem::directory_entry& fileEntry)
{
const std::filesystem::path filePath = fileEntry.path();
ImGui::PushID(filePath.string().c_str());
ImGui::TextUnformatted("[F]");
ImGui::SameLine();
ImGui::Selectable(filePath.filename().string().c_str(), false, 0, {ImGui::GetContentRegionAvail().x, 0.0f});
if(ImGui::IsItemClicked(ImGuiMouseButton_Left))
OpenFileProperties(filePath.string());
if(ImGui::BeginDragDropSource())
{
const std::string payloadPath = filePath.string();
ImGui::SetDragDropPayload("ASSET_FILE_PATH", payloadPath.c_str(), payloadPath.size() + 1);
ImGui::Text("%s", filePath.filename().string().c_str());
ImGui::EndDragDropSource();
}
if(ImGui::BeginPopupContextItem())
{
DefineFileContextMenu(filePath);
ImGui::EndPopup();
}
ImGui::PopID();
}
void TSE::EDITOR::AssetsView::DefineFolderTileItem(const std::filesystem::directory_entry& folderEntry)
{
const std::filesystem::path folderPath = folderEntry.path();
const float tileSize = 96.0f;
ImGui::PushID(folderPath.string().c_str());
const bool selected = currentSelectedPath == folderPath;
ImGui::Selectable("##FolderTile", selected, 0, {tileSize, tileSize});
if(ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
currentSelectedPath = folderPath;
ImVec2 itemMin = ImGui::GetItemRectMin();
ImVec2 itemMax = ImGui::GetItemRectMax();
ImDrawList* drawList = ImGui::GetWindowDrawList();
const std::string icon = "[D]";
const std::string name = FitTextToWidth(folderPath.filename().string(), tileSize - 12.0f);
const ImVec2 iconSize = ImGui::CalcTextSize(icon.c_str());
const ImVec2 nameSize = ImGui::CalcTextSize(name.c_str());
drawList->AddText({itemMin.x + (tileSize - iconSize.x) * 0.5f, itemMin.y + 22.0f}, ImGui::GetColorU32(ImGuiCol_Text), icon.c_str());
drawList->AddText({itemMin.x + (tileSize - nameSize.x) * 0.5f, itemMax.y - 28.0f}, ImGui::GetColorU32(ImGuiCol_Text), name.c_str());
if(ImGui::BeginDragDropSource())
{
const std::string payloadPath = folderPath.string();
ImGui::SetDragDropPayload("ASSET_FOLDER_PATH", payloadPath.c_str(), payloadPath.size() + 1);
ImGui::Text("%s", folderPath.filename().string().c_str());
ImGui::EndDragDropSource();
}
AcceptAssetDrop(folderPath);
if(ImGui::BeginPopupContextItem())
{
DefineFolderContextMenu(folderPath);
ImGui::EndPopup();
}
ImGui::PopID();
}
void TSE::EDITOR::AssetsView::DefineFileTileItem(const std::filesystem::directory_entry& fileEntry)
{
const std::filesystem::path filePath = fileEntry.path();
const float tileSize = 96.0f;
ImGui::PushID(filePath.string().c_str());
ImGui::Selectable("##FileTile", false, 0, {tileSize, tileSize});
if(ImGui::IsItemClicked(ImGuiMouseButton_Left))
OpenFileProperties(filePath.string());
ImVec2 itemMin = ImGui::GetItemRectMin();
ImVec2 itemMax = ImGui::GetItemRectMax();
ImDrawList* drawList = ImGui::GetWindowDrawList();
const std::string icon = "[F]";
const std::string name = FitTextToWidth(filePath.filename().string(), tileSize - 12.0f);
const ImVec2 iconSize = ImGui::CalcTextSize(icon.c_str());
const ImVec2 nameSize = ImGui::CalcTextSize(name.c_str());
drawList->AddText({itemMin.x + (tileSize - iconSize.x) * 0.5f, itemMin.y + 22.0f}, ImGui::GetColorU32(ImGuiCol_Text), icon.c_str());
drawList->AddText({itemMin.x + (tileSize - nameSize.x) * 0.5f, itemMax.y - 28.0f}, ImGui::GetColorU32(ImGuiCol_Text), name.c_str());
if(ImGui::BeginDragDropSource())
{
const std::string payloadPath = filePath.string();
ImGui::SetDragDropPayload("ASSET_FILE_PATH", payloadPath.c_str(), payloadPath.size() + 1);
ImGui::Text("%s", filePath.filename().string().c_str());
ImGui::EndDragDropSource();
}
if(ImGui::BeginPopupContextItem())
{
DefineFileContextMenu(filePath);
ImGui::EndPopup();
}
ImGui::PopID();
}
void TSE::EDITOR::AssetsView::DisplayDirectoryTree(const std::filesystem::path& folderPath)
{
std::vector<std::filesystem::directory_entry> childDirectories = GetDirectories(folderPath);
for(const auto& childDirectory : childDirectories)
{
const std::filesystem::path childPath = childDirectory.path();
const std::vector<std::filesystem::directory_entry> grandChildDirectories = GetDirectories(childPath);
ImGui::PushID(childPath.string().c_str());
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanFullWidth;
if(grandChildDirectories.empty())
flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
if(currentSelectedPath == childPath)
flags |= ImGuiTreeNodeFlags_Selected;
const bool open = ImGui::TreeNodeEx(childPath.filename().string().c_str(), flags);
if(ImGui::IsItemClicked(ImGuiMouseButton_Left) && !ImGui::IsItemToggledOpen())
currentSelectedPath = childPath;
if(ImGui::BeginDragDropSource())
{
const std::string payloadPath = childPath.string();
ImGui::SetDragDropPayload("ASSET_FOLDER_PATH", payloadPath.c_str(), payloadPath.size() + 1);
ImGui::Text("%s", childPath.filename().string().c_str());
ImGui::EndDragDropSource();
}
AcceptAssetDrop(childPath);
bool folderDeleted = false;
if(ImGui::BeginPopupContextItem())
{
folderDeleted = DefineFolderContextMenu(childPath);
ImGui::EndPopup();
}
if(open && !grandChildDirectories.empty())
{
if(!folderDeleted)
DisplayDirectoryTree(childPath);
ImGui::TreePop();
}
ImGui::PopID();
}
}
bool TSE::EDITOR::AssetsView::DefineFolderContextMenu(const std::filesystem::path& folderPath)
{
if(ImGui::MenuItem("Rename"))
RequestFolderNamePopup(FolderPopupPurpose::Rename, folderPath);
bool folderDeleted = false;
if(ImGui::MenuItem("Delete"))
{
DeleteFolder(folderPath);
folderDeleted = true;
}
if(ImGui::MenuItem("New Folder"))
RequestFolderNamePopup(FolderPopupPurpose::NewFolder, folderPath);
return folderDeleted;
}
void TSE::EDITOR::AssetsView::DefineFolderBackgroundContextMenu(const std::filesystem::path& folderPath)
{
if(ImGui::MenuItem("New Folder"))
RequestFolderNamePopup(FolderPopupPurpose::NewFolder, folderPath);
}
bool TSE::EDITOR::AssetsView::DefineFileContextMenu(const std::filesystem::path& filePath)
{
if(ImGui::MenuItem("Rename"))
RequestFolderNamePopup(FolderPopupPurpose::Rename, filePath);
bool fileDeleted = false;
if(ImGui::MenuItem("Delete"))
{
DeleteFile(filePath);
fileDeleted = true;
}
return fileDeleted;
}
void TSE::EDITOR::AssetsView::AcceptAssetDrop(const std::filesystem::path& targetFolderPath)
{
if(ImGui::BeginDragDropTarget())
{
const ImGuiPayload* folderPayload = ImGui::AcceptDragDropPayload("ASSET_FOLDER_PATH");
if(folderPayload != nullptr && folderPayload->Data != nullptr)
{
const char* payloadPath = static_cast<const char*>(folderPayload->Data);
MoveFolder(std::filesystem::path(payloadPath), targetFolderPath);
}
const ImGuiPayload* filePayload = ImGui::AcceptDragDropPayload("ASSET_FILE_PATH");
if(filePayload != nullptr && filePayload->Data != nullptr)
{
const char* payloadPath = static_cast<const char*>(filePayload->Data);
MoveFile(std::filesystem::path(payloadPath), targetFolderPath);
}
ImGui::EndDragDropTarget();
}
}
void TSE::EDITOR::AssetsView::MoveFolder(const std::filesystem::path& sourceFolderPath, const std::filesystem::path& targetFolderPath)
{
const std::filesystem::path sourcePath = sourceFolderPath.lexically_normal();
const std::filesystem::path targetPath = targetFolderPath.lexically_normal();
if(sourcePath.empty() || targetPath.empty())
return;
if(sourcePath.parent_path() == targetPath)
return;
if(IsSameOrChildPath(targetPath, sourcePath))
return;
const std::filesystem::path newFolderPath = targetPath / sourcePath.filename();
std::error_code errorCode;
if(std::filesystem::exists(newFolderPath, errorCode))
return;
std::filesystem::rename(sourcePath, newFolderPath, errorCode);
if(errorCode)
return;
if(currentSelectedPath == sourcePath)
currentSelectedPath = newFolderPath;
else if(IsSameOrChildPath(currentSelectedPath, sourcePath))
currentSelectedPath = newFolderPath / currentSelectedPath.lexically_relative(sourcePath);
TSE::AssetLibrary::RescanAssets();
}
void TSE::EDITOR::AssetsView::MoveFile(const std::filesystem::path& sourceFilePath, const std::filesystem::path& targetFolderPath)
{
const std::filesystem::path sourcePath = sourceFilePath.lexically_normal();
const std::filesystem::path targetPath = targetFolderPath.lexically_normal();
if(sourcePath.empty() || targetPath.empty())
return;
if(sourcePath.parent_path() == targetPath)
return;
const std::filesystem::path newFilePath = targetPath / sourcePath.filename();
std::error_code errorCode;
if(std::filesystem::exists(newFilePath, errorCode))
return;
std::filesystem::rename(sourcePath, newFilePath, errorCode);
if(!errorCode)
TSE::AssetLibrary::RescanAssets();
}
void TSE::EDITOR::AssetsView::RequestFolderNamePopup(FolderPopupPurpose purpose, const std::filesystem::path& folderPath)
{
folderPopupPurpose = purpose;
pendingFolderPath = folderPath;
openFolderNamePopup = true;
focusFolderNameInput = true;
const std::string defaultName = purpose == FolderPopupPurpose::Rename ? folderPath.filename().string() : "";
std::snprintf(folderNameBuffer, sizeof(folderNameBuffer), "%s", defaultName.c_str());
}
void TSE::EDITOR::AssetsView::DefineFolderNamePopup()
{
if(openFolderNamePopup)
{
openFolderNamePopup = false;
ImGui::OpenPopup("Folder Name");
}
if(ImGui::BeginPopupModal("Folder Name", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("Name:");
if(focusFolderNameInput)
{
ImGui::SetKeyboardFocusHere();
focusFolderNameInput = false;
}
ImGui::InputText("##FolderName", folderNameBuffer, sizeof(folderNameBuffer));
const bool inputValid = folderNameBuffer[0] != '\0';
if(!inputValid)
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Not Valid.");
if(!inputValid)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
if(ImGui::Button("OK", ImVec2(120, 0)) && inputValid)
{
ConfirmFolderNamePopup();
ImGui::CloseCurrentPopup();
}
if(!inputValid)
ImGui::PopStyleVar();
ImGui::SameLine();
if(ImGui::Button("Cancel", ImVec2(120, 0)))
{
folderPopupPurpose = FolderPopupPurpose::None;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void TSE::EDITOR::AssetsView::ConfirmFolderNamePopup()
{
const std::string folderName = folderNameBuffer;
if(folderName.empty())
return;
std::error_code errorCode;
if(folderPopupPurpose == FolderPopupPurpose::Rename)
{
const std::filesystem::path newFolderPath = pendingFolderPath.parent_path() / folderName;
if(newFolderPath != pendingFolderPath && !std::filesystem::exists(newFolderPath, errorCode))
{
const bool selectedPathIsInRenamedFolder = IsSameOrChildPath(currentSelectedPath, pendingFolderPath);
const std::filesystem::path selectedRelativePath = selectedPathIsInRenamedFolder ? currentSelectedPath.lexically_relative(pendingFolderPath) : std::filesystem::path();
std::filesystem::rename(pendingFolderPath, newFolderPath, errorCode);
if(!errorCode)
{
if(selectedPathIsInRenamedFolder)
currentSelectedPath = newFolderPath / selectedRelativePath;
TSE::AssetLibrary::RescanAssets();
}
}
}
else if(folderPopupPurpose == FolderPopupPurpose::NewFolder)
{
const std::filesystem::path newFolderPath = pendingFolderPath / folderName;
if(!std::filesystem::exists(newFolderPath, errorCode))
{
std::filesystem::create_directory(newFolderPath, errorCode);
if(!errorCode)
{
currentSelectedPath = newFolderPath;
TSE::AssetLibrary::RescanAssets();
}
}
}
folderPopupPurpose = FolderPopupPurpose::None;
}
void TSE::EDITOR::AssetsView::DeleteFolder(const std::filesystem::path& folderPath)
{
std::error_code errorCode;
std::filesystem::remove_all(folderPath, errorCode);
if(!errorCode && IsPathInFolder(currentSelectedPath, folderPath))
currentSelectedPath.clear();
if(!errorCode)
TSE::AssetLibrary::RescanAssets();
}
void TSE::EDITOR::AssetsView::DeleteFile(const std::filesystem::path& filePath)
{
std::error_code errorCode;
std::filesystem::remove(filePath, errorCode);
if(!errorCode)
TSE::AssetLibrary::RescanAssets();
}
std::filesystem::path TSE::EDITOR::AssetsView::GetCurrentBrowserPath() const
{
std::error_code errorCode;
if(!currentSelectedPath.empty() && std::filesystem::exists(currentSelectedPath, errorCode) && std::filesystem::is_directory(currentSelectedPath, errorCode))
return currentSelectedPath;
return TSE::AssetLibrary::GetCurrentAssetPath();
}
void TSE::EDITOR::AssetsView::OpenFileProperties(string path)
{
string metapath = path + ".meta";
if(FileExists(metapath))
{
using json = nlohmann::ordered_json;
std::ifstream metaStream;
OpenFileReading(metaStream, metapath);
json meta = json::parse(metaStream);
uuids::uuid id = uuids::uuid::from_string((string)meta["id"]).value_or(id);
if(!AssetLibrary::HasValue(id)) return;
IAsset* assetPtr = nullptr;
if(meta["assetType"] == "material")
{
assetPtr = static_cast<IAsset*>(AssetLibrary::GetValue<Material*>(id));
}
else if(meta["assetType"] == "texture")
{
assetPtr = static_cast<IAsset*>(AssetLibrary::GetValue<Texture*>(id));
}
if(assetPtr != nullptr)
{
PropertiesView::SetInspectorElement(InspectableType::IAsset, assetPtr);
}
}
}

View File

@@ -0,0 +1,62 @@
#pragma once
#include "UI/base/GuiWindow.h"
#include <filesystem>
namespace TSE::EDITOR
{
class AssetsView : public GuiWindow
{
private:
enum class FolderPopupPurpose
{
None,
Rename,
NewFolder
};
enum class ItemViewMode
{
List,
Tiles
};
float leftPanelWidth = -1.0f;
ItemViewMode itemViewMode = ItemViewMode::List;
std::filesystem::path currentSelectedPath;
std::filesystem::path pendingFolderPath;
FolderPopupPurpose folderPopupPurpose = FolderPopupPurpose::None;
bool openFolderNamePopup = false;
bool focusFolderNameInput = false;
char folderNameBuffer[256] = "";
void DefineTreeView();
void DefineItemView();
void DefineItemViewToolbar();
void DefineItemListView(const std::filesystem::path& folderPath);
void DefineItemTileView(const std::filesystem::path& folderPath);
void DefineFolderListItem(const std::filesystem::directory_entry& folderEntry);
void DefineFileListItem(const std::filesystem::directory_entry& fileEntry);
void DefineFolderTileItem(const std::filesystem::directory_entry& folderEntry);
void DefineFileTileItem(const std::filesystem::directory_entry& fileEntry);
void DisplayDirectoryTree(const std::filesystem::path& folderPath);
bool DefineFolderContextMenu(const std::filesystem::path& folderPath);
void DefineFolderBackgroundContextMenu(const std::filesystem::path& folderPath);
bool DefineFileContextMenu(const std::filesystem::path& filePath);
void AcceptAssetDrop(const std::filesystem::path& targetFolderPath);
void MoveFolder(const std::filesystem::path& sourceFolderPath, const std::filesystem::path& targetFolderPath);
void MoveFile(const std::filesystem::path& sourceFilePath, const std::filesystem::path& targetFolderPath);
void RequestFolderNamePopup(FolderPopupPurpose purpose, const std::filesystem::path& folderPath);
void DefineFolderNamePopup();
void ConfirmFolderNamePopup();
void DeleteFolder(const std::filesystem::path& folderPath);
void DeleteFile(const std::filesystem::path& filePath);
std::filesystem::path GetCurrentBrowserPath() const;
void OpenFileProperties(string path);
public:
AssetsView();
void Define() override;
};
} // namespace TSE::EDITOR

View File

@@ -19,7 +19,7 @@ void TSE::EDITOR::CameraView::Define()
ImGuiWindowFlags flags2 = ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar;
if(ImGui::BeginChild("##CameraChild", {0,0}, ImGuiChildFlags_None, flags2))
{
ImGui::Image(fb->GetTextureId(), {fb->Width(), fb->Height()},{0,1}, {1,0});
ImGui::Image(fb->GetTextureId(0), {fb->Width(), fb->Height()},{0,1}, {1,0});
auto vec2 = ImGui::GetWindowSize();
if(fb->Width() != vec2.x || fb->Height() != vec2.y)
{

View File

@@ -17,7 +17,6 @@ namespace TSE::EDITOR
RenamingTransformable = 3,
RenamingScene = 4
};
Scene* currentScene;
uuids::uuid selected = uuids::uuid();
bool openPopUpNamingLayer = false;
@@ -29,6 +28,7 @@ namespace TSE::EDITOR
Layer* tmpHolder2 = nullptr;
public:
inline static Scene* currentScene = nullptr;
HirearchieView(Scene* s);
void SetScene(Scene* s);
void Define() override;

View File

@@ -5,25 +5,37 @@ TSE::EDITOR::SceneView::SceneView(TSE::IRenderTexture *frameBuffer) : GuiWindow(
fb = frameBuffer;
}
int selected = 0;
void TSE::EDITOR::SceneView::Define()
{
ImGuiWindowFlags flags2 = ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar;
if(ImGui::BeginChild("##SceneChild", {0,0}, ImGuiChildFlags_None, flags2))
{
ImGui::Image(fb->GetTextureId(), {fb->Width(), fb->Height()},{0,1}, {1,0});
ImGui::Image(fb->GetTextureId(selected), {fb->Width(), fb->Height()},{0,1}, {1,0});
auto vec2 = ImGui::GetWindowSize();
if(fb->Width() != vec2.x || fb->Height() != vec2.y)
{
fb->SetSize({vec2.x, vec2.y});
}
if(ImGui::IsWindowFocused())
{
IsHovered = true;
}
else
{
IsHovered = false;
}
static const char* items[] = {
"0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15",
"16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31"
};
ImGui::SetCursorPos(ImVec2(6.0f, 6.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0.6f));
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0,0,0,0.9f));
ImGui::SetNextItemWidth(80.0f);
ImGui::Combo("##SceneDropdown", &selected, items, IM_ARRAYSIZE(items));
ImGui::PopStyleColor(2);
IsHovered = ImGui::IsWindowFocused();
}
ImGui::EndChild();
}

View File

@@ -149,3 +149,13 @@ bool TSE::GLFW::WindowGlfw::ShouldClose() const
{
return glfwWindowShouldClose(window);
}
void TSE::GLFW::WindowGlfw::DoneSetup()
{
renderingBackend->onResize(width, height);
for (auto const& i : objectsToResize)
{
i->OnResize(width, height, this);
}
}

View File

@@ -7,7 +7,6 @@
#include "enums/WindowType.hpp"
#include "Color.hpp"
namespace TSE::GLFW
{
class WindowGlfw : public IWindow
@@ -36,5 +35,6 @@ namespace TSE::GLFW
bool ShouldClose() const override;
inline void Bind() override { };
inline void Unbind() override { };
void DoneSetup() override;
};
} // namespace TSE::GLFW

View File

@@ -0,0 +1,3 @@
#pragma once
#define TSE_GLFW

View File

@@ -1,54 +0,0 @@
#include "RenderTexture.hpp"
TSE::GLFW::RenderTexture::RenderTexture(Vector2 v) : buffer(v)
{
buffer.AddResizeNotifiable(this);
}
TSE::Vector2 TSE::GLFW::RenderTexture::size() const
{
return buffer.GetSize();
}
void TSE::GLFW::RenderTexture::SetSize(Vector2 v)
{
buffer.Resize(v);
}
float TSE::GLFW::RenderTexture::Width() const
{
return buffer.GetSize().x;
}
float TSE::GLFW::RenderTexture::Height() const
{
return buffer.GetSize().y;
}
TSE::uint TSE::GLFW::RenderTexture::GetTextureId() const
{
return buffer.GetTextureId();
}
void TSE::GLFW::RenderTexture::Update()
{
buffer.Update();
}
void TSE::GLFW::RenderTexture::Bind()
{
buffer.Bind();
}
void TSE::GLFW::RenderTexture::Unbind()
{
buffer.Unbind();
}
void TSE::GLFW::RenderTexture::OnResize(float width, float height, IResizable *wnd)
{
for (auto const& i : objectsToResize)
{
i->OnResize(width, height, this);
}
}

View File

@@ -1,61 +0,0 @@
#include "GL/gl3w.h"
#include "GL/gl.h"
#include "TextureHelperOpenGL.hpp"
void TSE::GLFW::TextureHelperOpenGL::Bind(const Texture *tex)
{
glBindTexture(GL_TEXTURE_2D, tex->GetTextureId());
}
void TSE::GLFW::TextureHelperOpenGL::UnBind(const Texture *tex)
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void TSE::GLFW::TextureHelperOpenGL::Apply(Texture *tex)
{
glBindTexture(GL_TEXTURE_2D, tex->GetTextureId());
if(tex->Chanels() == 1)
{
if (tex->bpp() == 8)
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, tex->Width(), tex->Height(), 0, GL_RED, GL_UNSIGNED_BYTE, tex->GetImagePtr());
}
if(tex->Chanels() == 3)
{
if(tex->bpp() == 24)
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, tex->Width(), tex->Height(), 0, GL_BGR, GL_UNSIGNED_BYTE, tex->GetImagePtr());
}
else if(tex->Chanels() == 4)
{
if(tex->bpp() == 32)
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, tex->Width(), tex->Height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, tex->GetImagePtr());
if (tex->bpp() == 8) //need to decode it with bitwise operations in shader
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, tex->Width(), tex->Height(), 0, GL_RED, GL_UNSIGNED_BYTE, tex->GetImagePtr());
}
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
void TSE::GLFW::TextureHelperOpenGL::Regist(Texture *tex)
{
uint TextureID;
glGenTextures(1, &TextureID);
glBindTexture(GL_TEXTURE_2D, TextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
tex->SetTextureId(TextureID);
tex->Apply();
}
void TSE::GLFW::TextureHelperOpenGL::PlatromDestroy(Texture *tex)
{
uint id = tex->GetTextureId();
glDeleteTextures(1, &id);
}

View File

@@ -1,99 +0,0 @@
#include "FrameBuffer.hpp"
#include "Debug.hpp"
TSE::GLFW::FrameBuffer::FrameBuffer(const Vector2 &size)
{
width = size.x;
height = size.y;
CreateFBTexture();
for (auto const& i : objectsToResize)
{
i->OnResize(size.x, size.y, this);
}
Initialize();
}
void TSE::GLFW::FrameBuffer::Bind()
{
glBindFramebuffer(GL_FRAMEBUFFER, bufferID);
}
void TSE::GLFW::FrameBuffer::Unbind()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
TSE::GLFW::FrameBuffer::~FrameBuffer()
{
glDeleteFramebuffers(1,&bufferID);
glDeleteTextures(1, &textureID);
glDeleteRenderbuffers(1, &depthRboID);
}
void TSE::GLFW::FrameBuffer::Resize(Vector2 size)
{
width = size.x;
height = size.y;
shouldResize = true;
}
void TSE::GLFW::FrameBuffer::Update()
{
if (!shouldResize) return;
shouldResize = false;
CreateFBTexture();
for (auto const& i : objectsToResize)
{
i->OnResize(width, height, this);
}
}
TSE::uint TSE::GLFW::FrameBuffer::GetTextureId() const
{
return textureID;
}
TSE::Vector2 TSE::GLFW::FrameBuffer::GetSize() const
{
return {width, height};
}
void TSE::GLFW::FrameBuffer::Initialize()
{
glGenFramebuffers(1, &bufferID);
Bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRboID);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
TSE_ERROR("Failed to create OpenGL FBO.");
TSE_LOG(std::to_string(glGetError()));
}
Unbind();
}
void TSE::GLFW::FrameBuffer::LoadFBTexture()
{
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindRenderbuffer(GL_RENDERBUFFER, depthRboID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
}
void TSE::GLFW::FrameBuffer::CreateFBTexture()
{
glViewport(0,0, width, height);
//resize
if(textureID == 0)
glGenTextures(1, &textureID);
if(depthRboID == 0)
glGenRenderbuffers(1, &depthRboID);
LoadFBTexture();
}

View File

@@ -1,30 +0,0 @@
#include "defaultShaderHandler.hpp"
#include "basicShader.hpp"
#include "basicTextureShader.hpp"
#include "ditheringShader.hpp"
#include "basicParticleShader.hpp"
#include "elements/ShaderRegistry.hpp"
void TSE::GLFW::LoadBasicShaders(float width, float height)
{
BasicShader::Init(width, height);
BasicTextureShader::Init(width, height);
DitheringShader::Init(width, height);
BasicParticleShader::Init(width, height);
ShaderRegistry::SetShader("Basic Unlit Shader", BasicShader::Instance());
ShaderRegistry::SetShader("Basic Unlit Texture Shader", BasicTextureShader::Instance());
ShaderRegistry::SetShader("Basic Unlit Dithering Shader", DitheringShader::Instance());
ShaderRegistry::SetShader("Basic Unlit Particle Shader", BasicParticleShader::Instance());
}
void TSE::GLFW::UnLoadBasicShaders()
{
ShaderRegistry::RemoveShader("Basic Unlit Shader");
ShaderRegistry::RemoveShader("Basic Unlit Texture Shader");
ShaderRegistry::RemoveShader("Basic Unlit Dithering Shader");
ShaderRegistry::RemoveShader("Basic Unlit Particle Shader");
BasicShader::Destroy();
BasicTextureShader::Destroy();
DitheringShader::Destroy();
BasicParticleShader::Destroy();
}

View File

@@ -11,6 +11,9 @@ namespace TSE
/// @brief the epsilon used as min float value for comparisons in the engine
constexpr float TSE_EPSILON = 1e-6f;
/// @brief 32-bit golden ratio constant used for hash mixing
constexpr uint TSE_HASH_GOLDEN_RATIO_32 = 0x9e3779b9u;
/// @brief a simple degrees to radiant conversion function
/// @param deg the degrees value
/// @return the radiant value

View File

@@ -1,78 +0,0 @@
#include "Mesh.hpp"
#include "MathF.hpp"
#include <cmath>
TSE::Mesh::Mesh()
{
name = "";
}
TSE::Mesh::Mesh(string _name, const std::vector<Vector3> &_vertecies, const std::vector<ushort> &_indecies, const std::vector<Vector2> &_uvs)
{
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);
}

View File

@@ -0,0 +1,659 @@
//----------------------------------------------------------------------------------------
//
// siv::PerlinNoise
// Perlin noise library for modern C++
//
// Copyright (C) 2013-2021 Ryo Suzuki <reputeless@gmail.com>
//
// 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 <cstdint>
# include <algorithm>
# include <array>
# include <iterator>
# include <numeric>
# include <random>
# include <type_traits>
# if __has_include(<concepts>) && defined(__cpp_concepts)
# include <concepts>
# endif
// Library major version
# define SIVPERLIN_VERSION_MAJOR 3
// Library minor version
# define SIVPERLIN_VERSION_MINOR 0
// Library revision version
# define SIVPERLIN_VERSION_REVISION 0
// Library version
# define SIVPERLIN_VERSION ((SIVPERLIN_VERSION_MAJOR * 100 * 100) + (SIVPERLIN_VERSION_MINOR * 100) + (SIVPERLIN_VERSION_REVISION))
// [[nodiscard]] for constructors
# if (201907L <= __has_cpp_attribute(nodiscard))
# define SIVPERLIN_NODISCARD_CXX20 [[nodiscard]]
# else
# define SIVPERLIN_NODISCARD_CXX20
# endif
// std::uniform_random_bit_generator concept
# if __cpp_lib_concepts
# define SIVPERLIN_CONCEPT_URBG template <std::uniform_random_bit_generator URBG>
# define SIVPERLIN_CONCEPT_URBG_ template <std::uniform_random_bit_generator URBG>
# else
# define SIVPERLIN_CONCEPT_URBG template <class URBG, std::enable_if_t<std::conjunction_v<std::is_invocable<URBG&>, std::is_unsigned<std::invoke_result_t<URBG&>>>>* = nullptr>
# define SIVPERLIN_CONCEPT_URBG_ template <class URBG, std::enable_if_t<std::conjunction_v<std::is_invocable<URBG&>, std::is_unsigned<std::invoke_result_t<URBG&>>>>*>
# endif
// arbitrary value for increasing entropy
# ifndef SIVPERLIN_DEFAULT_Y
# define SIVPERLIN_DEFAULT_Y (0.12345)
# endif
// arbitrary value for increasing entropy
# ifndef SIVPERLIN_DEFAULT_Z
# define SIVPERLIN_DEFAULT_Z (0.34567)
# endif
namespace siv
{
template <class Float>
class BasicPerlinNoise
{
public:
static_assert(std::is_floating_point_v<Float>);
///////////////////////////////////////
//
// Typedefs
//
using state_type = std::array<std::uint8_t, 256>;
using value_type = Float;
using default_random_engine = std::mt19937;
using seed_type = typename default_random_engine::result_type;
///////////////////////////////////////
//
// Constructors
//
SIVPERLIN_NODISCARD_CXX20
constexpr BasicPerlinNoise() noexcept;
SIVPERLIN_NODISCARD_CXX20
explicit BasicPerlinNoise(seed_type seed);
SIVPERLIN_CONCEPT_URBG
SIVPERLIN_NODISCARD_CXX20
explicit BasicPerlinNoise(URBG&& urbg);
///////////////////////////////////////
//
// Reseed
//
void reseed(seed_type seed);
SIVPERLIN_CONCEPT_URBG
void reseed(URBG&& urbg);
///////////////////////////////////////
//
// Serialization
//
[[nodiscard]]
constexpr const state_type& serialize() const noexcept;
constexpr void deserialize(const state_type& state) noexcept;
///////////////////////////////////////
//
// Noise (The result is in the range [-1, 1])
//
[[nodiscard]]
value_type noise1D(value_type x) const noexcept;
[[nodiscard]]
value_type noise2D(value_type x, value_type y) const noexcept;
[[nodiscard]]
value_type noise3D(value_type x, value_type y, value_type z) const noexcept;
///////////////////////////////////////
//
// Noise (The result is remapped to the range [0, 1])
//
[[nodiscard]]
value_type noise1D_01(value_type x) const noexcept;
[[nodiscard]]
value_type noise2D_01(value_type x, value_type y) const noexcept;
[[nodiscard]]
value_type noise3D_01(value_type x, value_type y, value_type z) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result can be out of the range [-1, 1])
//
[[nodiscard]]
value_type octave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is clamped to the range [-1, 1])
//
[[nodiscard]]
value_type octave1D_11(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D_11(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D_11(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is clamped and remapped to the range [0, 1])
//
[[nodiscard]]
value_type octave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is normalized to the range [-1, 1])
//
[[nodiscard]]
value_type normalizedOctave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is normalized and remapped to the range [0, 1])
//
[[nodiscard]]
value_type normalizedOctave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
private:
state_type m_permutation;
};
using PerlinNoise = BasicPerlinNoise<double>;
namespace perlin_detail
{
////////////////////////////////////////////////
//
// These functions are provided for consistency.
// You may get different results from std::shuffle() with different standard library implementations.
//
SIVPERLIN_CONCEPT_URBG
[[nodiscard]]
inline std::uint64_t Random(const std::uint64_t max, URBG&& urbg)
{
return (urbg() % (max + 1));
}
template <class RandomIt, class URBG>
inline void Shuffle(RandomIt first, RandomIt last, URBG&& urbg)
{
if (first == last)
{
return;
}
using difference_type = typename std::iterator_traits<RandomIt>::difference_type;
for (RandomIt it = first + 1; it < last; ++it)
{
const std::uint64_t n = static_cast<std::uint64_t>(it - first);
std::iter_swap(it, first + static_cast<difference_type>(Random(n, std::forward<URBG>(urbg))));
}
}
//
////////////////////////////////////////////////
template <class Float>
[[nodiscard]]
inline constexpr Float Fade(const Float t) noexcept
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Lerp(const Float a, const Float b, const Float t) noexcept
{
return (a + (b - a) * t);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Grad(const std::uint8_t hash, const Float x, const Float y, const Float z) noexcept
{
const std::uint8_t h = hash & 15;
const Float u = h < 8 ? x : y;
const Float v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Remap_01(const Float x) noexcept
{
return (x * Float(0.5) + Float(0.5));
}
template <class Float>
[[nodiscard]]
inline constexpr Float Clamp_11(const Float x) noexcept
{
return std::clamp(x, Float(-1.0), Float(1.0));
}
template <class Float>
[[nodiscard]]
inline constexpr Float RemapClamp_01(const Float x) noexcept
{
if (x <= Float(-1.0))
{
return Float(0.0);
}
else if (Float(1.0) <= x)
{
return Float(1.0);
}
return (x * Float(0.5) + Float(0.5));
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave1D(const Noise& noise, Float x, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise1D(x) * amplitude);
x *= 2;
amplitude *= persistence;
}
return result;
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave2D(const Noise& noise, Float x, Float y, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise2D(x, y) * amplitude);
x *= 2;
y *= 2;
amplitude *= persistence;
}
return result;
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave3D(const Noise& noise, Float x, Float y, Float z, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise3D(x, y, z) * amplitude);
x *= 2;
y *= 2;
z *= 2;
amplitude *= persistence;
}
return result;
}
template <class Float>
[[nodiscard]]
inline constexpr Float MaxAmplitude(const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += amplitude;
amplitude *= persistence;
}
return result;
}
}
///////////////////////////////////////
template <class Float>
inline constexpr BasicPerlinNoise<Float>::BasicPerlinNoise() noexcept
: m_permutation{ 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 } {}
template <class Float>
inline BasicPerlinNoise<Float>::BasicPerlinNoise(const seed_type seed)
{
reseed(seed);
}
template <class Float>
SIVPERLIN_CONCEPT_URBG_
inline BasicPerlinNoise<Float>::BasicPerlinNoise(URBG&& urbg)
{
reseed(std::forward<URBG>(urbg));
}
///////////////////////////////////////
template <class Float>
inline void BasicPerlinNoise<Float>::reseed(const seed_type seed)
{
reseed(default_random_engine{ seed });
}
template <class Float>
SIVPERLIN_CONCEPT_URBG_
inline void BasicPerlinNoise<Float>::reseed(URBG&& urbg)
{
std::iota(m_permutation.begin(), m_permutation.end(), uint8_t{ 0 });
perlin_detail::Shuffle(m_permutation.begin(), m_permutation.end(), std::forward<URBG>(urbg));
}
///////////////////////////////////////
template <class Float>
inline constexpr const typename BasicPerlinNoise<Float>::state_type& BasicPerlinNoise<Float>::serialize() const noexcept
{
return m_permutation;
}
template <class Float>
inline constexpr void BasicPerlinNoise<Float>::deserialize(const state_type& state) noexcept
{
m_permutation = state;
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise1D(const value_type x) const noexcept
{
return noise3D(x,
static_cast<value_type>(SIVPERLIN_DEFAULT_Y),
static_cast<value_type>(SIVPERLIN_DEFAULT_Z));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise2D(const value_type x, const value_type y) const noexcept
{
return noise3D(x,
y,
static_cast<value_type>(SIVPERLIN_DEFAULT_Z));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise3D(const value_type x, const value_type y, const value_type z) const noexcept
{
const value_type _x = std::floor(x);
const value_type _y = std::floor(y);
const value_type _z = std::floor(z);
const std::int32_t ix = static_cast<std::int32_t>(_x) & 255;
const std::int32_t iy = static_cast<std::int32_t>(_y) & 255;
const std::int32_t iz = static_cast<std::int32_t>(_z) & 255;
const value_type fx = (x - _x);
const value_type fy = (y - _y);
const value_type fz = (z - _z);
const value_type u = perlin_detail::Fade(fx);
const value_type v = perlin_detail::Fade(fy);
const value_type w = perlin_detail::Fade(fz);
const std::uint8_t A = (m_permutation[ix & 255] + iy) & 255;
const std::uint8_t B = (m_permutation[(ix + 1) & 255] + iy) & 255;
const std::uint8_t AA = (m_permutation[A] + iz) & 255;
const std::uint8_t AB = (m_permutation[(A + 1) & 255] + iz) & 255;
const std::uint8_t BA = (m_permutation[B] + iz) & 255;
const std::uint8_t BB = (m_permutation[(B + 1) & 255] + iz) & 255;
const value_type p0 = perlin_detail::Grad(m_permutation[AA], fx, fy, fz);
const value_type p1 = perlin_detail::Grad(m_permutation[BA], fx - 1, fy, fz);
const value_type p2 = perlin_detail::Grad(m_permutation[AB], fx, fy - 1, fz);
const value_type p3 = perlin_detail::Grad(m_permutation[BB], fx - 1, fy - 1, fz);
const value_type p4 = perlin_detail::Grad(m_permutation[(AA + 1) & 255], fx, fy, fz - 1);
const value_type p5 = perlin_detail::Grad(m_permutation[(BA + 1) & 255], fx - 1, fy, fz - 1);
const value_type p6 = perlin_detail::Grad(m_permutation[(AB + 1) & 255], fx, fy - 1, fz - 1);
const value_type p7 = perlin_detail::Grad(m_permutation[(BB + 1) & 255], fx - 1, fy - 1, fz - 1);
const value_type q0 = perlin_detail::Lerp(p0, p1, u);
const value_type q1 = perlin_detail::Lerp(p2, p3, u);
const value_type q2 = perlin_detail::Lerp(p4, p5, u);
const value_type q3 = perlin_detail::Lerp(p6, p7, u);
const value_type r0 = perlin_detail::Lerp(q0, q1, v);
const value_type r1 = perlin_detail::Lerp(q2, q3, v);
return perlin_detail::Lerp(r0, r1, w);
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise1D_01(const value_type x) const noexcept
{
return perlin_detail::Remap_01(noise1D(x));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise2D_01(const value_type x, const value_type y) const noexcept
{
return perlin_detail::Remap_01(noise2D(x, y));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise3D_01(const value_type x, const value_type y, const value_type z) const noexcept
{
return perlin_detail::Remap_01(noise3D(x, y, z));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave1D(*this, x, octaves, persistence);
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave2D(*this, x, y, octaves, persistence);
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave3D(*this, x, y, z, octaves, persistence);
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D_11(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D_11(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D_11(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave3D(x, y, z, octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave3D(x, y, z, octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave1D(x, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave2D(x, y, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave3D(x, y, z, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave3D(x, y, z, octaves, persistence));
}
}
# undef SIVPERLIN_NODISCARD_CXX20
# undef SIVPERLIN_CONCEPT_URBG
# undef SIVPERLIN_CONCEPT_URBG_

107
TSE_Math/src/Random.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "Random.hpp"
#include <bit>
#include <cstdint>
TSE::Random::Random(uint seed)
{
state = static_cast<uint>(static_cast<std::uint32_t>(seed));
}
TSE::uint TSE::Random::nextUInt(uint minInc, uint maxInc)
{
constexpr std::uint32_t multiplier = 1664525u;
constexpr std::uint32_t increment = 1013904223u;
std::uint32_t nextState = static_cast<std::uint32_t>(state);
nextState = nextState * multiplier + increment;
state = static_cast<uint>(nextState);
if(minInc == 0u && maxInc == 0u)
{
return state;
}
if(minInc > maxInc)
{
uint temp = minInc;
minInc = maxInc;
maxInc = temp;
}
const std::uint64_t span = static_cast<std::uint64_t>(maxInc) - static_cast<std::uint64_t>(minInc) + 1ull;
const std::uint64_t offset = static_cast<std::uint64_t>(nextState) % span;
return static_cast<uint>(static_cast<std::uint64_t>(minInc) + offset);
}
int TSE::Random::nextInt(int minInc, int maxInc)
{
const std::uint32_t bits = static_cast<std::uint32_t>(nextUInt());
if(minInc == 0 && maxInc == 0)
{
return static_cast<int>(std::bit_cast<std::int32_t>(bits));
}
if(minInc > maxInc)
{
int temp = minInc;
minInc = maxInc;
maxInc = temp;
}
const std::int64_t span = static_cast<std::int64_t>(maxInc) - static_cast<std::int64_t>(minInc) + 1ll;
const std::uint64_t offset = static_cast<std::uint64_t>(bits) % static_cast<std::uint64_t>(span);
const std::int64_t value = static_cast<std::int64_t>(minInc) + static_cast<std::int64_t>(offset);
return static_cast<int>(value);
}
short TSE::Random::nextShort(short minInc, short maxInc)
{
const std::uint32_t bits = static_cast<std::uint32_t>(nextUInt());
const std::uint16_t lowerBits = static_cast<std::uint16_t>(bits);
if(minInc == 0 && maxInc == 0)
{
return static_cast<short>(std::bit_cast<std::int16_t>(lowerBits));
}
if(minInc > maxInc)
{
short temp = minInc;
minInc = maxInc;
maxInc = temp;
}
const std::int32_t span = static_cast<std::int32_t>(maxInc) - static_cast<std::int32_t>(minInc) + 1;
const std::uint32_t offset = static_cast<std::uint32_t>(lowerBits) % static_cast<std::uint32_t>(span);
const std::int32_t value = static_cast<std::int32_t>(minInc) + static_cast<std::int32_t>(offset);
return static_cast<short>(value);
}
TSE::byte TSE::Random::nextByte(byte minInc, byte maxInc)
{
const std::uint32_t bits = static_cast<std::uint32_t>(nextUInt());
const std::uint8_t lowerBits = static_cast<std::uint8_t>(bits);
if(minInc == 0 && maxInc == 0)
{
return static_cast<byte>(lowerBits);
}
if(minInc > maxInc)
{
byte temp = minInc;
minInc = maxInc;
maxInc = temp;
}
const std::uint16_t span = static_cast<std::uint16_t>(maxInc) - static_cast<std::uint16_t>(minInc) + 1u;
const std::uint16_t offset = static_cast<std::uint16_t>(lowerBits) % span;
return static_cast<byte>(static_cast<std::uint16_t>(minInc) + offset);
}
float TSE::Random::nextFloat01()
{
constexpr float invRange = 1.0f / 4294967296.0f;
return static_cast<float>(static_cast<std::uint32_t>(nextUInt())) * invRange;
}

20
TSE_Math/src/Random.hpp Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "Types.hpp"
namespace TSE
{
class Random
{
private:
uint state;
public:
Random(uint seed);
uint nextUInt(uint minInc = 0, uint maxInc = 0);
int nextInt(int minInc = 0, int maxInc = 0);
short nextShort(short minInc = 0, short maxInc = 0);
byte nextByte(byte minInc = 0, byte maxInc = 0);
float nextFloat01();
};
}

View File

@@ -1,6 +1,8 @@
#pragma once
#include "Types.hpp"
#include "MathF.hpp"
#include <functional>
namespace TSE
{
@@ -135,3 +137,17 @@ namespace TSE
#pragma endregion methods
};
} // namespace TSE
namespace std
{
template<>
struct hash<TSE::Vector2>
{
size_t operator()(const TSE::Vector2& v) const noexcept
{
size_t h1 = std::hash<float>{}(v.x);
size_t h2 = std::hash<float>{}(v.y);
return h1 ^ (h2 + TSE::TSE_HASH_GOLDEN_RATIO_32 + (h1 << 6) + (h1 >> 2));
}
};
}

138
TSE_Math/src/Vector2i.cpp Normal file
View File

@@ -0,0 +1,138 @@
#include "Vector2i.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include "Vector4.hpp"
#include <cmath>
TSE::Vector2i::Vector2i() { }
TSE::Vector2i::Vector2i(int _x, int _y)
{
x = _x;
y = _y;
}
TSE::Vector2i::Vector2i(const Vector2i &other)
{
x = other.x;
y = other.y;
}
TSE::Vector2i::Vector2i(const Vector2 &other)
{
x = other.x;
y = other.y;
}
TSE::Vector2i::Vector2i(const Vector3 &other)
{
x = other.x;
y = other.y;
}
TSE::Vector2i::Vector2i(const Vector4 &other)
{
x = other.x;
y = other.y;
}
bool TSE::Vector2i::IsValid() const
{
return !std::isnan(x) && !std::isnan(y);
}
TSE::string TSE::Vector2i::ToString() const
{
return "(" + std::to_string(x) + "|" + std::to_string(y) + ")";
}
TSE::Vector2 TSE::Vector2i::ToVector2() const
{
return Vector2();
}
TSE::Vector3 TSE::Vector2i::ToVector3() const
{
return Vector3(x,y,0);
}
TSE::Vector4 TSE::Vector2i::ToVector4() const
{
return Vector4(x,y,0,0);
}
TSE::Vector2i TSE::Vector2i::operator+(const Vector2i &other) const
{
return Vector2i(x + other.x, y + other.y);
}
TSE::Vector2i TSE::Vector2i::operator+=(const Vector2i &other)
{
*this = *this + other;
return *this;
}
TSE::Vector2i TSE::Vector2i::operator-(const Vector2i &other) const
{
return Vector2i(x - other.x, y - other.y);
}
TSE::Vector2i TSE::Vector2i::operator-=(const Vector2i &other)
{
*this = *this - other;
return *this;
}
TSE::Vector2i TSE::Vector2i::operator*(const Vector2i &other) const
{
return Vector2i(x * other.x, y * other.y);
}
TSE::Vector2i TSE::Vector2i::operator*=(const Vector2i &other)
{
*this = *this * other;
return *this;
}
TSE::Vector2i TSE::Vector2i::operator/(const Vector2i &other) const
{
return Vector2i(x / other.x, y / other.y);
}
TSE::Vector2i TSE::Vector2i::operator/=(const Vector2i &other)
{
*this = *this / other;
return *this;
}
TSE::Vector2i TSE::Vector2i::operator*(const float other) const
{
return Vector2i(x * other, y * other);
}
TSE::Vector2i TSE::Vector2i::operator*=(const float other)
{
*this = *this * other;
return *this;
}
TSE::Vector2i TSE::Vector2i::operator/(const float other) const
{
return Vector2i(x / other, y / other);
}
TSE::Vector2i TSE::Vector2i::operator/=(const float other)
{
*this = *this / other;
return *this;
}
bool TSE::Vector2i::operator==(const Vector2i &other) const
{
return x == other.x && y == other.y;
}
bool TSE::Vector2i::operator!=(const Vector2i &other) const
{
return !(*this == other);
}

85
TSE_Math/src/Vector2i.hpp Normal file
View File

@@ -0,0 +1,85 @@
#pragma once
#include "Types.hpp"
#include "MathF.hpp"
#include <functional>
namespace TSE
{
class Vector2;
class Vector3;
class Vector4;
class Vector2i
{
public:
#pragma region members
int x = 0, y = 0;
#pragma endregion members
#pragma region consts
static const Vector2i left;
static const Vector2i right;
static const Vector2i up;
static const Vector2i down;
static const Vector2i one;
static const Vector2i zero;
#pragma endregion
#pragma region ctor
/// @brief enpty constructor defined as (0,0)
Vector2i();
/// @brief constructs a Vector2i with custom values
/// @param _x the x component
/// @param _y the y component
Vector2i(int _x, int _y);
/// @brief copy constructor
/// @param other the Vector2i to be copied from
Vector2i(const Vector2i& other);
/// @brief copy constructor
/// @param other the Vector2i to be copied from
Vector2i(const Vector2& other);
/// @brief converter constructor. it converts a Vector3 to a Vector2i without encointing for the z component
/// @param other the Vector3 to convert
Vector2i(const Vector3& other);
/// @brief converter constructor. it converts a Vector4 to a Vector2i without encointing for the z, and w component
/// @param other the Vector4 to convert
Vector2i(const Vector4& other);
#pragma endregion ctor
#pragma region methods
/// @brief checks if the individual components have valid values aka are not nan
/// @return are the values valid
bool IsValid() const;
/// @brief gives you the Vector2i as a string representation. mostly for debugging
/// @return the Vector2i in a format like (x|y)
string ToString() const;
/// @brief creates a Vector3 with the same values as the Vector2i, the y component gets the value 0
/// @return the Vector2i as a Vector3
Vector2 ToVector2() const;
/// @brief creates a Vector3 with the same values as the Vector2i, the y component gets the value 0
/// @return the Vector2i as a Vector3
Vector3 ToVector3() const;
/// @brief creates a Vector4 with the same values as the Vector2i, the y and w components get the value 0
/// @return the Vector2i as a Vector4
Vector4 ToVector4() const;
#pragma region operators
Vector2i operator+(const Vector2i& other) const;
Vector2i operator+=(const Vector2i& other);
Vector2i operator-(const Vector2i& other) const;
Vector2i operator-=(const Vector2i& other);
Vector2i operator*(const Vector2i& other) const;
Vector2i operator*=(const Vector2i& other);
Vector2i operator/(const Vector2i& other) const;
Vector2i operator/=(const Vector2i& other);
Vector2i operator*(const float other) const;
Vector2i operator*=(const float other);
Vector2i operator/(const float other) const;
Vector2i operator/=(const float other);
bool operator==(const Vector2i& other) const;
bool operator!=(const Vector2i& other) const;
#pragma endregion operators
#pragma endregion methods
};
} // namespace TSE

View File

@@ -1,6 +1,9 @@
#pragma once
#include "Types.hpp"
#include <functional>
#include <cstddef>
#include "MathF.hpp"
namespace TSE
{
@@ -145,3 +148,22 @@ namespace TSE
};
} // namespace TSE
namespace std
{
template<>
struct hash<TSE::Vector3>
{
size_t operator()(const TSE::Vector3& v) const noexcept
{
size_t h1 = std::hash<float>{}(v.x);
size_t h2 = std::hash<float>{}(v.y);
size_t h3 = std::hash<float>{}(v.z);
size_t hash = h1;
hash ^= h2 + TSE::TSE_HASH_GOLDEN_RATIO_32 + (hash << 6) + (hash >> 2);
hash ^= h3 + TSE::TSE_HASH_GOLDEN_RATIO_32 + (hash << 6) + (hash >> 2);
return hash;
}
};
}

View File

@@ -0,0 +1,71 @@
#cmake version
cmake_minimum_required(VERSION 3.31)
#project name
project(TSE_OpenGlImpl)
#cpp settings
find_program(CLANG_C NAMES clang)
find_program(CLANG_CXX NAMES clang++)
if(CLANG_C AND CLANG_CXX)
message(STATUS "foung Clang, using as Compiler")
set(CMAKE_C_COMPILER ${CLANG_C} CACHE STRING "C Compiler" FORCE)
set(CMAKE_CXX_COMPILER ${CLANG_CXX} CACHE STRING "C++ Compiler" FORCE)
else()
message(STATUS "Clang not found, using Standard-Compiler")
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#project output settings
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PROJECT_SOURCE_DIR}/lib/Debug")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/lib/Release")
#source files
file(GLOB CPP_SOURCE_TSE
"${PROJECT_SOURCE_DIR}/src/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*.c"
"${PROJECT_SOURCE_DIR}/src/*/*/*/*.c"
)
#includes
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Base/src)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Base/include)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Math/src)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Core/src)
include_directories(${PROJECT_SOURCE_DIR}/../TSE_Core/include)
#project def
if(Lib)
add_library(TSE_OpenGlImpl SHARED ${CPP_SOURCE_TSE})
else()
add_library(TSE_OpenGlImpl STATIC ${CPP_SOURCE_TSE})
endif()
# Window backend specific includes for WindowManager.hpp and platform glue.
if(USE_GLFW)
target_include_directories(TSE_OpenGlImpl PRIVATE
${PROJECT_SOURCE_DIR}/../TSE_GlfwImpl/src
${PROJECT_SOURCE_DIR}/../TSE_GlfwImpl/include
)
elseif(USE_SDL3)
target_include_directories(TSE_OpenGlImpl PRIVATE
${PROJECT_SOURCE_DIR}/../TSE_Sdl3Impl/src
${PROJECT_SOURCE_DIR}/../TSE_Sdl3Impl/include
)
endif()
#flags
target_compile_options(TSE_OpenGlImpl PRIVATE -march=native)

View File

@@ -4,7 +4,7 @@
#include "GL/gl3w.h"
#include "GL/gl.h"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class CameraHelperOpenGL : public ICameraHelper
{
@@ -14,4 +14,4 @@ namespace TSE::GLFW
glViewport(0, 0, width, height);
};
};
} // namespace TSE::GLFW
} // namespace TSE::OpenGL

View File

@@ -1,17 +1,18 @@
#include "DefaultRendererOpenGL.hpp"
#include "BehaviourScripts/Camera.hpp"
#include "BehaviourScripts/Renderable.hpp"
#include "Debug.hpp"
#define RENDERER_MAX_SPRITES 20000
#define RENDERER_MAX_INDECIES 60000
TSE::GLFW::DefaultRendererOpenGL::DefaultRendererOpenGL(Shader &shader)
TSE::OpenGL::DefaultRendererOpenGL::DefaultRendererOpenGL(Shader &shader)
{
iboData = new ushort[RENDERER_MAX_INDECIES];
InitShader(shader, true);
}
TSE::GLFW::DefaultRendererOpenGL::~DefaultRendererOpenGL()
TSE::OpenGL::DefaultRendererOpenGL::~DefaultRendererOpenGL()
{
if(vao != 0)
glDeleteVertexArrays(1, &vao);
@@ -19,7 +20,7 @@ TSE::GLFW::DefaultRendererOpenGL::~DefaultRendererOpenGL()
delete ibo;
}
void TSE::GLFW::DefaultRendererOpenGL::InitShader(Shader &s, bool init)
void TSE::OpenGL::DefaultRendererOpenGL::InitShader(Shader &s, bool init)
{
if(!init) End();
if(vao != 0)
@@ -50,13 +51,13 @@ void TSE::GLFW::DefaultRendererOpenGL::InitShader(Shader &s, bool init)
if(!init) Begin();
}
void TSE::GLFW::DefaultRendererOpenGL::End()
void TSE::OpenGL::DefaultRendererOpenGL::End()
{
glUnmapBuffer(GL_ARRAY_BUFFER);
vbo.Unbind();
}
void TSE::GLFW::DefaultRendererOpenGL::Flush()
void TSE::OpenGL::DefaultRendererOpenGL::Flush()
{
lastShader->Flush();
@@ -78,6 +79,8 @@ void TSE::GLFW::DefaultRendererOpenGL::Flush()
camerasToRenderWith[i]->PostDraw();
}
lastShader->PostDraw();
if(ibobound)
{
ibo->Unbind();
@@ -88,18 +91,18 @@ void TSE::GLFW::DefaultRendererOpenGL::Flush()
iboOffset = 0;
}
void TSE::GLFW::DefaultRendererOpenGL::Begin()
void TSE::OpenGL::DefaultRendererOpenGL::Begin()
{
vbo.Bind();
bufferPointer = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
}
void TSE::GLFW::DefaultRendererOpenGL::Submit(const Transformable &trans, TransformationStack &stack)
void TSE::OpenGL::DefaultRendererOpenGL::Submit(const Transformable &trans, TransformationStack &stack)
{
Submit(trans, (IShader*)lastShader, stack);
}
void TSE::GLFW::DefaultRendererOpenGL::Submit(const Transformable &trans, IShader *shader, TransformationStack &stack)
void TSE::OpenGL::DefaultRendererOpenGL::Submit(const Transformable &trans, IShader *shader, TransformationStack &stack)
{
Shader* s = dynamic_cast<Shader*>(shader);
if(lastShader == nullptr) InitShader(*s, true);
@@ -134,14 +137,14 @@ void TSE::GLFW::DefaultRendererOpenGL::Submit(const Transformable &trans, IShade
lastShader->Submit(trans, bufferPointer, stack, Redraw, *this);
}
void TSE::GLFW::DefaultRendererOpenGL::Redraw(IRenderer &rnd)
void TSE::OpenGL::DefaultRendererOpenGL::Redraw(IRenderer &rnd)
{
rnd.End();
rnd.Flush();
rnd.Begin();
}
bool TSE::GLFW::DefaultRendererOpenGL::CreateIbo()
bool TSE::OpenGL::DefaultRendererOpenGL::CreateIbo()
{
if(indexCount == 0) return true;
if(ibo != nullptr)

View File

@@ -6,7 +6,7 @@
#include "interfaces/IRenderer.hpp"
#include <vector>
namespace TSE::GLFW
namespace TSE::OpenGL
{
class DefaultRendererOpenGL : public IRenderer
{
@@ -35,4 +35,4 @@ namespace TSE::GLFW
static void Redraw(IRenderer& rnd);
bool CreateIbo();
};
} // namespace TSE::GLFW
} // namespace TSE::OpenGL

View File

@@ -1,24 +1,36 @@
#include "GL/gl3w.h"
#include "GL/gl.h"
#include "OpenGLRenderingBackend.hpp"
#include "GLFW/glfw3.h"
#include "WindowGlfw.hpp"
#include "Debug.hpp"
#include "imgui/imgui.h"
#include "extern/imgui_impl_glfw.h"
#include "extern/imgui_impl_opengl3.h"
#include "PathHelper.hpp"
#include "elements/Texture.hpp"
#include "interfaces/ITexture.hpp"
#include "TextureHelperOpenGL.hpp"
#include "interfaces/IRenderer.hpp"
#include "BehaviourScripts/Camera.hpp"
#include "RenderTextureCreatorOpenGL.hpp"
#include "CameraHelperOpenGL.hpp"
TSE::GLFW::OpenGLRenderingBackend::OpenGLRenderingBackend(Color _backgroundColor, bool _vsync)
#include "WindowManager.hpp"
#if defined(TSE_GLFW)
#include "GLFW/glfw3.h"
#include "WindowGlfw.hpp"
#include "extern/imgui_impl_glfw.h"
using namespace TSE::GLFW;
#elif defined(TSE_SDL3)
#include "SDL3/SDL.h"
#include "WindowSdl3.hpp"
#include "extern/imgui_impl_sdl3.h"
using namespace TSE::SDL3;
#endif
TSE::OpenGL::OpenGLRenderingBackend::OpenGLRenderingBackend(Color _backgroundColor, bool _vsync)
: OpenGLRenderingBackend(_backgroundColor, _vsync, 0, false){ }
TSE::GLFW::OpenGLRenderingBackend::OpenGLRenderingBackend(Color _backgroundColor, bool _vsync, int _samples, bool _useseImGui)
TSE::OpenGL::OpenGLRenderingBackend::OpenGLRenderingBackend(Color _backgroundColor, bool _vsync, int _samples, bool _useseImGui)
{
backgroundColor = _backgroundColor;
vsync = _vsync;
@@ -26,33 +38,50 @@ TSE::GLFW::OpenGLRenderingBackend::OpenGLRenderingBackend(Color _backgroundColor
useseImGui = _useseImGui;
}
TSE::GLFW::OpenGLRenderingBackend::~OpenGLRenderingBackend()
TSE::OpenGL::OpenGLRenderingBackend::~OpenGLRenderingBackend()
{
if(useseImGui)
{
ImGui_ImplOpenGL3_Shutdown();
#if defined(TSE_GLFW)
ImGui_ImplGlfw_Shutdown();
#elif defined(TSE_SDL3)
ImGui_ImplSDL3_Shutdown();
#endif
ImGui::DestroyContext();
}
}
void TSE::GLFW::OpenGLRenderingBackend::InitPreWindow()
void TSE::OpenGL::OpenGLRenderingBackend::InitPreWindow()
{
IRenderTexture::factory = new RenderTextureCreatorOpenGL();
Texture::helper = new TextureHelperOpenGL();
ITexture::helper = new TextureHelperOpenGL();
Camera::helper = new CameraHelperOpenGL();
#if defined(TSE_GLFW)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, TSE_OPENGL_VERSION_MAJOR);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, TSE_OPENGL_VERSION_MINOR);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_SAMPLES, samples);
#elif defined(TSE_SDL3)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, TSE_OPENGL_VERSION_MAJOR);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, TSE_OPENGL_VERSION_MINOR);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
#endif
}
bool TSE::GLFW::OpenGLRenderingBackend::InitPostWindow()
bool TSE::OpenGL::OpenGLRenderingBackend::InitPostWindow()
{
#if defined(TSE_GLFW)
WindowGlfw* wnd = static_cast<WindowGlfw*>(window);
glfwMakeContextCurrent(wnd->window);
#elif defined(TSE_SDL3)
WindowSdl3* wnd = static_cast<WindowSdl3*>(window);
wnd->context = SDL_GL_CreateContext(wnd->window);
SDL_GL_MakeCurrent(wnd->window, wnd->context);
#endif
if(gl3wInit())
{
Debug::Log("Failed to initialize gl3w.");
@@ -63,9 +92,17 @@ bool TSE::GLFW::OpenGLRenderingBackend::InitPostWindow()
Debug::Log("gl3w dose not support the selected version of OpenGL.");
return false;
}
#if defined(TSE_GLFW)
if(vsync) glfwSwapInterval(1);
else glfwSwapInterval(0);
#elif defined(TSE_SDL3)
if(vsync)
{
if(!SDL_GL_SetSwapInterval(-1))
SDL_GL_SetSwapInterval(1);
}
else SDL_GL_SetSwapInterval(0);
#endif
Debug::Log("OpenGL:" + std::string((const char*)glGetString(GL_VERSION)));
Debug::Log("GLSL:" + std::string((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)));
@@ -88,7 +125,7 @@ bool TSE::GLFW::OpenGLRenderingBackend::InitPostWindow()
std::string imguiIniPath;
bool TSE::GLFW::OpenGLRenderingBackend::InitEnd()
bool TSE::OpenGL::OpenGLRenderingBackend::InitEnd()
{
if(useseImGui)
{
@@ -102,8 +139,15 @@ bool TSE::GLFW::OpenGLRenderingBackend::InitEnd()
io.IniFilename = imguiIniPath.c_str();
ImGui::StyleColorsDark();
#if defined(TSE_GLFW)
WindowGlfw* wnd = static_cast<WindowGlfw*>(window);
wnd->useImGui = true;
ImGui_ImplGlfw_InitForOpenGL(wnd->window, true);
#elif defined(TSE_SDL3)
WindowSdl3* wnd = static_cast<WindowSdl3*>(window);
wnd->useImGui = true;
ImGui_ImplSDL3_InitForOpenGL(wnd->window, wnd->context);
#endif
ImGui_ImplOpenGL3_Init("#version 130");
Debug::Log("ImGui:" + std::string(ImGui::GetVersion()));
@@ -111,12 +155,12 @@ bool TSE::GLFW::OpenGLRenderingBackend::InitEnd()
return true;
}
void TSE::GLFW::OpenGLRenderingBackend::onResize(int width, int height)
void TSE::OpenGL::OpenGLRenderingBackend::onResize(int width, int height)
{
glViewport(0,0,width, height);
}
void TSE::GLFW::OpenGLRenderingBackend::onUpdate() const
void TSE::OpenGL::OpenGLRenderingBackend::onUpdate() const
{
int error = glGetError();
if(error != GL_NO_ERROR)
@@ -124,6 +168,12 @@ void TSE::GLFW::OpenGLRenderingBackend::onUpdate() const
Debug::Log("OpenGL Error: " + std::to_string(error));
}
#if defined(TSE_GLFW)
WindowGlfw* wnd = static_cast<WindowGlfw*>(window);
#elif defined(TSE_SDL3)
WindowSdl3* wnd = static_cast<WindowSdl3*>(window);
#endif
if(useseImGui)
{
ImGui::Render();
@@ -132,19 +182,30 @@ void TSE::GLFW::OpenGLRenderingBackend::onUpdate() const
if(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
#if defined(TSE_GLFW)
GLFWwindow* backup_current_context = glfwGetCurrentContext();
#elif defined(TSE_SDL3)
SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
#endif
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
#if defined(TSE_GLFW)
glfwMakeContextCurrent(backup_current_context);
#elif defined(TSE_SDL3)
SDL_GL_MakeCurrent(wnd->window, backup_current_context);
#endif
}
}
WindowGlfw* wnd = static_cast<WindowGlfw*>(window);
#if defined(TSE_GLFW)
glfwSwapBuffers(wnd->window);
#elif defined(TSE_SDL3)
SDL_GL_SwapWindow(wnd->window);
#endif
}
void TSE::GLFW::OpenGLRenderingBackend::onClear() const
void TSE::OpenGL::OpenGLRenderingBackend::onClear() const
{
for (int i = 0; i < IRenderer::camerasToRenderWith.size(); i++)
{
@@ -158,12 +219,16 @@ void TSE::GLFW::OpenGLRenderingBackend::onClear() const
if(useseImGui)
{
ImGui_ImplOpenGL3_NewFrame();
#if defined(TSE_GLFW)
ImGui_ImplGlfw_NewFrame();
#elif defined(TSE_SDL3)
ImGui_ImplSDL3_NewFrame();
#endif
ImGui::NewFrame();
}
}
void TSE::GLFW::OpenGLRenderingBackend::onClearDepthBuffer() const
void TSE::OpenGL::OpenGLRenderingBackend::onClearDepthBuffer() const
{
for (int i = 0; i < IRenderer::camerasToRenderWith.size(); i++)
{

View File

@@ -5,7 +5,7 @@
#define TSE_OPENGL_VERSION_MAJOR 3
#define TSE_OPENGL_VERSION_MINOR 3
namespace TSE::GLFW
namespace TSE::OpenGL
{
class OpenGLRenderingBackend : public IRenderingBackend
{
@@ -25,4 +25,4 @@ namespace TSE::GLFW
void onClear() const override;
void onClearDepthBuffer() const override;
};
} // namespace TSE
} // namespace OpenGL

View File

@@ -0,0 +1,59 @@
#include "RenderTexture.hpp"
TSE::OpenGL::RenderTexture::RenderTexture(Vector2 v, uint textureCount) : buffer(v, textureCount)
{
buffer.AddResizeNotifiable(this);
}
TSE::Vector2 TSE::OpenGL::RenderTexture::size() const
{
return buffer.GetSize();
}
void TSE::OpenGL::RenderTexture::SetSize(Vector2 v)
{
buffer.Resize(v);
}
float TSE::OpenGL::RenderTexture::Width() const
{
return buffer.GetSize().x;
}
float TSE::OpenGL::RenderTexture::Height() const
{
return buffer.GetSize().y;
}
TSE::uint TSE::OpenGL::RenderTexture::GetTextureId() const
{
return buffer.GetTextureId();
}
TSE::uint TSE::OpenGL::RenderTexture::GetTextureId(uint id) const
{
return buffer.GetTextureId(id);
}
void TSE::OpenGL::RenderTexture::Update()
{
buffer.Update();
}
void TSE::OpenGL::RenderTexture::Bind()
{
buffer.Bind();
}
void TSE::OpenGL::RenderTexture::Unbind()
{
buffer.Unbind();
}
void TSE::OpenGL::RenderTexture::OnResize(float width, float height, IResizable *wnd)
{
for (auto const& i : objectsToResize)
{
i->OnResize(width, height, this);
}
}

View File

@@ -6,20 +6,21 @@
#include "interfaces/IResizeNotifiable.hpp"
#include "interfaces/IRenderTexture.hpp"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class RenderTexture : public IRenderTexture
{
public:
FrameBuffer buffer;
RenderTexture(Vector2 v);
RenderTexture(Vector2 v, uint textureCount = 1);
Vector2 size() const override;
void SetSize(Vector2 v) override;
float Width() const override;
float Height() const override;
uint GetTextureId() const override;
uint GetTextureId(uint id) const override;
void Update() override;
void Bind() override;
@@ -27,4 +28,4 @@ namespace TSE::GLFW
void OnResize(float width, float height, IResizable* wnd) override;
};
} // namespace TSE::GLFW
} // namespace TSE::OpenGL

View File

@@ -3,14 +3,14 @@
#include "interfaces/IRenderTexture.hpp"
#include "RenderTexture.hpp"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class RenderTextureCreatorOpenGL : public IRenderTextureCreator
{
public:
inline IRenderTexture* CreateTextureHeap(Vector2 v) override
inline IRenderTexture* CreateTextureHeap(Vector2 v, uint textureCount = 1) override
{
return new RenderTexture(v);
return new RenderTexture(v, textureCount);
};
};
} // namespace name
} // namespace OpenGL

View File

@@ -0,0 +1,165 @@
#include "GL/gl3w.h"
#include "GL/gl.h"
#include "TextureHelperOpenGL.hpp"
void TSE::OpenGL::TextureHelperOpenGL::Bind(const Texture *tex)
{
glBindTexture(GL_TEXTURE_2D, tex->GetTextureId());
}
void TSE::OpenGL::TextureHelperOpenGL::UnBind(const Texture *tex)
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void TSE::OpenGL::TextureHelperOpenGL::Apply(Texture *tex)
{
glBindTexture(GL_TEXTURE_2D, tex->GetTextureId());
if(tex->Chanels() == 1)
{
if (tex->bpp() == 8)
glTexImage2D(GL_TEXTURE_2D, 0,GL_R8, tex->Width(), tex->Height(), 0, GL_RED, GL_UNSIGNED_BYTE, tex->GetImagePtr());
if (tex->bpp() == 16)
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16I, tex->Width(), tex->Height(), 0, GL_RED, GL_SHORT, tex->GetImagePtr());
}
if(tex->Chanels() == 3)
{
if(tex->bpp() == 24)
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, tex->Width(), tex->Height(), 0, GL_BGR, GL_UNSIGNED_BYTE, tex->GetImagePtr());
}
else if(tex->Chanels() == 4)
{
if(tex->bpp() == 32)
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, tex->Width(), tex->Height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, tex->GetImagePtr());
if (tex->bpp() == 8) //need to decode it with bitwise operations in shader
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA2, tex->Width(), tex->Height(), 0, GL_RED, GL_UNSIGNED_BYTE, tex->GetImagePtr());
}
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
void TSE::OpenGL::TextureHelperOpenGL::Regist(Texture *tex)
{
uint TextureID;
glGenTextures(1, &TextureID);
glBindTexture(GL_TEXTURE_2D, TextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
tex->SetTextureId(TextureID);
tex->Apply();
}
void TSE::OpenGL::TextureHelperOpenGL::PlatromDestroy(Texture *tex)
{
uint id = tex->GetTextureId();
glDeleteTextures(1, &id);
}
void TSE::OpenGL::TextureHelperOpenGL::Bind3D(const VolumeTexture3D *tex)
{
glBindTexture(GL_TEXTURE_3D, tex->GetTextureId());
}
void TSE::OpenGL::TextureHelperOpenGL::UnBind3D(const VolumeTexture3D *tex)
{
glBindTexture(GL_TEXTURE_3D, 0);
}
void TSE::OpenGL::TextureHelperOpenGL::Apply3D(VolumeTexture3D *tex)
{
glBindTexture(GL_TEXTURE_3D, tex->GetTextureId());
ushort internal,input,size;
if(tex->Chanels() == 1)
{
if (tex->bpp() == 8)
{
internal = GL_R8;
input = GL_RED;
size = GL_UNSIGNED_BYTE;
}
if (tex->bpp() == 16)
{
internal = GL_R16I;
input = GL_RED;
size = GL_SHORT;
}
}
if(tex->Chanels() == 3)
{
if(tex->bpp() == 24)
{
internal = GL_RGB;
input = GL_BGR;
size = GL_UNSIGNED_BYTE;
}
}
else if(tex->Chanels() == 4)
{
if(tex->bpp() == 32)
{
internal = GL_RGBA;
input = GL_BGRA;
size = GL_UNSIGNED_BYTE;
}
if (tex->bpp() == 8) //need to decode it with bitwise operations in shader
{
internal = GL_RGBA2;
input = GL_RED;
size = GL_UNSIGNED_BYTE;
}
}
glTexImage3D(GL_TEXTURE_3D, 0, internal, tex->Width(), tex->Height(), tex->Depth(), 0, input, size, nullptr);
for (int z = 0; z < tex->Depth(); ++z)
{
glTexSubImage3D(
GL_TEXTURE_3D,
0,
0,
0,
z,
tex->Width(),
tex->Height(),
1,
input,
size,
tex->GetImagePtr(z)
);
}
glGenerateMipmap(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D, 0);
}
void TSE::OpenGL::TextureHelperOpenGL::Regist3D(VolumeTexture3D *tex)
{
uint TextureID;
glGenTextures(1, &TextureID);
glBindTexture(GL_TEXTURE_3D, TextureID);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
tex->SetTextureId(TextureID);
tex->Apply();
}
void TSE::OpenGL::TextureHelperOpenGL::PlatromDestroy3D(VolumeTexture3D *tex)
{
uint id = tex->GetTextureId();
glDeleteTextures(1, &id);
}

View File

@@ -2,8 +2,9 @@
#include "interfaces/ITextureHelper.hpp"
#include "elements/Texture.hpp"
#include "elements/VolumeTexture3D.hpp"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class TextureHelperOpenGL : public ITextureHelper
{
@@ -13,5 +14,11 @@ namespace TSE::GLFW
void Apply(Texture* tex) override;
void Regist(Texture* tex) override;
void PlatromDestroy(Texture* tex) override;
void Bind3D(const VolumeTexture3D* tex) override;
void UnBind3D(const VolumeTexture3D* tex) override;
void Apply3D(VolumeTexture3D* tex) override;
void Regist3D(VolumeTexture3D* tex) override;
void PlatromDestroy3D(VolumeTexture3D* tex) override;
};
} // namespace TSE::GLFW
} // namespace TSE::OpenGL

View File

@@ -0,0 +1,119 @@
#include "FrameBuffer.hpp"
#include "Debug.hpp"
TSE::OpenGL::FrameBuffer::FrameBuffer(const Vector2 &size, uint textureCount)
{
textureOutputCount = textureCount;
width = size.x;
height = size.y;
CreateFBTexture();
for (auto const& i : objectsToResize)
{
i->OnResize(size.x, size.y, this);
}
Initialize();
}
void TSE::OpenGL::FrameBuffer::Bind()
{
glBindFramebuffer(GL_FRAMEBUFFER, bufferID);
}
void TSE::OpenGL::FrameBuffer::Unbind()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
TSE::OpenGL::FrameBuffer::~FrameBuffer()
{
glDeleteFramebuffers(1,&bufferID);
for (int i = 0; i < textureOutputCount; i++)
{
glDeleteTextures(1, &(textureIDs[i]));
}
glDeleteRenderbuffers(1, &depthRboID);
}
void TSE::OpenGL::FrameBuffer::Resize(Vector2 size)
{
width = size.x;
height = size.y;
shouldResize = true;
}
void TSE::OpenGL::FrameBuffer::Update()
{
if (!shouldResize) return;
shouldResize = false;
CreateFBTexture();
for (auto const& i : objectsToResize)
{
i->OnResize(width, height, this);
}
}
TSE::uint TSE::OpenGL::FrameBuffer::GetTextureId(uint id) const
{
return textureIDs[id];
}
TSE::Vector2 TSE::OpenGL::FrameBuffer::GetSize() const
{
return {width, height};
}
void TSE::OpenGL::FrameBuffer::Initialize()
{
glGenFramebuffers(1, &bufferID);
Bind();
uint bufs[32];
for (int i = 0; i < textureOutputCount; i++)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textureIDs[i], 0);
bufs[i] = GL_COLOR_ATTACHMENT0 + i;
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRboID);
if(textureOutputCount > 1)
glDrawBuffers(textureOutputCount, bufs);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
TSE_ERROR("Failed to create OpenGL FBO.");
TSE_LOG(std::to_string(glGetError()));
}
Unbind();
}
void TSE::OpenGL::FrameBuffer::LoadFBTexture()
{
for (int i = 0; i < textureOutputCount; i++)
{
glBindTexture(GL_TEXTURE_2D, textureIDs[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glBindRenderbuffer(GL_RENDERBUFFER, depthRboID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
}
}
void TSE::OpenGL::FrameBuffer::CreateFBTexture()
{
glViewport(0,0, width, height);
//resize
for (int i = 0; i < textureOutputCount; i++)
{
if(textureIDs[i] == 0)
glGenTextures(1, &(textureIDs[i]));
}
if(depthRboID == 0)
glGenRenderbuffers(1, &depthRboID);
LoadFBTexture();
}

View File

@@ -4,23 +4,24 @@
#include "interfaces/IResizable.hpp"
#include "Vector2.hpp"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class FrameBuffer : public buffer, public IResizable
{
private:
uint textureID = 0;
uint textureOutputCount = 1;
uint textureIDs[32] = {0};
uint depthRboID = 0;
bool shouldResize = false;
public:
FrameBuffer(const Vector2& size);
FrameBuffer(const Vector2& size, uint textureCount = 1);
void Bind() override;
void Unbind() override;
~FrameBuffer() override;
void Resize(Vector2 size);
void Update();
uint GetTextureId() const;
uint GetTextureId(uint id = 0) const;
Vector2 GetSize() const;
private:

View File

@@ -1,24 +1,24 @@
#include "IndexBuffer.hpp"
TSE::GLFW::IndexBuffer::IndexBuffer(ushort *data, ushort count)
TSE::OpenGL::IndexBuffer::IndexBuffer(ushort *data, ushort count)
{
glGenBuffers(1, &bufferID);
WriteData(data, count);
}
void TSE::GLFW::IndexBuffer::WriteData(ushort *data, ushort count)
void TSE::OpenGL::IndexBuffer::WriteData(ushort *data, ushort count)
{
Bind();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort) * count, data, GL_DYNAMIC_DRAW);
Unbind();
}
void TSE::GLFW::IndexBuffer::Bind()
void TSE::OpenGL::IndexBuffer::Bind()
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferID);
}
void TSE::GLFW::IndexBuffer::Unbind()
void TSE::OpenGL::IndexBuffer::Unbind()
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

View File

@@ -3,7 +3,7 @@
#include "buffer.hpp"
#include "Types.hpp"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class IndexBuffer : public buffer
{

View File

@@ -1,35 +1,35 @@
#include "VertexBuffer.hpp"
TSE::uint TSE::GLFW::VertexBuffer::boundBuffer = 0;
TSE::uint TSE::OpenGL::VertexBuffer::boundBuffer = 0;
TSE::GLFW::VertexBuffer::VertexBuffer()
TSE::OpenGL::VertexBuffer::VertexBuffer()
{
glGenBuffers(1, &bufferID);
}
void TSE::GLFW::VertexBuffer::SetData(int size, void *buffer, GLenum usage)
void TSE::OpenGL::VertexBuffer::SetData(int size, void *buffer, GLenum usage)
{
glBufferData(GL_ARRAY_BUFFER, size, buffer, usage);
}
void TSE::GLFW::VertexBuffer::Bind()
void TSE::OpenGL::VertexBuffer::Bind()
{
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
boundBuffer = bufferID;
}
void TSE::GLFW::VertexBuffer::Unbind()
void TSE::OpenGL::VertexBuffer::Unbind()
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
boundBuffer = 0;
}
bool TSE::GLFW::VertexBuffer::IsBound()
bool TSE::OpenGL::VertexBuffer::IsBound()
{
return boundBuffer == bufferID;
}
TSE::GLFW::VertexBuffer::~VertexBuffer()
TSE::OpenGL::VertexBuffer::~VertexBuffer()
{
if(bufferID != 0)
{

View File

@@ -2,7 +2,7 @@
#include "buffer.hpp"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class VertexBuffer : public buffer
{

View File

@@ -4,7 +4,7 @@
#include "GL/gl.h"
#include "Types.hpp"
namespace TSE::GLFW
namespace TSE::OpenGL
{
class buffer
{

Some files were not shown because too many files have changed in this diff Show More