12 Commits

203 changed files with 89022 additions and 543 deletions

View File

@@ -1,2 +1,5 @@
# TSE # 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,6 +1,7 @@
#include "Camera.hpp" #include "Camera.hpp"
#include "elements/Transformable.hpp" #include "elements/Transformable.hpp"
#include "interfaces/IRenderer.hpp" #include "interfaces/IRenderer.hpp"
#include "interfaces/IWindow.hpp"
#include "uuid.h" #include "uuid.h"
TSE::Camera* TSE::Camera::mainCamera = nullptr; TSE::Camera* TSE::Camera::mainCamera = nullptr;
@@ -101,7 +102,11 @@ void TSE::Camera::SetRenderTarget(IRenderTarget *target)
if(target != nullptr) if(target != nullptr)
target->AddResizeNotifiable(this); target->AddResizeNotifiable(this);
rt = target; rt = target;
RecalculateProjMatrix(); if(lastRtSize != rt->GetRawIResizableSize())
{
lastRtSize = rt->GetRawIResizableSize();
RecalculateProjMatrix();
}
} }
TSE::IRenderTarget *TSE::Camera::GetRenderTarget() TSE::IRenderTarget *TSE::Camera::GetRenderTarget()
@@ -209,5 +214,8 @@ void TSE::Camera::Unbind()
void TSE::Camera::UpdateRenderTarget() void TSE::Camera::UpdateRenderTarget()
{ {
rt->Update(); if (dynamic_cast<IWindow*>(rt) == nullptr)
{
rt->Update();
}
} }

View File

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

View File

@@ -3,7 +3,7 @@
#define MESH_CONTAINER typeid(TSE::MeshContainer).name() #define MESH_CONTAINER typeid(TSE::MeshContainer).name()
#include "Types.hpp" #include "Types.hpp"
#include "Mesh.hpp" #include "elements/Mesh.hpp"
#include "elements/BehaviourScript.hpp" #include "elements/BehaviourScript.hpp"
namespace TSE namespace TSE
@@ -19,6 +19,7 @@ namespace TSE
void SetMesh(Mesh* mesh); void SetMesh(Mesh* mesh);
Mesh* GetMesh() const; Mesh* GetMesh() const;
Mesh** GetMeshRef();
inline const char* GetName() override 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 "elements/BehaviourScript.hpp"
#include "Rect.hpp" #include "Rect.hpp"
#include "Vector2.hpp" #include "Vector2.hpp"
#include "Mesh.hpp" #include "elements/Mesh.hpp"
namespace TSE namespace TSE
{ {

View File

@@ -22,6 +22,11 @@ namespace TSE
return material; return material;
} }
Material **Renderable::GetMaterialRef()
{
return &material;
}
Mesh* Renderable::GetMeshContainer() const { Mesh* Renderable::GetMeshContainer() const {
if(baseObject->HasBehaviourScript(MESH_CONTAINER)) if(baseObject->HasBehaviourScript(MESH_CONTAINER))
return dynamic_cast<MeshContainer*>(baseObject->GetBehaviourScript(MESH_CONTAINER))->GetMesh(); return dynamic_cast<MeshContainer*>(baseObject->GetBehaviourScript(MESH_CONTAINER))->GetMesh();

View File

@@ -5,7 +5,7 @@
#include "elements/Material.hpp" #include "elements/Material.hpp"
#include "interfaces/IRenderable.hpp" #include "interfaces/IRenderable.hpp"
#include "elements/BehaviourScript.hpp" #include "elements/BehaviourScript.hpp"
#include "Mesh.hpp" #include "elements/Mesh.hpp"
namespace TSE namespace TSE
{ {
@@ -28,6 +28,7 @@ namespace TSE
} }
void SetMaterial(Material* material); void SetMaterial(Material* material);
Material* GetMaterial(); Material* GetMaterial();
Material** GetMaterialRef();
private: private:
Mesh* GetMeshContainer() const; Mesh* GetMeshContainer() const;

View File

@@ -25,6 +25,8 @@ void TSE::TileMapChunk::RemoveTile(Vector2 p)
void TSE::TileMapChunk::SetOrdering(SortingOrder _order) void TSE::TileMapChunk::SetOrdering(SortingOrder _order)
{ {
order = _order; order = _order;
dirtyPositions = true;
dirtySpriteIds = true;
} }
const std::vector<TSE::Vector2>* TSE::TileMapChunk::GetOrderedPositions() const std::vector<TSE::Vector2>* TSE::TileMapChunk::GetOrderedPositions()
@@ -43,7 +45,7 @@ const std::vector<TSE::Vector2>* TSE::TileMapChunk::GetOrderedPositions()
Vector2 p(x,y); Vector2 p(x,y);
auto v = sprites.find(p); auto v = sprites.find(p);
if(v != sprites.end()) if(v != sprites.end())
orderedPositions.push_back(v->first - offset); orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
} }
} }
break; break;
@@ -56,7 +58,7 @@ const std::vector<TSE::Vector2>* TSE::TileMapChunk::GetOrderedPositions()
Vector2 p(x,y); Vector2 p(x,y);
auto v = sprites.find(p); auto v = sprites.find(p);
if(v != sprites.end()) if(v != sprites.end())
orderedPositions.push_back(v->first - offset); orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
} }
} }
break; break;
@@ -69,7 +71,7 @@ const std::vector<TSE::Vector2>* TSE::TileMapChunk::GetOrderedPositions()
Vector2 p(x,y); Vector2 p(x,y);
auto v = sprites.find(p); auto v = sprites.find(p);
if(v != sprites.end()) if(v != sprites.end())
orderedPositions.push_back(v->first - offset); orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
} }
} }
break; break;
@@ -82,7 +84,7 @@ const std::vector<TSE::Vector2>* TSE::TileMapChunk::GetOrderedPositions()
Vector2 p(x,y); Vector2 p(x,y);
auto v = sprites.find(p); auto v = sprites.find(p);
if(v != sprites.end()) if(v != sprites.end())
orderedPositions.push_back(v->first - offset); orderedPositions.push_back(v->first * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * y, nextLine.y * 0.5f * x));
} }
} }
break; break;
@@ -271,6 +273,7 @@ void TSE::TileMap::SetNextLineOffset(const Vector2 &offset)
{ {
chunk.nextLine = offset; chunk.nextLine = offset;
} }
DirtyAll();
} }
TSE::Vector2 TSE::TileMap::GetNextLineOffset() TSE::Vector2 TSE::TileMap::GetNextLineOffset()
@@ -278,6 +281,16 @@ TSE::Vector2 TSE::TileMap::GetNextLineOffset()
return nextLine; 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) void TSE::TileMap::CheckBounds(Vector2 pos)
{ {
if(pos.x > bounds.p2.x) if(pos.x > bounds.p2.x)
@@ -305,10 +318,10 @@ TSE::Vector2 TSE::TileMap::ChunkToLocalPos(const Vector2 &v, const TileMapChunk
TSE::Vector2 TSE::TileMap::RealPosToTileMapPos(const Vector2 &v) TSE::Vector2 TSE::TileMap::RealPosToTileMapPos(const Vector2 &v)
{ {
return v + nextLine * v.y; 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) TSE::Vector2 TSE::TileMap::TileMapToRealPos(const Vector2 &v)
{ {
return v - nextLine * v.y; return v * Vector2(nextLine.x, nextLine.y * 0.5f) + Vector2(-nextLine.x * v.y, nextLine.y * 0.5f * v.x);
} }

View File

@@ -8,28 +8,21 @@
#include "Vector2i.hpp" #include "Vector2i.hpp"
#include "elements/Sprite.hpp" #include "elements/Sprite.hpp"
#include "elements/TileSet.hpp" #include "elements/TileSet.hpp"
#include "enums/SortingOrder.hpp"
namespace TSE namespace TSE
{ {
enum SortingOrder
{
TopRight,
TopLeft,
BottomRight,
BottomLeft,
};
struct TileMapChunk struct TileMapChunk
{ {
private: private:
bool dirtyPositions = true;
bool dirtySpriteIds = true;
std::vector<Vector2> orderedPositions; std::vector<Vector2> orderedPositions;
std::vector<Vector2i> orderedSpriteIDs; std::vector<Vector2i> orderedSpriteIDs;
SortingOrder order; SortingOrder order;
int chunksize; int chunksize;
std::unordered_map<Vector2, Vector2i> sprites; std::unordered_map<Vector2, Vector2i> sprites;
public: public:
bool dirtyPositions = true;
bool dirtySpriteIds = true;
Vector2 nextLine; Vector2 nextLine;
Vector2 pos; Vector2 pos;
TileMapChunk(int _chunksize = 16, const Vector2& _pos = {0,0}, SortingOrder _order = TopRight); TileMapChunk(int _chunksize = 16, const Vector2& _pos = {0,0}, SortingOrder _order = TopRight);
@@ -50,10 +43,10 @@ namespace TSE
bool dirty = true; bool dirty = true;
std::vector<Vector2> orderedChunks; std::vector<Vector2> orderedChunks;
Rect bounds = Rect(0,0,0,0); Rect bounds = Rect(0,0,0,0);
Vector2 nextLine = Vector2(-0.5f, 1.25f); Vector2 nextLine = Vector2(0.5f, 0.5f);
public: public:
int chunkSize = 16; int chunkSize = 16;
SortingOrder order = TopRight; SortingOrder order = BottomRight;
Vector2 SpriteScale = Vector2(1,1); Vector2 SpriteScale = Vector2(1,1);
TileSet* set; TileSet* set;
std::unordered_map<Vector2, TileMapChunk> chunks; std::unordered_map<Vector2, TileMapChunk> chunks;
@@ -69,6 +62,7 @@ namespace TSE
Vector2 GetNextLineOffset(); Vector2 GetNextLineOffset();
Vector2 RealPosToTileMapPos(const Vector2& v); Vector2 RealPosToTileMapPos(const Vector2& v);
Vector2 TileMapToRealPos(const Vector2& v); Vector2 TileMapToRealPos(const Vector2& v);
void DirtyAll();
inline const char* GetName() override inline const char* GetName() override
{ {

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

@@ -9,6 +9,11 @@
#include "Vector4.hpp" #include "Vector4.hpp"
#include "Color.hpp" #include "Color.hpp"
#include "Matrix4x4.hpp" #include "Matrix4x4.hpp"
#include "PathHelper.hpp"
#include "utils/JsonExports.hpp"
#include "Debug.hpp"
#include "ShaderRegistry.hpp"
#include "AssetLibrary.hpp"
namespace TSE namespace TSE
{ {
@@ -18,7 +23,9 @@ namespace TSE
id = GenerateRandomUUID(); id = GenerateRandomUUID();
} }
Material::Material(const string& name, IShader* shader, uuids::uuid id) 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) Material::Material(const string &name, IShader *shader)
: name(name), shader(shader) : name(name), shader(shader)
@@ -59,6 +66,266 @@ namespace TSE
return id; 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<int>(const string&, const int&);
template void Material::SetValue<uint>(const string&, const uint&); template void Material::SetValue<uint>(const string&, const uint&);
template void Material::SetValue<float>(const string&, const float&); template void Material::SetValue<float>(const string&, const float&);

View File

@@ -6,14 +6,15 @@
#include <any> #include <any>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include "interfaces/IAsset.hpp"
#include "json.hpp"
namespace TSE namespace TSE
{ {
struct Material struct Material : public IAsset
{ {
private: private:
string name; string name;
uuids::uuid id;
IShader* shader; IShader* shader;
std::unordered_map<string, std::tuple<std::any, string, string>> values; std::unordered_map<string, std::tuple<std::any, string, string>> values;
@@ -40,6 +41,15 @@ namespace TSE
IShader* GetShader() const; IShader* GetShader() const;
void SetShader(IShader* shader); void SetShader(IShader* shader);
uuids::uuid GetID() const; 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> 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 "Types.hpp"
#include "Vector3.hpp" #include "Vector3.hpp"
#include "Vector2.hpp" #include "Vector2.hpp"
#include "interfaces/IAsset.hpp"
namespace TSE namespace TSE
{ {
class Mesh class Mesh : public IAsset
{ {
public: public:
string name; string name;
@@ -41,5 +42,16 @@ namespace TSE
/// @brief gives you a basic unit quad with (-0.5, -0.5) -> (0.5, 0.5) /// @brief gives you a basic unit quad with (-0.5, -0.5) -> (0.5, 0.5)
/// @return the resulting mesh /// @return the resulting mesh
static Mesh GetQuadMesh(); 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 } // 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

@@ -2,38 +2,88 @@
#include "BehaviourScripts/Camera.hpp" #include "BehaviourScripts/Camera.hpp"
#include <algorithm> #include <algorithm>
#include "Debug.hpp" #include "Debug.hpp"
#include "RenderPipeline.hpp"
void TSE::Scene::Render(IRenderer &rnd, const IWindow &wnd) void TSE::Scene::Render(IRenderer &rnd, const IWindow &wnd)
{ {
RenderPipeline* pipeline = IRenderer::pipeline;
auto camerasBackup = std::vector<Camera*>(IRenderer::camerasToRenderWith); auto camerasBackup = std::vector<Camera*>(IRenderer::camerasToRenderWith);
int counter = 1;
for(auto l : layers) if(pipeline != nullptr)
{ {
IRenderer::camerasToRenderWith.clear(); for(int i = 0; i < pipeline->GetRenderStepCount(); i++)
if(!l.second->IsVisual()) continue;
for(auto camera : camerasBackup)
{ {
auto it = std::find(camera->layersNotToRender.begin(), camera->layersNotToRender.end(), l.second->GetID()); IRenderer::camerasToRenderWith = std::vector<Camera*>(camerasBackup);
if(it == camera->layersNotToRender.end()) const RenderStep& step = pipeline->GetRenderStepAt(i);
if(!step.EditorCamera)
{ {
IRenderer::camerasToRenderWith.push_back(camera);
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();
}
} }
} }
}
l.second->Render(rnd); else
if(counter++ != layers.size()) {
int counter = 1;
for(auto l : layers)
{ {
rnd.End(); //OPTIMIZE: IRenderer::camerasToRenderWith.clear();
//takes up 13,97% of function, but only needed, if there is more then one layer if(!l.second->IsVisual()) continue;
//possible optimizations: for(auto camera : camerasBackup)
// -remove layers {
// -make layer calculations, in shader auto it = std::find(camera->layersNotToRender.begin(), camera->layersNotToRender.end(), l.second->GetID());
// -make an offset, that is calculated on cpu, and then commit everything at once if(it == camera->layersNotToRender.end())
{
IRenderer::camerasToRenderWith.push_back(camera);
}
}
// 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 l.second->Render(rnd);
rnd.Flush(); if(counter++ != layers.size())
rnd.Begin(); {
wnd.ClearDepthBuffer(); 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 = {}; inline static std::unordered_map<string, IShader*> registeredShaders = {};
public: 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) inline static IShader* GetShader(const string& name)
{ {

View File

@@ -3,8 +3,19 @@
#include "Color.hpp" #include "Color.hpp"
#include "ErrorTextureData.hpp" #include "ErrorTextureData.hpp"
#include <filesystem> #include <filesystem>
#include "json.hpp"
#include "PathHelper.hpp"
#include "utils/JsonExports.hpp"
#include "IdGenerator.hpp"
#include "AssetLibrary.hpp"
TSE::Texture::Texture(const string &path) 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; FREE_IMAGE_FORMAT fif = FREE_IMAGE_FORMAT::FIF_UNKNOWN;
bmp = nullptr; bmp = nullptr;
@@ -19,7 +30,7 @@ TSE::Texture::Texture(const string &path)
TSE_ERROR(msg); TSE_ERROR(msg);
Bpp = 24; Bpp = 24;
makeError(*this); makeError(*this);
return; return false;
} }
fif = FreeImage_GetFileType(name.c_str(), 0); fif = FreeImage_GetFileType(name.c_str(), 0);
@@ -30,12 +41,12 @@ TSE::Texture::Texture(const string &path)
TSE_ERROR("Failed to load image. Unsupported Format."); TSE_ERROR("Failed to load image. Unsupported Format.");
Bpp = 24; Bpp = 24;
makeError(*this); makeError(*this);
return; return false;
} }
if(FreeImage_FIFSupportsReading(fif)) if(FreeImage_FIFSupportsReading(fif))
{ {
bmp = FreeImage_Load(fif, path.c_str()); bmp = FreeImage_Load(fif, name.c_str());
if(FreeImage_GetBPP(bmp) != 32) if(bmp != nullptr && FreeImage_GetBPP(bmp) != 32)
{ {
auto tmpBmp = FreeImage_ConvertTo32Bits(bmp); auto tmpBmp = FreeImage_ConvertTo32Bits(bmp);
FreeImage_Unload(bmp); FreeImage_Unload(bmp);
@@ -47,7 +58,7 @@ TSE::Texture::Texture(const string &path)
TSE_ERROR("Failed to load image. Bitmap was nullptr."); TSE_ERROR("Failed to load image. Bitmap was nullptr.");
Bpp = 24; Bpp = 24;
makeError(*this); makeError(*this);
return; return false;
} }
Bpp = FreeImage_GetBPP(bmp); Bpp = FreeImage_GetBPP(bmp);
imagePtr = FreeImage_GetBits(bmp); imagePtr = FreeImage_GetBits(bmp);
@@ -65,10 +76,12 @@ TSE::Texture::Texture(const string &path)
Size = Vector2(FreeImage_GetWidth(bmp), FreeImage_GetHeight(bmp)); Size = Vector2(FreeImage_GetWidth(bmp), FreeImage_GetHeight(bmp));
regist(); regist();
return true;
} }
TSE::Texture::Texture(const int &width, const int &height, int bpp) TSE::Texture::Texture(const int &width, const int &height, int bpp)
{ {
id = GenerateRandomUUID();
switch (bpp) switch (bpp)
{ {
case 32: case 32:
@@ -88,6 +101,7 @@ TSE::Texture::Texture(const int &width, const int &height, int bpp)
TSE::Texture::Texture(const Vector2 &size, int bpp) TSE::Texture::Texture(const Vector2 &size, int bpp)
{ {
id = GenerateRandomUUID();
switch (bpp) switch (bpp)
{ {
case 32: case 32:
@@ -120,6 +134,11 @@ TSE::Texture::~Texture()
} }
} }
TSE::string TSE::Texture::name() const
{
return settings.name;
}
TSE::uint TSE::Texture::bpp() const TSE::uint TSE::Texture::bpp() const
{ {
return Bpp; return Bpp;
@@ -461,3 +480,154 @@ void TSE::Texture::PlatformDestroy()
{ {
helper->PlatromDestroy(this); 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 "Types.hpp"
#include "Vector2.hpp" #include "Vector2.hpp"
#include "interfaces/ITextureHelper.hpp" #include "interfaces/ITextureHelper.hpp"
#include "interfaces/IAsset.hpp"
#define FREEIMAGE_LIB #define FREEIMAGE_LIB
#include "FI/FreeImage.h" #include "FI/FreeImage.h"
namespace TSE 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: protected:
TextureImportSettings settings;
uint TextureID = 0; uint TextureID = 0;
Vector2 Size; Vector2 Size;
uint Bpp; uint Bpp;
@@ -22,14 +38,13 @@ namespace TSE
byte* imagePtr = nullptr; byte* imagePtr = nullptr;
public: public:
string name = "Unnamed";
inline static ITextureHelper* helper = nullptr;
Texture(const string& path); Texture(const string& path);
Texture(const int& width, const int& height, int bpp = 32); Texture(const int& width, const int& height, int bpp = 32);
Texture(const Vector2& size, int bpp = 32); Texture(const Vector2& size, int bpp = 32);
~Texture(); ~Texture();
string name() const;
uint bpp() const; uint bpp() const;
Vector2 size() const override; Vector2 size() const override;
float Width() const override; float Width() const override;
@@ -60,5 +75,18 @@ namespace TSE
void Apply(); void Apply();
void regist(); void regist();
void PlatformDestroy(); 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 } // namespace TSE

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 enum Modifier
{ {
None = 0x0000,
ShiftMod = 0x0001, ShiftMod = 0x0001,
ControlMod = 0x0002, ControlMod = 0x0002,
AltMod = 0x0004, 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

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

View File

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

View File

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

View File

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

View File

@@ -3,6 +3,7 @@
namespace TSE namespace TSE
{ {
class Texture; class Texture;
class VolumeTexture3D;
class ITextureHelper class ITextureHelper
{ {
@@ -12,5 +13,11 @@ namespace TSE
virtual void Apply(Texture* tex) = 0; virtual void Apply(Texture* tex) = 0;
virtual void Regist(Texture* tex) = 0; virtual void Regist(Texture* tex) = 0;
virtual void PlatromDestroy(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 } // namespace TSE

View File

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

View File

@@ -3,19 +3,24 @@
#include "BehaviourScriptRegistry.hpp" #include "BehaviourScriptRegistry.hpp"
#include "BehaviourScripts/AudioListener.hpp" #include "BehaviourScripts/AudioListener.hpp"
#include "BehaviourScripts/AudioSource.hpp" #include "BehaviourScripts/AudioSource.hpp"
#include "BehaviourScripts/TileMap.hpp"
#include "BehaviourScripts/OrdererSpriteSet.hpp"
#include "BehaviourScripts/PhysicsObject.hpp"
#include "BehaviourScripts/basicEditorCamera.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}, 2); rt = IRenderTexture::factory->CreateTextureHeap({100,100}, 5);
sv = SceneView(rt); sv = SceneView(rt);
cv = cvp;
controller.AddGuiElement("Scene", &sv); controller.AddGuiElement("Scene", &sv);
controller.AddGuiElement("Consol", &cv); controller.AddGuiElement("Consol", cv);
controller.AddGuiElement("Hirearchie", &hv); controller.AddGuiElement("Hirearchie", &hv);
controller.AddGuiElement("Properties", &pv); controller.AddGuiElement("Properties", &pv);
controller.AddGuiElement("Debug", &dv); controller.AddGuiElement("Debug", &dv);
controller.AddGuiElement("Camera", &camv); controller.AddGuiElement("Camera", &camv);
controller.AddGuiElement("Assets", &av);
BehaviourScriptRegistry::RegisterBehaviourScript("Image", []() -> BehaviourScript* {return new Image();}); BehaviourScriptRegistry::RegisterBehaviourScript("Image", []() -> BehaviourScript* {return new Image();});
BehaviourScriptRegistry::RegisterBehaviourScript("Image Animation", []() -> BehaviourScript* {return new ImageAnimation();}); 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("Camera", []() -> BehaviourScript* {return new Camera();});
BehaviourScriptRegistry::RegisterBehaviourScript("Audio Listener", []() -> BehaviourScript* {return new AudioListener();}); BehaviourScriptRegistry::RegisterBehaviourScript("Audio Listener", []() -> BehaviourScript* {return new AudioListener();});
BehaviourScriptRegistry::RegisterBehaviourScript("Audio Source", []() -> BehaviourScript* {return new AudioSource();}); 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 #pragma region camerastuff
@@ -43,4 +51,4 @@ TSE::EDITOR::EditorSubsystem::EditorSubsystem() : sv(nullptr), editorLayer("")
editorLayer.SetNonVisual(true); editorLayer.SetNonVisual(true);
#pragma endregion #pragma endregion
} }

View File

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

View File

@@ -1,11 +1,167 @@
#include "ElementDrawer.hpp" #include "ElementDrawer.hpp"
#include "BehaviourScriptRegistry.hpp" #include "BehaviourScriptRegistry.hpp"
#include "elements/ShaderRegistry.hpp" #include "elements/ShaderRegistry.hpp"
#include "elements/AssetLibrary.hpp"
#include "BehaviourScripts/Camera.hpp" #include "BehaviourScripts/Camera.hpp"
#include "windows/HirearchieView.hpp"
#include "windows/PropertiesView.hpp"
#include <algorithm> #include <algorithm>
#include <any>
#include <cctype>
namespace TSE::EDITOR 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 #pragma region helper
bool InputText(const char* label, std::string& str, size_t bufferSize = 256) { bool InputText(const char* label, std::string& str, size_t bufferSize = 256) {
std::vector<char> buffer(bufferSize); std::vector<char> buffer(bufferSize);
@@ -207,6 +363,10 @@ namespace TSE::EDITOR
{ {
Draw((TileMap*)element, debug); Draw((TileMap*)element, debug);
} }
else if (name == "Orderer Sprite Set")
{
Draw((OrdererSpriteSet*)element, debug);
}
else else
{ {
element->CustomDraw(debug); element->CustomDraw(debug);
@@ -217,15 +377,7 @@ namespace TSE::EDITOR
void ElementDrawer::Draw(Renderable *element, const bool &debug) void ElementDrawer::Draw(Renderable *element, const bool &debug)
{ {
ImGui::SeparatorText("Material"); ImGui::SeparatorText("Material");
int height = 100; DrawMaterialField(element->GetMaterialRef());
if(element->GetMaterial() == nullptr)
{
height = 35;
}
ImVec2 size(0, height);
ImGui::BeginChild("MaterialViewer", size, ImGuiChildFlags_Borders);
Draw(element->GetMaterial(), debug);
ImGui::EndChild();
} }
void ElementDrawer::Draw(MeshContainer *element, const bool &debug) void ElementDrawer::Draw(MeshContainer *element, const bool &debug)
{ {
@@ -235,7 +387,7 @@ namespace TSE::EDITOR
height = 35; height = 35;
} }
ImVec2 size(0, height); ImVec2 size(0, height);
Draw(element->GetMesh(), debug, "Mesh", true); DrawMeshField(element->GetMeshRef());
} }
void ElementDrawer::Draw(Image *element, const bool &debug) void ElementDrawer::Draw(Image *element, const bool &debug)
{ {
@@ -439,7 +591,7 @@ namespace TSE::EDITOR
Texture* value = element->GetValue<Texture*>(name); Texture* value = element->GetValue<Texture*>(name);
Draw(value, debug, name , true); Draw(value, debug, name , true);
} }
if (type == typeid(uint).name()) else if (type == typeid(uint).name())
{ {
int value = element->GetValue<uint>(name); int value = element->GetValue<uint>(name);
if(ImGui::InputInt(name.c_str(), &value)) if(ImGui::InputInt(name.c_str(), &value))
@@ -476,11 +628,6 @@ namespace TSE::EDITOR
} }
void ElementDrawer::Draw(Mesh *element, const bool &debug, const std::string &label, const bool small) 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); if(small) DrawMeshCompact(element, debug, label);
else DrawMeshNormal(element, debug, label); else DrawMeshNormal(element, debug, label);
} }
@@ -581,7 +728,7 @@ namespace TSE::EDITOR
ImGui::Text("Editor Camera can't be main camera"); ImGui::Text("Editor Camera can't be main camera");
} }
ImGui::Separator(); ImGui::Separator();
// Render Scale // Render Scale
float renderScale = element->GetRenderScale(); float renderScale = element->GetRenderScale();
if (ImGui::DragFloat("Render Scale", &renderScale, 0.1f)) if (ImGui::DragFloat("Render Scale", &renderScale, 0.1f))
@@ -612,6 +759,56 @@ namespace TSE::EDITOR
if (ImGui::DragFloat("Field of View (deg)", &fov, 0.1f)) if (ImGui::DragFloat("Field of View (deg)", &fov, 0.1f))
element->SetFov(fov); element->SetFov(fov);
if (!isPerspective) ImGui::EndDisabled(); 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) void ElementDrawer::Draw(ParticleSystem *element, const bool &debug)
{ {
@@ -836,6 +1033,7 @@ namespace TSE::EDITOR
{ {
chunk.SetOrdering(element->order); chunk.SetOrdering(element->order);
} }
element->DirtyAll();
} }
ImGui::BeginDisabled(); ImGui::BeginDisabled();
@@ -863,6 +1061,48 @@ namespace TSE::EDITOR
ImGui::TextDisabled(("Chunk Count: " + std::to_string(element->GetChunkCount())).c_str()); 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) void ElementDrawer::DrawAudioClipCompact(AudioClip *element, const bool &debug, const std::string &label)
{ {
float item_spacing = ImGui::GetStyle().ItemSpacing.x; float item_spacing = ImGui::GetStyle().ItemSpacing.x;
@@ -954,6 +1194,21 @@ namespace TSE::EDITOR
} }
void ElementDrawer::DrawMeshCompact(Mesh *element, const bool &debug, const std::string &label) 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; float item_spacing = ImGui::GetStyle().ItemSpacing.x;
ImVec2 label_size = ImGui::CalcTextSize(label.c_str()); ImVec2 label_size = ImGui::CalcTextSize(label.c_str());
@@ -980,54 +1235,6 @@ namespace TSE::EDITOR
cursorCurrent.y += 2; cursorCurrent.y += 2;
ImGui::SetCursorPos(cursorCurrent); ImGui::SetCursorPos(cursorCurrent);
ImGui::TextUnformatted(label.c_str()); 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) void ElementDrawer::DrawSpriteCompact(Sprite *element, const bool &debug, const std::string &label)
@@ -1103,7 +1310,7 @@ namespace TSE::EDITOR
ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0}); ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0});
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPos(ImVec2(field_size.y + 1,(60-label_size.y) / 2)); 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(); ImGui::EndChild();
@@ -1118,7 +1325,7 @@ namespace TSE::EDITOR
} }
void ElementDrawer::DrawTextureNormal(Texture *element, const bool &debug, const std::string& label) 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) if(debug)
{ {
ImGui::Separator(); ImGui::Separator();
@@ -1135,6 +1342,98 @@ namespace TSE::EDITOR
ImVec2 texSize (available_width, (available_width) * ymultiplyer); ImVec2 texSize (available_width, (available_width) * ymultiplyer);
ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0}); 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 } // namespace TSE::EDITOR

View File

@@ -14,6 +14,7 @@
#include "BehaviourScripts/AudioListener.hpp" #include "BehaviourScripts/AudioListener.hpp"
#include "BehaviourScripts/AudioSource.hpp" #include "BehaviourScripts/AudioSource.hpp"
#include "BehaviourScripts/TileMap.hpp" #include "BehaviourScripts/TileMap.hpp"
#include "BehaviourScripts/OrdererSpriteSet.hpp"
namespace TSE::EDITOR namespace TSE::EDITOR
{ {
@@ -22,7 +23,8 @@ namespace TSE::EDITOR
None, None,
Transformable, Transformable,
Scene, Scene,
Layer Layer,
IAsset
}; };
struct Inspectable struct Inspectable
@@ -53,6 +55,9 @@ namespace TSE::EDITOR
case InspectableType::Layer: case InspectableType::Layer:
Draw(static_cast<Layer*>(element.ptr), debug); Draw(static_cast<Layer*>(element.ptr), debug);
break; break;
case InspectableType::IAsset:
Draw(static_cast<IAsset*>(element.ptr), debug);
break;
default: default:
TSE_WARNING("Draw not implemented for this type."); TSE_WARNING("Draw not implemented for this type.");
break; break;
@@ -81,6 +86,8 @@ namespace TSE::EDITOR
static void Draw(Camera* element, const bool& debug); static void Draw(Camera* element, const bool& debug);
static void Draw(ParticleSystem* element, const bool& debug); static void Draw(ParticleSystem* element, const bool& debug);
static void Draw(TileMap* 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 DrawAudioClipCompact(AudioClip* element, const bool& debug, const std::string& label);
static void DrawAudioClipNormal(AudioClip* element, const bool& debug, const std::string& label); static void DrawAudioClipNormal(AudioClip* element, const bool& debug, const std::string& label);
@@ -92,5 +99,9 @@ namespace TSE::EDITOR
static void DrawSpriteNormal(Sprite* element, const bool& debug, const std::string& label); 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 DrawTextureCompact(Texture* element, const bool& debug, const std::string& label);
static void DrawTextureNormal(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 } // 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

@@ -17,9 +17,8 @@ namespace TSE::EDITOR
RenamingTransformable = 3, RenamingTransformable = 3,
RenamingScene = 4 RenamingScene = 4
}; };
Scene* currentScene;
uuids::uuid selected = uuids::uuid(); uuids::uuid selected = uuids::uuid();
bool openPopUpNamingLayer = false; bool openPopUpNamingLayer = false;
bool activatePopUpNamingLayer = false; bool activatePopUpNamingLayer = false;
char inputBuffer[128] = ""; char inputBuffer[128] = "";
@@ -27,8 +26,9 @@ namespace TSE::EDITOR
NamingPopUpPorPuse inputPurpose = Nothing; NamingPopUpPorPuse inputPurpose = Nothing;
Transformable* tmpHolder1 = nullptr; Transformable* tmpHolder1 = nullptr;
Layer* tmpHolder2 = nullptr; Layer* tmpHolder2 = nullptr;
public: public:
inline static Scene* currentScene = nullptr;
HirearchieView(Scene* s); HirearchieView(Scene* s);
void SetScene(Scene* s); void SetScene(Scene* s);
void Define() override; void Define() override;

View File

@@ -7,7 +7,6 @@
#include "enums/WindowType.hpp" #include "enums/WindowType.hpp"
#include "Color.hpp" #include "Color.hpp"
namespace TSE::GLFW namespace TSE::GLFW
{ {
class WindowGlfw : public IWindow class WindowGlfw : public IWindow

View File

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

View File

@@ -1,59 +0,0 @@
#include "RenderTexture.hpp"
TSE::GLFW::RenderTexture::RenderTexture(Vector2 v, uint textureCount) : buffer(v, textureCount)
{
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();
}
TSE::uint TSE::GLFW::RenderTexture::GetTextureId(uint id) const
{
return buffer.GetTextureId(id);
}
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

@@ -13,7 +13,7 @@ namespace TSE
/// @brief 32-bit golden ratio constant used for hash mixing /// @brief 32-bit golden ratio constant used for hash mixing
constexpr uint TSE_HASH_GOLDEN_RATIO_32 = 0x9e3779b9u; constexpr uint TSE_HASH_GOLDEN_RATIO_32 = 0x9e3779b9u;
/// @brief a simple degrees to radiant conversion function /// @brief a simple degrees to radiant conversion function
/// @param deg the degrees value /// @param deg the degrees value
/// @return the radiant 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);
}

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,9 @@
#pragma once #pragma once
#include "Types.hpp" #include "Types.hpp"
#include <functional>
#include <cstddef>
#include "MathF.hpp"
namespace TSE namespace TSE
{ {
@@ -145,3 +148,22 @@ namespace TSE
}; };
} // 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/gl3w.h"
#include "GL/gl.h" #include "GL/gl.h"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class CameraHelperOpenGL : public ICameraHelper class CameraHelperOpenGL : public ICameraHelper
{ {
@@ -14,4 +14,4 @@ namespace TSE::GLFW
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
}; };
}; };
} // namespace TSE::GLFW } // namespace TSE::OpenGL

View File

@@ -6,13 +6,13 @@
#define RENDERER_MAX_SPRITES 20000 #define RENDERER_MAX_SPRITES 20000
#define RENDERER_MAX_INDECIES 60000 #define RENDERER_MAX_INDECIES 60000
TSE::GLFW::DefaultRendererOpenGL::DefaultRendererOpenGL(Shader &shader) TSE::OpenGL::DefaultRendererOpenGL::DefaultRendererOpenGL(Shader &shader)
{ {
iboData = new ushort[RENDERER_MAX_INDECIES]; iboData = new ushort[RENDERER_MAX_INDECIES];
InitShader(shader, true); InitShader(shader, true);
} }
TSE::GLFW::DefaultRendererOpenGL::~DefaultRendererOpenGL() TSE::OpenGL::DefaultRendererOpenGL::~DefaultRendererOpenGL()
{ {
if(vao != 0) if(vao != 0)
glDeleteVertexArrays(1, &vao); glDeleteVertexArrays(1, &vao);
@@ -20,7 +20,7 @@ TSE::GLFW::DefaultRendererOpenGL::~DefaultRendererOpenGL()
delete ibo; delete ibo;
} }
void TSE::GLFW::DefaultRendererOpenGL::InitShader(Shader &s, bool init) void TSE::OpenGL::DefaultRendererOpenGL::InitShader(Shader &s, bool init)
{ {
if(!init) End(); if(!init) End();
if(vao != 0) if(vao != 0)
@@ -51,13 +51,13 @@ void TSE::GLFW::DefaultRendererOpenGL::InitShader(Shader &s, bool init)
if(!init) Begin(); if(!init) Begin();
} }
void TSE::GLFW::DefaultRendererOpenGL::End() void TSE::OpenGL::DefaultRendererOpenGL::End()
{ {
glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ARRAY_BUFFER);
vbo.Unbind(); vbo.Unbind();
} }
void TSE::GLFW::DefaultRendererOpenGL::Flush() void TSE::OpenGL::DefaultRendererOpenGL::Flush()
{ {
lastShader->Flush(); lastShader->Flush();
@@ -91,18 +91,18 @@ void TSE::GLFW::DefaultRendererOpenGL::Flush()
iboOffset = 0; iboOffset = 0;
} }
void TSE::GLFW::DefaultRendererOpenGL::Begin() void TSE::OpenGL::DefaultRendererOpenGL::Begin()
{ {
vbo.Bind(); vbo.Bind();
bufferPointer = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); 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); 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); Shader* s = dynamic_cast<Shader*>(shader);
if(lastShader == nullptr) InitShader(*s, true); if(lastShader == nullptr) InitShader(*s, true);
@@ -137,14 +137,14 @@ void TSE::GLFW::DefaultRendererOpenGL::Submit(const Transformable &trans, IShade
lastShader->Submit(trans, bufferPointer, stack, Redraw, *this); lastShader->Submit(trans, bufferPointer, stack, Redraw, *this);
} }
void TSE::GLFW::DefaultRendererOpenGL::Redraw(IRenderer &rnd) void TSE::OpenGL::DefaultRendererOpenGL::Redraw(IRenderer &rnd)
{ {
rnd.End(); rnd.End();
rnd.Flush(); rnd.Flush();
rnd.Begin(); rnd.Begin();
} }
bool TSE::GLFW::DefaultRendererOpenGL::CreateIbo() bool TSE::OpenGL::DefaultRendererOpenGL::CreateIbo()
{ {
if(indexCount == 0) return true; if(indexCount == 0) return true;
if(ibo != nullptr) if(ibo != nullptr)

View File

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

View File

@@ -1,24 +1,36 @@
#include "GL/gl3w.h" #include "GL/gl3w.h"
#include "GL/gl.h" #include "GL/gl.h"
#include "OpenGLRenderingBackend.hpp" #include "OpenGLRenderingBackend.hpp"
#include "GLFW/glfw3.h"
#include "WindowGlfw.hpp"
#include "Debug.hpp" #include "Debug.hpp"
#include "imgui/imgui.h" #include "imgui/imgui.h"
#include "extern/imgui_impl_glfw.h"
#include "extern/imgui_impl_opengl3.h" #include "extern/imgui_impl_opengl3.h"
#include "PathHelper.hpp" #include "PathHelper.hpp"
#include "elements/Texture.hpp" #include "interfaces/ITexture.hpp"
#include "TextureHelperOpenGL.hpp" #include "TextureHelperOpenGL.hpp"
#include "interfaces/IRenderer.hpp" #include "interfaces/IRenderer.hpp"
#include "BehaviourScripts/Camera.hpp" #include "BehaviourScripts/Camera.hpp"
#include "RenderTextureCreatorOpenGL.hpp" #include "RenderTextureCreatorOpenGL.hpp"
#include "CameraHelperOpenGL.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){ } : 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; backgroundColor = _backgroundColor;
vsync = _vsync; vsync = _vsync;
@@ -26,33 +38,50 @@ TSE::GLFW::OpenGLRenderingBackend::OpenGLRenderingBackend(Color _backgroundColor
useseImGui = _useseImGui; useseImGui = _useseImGui;
} }
TSE::GLFW::OpenGLRenderingBackend::~OpenGLRenderingBackend() TSE::OpenGL::OpenGLRenderingBackend::~OpenGLRenderingBackend()
{ {
if(useseImGui) if(useseImGui)
{ {
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
#if defined(TSE_GLFW)
ImGui_ImplGlfw_Shutdown(); ImGui_ImplGlfw_Shutdown();
#elif defined(TSE_SDL3)
ImGui_ImplSDL3_Shutdown();
#endif
ImGui::DestroyContext(); ImGui::DestroyContext();
} }
} }
void TSE::GLFW::OpenGLRenderingBackend::InitPreWindow() void TSE::OpenGL::OpenGLRenderingBackend::InitPreWindow()
{ {
IRenderTexture::factory = new RenderTextureCreatorOpenGL(); IRenderTexture::factory = new RenderTextureCreatorOpenGL();
Texture::helper = new TextureHelperOpenGL(); ITexture::helper = new TextureHelperOpenGL();
Camera::helper = new CameraHelperOpenGL(); Camera::helper = new CameraHelperOpenGL();
#if defined(TSE_GLFW)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, TSE_OPENGL_VERSION_MAJOR); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, TSE_OPENGL_VERSION_MAJOR);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, TSE_OPENGL_VERSION_MINOR); 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_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_SAMPLES, samples); 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); WindowGlfw* wnd = static_cast<WindowGlfw*>(window);
glfwMakeContextCurrent(wnd->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()) if(gl3wInit())
{ {
Debug::Log("Failed to initialize gl3w."); 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."); Debug::Log("gl3w dose not support the selected version of OpenGL.");
return false; return false;
} }
#if defined(TSE_GLFW)
if(vsync) glfwSwapInterval(1); if(vsync) glfwSwapInterval(1);
else glfwSwapInterval(0); 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("OpenGL:" + std::string((const char*)glGetString(GL_VERSION)));
Debug::Log("GLSL:" + std::string((const char*)glGetString(GL_SHADING_LANGUAGE_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; std::string imguiIniPath;
bool TSE::GLFW::OpenGLRenderingBackend::InitEnd() bool TSE::OpenGL::OpenGLRenderingBackend::InitEnd()
{ {
if(useseImGui) if(useseImGui)
{ {
@@ -102,8 +139,15 @@ bool TSE::GLFW::OpenGLRenderingBackend::InitEnd()
io.IniFilename = imguiIniPath.c_str(); io.IniFilename = imguiIniPath.c_str();
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
#if defined(TSE_GLFW)
WindowGlfw* wnd = static_cast<WindowGlfw*>(window); WindowGlfw* wnd = static_cast<WindowGlfw*>(window);
wnd->useImGui = true;
ImGui_ImplGlfw_InitForOpenGL(wnd->window, 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"); ImGui_ImplOpenGL3_Init("#version 130");
Debug::Log("ImGui:" + std::string(ImGui::GetVersion())); Debug::Log("ImGui:" + std::string(ImGui::GetVersion()));
@@ -111,12 +155,12 @@ bool TSE::GLFW::OpenGLRenderingBackend::InitEnd()
return true; 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); glViewport(0,0,width, height);
} }
void TSE::GLFW::OpenGLRenderingBackend::onUpdate() const void TSE::OpenGL::OpenGLRenderingBackend::onUpdate() const
{ {
int error = glGetError(); int error = glGetError();
if(error != GL_NO_ERROR) if(error != GL_NO_ERROR)
@@ -124,6 +168,12 @@ void TSE::GLFW::OpenGLRenderingBackend::onUpdate() const
Debug::Log("OpenGL Error: " + std::to_string(error)); 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) if(useseImGui)
{ {
ImGui::Render(); ImGui::Render();
@@ -132,19 +182,30 @@ void TSE::GLFW::OpenGLRenderingBackend::onUpdate() const
if(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) if(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{ {
#if defined(TSE_GLFW)
GLFWwindow* backup_current_context = glfwGetCurrentContext(); GLFWwindow* backup_current_context = glfwGetCurrentContext();
#elif defined(TSE_SDL3)
SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
#endif
ImGui::UpdatePlatformWindows(); ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault(); ImGui::RenderPlatformWindowsDefault();
#if defined(TSE_GLFW)
glfwMakeContextCurrent(backup_current_context); 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); 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++) for (int i = 0; i < IRenderer::camerasToRenderWith.size(); i++)
{ {
@@ -158,12 +219,16 @@ void TSE::GLFW::OpenGLRenderingBackend::onClear() const
if(useseImGui) if(useseImGui)
{ {
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
#if defined(TSE_GLFW)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
#elif defined(TSE_SDL3)
ImGui_ImplSDL3_NewFrame();
#endif
ImGui::NewFrame(); ImGui::NewFrame();
} }
} }
void TSE::GLFW::OpenGLRenderingBackend::onClearDepthBuffer() const void TSE::OpenGL::OpenGLRenderingBackend::onClearDepthBuffer() const
{ {
for (int i = 0; i < IRenderer::camerasToRenderWith.size(); i++) 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_MAJOR 3
#define TSE_OPENGL_VERSION_MINOR 3 #define TSE_OPENGL_VERSION_MINOR 3
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class OpenGLRenderingBackend : public IRenderingBackend class OpenGLRenderingBackend : public IRenderingBackend
{ {
@@ -25,4 +25,4 @@ namespace TSE::GLFW
void onClear() const override; void onClear() const override;
void onClearDepthBuffer() 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,7 +6,7 @@
#include "interfaces/IResizeNotifiable.hpp" #include "interfaces/IResizeNotifiable.hpp"
#include "interfaces/IRenderTexture.hpp" #include "interfaces/IRenderTexture.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class RenderTexture : public IRenderTexture class RenderTexture : public IRenderTexture
{ {
@@ -28,4 +28,4 @@ namespace TSE::GLFW
void OnResize(float width, float height, IResizable* wnd) override; void OnResize(float width, float height, IResizable* wnd) override;
}; };
} // namespace TSE::GLFW } // namespace TSE::OpenGL

View File

@@ -3,7 +3,7 @@
#include "interfaces/IRenderTexture.hpp" #include "interfaces/IRenderTexture.hpp"
#include "RenderTexture.hpp" #include "RenderTexture.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class RenderTextureCreatorOpenGL : public IRenderTextureCreator class RenderTextureCreatorOpenGL : public IRenderTextureCreator
{ {
@@ -13,4 +13,4 @@ namespace TSE::GLFW
return new RenderTexture(v, textureCount); 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 "interfaces/ITextureHelper.hpp"
#include "elements/Texture.hpp" #include "elements/Texture.hpp"
#include "elements/VolumeTexture3D.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class TextureHelperOpenGL : public ITextureHelper class TextureHelperOpenGL : public ITextureHelper
{ {
@@ -13,5 +14,11 @@ namespace TSE::GLFW
void Apply(Texture* tex) override; void Apply(Texture* tex) override;
void Regist(Texture* tex) override; void Regist(Texture* tex) override;
void PlatromDestroy(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

@@ -1,7 +1,7 @@
#include "FrameBuffer.hpp" #include "FrameBuffer.hpp"
#include "Debug.hpp" #include "Debug.hpp"
TSE::GLFW::FrameBuffer::FrameBuffer(const Vector2 &size, uint textureCount) TSE::OpenGL::FrameBuffer::FrameBuffer(const Vector2 &size, uint textureCount)
{ {
textureOutputCount = textureCount; textureOutputCount = textureCount;
width = size.x; width = size.x;
@@ -14,17 +14,17 @@ TSE::GLFW::FrameBuffer::FrameBuffer(const Vector2 &size, uint textureCount)
Initialize(); Initialize();
} }
void TSE::GLFW::FrameBuffer::Bind() void TSE::OpenGL::FrameBuffer::Bind()
{ {
glBindFramebuffer(GL_FRAMEBUFFER, bufferID); glBindFramebuffer(GL_FRAMEBUFFER, bufferID);
} }
void TSE::GLFW::FrameBuffer::Unbind() void TSE::OpenGL::FrameBuffer::Unbind()
{ {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
TSE::GLFW::FrameBuffer::~FrameBuffer() TSE::OpenGL::FrameBuffer::~FrameBuffer()
{ {
glDeleteFramebuffers(1,&bufferID); glDeleteFramebuffers(1,&bufferID);
for (int i = 0; i < textureOutputCount; i++) for (int i = 0; i < textureOutputCount; i++)
@@ -34,14 +34,14 @@ TSE::GLFW::FrameBuffer::~FrameBuffer()
glDeleteRenderbuffers(1, &depthRboID); glDeleteRenderbuffers(1, &depthRboID);
} }
void TSE::GLFW::FrameBuffer::Resize(Vector2 size) void TSE::OpenGL::FrameBuffer::Resize(Vector2 size)
{ {
width = size.x; width = size.x;
height = size.y; height = size.y;
shouldResize = true; shouldResize = true;
} }
void TSE::GLFW::FrameBuffer::Update() void TSE::OpenGL::FrameBuffer::Update()
{ {
if (!shouldResize) return; if (!shouldResize) return;
shouldResize = false; shouldResize = false;
@@ -52,17 +52,17 @@ void TSE::GLFW::FrameBuffer::Update()
} }
} }
TSE::uint TSE::GLFW::FrameBuffer::GetTextureId(uint id) const TSE::uint TSE::OpenGL::FrameBuffer::GetTextureId(uint id) const
{ {
return textureIDs[id]; return textureIDs[id];
} }
TSE::Vector2 TSE::GLFW::FrameBuffer::GetSize() const TSE::Vector2 TSE::OpenGL::FrameBuffer::GetSize() const
{ {
return {width, height}; return {width, height};
} }
void TSE::GLFW::FrameBuffer::Initialize() void TSE::OpenGL::FrameBuffer::Initialize()
{ {
glGenFramebuffers(1, &bufferID); glGenFramebuffers(1, &bufferID);
Bind(); Bind();
@@ -85,7 +85,7 @@ void TSE::GLFW::FrameBuffer::Initialize()
Unbind(); Unbind();
} }
void TSE::GLFW::FrameBuffer::LoadFBTexture() void TSE::OpenGL::FrameBuffer::LoadFBTexture()
{ {
for (int i = 0; i < textureOutputCount; i++) for (int i = 0; i < textureOutputCount; i++)
{ {
@@ -104,7 +104,7 @@ void TSE::GLFW::FrameBuffer::LoadFBTexture()
} }
} }
void TSE::GLFW::FrameBuffer::CreateFBTexture() void TSE::OpenGL::FrameBuffer::CreateFBTexture()
{ {
glViewport(0,0, width, height); glViewport(0,0, width, height);
//resize //resize

View File

@@ -4,7 +4,7 @@
#include "interfaces/IResizable.hpp" #include "interfaces/IResizable.hpp"
#include "Vector2.hpp" #include "Vector2.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class FrameBuffer : public buffer, public IResizable class FrameBuffer : public buffer, public IResizable
{ {

View File

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

View File

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

View File

@@ -1,35 +1,35 @@
#include "VertexBuffer.hpp" #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); 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); glBufferData(GL_ARRAY_BUFFER, size, buffer, usage);
} }
void TSE::GLFW::VertexBuffer::Bind() void TSE::OpenGL::VertexBuffer::Bind()
{ {
glBindBuffer(GL_ARRAY_BUFFER, bufferID); glBindBuffer(GL_ARRAY_BUFFER, bufferID);
boundBuffer = bufferID; boundBuffer = bufferID;
} }
void TSE::GLFW::VertexBuffer::Unbind() void TSE::OpenGL::VertexBuffer::Unbind()
{ {
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
boundBuffer = 0; boundBuffer = 0;
} }
bool TSE::GLFW::VertexBuffer::IsBound() bool TSE::OpenGL::VertexBuffer::IsBound()
{ {
return boundBuffer == bufferID; return boundBuffer == bufferID;
} }
TSE::GLFW::VertexBuffer::~VertexBuffer() TSE::OpenGL::VertexBuffer::~VertexBuffer()
{ {
if(bufferID != 0) if(bufferID != 0)
{ {

View File

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

View File

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

View File

@@ -3,63 +3,63 @@
#include "Shader.hpp" #include "Shader.hpp"
#include "Debug.hpp" #include "Debug.hpp"
TSE::uint TSE::GLFW::Shader::activeProgramID = 0; TSE::uint TSE::OpenGL::Shader::activeProgramID = 0;
void TSE::GLFW::Shader::Bind() const void TSE::OpenGL::Shader::Bind() const
{ {
Enable(true); Enable(true);
} }
void TSE::GLFW::Shader::Unbind() const void TSE::OpenGL::Shader::Unbind() const
{ {
Disable(true); Disable(true);
} }
void TSE::GLFW::Shader::Enable(bool notify) const void TSE::OpenGL::Shader::Enable(bool notify) const
{ {
activeProgramID = programID; activeProgramID = programID;
glUseProgram(programID); glUseProgram(programID);
if(notify) OnEnable(); if(notify) OnEnable();
} }
void TSE::GLFW::Shader::Disable(bool notify) const void TSE::OpenGL::Shader::Disable(bool notify) const
{ {
activeProgramID = 0; activeProgramID = 0;
glUseProgram(0); glUseProgram(0);
if(notify) OnDisable(); if(notify) OnDisable();
} }
void TSE::GLFW::Shader::Flush() void TSE::OpenGL::Shader::Flush()
{ {
OnFlush(); OnFlush();
} }
void TSE::GLFW::Shader::DrawCall(int indexCount) void TSE::OpenGL::Shader::DrawCall(int indexCount)
{ {
OnDrawCall(indexCount); OnDrawCall(indexCount);
} }
void TSE::GLFW::Shader::PostDraw() void TSE::OpenGL::Shader::PostDraw()
{ {
OnPostDraw(); OnPostDraw();
} }
void TSE::GLFW::Shader::Submit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) void TSE::OpenGL::Shader::Submit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd)
{ {
OnSubmit(t, target, stack, restartDrawcall, rnd); OnSubmit(t, target, stack, restartDrawcall, rnd);
} }
bool TSE::GLFW::Shader::IsEnabled() const bool TSE::OpenGL::Shader::IsEnabled() const
{ {
return programID == activeProgramID; return programID == activeProgramID;
} }
int TSE::GLFW::Shader::packageSize() int TSE::OpenGL::Shader::packageSize()
{ {
return PackageSize; return PackageSize;
} }
TSE::GLFW::Shader::Shader(const std::vector<std::unique_ptr<ShaderPart>> &parts) TSE::OpenGL::Shader::Shader(const std::vector<std::unique_ptr<ShaderPart>> &parts)
{ {
programID = glCreateProgram(); programID = glCreateProgram();
@@ -85,12 +85,12 @@ TSE::GLFW::Shader::Shader(const std::vector<std::unique_ptr<ShaderPart>> &parts)
} }
} }
TSE::GLFW::Shader::~Shader() TSE::OpenGL::Shader::~Shader()
{ {
glDeleteProgram(programID); glDeleteProgram(programID);
} }
int TSE::GLFW::Shader::GetUniformLocation(const char *name) int TSE::OpenGL::Shader::GetUniformLocation(const char *name)
{ {
auto it = uniformLocations.find(name); auto it = uniformLocations.find(name);
if (it != uniformLocations.end()) return it->second; if (it != uniformLocations.end()) return it->second;
@@ -100,44 +100,44 @@ int TSE::GLFW::Shader::GetUniformLocation(const char *name)
return loc; return loc;
} }
void TSE::GLFW::Shader::SetUniform(const char *name, int value) void TSE::OpenGL::Shader::SetUniform(const char *name, int value)
{ {
glUniform1i(GetUniformLocation(name), value); glUniform1i(GetUniformLocation(name), value);
} }
void TSE::GLFW::Shader::SetUniform(const char *name, const int *value, const int count) void TSE::OpenGL::Shader::SetUniform(const char *name, const int *value, const int count)
{ {
glUniform1iv(GetUniformLocation(name), count, value); glUniform1iv(GetUniformLocation(name), count, value);
} }
void TSE::GLFW::Shader::SetUniform(const char *name, const Matrix4x4 *value) void TSE::OpenGL::Shader::SetUniform(const char *name, const Matrix4x4 *value)
{ {
float colmbMajor[16]; float colmbMajor[16];
value->ToArrayColumnMajor(colmbMajor); value->ToArrayColumnMajor(colmbMajor);
glUniformMatrix4fv(GetUniformLocation(name),1, false, colmbMajor); glUniformMatrix4fv(GetUniformLocation(name),1, false, colmbMajor);
} }
void TSE::GLFW::Shader::SetUniform(const char *name, float value) void TSE::OpenGL::Shader::SetUniform(const char *name, float value)
{ {
glUniform1f(GetUniformLocation(name), value); glUniform1f(GetUniformLocation(name), value);
} }
void TSE::GLFW::Shader::SetUniform(const char *name, const float *value, const int count) void TSE::OpenGL::Shader::SetUniform(const char *name, const float *value, const int count)
{ {
glUniform1fv(GetUniformLocation(name), count, value); glUniform1fv(GetUniformLocation(name), count, value);
} }
void TSE::GLFW::Shader::SetUniform(const char *name, const Vector2 *value) void TSE::OpenGL::Shader::SetUniform(const char *name, const Vector2 *value)
{ {
glUniform2f(GetUniformLocation(name), value->x, value->y); glUniform2f(GetUniformLocation(name), value->x, value->y);
} }
void TSE::GLFW::Shader::SetUniform(const char *name, const Vector3 *value) void TSE::OpenGL::Shader::SetUniform(const char *name, const Vector3 *value)
{ {
glUniform3f(GetUniformLocation(name), value->x, value->y, value->z); glUniform3f(GetUniformLocation(name), value->x, value->y, value->z);
} }
void TSE::GLFW::Shader::SetUniform(const char *name, const Vector4 *value) void TSE::OpenGL::Shader::SetUniform(const char *name, const Vector4 *value)
{ {
glUniform4f(GetUniformLocation(name), value->x, value->y, value->z, value->w); glUniform4f(GetUniformLocation(name), value->x, value->y, value->z, value->w);
} }

View File

@@ -9,7 +9,7 @@
#include "TransformationStack.hpp" #include "TransformationStack.hpp"
#include "interfaces/IRenderer.hpp" #include "interfaces/IRenderer.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class Shader : public IShader class Shader : public IShader
{ {
@@ -54,4 +54,4 @@ namespace TSE::GLFW
void SetUniform(const char* name, const Vector3* value) override; void SetUniform(const char* name, const Vector3* value) override;
void SetUniform(const char* name, const Vector4* value) override; void SetUniform(const char* name, const Vector4* value) override;
}; };
} // namespace TSE::GLFW } // namespace TSE::OpenGL

View File

@@ -6,7 +6,7 @@
#include <fstream> #include <fstream>
#include "PathHelper.hpp" #include "PathHelper.hpp"
void TSE::GLFW::ShaderPart::Init(const string &str, int shaderType) void TSE::OpenGL::ShaderPart::Init(const string &str, int shaderType)
{ {
shaderPartID = glCreateShader(shaderType); shaderPartID = glCreateShader(shaderType);
const char * cstr = str.c_str(); const char * cstr = str.c_str();
@@ -27,12 +27,12 @@ void TSE::GLFW::ShaderPart::Init(const string &str, int shaderType)
} }
} }
TSE::GLFW::ShaderPart::~ShaderPart() TSE::OpenGL::ShaderPart::~ShaderPart()
{ {
glDeleteShader(shaderPartID); glDeleteShader(shaderPartID);
} }
std::unique_ptr<TSE::GLFW::ShaderPart> TSE::GLFW::ShaderPart::LoadFromString(const std::string &str, int shaderType) std::unique_ptr<TSE::OpenGL::ShaderPart> TSE::OpenGL::ShaderPart::LoadFromString(const std::string &str, int shaderType)
{ {
if (str.length() == 0) throw; if (str.length() == 0) throw;
std::unique_ptr<ShaderPart> shader = std::make_unique<ShaderPart>(); std::unique_ptr<ShaderPart> shader = std::make_unique<ShaderPart>();
@@ -40,7 +40,7 @@ std::unique_ptr<TSE::GLFW::ShaderPart> TSE::GLFW::ShaderPart::LoadFromString(con
return shader; return shader;
} }
std::unique_ptr<TSE::GLFW::ShaderPart> TSE::GLFW::ShaderPart::LoadFromPath(const std::string &path, int shaderType) std::unique_ptr<TSE::OpenGL::ShaderPart> TSE::OpenGL::ShaderPart::LoadFromPath(const std::string &path, int shaderType)
{ {
std::ifstream stream; std::ifstream stream;
OpenFileReading(stream, path); OpenFileReading(stream, path);

View File

@@ -3,7 +3,7 @@
#include "Types.hpp" #include "Types.hpp"
#include <memory> #include <memory>
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class ShaderPart class ShaderPart
{ {
@@ -20,4 +20,4 @@ namespace TSE::GLFW
static std::unique_ptr<ShaderPart> LoadFromString(const std::string& str, int shaderType); static std::unique_ptr<ShaderPart> LoadFromString(const std::string& str, int shaderType);
static std::unique_ptr<ShaderPart> LoadFromPath(const std::string& path, int shaderType); static std::unique_ptr<ShaderPart> LoadFromPath(const std::string& path, int shaderType);
}; };
} // namespace TSE } // namespace OpenGL

View File

@@ -0,0 +1,239 @@
#include "basicOrderedSpriteSetShader.hpp"
#include "BehaviourScripts/Renderable.hpp"
#include "BehaviourScripts/OrdererSpriteSet.hpp"
#include "Color.hpp"
#include "basicOrderedSpriteSetShaderGLSL.hpp"
using namespace TSE;
using namespace TSE::OpenGL;
#define SHADER_MESH_INDEX 0
#define SHADER_POS_INDEX 1
#define SHADER_LAYER_HEIGHT_INDEX 2
#define SHADER_SPRITE_INDEX 3
#define SHADER_NORMAL_INDEX 4
#define SHADER_SCALE_INDEX 5
#define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 1 + 1 + 1 + 2)
TSE::OpenGL::BasicOrderedSpriteSetShader* BasicOrderedSpriteSetShader::instance = nullptr;
TSE::OpenGL::BasicOrderedSpriteSetShader *TSE::OpenGL::BasicOrderedSpriteSetShader::Instance()
{
return instance;
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::Destroy()
{
if(instance != nullptr)
delete instance;
instance = nullptr;
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::Init(float width, float height)
{
std::vector<std::unique_ptr<ShaderPart>> parts;
parts.push_back(ShaderPart::LoadFromString(vertOrderedSet, GL_VERTEX_SHADER));
parts.push_back(ShaderPart::LoadFromString(fragOrderedSet, GL_FRAGMENT_SHADER));
instance = new BasicOrderedSpriteSetShader(std::move(parts));
instance->Enable();
int texIDs[] = { 0 };
instance->SetUniform("atlas", 0);
instance->Disable();
}
TSE::OpenGL::BasicOrderedSpriteSetShader::BasicOrderedSpriteSetShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts)
{
name = "Basic Ordered Sprite Set Shader";
PackageSize = SHADER_PACKAGE_SIZE;
}
TSE::OpenGL::BasicOrderedSpriteSetShader::~BasicOrderedSpriteSetShader()
{
if (meshVBO) glDeleteBuffers(1, &meshVBO);
if (meshIBO) glDeleteBuffers(1, &meshIBO);
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::SetMesh(const void *verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void *indices, int indexCount, GLenum indexType)
{
GLint prevVAO = 0, prevArrayBuffer = 0, prevElementBuffer = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevArrayBuffer);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevElementBuffer);
if (!meshVBO) glGenBuffers(1, &meshVBO);
glBindBuffer(GL_ARRAY_BUFFER, meshVBO);
glBufferData(GL_ARRAY_BUFFER, vertCount * stride, verts, GL_STATIC_DRAW);
if (indices && indexCount > 0)
{
if (!meshIBO) glGenBuffers(1, &meshIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshIBO);
GLsizeiptr idxSize =
(indexType == GL_UNSIGNED_INT ? 4 :
indexType == GL_UNSIGNED_SHORT? 2 : 1) * indexCount;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idxSize, indices, GL_STATIC_DRAW);
meshIndexCount = indexCount;
meshIndexType = indexType;
}
else
{
// Kein Index-Buffer
if (meshIBO) { glDeleteBuffers(1, &meshIBO); meshIBO = 0; }
meshIndexCount = 0;
}
meshVertexCount = vertCount;
meshStride = stride;
meshPosOffset = posOffsetBytes;
meshPosSize = floatCountPerVertex;
meshPrimitive = primitive;
meshReady = true;
glBindBuffer(GL_ARRAY_BUFFER, prevArrayBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevElementBuffer);
glBindVertexArray(prevVAO);
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::OnEnable() const
{
if (!meshReady)
{
// Fallback: unit-Quad als TRIANGLE_FAN (4 Vertices, 2D Positionen)
const float quad[8] = { -0.5f,0, 0.5f,0, 0.5f,1, -0.5f,1 };
const_cast<BasicOrderedSpriteSetShader*>(this)->SetMesh(
quad, 4, sizeof(float)*2, 2, 0, GL_TRIANGLE_FAN
);
}
GLint prevArrayBuffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevArrayBuffer);
glBindBuffer(GL_ARRAY_BUFFER, meshVBO);
glEnableVertexAttribArray(SHADER_MESH_INDEX); // LOC_QUAD/pos
glVertexAttribPointer(SHADER_MESH_INDEX, meshPosSize, GL_FLOAT, GL_FALSE, meshStride, (void*)meshPosOffset);
glVertexAttribDivisor(SHADER_MESH_INDEX, 0); // per-vertex (Mesh)
glBindBuffer(GL_ARRAY_BUFFER, prevArrayBuffer);
glEnableVertexAttribArray(SHADER_POS_INDEX);
glVertexAttribPointer(SHADER_POS_INDEX, 3, GL_FLOAT, GL_FALSE, PackageSize, (void*)0);
glVertexAttribDivisor(SHADER_POS_INDEX, 1);
glEnableVertexAttribArray(SHADER_LAYER_HEIGHT_INDEX);
glVertexAttribPointer(SHADER_LAYER_HEIGHT_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*3));
glVertexAttribDivisor(SHADER_LAYER_HEIGHT_INDEX, 1);
glEnableVertexAttribArray(SHADER_SPRITE_INDEX);
glVertexAttribPointer(SHADER_SPRITE_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*4));
glVertexAttribDivisor(SHADER_SPRITE_INDEX, 1);
glEnableVertexAttribArray(SHADER_NORMAL_INDEX);
glVertexAttribPointer(SHADER_NORMAL_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*5));
glVertexAttribDivisor(SHADER_NORMAL_INDEX, 1);
glEnableVertexAttribArray(SHADER_SCALE_INDEX);
glVertexAttribPointer(SHADER_SCALE_INDEX, 2, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*6));
glVertexAttribDivisor(SHADER_SCALE_INDEX, 1);
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::OnDisable() const
{
glDisableVertexAttribArray(SHADER_MESH_INDEX);
glDisableVertexAttribArray(SHADER_POS_INDEX);
glDisableVertexAttribArray(SHADER_LAYER_HEIGHT_INDEX);
glDisableVertexAttribArray(SHADER_SPRITE_INDEX);
glDisableVertexAttribArray(SHADER_NORMAL_INDEX);
glDisableVertexAttribArray(SHADER_SCALE_INDEX);
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::OnFlush()
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, TextureID);
glDisable(GL_BLEND);
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::OnDrawCall(int indexCount)
{
if (instanceCount <= 0) return;
SetUniform("spriteCount", &SpriteCount);
GLint prevElementBuffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevElementBuffer);
if (meshIBO && meshIndexCount > 0)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshIBO);
glDrawElementsInstanced(meshPrimitive, meshIndexCount, meshIndexType, (void*)0, instanceCount);
}
else
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArraysInstanced(meshPrimitive, 0, meshVertexCount, instanceCount);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)prevElementBuffer);
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::OnPostDraw()
{
glEnable(GL_BLEND);
instanceCount = 0;
}
void TSE::OpenGL::BasicOrderedSpriteSetShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd)
{
auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE));
if (!r) return;
auto* tm = dynamic_cast<OrdererSpriteSet*>(t.GetBehaviourScript(ORDERERSPRITESET));
if (!tm) return;
auto tileSet = tm->GetTileSet();
TextureID = tileSet->GetTextueID();
SpriteCount = tileSet->GetCount();
const std::vector<Vector2> orderedChunks = *tm->GetChunkPositionsInOrder();
Matrix4x4 matr = t.GetLocalMatrix();
stack.Push(matr);
for(auto chunkPos : orderedChunks)
{
auto chunk = tm->GetChunk(chunkPos);
const int spriteCount = chunk->GetSpriteCount();
const std::vector<Vector3> spritePositions = *chunk->GetOrderedPositions();
const std::vector<Vector2i> spriteIds = *chunk->GetOrderedSpriteIds();
const std::vector<Vector2> spriteScales = *chunk->GetOrderedScales();
int chunkSize = chunk->GetChunksize();
for (int i = 0; i < spriteCount; i++)
{
Matrix4x4 mat = Matrix4x4::ToTranslationMatrix(chunkPos + spritePositions[i].ToVector2()) * Matrix4x4::ToRotationMatrix(Quaternion()) * Matrix4x4::ToScaleMatrix({1,1,1});
stack.Push(mat);
Vector3 pos = stack.Top() * Vector3(0,0,0);
*target++ = pos.x;
*target++ = pos.y;
*target++ = pos.z;
*target++ = spritePositions[i].z;
*target++ = spriteIds[i].x;
*target++ = spriteIds[i].y;
*target++ = spriteScales[i].x;
*target++ = spriteScales[i].y;
++instanceCount;
stack.Pop();
if(instanceCount >= 16000)
restartDrawcall(rnd);
}
}
stack.Pop();
restartDrawcall(rnd);
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include "GL/gl3w.h"
#include "GL/gl.h"
#include "Shader.hpp"
#include "Types.hpp"
namespace TSE::OpenGL
{
class BasicOrderedSpriteSetShader : public Shader
{
private:
static BasicOrderedSpriteSetShader* instance;
mutable bool meshReady = false;
GLuint meshVBO = 0;
GLuint meshIBO = 0;
GLsizei meshVertexCount = 0; // für DrawArraysInstanced
GLsizei meshIndexCount = 0; // für DrawElementsInstanced
GLenum meshPrimitive = GL_TRIANGLES;
GLenum meshIndexType = GL_UNSIGNED_SHORT;
int instanceCount = 0; // eigener Instanzzähler
GLint meshPosSize = 2; // 2D (Billboard-Formen), für 3D Meshes: 3
GLsizei meshStride = sizeof(float) * 2;
size_t meshPosOffset = 0;
GLuint TextureID;
Vector2 SpriteCount;
public:
static BasicOrderedSpriteSetShader* Instance();
static void Destroy();
static void Init(float width, float height);
BasicOrderedSpriteSetShader(std::vector<std::unique_ptr<ShaderPart>>&& parts);
~BasicOrderedSpriteSetShader();
void SetMesh(const void* verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void* indices = nullptr, int indexCount = 0, GLenum indexType = GL_UNSIGNED_SHORT);
protected:
void OnEnable() const override;
void OnDisable() const override;
void OnFlush() override;
void OnDrawCall(int indexCount) override;
void OnPostDraw() override;
void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override;
};
} // namespace TSE::GLFW

View File

@@ -0,0 +1,95 @@
#pragma once
inline const char* vertOrderedSet = R"(
#version 330 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec3 iTilePos;
layout(location = 2) in float height;
layout(location = 3) in float iSpriteId;
layout(location = 4) in float iNormalId;
layout(location = 5) in vec2 spriteScale;
uniform mat4 prMatrix;
uniform mat4 camMatrix;
out vec2 vUV;
flat out int vSpriteId;
flat out int vNormalId;
flat out float vTileNdcY;
flat out float layerHeight;
void main()
{
vec3 local = vec3(aPos.x, aPos.y, 0);
vec2 baseUV = aPos + vec2(0.5, 0);
vec3 tileSize = vec3(spriteScale.x, spriteScale.y, 1);
vec3 worldPos = (iTilePos * tileSize) + (local * tileSize);
vec4 clip = prMatrix * camMatrix * vec4(worldPos, 1.0);
gl_Position = clip;
vUV = baseUV;
vSpriteId = int(iSpriteId + 0.5);
vNormalId = int(iNormalId + 0.5);
layerHeight = height;
vec3 localbottom = vec3(0.5, 0, 0);
vec3 worldPosBottom = (iTilePos * tileSize) + (localbottom * tileSize);
vec4 clipbottom = prMatrix * camMatrix * vec4(worldPosBottom, 1.0);
float ndcY = clipbottom.y / clipbottom.w;
vTileNdcY = ndcY * 0.5 + 0.5;
}
)";
inline const char* fragOrderedSet = R"(
#version 330 core
in vec2 vUV;
flat in int vSpriteId;
flat in int vNormalId;
flat in float vTileNdcY;
flat in float layerHeight;
uniform sampler2D atlas;
uniform vec2 spriteCount;
layout(location = 0) out vec4 FragColor;
layout(location = 1) out vec4 FragHeight;
layout(location = 2) out vec4 FragDepth;
void main()
{
float t = (vTileNdcY + 1.0) * 0.5 *0.8;
FragDepth = vec4(t, 0, 0, 1.0);
vec2 tileUVSize = 1.0 / spriteCount;
int cols = int(spriteCount.x);
int sx = vSpriteId % cols;
int sy = vSpriteId / cols;
vec2 atlasOffset = vec2(float(sx), float(sy)) * tileUVSize;
vec2 atlasUV = atlasOffset + (vUV * tileUVSize);
vec4 c = texture(atlas, atlasUV);
if (c.a < 0.01) discard;
float colorScaler = 1 - ((layerHeight - 1) * -1) * 0.3;
c = vec4(c.x * colorScaler,c.y * colorScaler,c.z * colorScaler,c.w);
FragColor = c;
if(vNormalId != -1)
{
int sx2 = vNormalId % cols;
int sy2 = vNormalId / cols;
vec2 atlasOffsetNormal = vec2(float(sx2), float(sy2)) * tileUVSize;
vec2 atlasUVNormal = atlasOffsetNormal + (vUV * tileUVSize);
vec4 cNormal = texture(atlas, atlasUVNormal);
cNormal.w = layerHeight;
FragHeight = cNormal;
}
}
)";

View File

@@ -12,21 +12,21 @@
#define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 1 + 1 + 4) #define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 1 + 1 + 4)
TSE::GLFW::BasicParticleShader* TSE::GLFW::BasicParticleShader::instance = nullptr; TSE::OpenGL::BasicParticleShader* TSE::OpenGL::BasicParticleShader::instance = nullptr;
TSE::GLFW::BasicParticleShader *TSE::GLFW::BasicParticleShader::Instance() TSE::OpenGL::BasicParticleShader *TSE::OpenGL::BasicParticleShader::Instance()
{ {
return instance; return instance;
} }
void TSE::GLFW::BasicParticleShader::Destroy() void TSE::OpenGL::BasicParticleShader::Destroy()
{ {
if(instance != nullptr) if(instance != nullptr)
delete instance; delete instance;
instance = nullptr; instance = nullptr;
} }
void TSE::GLFW::BasicParticleShader::Init(float width, float height) void TSE::OpenGL::BasicParticleShader::Init(float width, float height)
{ {
std::vector<std::unique_ptr<ShaderPart>> parts; std::vector<std::unique_ptr<ShaderPart>> parts;
parts.push_back(ShaderPart::LoadFromString(vertPart, GL_VERTEX_SHADER)); parts.push_back(ShaderPart::LoadFromString(vertPart, GL_VERTEX_SHADER));
@@ -34,18 +34,19 @@ void TSE::GLFW::BasicParticleShader::Init(float width, float height)
instance = new BasicParticleShader(std::move(parts)); instance = new BasicParticleShader(std::move(parts));
} }
TSE::GLFW::BasicParticleShader::BasicParticleShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts) TSE::OpenGL::BasicParticleShader::BasicParticleShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts)
{ {
name = "Basic Unlit Particle Shader";
PackageSize = SHADER_PACKAGE_SIZE; PackageSize = SHADER_PACKAGE_SIZE;
} }
TSE::GLFW::BasicParticleShader::~BasicParticleShader() TSE::OpenGL::BasicParticleShader::~BasicParticleShader()
{ {
if (meshVBO) glDeleteBuffers(1, &meshVBO); if (meshVBO) glDeleteBuffers(1, &meshVBO);
if (meshIBO) glDeleteBuffers(1, &meshIBO); if (meshIBO) glDeleteBuffers(1, &meshIBO);
} }
void TSE::GLFW::BasicParticleShader::SetMesh(const void *verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void *indices, int indexCount, GLenum indexType) void TSE::OpenGL::BasicParticleShader::SetMesh(const void *verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void *indices, int indexCount, GLenum indexType)
{ {
GLint prevVAO = 0, prevArrayBuffer = 0, prevElementBuffer = 0; GLint prevVAO = 0, prevArrayBuffer = 0, prevElementBuffer = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO); glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO);
@@ -86,7 +87,7 @@ void TSE::GLFW::BasicParticleShader::SetMesh(const void *verts, int vertCount, i
glBindVertexArray(prevVAO); glBindVertexArray(prevVAO);
} }
void TSE::GLFW::BasicParticleShader::OnEnable() const void TSE::OpenGL::BasicParticleShader::OnEnable() const
{ {
if (!meshReady) if (!meshReady)
{ {
@@ -128,7 +129,7 @@ void TSE::GLFW::BasicParticleShader::OnEnable() const
glVertexAttribDivisor(SHADER_COLOR_INDEX, 1); glVertexAttribDivisor(SHADER_COLOR_INDEX, 1);
} }
void TSE::GLFW::BasicParticleShader::OnDisable() const void TSE::OpenGL::BasicParticleShader::OnDisable() const
{ {
glDisableVertexAttribArray(SHADER_MESH_INDEX); glDisableVertexAttribArray(SHADER_MESH_INDEX);
glDisableVertexAttribArray(SHADER_POS_INDEX); glDisableVertexAttribArray(SHADER_POS_INDEX);
@@ -137,11 +138,11 @@ void TSE::GLFW::BasicParticleShader::OnDisable() const
glDisableVertexAttribArray(SHADER_COLOR_INDEX); glDisableVertexAttribArray(SHADER_COLOR_INDEX);
} }
void TSE::GLFW::BasicParticleShader::OnFlush() void TSE::OpenGL::BasicParticleShader::OnFlush()
{ {
} }
void TSE::GLFW::BasicParticleShader::OnDrawCall(int indexCount) void TSE::OpenGL::BasicParticleShader::OnDrawCall(int indexCount)
{ {
if (instanceCount <= 0) return; if (instanceCount <= 0) return;
@@ -163,7 +164,7 @@ void TSE::GLFW::BasicParticleShader::OnDrawCall(int indexCount)
instanceCount = 0; instanceCount = 0;
} }
void TSE::GLFW::BasicParticleShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) void TSE::OpenGL::BasicParticleShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd)
{ {
auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE)); auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE));
if (!r) return; if (!r) return;

View File

@@ -5,7 +5,7 @@
#include "Shader.hpp" #include "Shader.hpp"
#include "Types.hpp" #include "Types.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class BasicParticleShader : public Shader class BasicParticleShader : public Shader
{ {

View File

@@ -11,21 +11,21 @@
#define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 4) #define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 4)
TSE::GLFW::BasicShader* TSE::GLFW::BasicShader::instance = nullptr; TSE::OpenGL::BasicShader* TSE::OpenGL::BasicShader::instance = nullptr;
TSE::GLFW::BasicShader *TSE::GLFW::BasicShader::Instance() TSE::OpenGL::BasicShader *TSE::OpenGL::BasicShader::Instance()
{ {
return instance; return instance;
} }
void TSE::GLFW::BasicShader::Destroy() void TSE::OpenGL::BasicShader::Destroy()
{ {
if(instance != nullptr) if(instance != nullptr)
delete instance; delete instance;
instance = nullptr; instance = nullptr;
} }
void TSE::GLFW::BasicShader::Init(float width, float height) void TSE::OpenGL::BasicShader::Init(float width, float height)
{ {
std::vector<std::unique_ptr<ShaderPart>> parts; std::vector<std::unique_ptr<ShaderPart>> parts;
parts.push_back(ShaderPart::LoadFromString(vert, GL_VERTEX_SHADER)); parts.push_back(ShaderPart::LoadFromString(vert, GL_VERTEX_SHADER));
@@ -33,12 +33,13 @@ void TSE::GLFW::BasicShader::Init(float width, float height)
instance = new BasicShader(std::move(parts)); instance = new BasicShader(std::move(parts));
} }
TSE::GLFW::BasicShader::BasicShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts) TSE::OpenGL::BasicShader::BasicShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts)
{ {
name = "Basic Unlit Shader";
PackageSize = SHADER_PACKAGE_SIZE; PackageSize = SHADER_PACKAGE_SIZE;
} }
void TSE::GLFW::BasicShader::OnEnable() const void TSE::OpenGL::BasicShader::OnEnable() const
{ {
glEnableVertexAttribArray(SHADER_VERTEX_INDEX); glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0); glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0);
@@ -46,22 +47,22 @@ void TSE::GLFW::BasicShader::OnEnable() const
glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 3)); glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 3));
} }
void TSE::GLFW::BasicShader::OnDisable() const void TSE::OpenGL::BasicShader::OnDisable() const
{ {
glDisableVertexAttribArray(SHADER_VERTEX_INDEX); glDisableVertexAttribArray(SHADER_VERTEX_INDEX);
glDisableVertexAttribArray(SHADER_COLOR_INDEX); glDisableVertexAttribArray(SHADER_COLOR_INDEX);
} }
void TSE::GLFW::BasicShader::OnFlush() void TSE::OpenGL::BasicShader::OnFlush()
{ {
} }
void TSE::GLFW::BasicShader::OnDrawCall(int indexCount) void TSE::OpenGL::BasicShader::OnDrawCall(int indexCount)
{ {
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL); glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL);
} }
void TSE::GLFW::BasicShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) void TSE::OpenGL::BasicShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd)
{ {
auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE)); auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE));
if (!r) return; if (!r) return;

View File

@@ -2,7 +2,7 @@
#include "Shader.hpp" #include "Shader.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class BasicShader : public Shader class BasicShader : public Shader
{ {
@@ -22,4 +22,4 @@ namespace TSE::GLFW
void OnDrawCall(int indexCount) override; void OnDrawCall(int indexCount) override;
void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override; void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override;
}; };
} // namespace TSE::GLFW } // namespace TSE::OpenGL

View File

@@ -13,22 +13,22 @@
#define SHADER_PACKAGE_SIZE (sizeof(float) * (3 + 4 + 2 + 1)) #define SHADER_PACKAGE_SIZE (sizeof(float) * (3 + 4 + 2 + 1))
TSE::GLFW::BasicTextureShader* TSE::GLFW::BasicTextureShader::instance = nullptr; TSE::OpenGL::BasicTextureShader* TSE::OpenGL::BasicTextureShader::instance = nullptr;
std::map<TSE::uint, float> TSE::GLFW::BasicTextureShader::textureSlots; std::map<TSE::uint, float> TSE::OpenGL::BasicTextureShader::textureSlots;
TSE::GLFW::BasicTextureShader *TSE::GLFW::BasicTextureShader::Instance() TSE::OpenGL::BasicTextureShader *TSE::OpenGL::BasicTextureShader::Instance()
{ {
return instance; return instance;
} }
void TSE::GLFW::BasicTextureShader::Destroy() void TSE::OpenGL::BasicTextureShader::Destroy()
{ {
if(instance != nullptr) if(instance != nullptr)
delete instance; delete instance;
instance = nullptr; instance = nullptr;
} }
void TSE::GLFW::BasicTextureShader::Init(float width, float height) void TSE::OpenGL::BasicTextureShader::Init(float width, float height)
{ {
std::vector<std::unique_ptr<ShaderPart>> parts; std::vector<std::unique_ptr<ShaderPart>> parts;
parts.push_back(ShaderPart::LoadFromString(vertT, GL_VERTEX_SHADER)); parts.push_back(ShaderPart::LoadFromString(vertT, GL_VERTEX_SHADER));
@@ -41,12 +41,13 @@ void TSE::GLFW::BasicTextureShader::Init(float width, float height)
instance->Disable(); instance->Disable();
} }
TSE::GLFW::BasicTextureShader::BasicTextureShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts) TSE::OpenGL::BasicTextureShader::BasicTextureShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts)
{ {
name = "Basic Unlit Texture Shader";
PackageSize = SHADER_PACKAGE_SIZE; PackageSize = SHADER_PACKAGE_SIZE;
} }
void TSE::GLFW::BasicTextureShader::OnEnable() const void TSE::OpenGL::BasicTextureShader::OnEnable() const
{ {
glEnableVertexAttribArray(SHADER_VERTEX_INDEX); glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0); glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0);
@@ -58,7 +59,7 @@ void TSE::GLFW::BasicTextureShader::OnEnable() const
glVertexAttribPointer(SHADER_TID_INDEX, 1, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 9)); glVertexAttribPointer(SHADER_TID_INDEX, 1, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 9));
} }
void TSE::GLFW::BasicTextureShader::OnDisable() const void TSE::OpenGL::BasicTextureShader::OnDisable() const
{ {
glDisableVertexAttribArray(SHADER_VERTEX_INDEX); glDisableVertexAttribArray(SHADER_VERTEX_INDEX);
glDisableVertexAttribArray(SHADER_COLOR_INDEX); glDisableVertexAttribArray(SHADER_COLOR_INDEX);
@@ -66,7 +67,7 @@ void TSE::GLFW::BasicTextureShader::OnDisable() const
glDisableVertexAttribArray(SHADER_TID_INDEX); glDisableVertexAttribArray(SHADER_TID_INDEX);
} }
void TSE::GLFW::BasicTextureShader::OnFlush() void TSE::OpenGL::BasicTextureShader::OnFlush()
{ {
auto it = textureSlots.begin(); auto it = textureSlots.begin();
for (int i = 0; i < textureSlots.size(); i++, it++) for (int i = 0; i < textureSlots.size(); i++, it++)
@@ -76,12 +77,12 @@ void TSE::GLFW::BasicTextureShader::OnFlush()
} }
} }
void TSE::GLFW::BasicTextureShader::OnDrawCall(int indexCount) void TSE::OpenGL::BasicTextureShader::OnDrawCall(int indexCount)
{ {
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL); glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL);
} }
void TSE::GLFW::BasicTextureShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) void TSE::OpenGL::BasicTextureShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd)
{ {
auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE)); auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE));
if (!r) return; if (!r) return;

View File

@@ -4,7 +4,7 @@
#include "Types.hpp" #include "Types.hpp"
#include <map> #include <map>
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class BasicTextureShader : public Shader class BasicTextureShader : public Shader
{ {
@@ -25,4 +25,4 @@ namespace TSE::GLFW
void OnDrawCall(int indexCount) override; void OnDrawCall(int indexCount) override;
void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override; void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override;
}; };
} // namespace TSE::GLFW } // namespace TSE::OpenGL

View File

@@ -10,21 +10,21 @@
#define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 1) #define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 1)
TSE::GLFW::BasicTileMapShader* TSE::GLFW::BasicTileMapShader::instance = nullptr; TSE::OpenGL::BasicTileMapShader* TSE::OpenGL::BasicTileMapShader::instance = nullptr;
TSE::GLFW::BasicTileMapShader *TSE::GLFW::BasicTileMapShader::Instance() TSE::OpenGL::BasicTileMapShader *TSE::OpenGL::BasicTileMapShader::Instance()
{ {
return instance; return instance;
} }
void TSE::GLFW::BasicTileMapShader::Destroy() void TSE::OpenGL::BasicTileMapShader::Destroy()
{ {
if(instance != nullptr) if(instance != nullptr)
delete instance; delete instance;
instance = nullptr; instance = nullptr;
} }
void TSE::GLFW::BasicTileMapShader::Init(float width, float height) void TSE::OpenGL::BasicTileMapShader::Init(float width, float height)
{ {
std::vector<std::unique_ptr<ShaderPart>> parts; std::vector<std::unique_ptr<ShaderPart>> parts;
parts.push_back(ShaderPart::LoadFromString(vertTile, GL_VERTEX_SHADER)); parts.push_back(ShaderPart::LoadFromString(vertTile, GL_VERTEX_SHADER));
@@ -37,18 +37,19 @@ void TSE::GLFW::BasicTileMapShader::Init(float width, float height)
instance->Disable(); instance->Disable();
} }
TSE::GLFW::BasicTileMapShader::BasicTileMapShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts) TSE::OpenGL::BasicTileMapShader::BasicTileMapShader(std::vector<std::unique_ptr<ShaderPart>> &&parts) : Shader(parts)
{ {
name = "Basic Unlit TileMap Shader";
PackageSize = SHADER_PACKAGE_SIZE; PackageSize = SHADER_PACKAGE_SIZE;
} }
TSE::GLFW::BasicTileMapShader::~BasicTileMapShader() TSE::OpenGL::BasicTileMapShader::~BasicTileMapShader()
{ {
if (meshVBO) glDeleteBuffers(1, &meshVBO); if (meshVBO) glDeleteBuffers(1, &meshVBO);
if (meshIBO) glDeleteBuffers(1, &meshIBO); if (meshIBO) glDeleteBuffers(1, &meshIBO);
} }
void TSE::GLFW::BasicTileMapShader::SetMesh(const void *verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void *indices, int indexCount, GLenum indexType) void TSE::OpenGL::BasicTileMapShader::SetMesh(const void *verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void *indices, int indexCount, GLenum indexType)
{ {
GLint prevVAO = 0, prevArrayBuffer = 0, prevElementBuffer = 0; GLint prevVAO = 0, prevArrayBuffer = 0, prevElementBuffer = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO); glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO);
@@ -89,7 +90,7 @@ void TSE::GLFW::BasicTileMapShader::SetMesh(const void *verts, int vertCount, in
glBindVertexArray(prevVAO); glBindVertexArray(prevVAO);
} }
void TSE::GLFW::BasicTileMapShader::OnEnable() const void TSE::OpenGL::BasicTileMapShader::OnEnable() const
{ {
if (!meshReady) if (!meshReady)
{ {
@@ -121,20 +122,20 @@ void TSE::GLFW::BasicTileMapShader::OnEnable() const
glVertexAttribDivisor(SHADER_SPRITE_INDEX, 1); glVertexAttribDivisor(SHADER_SPRITE_INDEX, 1);
} }
void TSE::GLFW::BasicTileMapShader::OnDisable() const void TSE::OpenGL::BasicTileMapShader::OnDisable() const
{ {
glDisableVertexAttribArray(SHADER_MESH_INDEX); glDisableVertexAttribArray(SHADER_MESH_INDEX);
glDisableVertexAttribArray(SHADER_POS_INDEX); glDisableVertexAttribArray(SHADER_POS_INDEX);
glDisableVertexAttribArray(SHADER_SPRITE_INDEX); glDisableVertexAttribArray(SHADER_SPRITE_INDEX);
} }
void TSE::GLFW::BasicTileMapShader::OnFlush() void TSE::OpenGL::BasicTileMapShader::OnFlush()
{ {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, TextureID); glBindTexture(GL_TEXTURE_2D, TextureID);
} }
void TSE::GLFW::BasicTileMapShader::OnDrawCall(int indexCount) void TSE::OpenGL::BasicTileMapShader::OnDrawCall(int indexCount)
{ {
if (instanceCount <= 0) return; if (instanceCount <= 0) return;
SetUniform("spriteCount", &SpriteCount); SetUniform("spriteCount", &SpriteCount);
@@ -158,7 +159,7 @@ void TSE::GLFW::BasicTileMapShader::OnDrawCall(int indexCount)
instanceCount = 0; instanceCount = 0;
} }
void TSE::GLFW::BasicTileMapShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) void TSE::OpenGL::BasicTileMapShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd)
{ {
auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE)); auto* r = dynamic_cast<Renderable*>(t.GetBehaviourScript(RENDERABLE));
if (!r) return; if (!r) return;

View File

@@ -5,7 +5,7 @@
#include "Shader.hpp" #include "Shader.hpp"
#include "Types.hpp" #include "Types.hpp"
namespace TSE::GLFW namespace TSE::OpenGL
{ {
class BasicTileMapShader : public Shader class BasicTileMapShader : public Shader
{ {
@@ -41,4 +41,4 @@ namespace TSE::GLFW
void OnDrawCall(int indexCount) override; void OnDrawCall(int indexCount) override;
void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override; void OnSubmit(const Transformable& t, float*& target, TransformationStack& stack, void (*restartDrawcall)(IRenderer&), IRenderer& rnd) override;
}; };
} // namespace TSE::GLFW } // namespace TSE::OpenGL

View File

@@ -4,32 +4,37 @@
#include "ditheringShader.hpp" #include "ditheringShader.hpp"
#include "basicParticleShader.hpp" #include "basicParticleShader.hpp"
#include "basicTileMapShader.hpp" #include "basicTileMapShader.hpp"
#include "basicOrderedSpriteSetShader.hpp"
#include "elements/ShaderRegistry.hpp" #include "elements/ShaderRegistry.hpp"
void TSE::GLFW::LoadBasicShaders(float width, float height) void TSE::OpenGL::LoadBasicShaders(float width, float height)
{ {
BasicShader::Init(width, height); BasicShader::Init(width, height);
BasicTextureShader::Init(width, height); BasicTextureShader::Init(width, height);
DitheringShader::Init(width, height); DitheringShader::Init(width, height);
BasicParticleShader::Init(width, height); BasicParticleShader::Init(width, height);
BasicTileMapShader::Init(width, height); BasicTileMapShader::Init(width, height);
ShaderRegistry::SetShader("Basic Unlit Shader", BasicShader::Instance()); BasicOrderedSpriteSetShader::Init(width, height);
ShaderRegistry::SetShader("Basic Unlit Texture Shader", BasicTextureShader::Instance()); ShaderRegistry::SetShader(BasicShader::Instance());
ShaderRegistry::SetShader("Basic Unlit Dithering Shader", DitheringShader::Instance()); ShaderRegistry::SetShader(BasicTextureShader::Instance());
ShaderRegistry::SetShader("Basic Unlit Particle Shader", BasicParticleShader::Instance()); ShaderRegistry::SetShader(DitheringShader::Instance());
ShaderRegistry::SetShader("Basic Unlit TileMap Shader", BasicTileMapShader::Instance()); ShaderRegistry::SetShader(BasicParticleShader::Instance());
ShaderRegistry::SetShader(BasicTileMapShader::Instance());
ShaderRegistry::SetShader(BasicOrderedSpriteSetShader::Instance());
} }
void TSE::GLFW::UnLoadBasicShaders() void TSE::OpenGL::UnLoadBasicShaders()
{ {
ShaderRegistry::RemoveShader("Basic Unlit Shader"); ShaderRegistry::RemoveShader("Basic Unlit Shader");
ShaderRegistry::RemoveShader("Basic Unlit Texture Shader"); ShaderRegistry::RemoveShader("Basic Unlit Texture Shader");
ShaderRegistry::RemoveShader("Basic Unlit Dithering Shader"); ShaderRegistry::RemoveShader("Basic Unlit Dithering Shader");
ShaderRegistry::RemoveShader("Basic Unlit Particle Shader"); ShaderRegistry::RemoveShader("Basic Unlit Particle Shader");
ShaderRegistry::RemoveShader("Basic Unlit TileMap Shader"); ShaderRegistry::RemoveShader("Basic Unlit TileMap Shader");
ShaderRegistry::RemoveShader("Basic Ordered Sprite Set Shader");
BasicShader::Destroy(); BasicShader::Destroy();
BasicTextureShader::Destroy(); BasicTextureShader::Destroy();
DitheringShader::Destroy(); DitheringShader::Destroy();
BasicParticleShader::Destroy(); BasicParticleShader::Destroy();
BasicTileMapShader::Destroy(); BasicTileMapShader::Destroy();
BasicOrderedSpriteSetShader::Destroy();
} }

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
namespace TSE::GLFW namespace TSE::OpenGL
{ {
void LoadBasicShaders(float width, float height); void LoadBasicShaders(float width, float height);
void UnLoadBasicShaders(); void UnLoadBasicShaders();

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