Add project files.

This commit is contained in:
det-fys 2023-12-08 18:28:01 +01:00
commit bb6eab5fdb
27 changed files with 2772 additions and 0 deletions

63
.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

368
.gitignore vendored Normal file
View File

@ -0,0 +1,368 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
#TSR
main/

1
README.md Normal file
View File

@ -0,0 +1 @@
# TSR_ECS

2
src/tsr/assets.cpp Normal file
View File

@ -0,0 +1,2 @@
#include "assets.hpp"
std::map<std::string, std::weak_ptr<TSR::Asset>> TSR::AssetMap::s_assets;

49
src/tsr/assets.hpp Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include <string>
#include <map>
#include <memory>
#include <stdexcept>
#include "tsr.hpp"
namespace TSR {
template <class T>
using AssetPtr = std::shared_ptr<T>;
class Asset {
public:
virtual ~Asset() {}
};
class AssetMap {
static std::map<std::string, std::weak_ptr<Asset>> s_assets;
public:
//AssetMap(Game& game_ref) : m_game_ref(game_ref) {}
template <class T>
static AssetPtr<T> Get(const std::string& name) {
try {
AssetPtr<Asset> asset_ptr;
auto asset_it = s_assets.find(name);
if (asset_it == s_assets.end() || asset_it->second.expired()) {
asset_ptr = AssetPtr<Asset>(new T(name)); //std::make_shared<T>(m_fs_ref, name);
s_assets[name] = asset_ptr;
}
else {
asset_ptr = asset_it->second.lock();
}
auto t_ptr = std::dynamic_pointer_cast<T>(asset_ptr);
if (!t_ptr) Throw("(AM) Asset type mismatch");
return t_ptr;
}
catch (std::exception ex) {
Throw(std::string("(AM) Error loading \"") + name + std::string("\":\n") + std::string(ex.what()));
}
}
};
}

81
src/tsr/camera.cpp Normal file
View File

@ -0,0 +1,81 @@
#include "camera.hpp"
#include <algorithm>
using namespace TSR;
void TSR::Camera::UpdateVectors() {
auto yaw_rad = glm::radians(yaw);
auto pitch_rad = glm::radians(pitch);
front_vector = glm::normalize(glm::vec3(cos(yaw_rad) * glm::cos(pitch_rad), glm::sin(pitch_rad), glm::sin(yaw_rad) * glm::cos(pitch_rad)));
forward_backward_vector = glm::normalize(glm::vec3(front_vector.x, 0.0f, front_vector.z));
right_vector = glm::normalize(glm::cross(front_vector, world_up));
up_vector = glm::normalize(glm::cross(right_vector, front_vector));
}
TSR::Camera::Camera(glm::vec3 i_position, float i_movement_speed, float i_mouse_sensitivity, float i_third_person_distance, float i_yaw, float i_pitch) :
position(i_position),
movement_speed(i_movement_speed),
mouse_sensitivity(i_mouse_sensitivity),
third_person_distance(i_third_person_distance),
yaw(i_yaw),
pitch(i_pitch),
world_up(glm::vec3(0.0f, 1.0f, 0.0f))
{
UpdateVectors();
}
glm::mat4 TSR::Camera::GetViewMatrix(bool firstperson) {
float space = 0.3f;
auto dist = firstperson ? 0.0f : third_person_distance;
//if (world) {
// auto to_glm = position - front_vector * (third_person_distance + space);
// auto position_bt = btVector3(position.x, position.y, position.z);
//
// auto to_bt = btVector3(to_glm.x, to_glm.y, to_glm.z);
// btCollisionWorld::ClosestRayResultCallback ray_callback(position_bt, to_bt);
// world->rayTest(position_bt, to_bt, ray_callback);
// if (ray_callback.hasHit()) {
// to_glm.x = ray_callback.m_hitPointWorld.x();
// to_glm.y = ray_callback.m_hitPointWorld.y();
// to_glm.z = ray_callback.m_hitPointWorld.z();
// dist = glm::distance(position, to_glm) - space;
// }
//}
return glm::lookAt(position - front_vector * dist, position + front_vector, up_vector);
}
void TSR::Camera::ProcessMovement(Movement direction, float time) {
float diff = movement_speed * time;
switch (direction) {
case Movement::FORWARD:
position += forward_backward_vector * diff;
break;
case Movement::BACKWARD:
position -= forward_backward_vector * diff;
break;
case Movement::RIGHT:
position += right_vector * diff;
break;
case Movement::LEFT:
position -= right_vector * diff;
break;
case Movement::UP:
position += world_up * diff;
break;
case Movement::DOWN:
position -= world_up * diff;
break;
}
}
void TSR::Camera::ProcessMouse(float x_offset, float y_offset) {
yaw += x_offset * mouse_sensitivity;
//pitch = std::min(89.0f, std::max(-89.0f, pitch + y_offset * mouse_sensitivity));
pitch = std::min(89.9f, std::max(-89.9f, pitch + y_offset * mouse_sensitivity));
UpdateVectors();
}

33
src/tsr/camera.hpp Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
namespace TSR {
class Camera {
glm::vec3 forward_backward_vector;
glm::vec3 world_up;
void UpdateVectors();
public:
glm::vec3 front_vector;
glm::vec3 up_vector;
glm::vec3 right_vector;
enum class Movement { FORWARD, BACKWARD, LEFT, RIGHT, UP, DOWN };
glm::vec3 position;
float yaw;
float pitch;
float movement_speed;
float mouse_sensitivity;
float third_person_distance;
Camera(glm::vec3 i_position = glm::vec3(0.0f), float i_movement_speed = 20.0f, float i_mouse_sensitivity = 0.1f, float i_third_person_distance = 0.0f, float i_yaw = 0.0f, float i_pitch = 0.0f);
glm::mat4 GetViewMatrix(bool firstperson = false);
void ProcessMovement(Movement direction, float time);
void ProcessMouse(float x_offset, float y_offset);
};
}

115
src/tsr/filesystem.cpp Normal file
View File

@ -0,0 +1,115 @@
#include "filesystem.hpp"
#include <fstream>
#include <sstream>
using namespace TSR;
std::filesystem::path Filesystem::s_main_dir;
Filesystem::FileIndex Filesystem::s_file_index;
void Filesystem::NormalizeFileName(std::string& file_name) {
std::transform(file_name.begin(), file_name.end(), file_name.begin(), [](unsigned char c) -> unsigned char {
if (c == '\\') return '/';
return std::tolower(c);
});
}
void Filesystem::Init(const std::string& directory) {
if (!std::filesystem::is_directory(directory)) throw std::runtime_error("(FS) Main directory does not exist!");
s_main_dir = std::filesystem::absolute(directory);
s_file_index.clear();
TsrPrintf("(FS) ---------- INIT ----------\n");
for (auto& p : std::filesystem::recursive_directory_iterator(directory)) {
if (!p.is_regular_file()) continue;
if (p.path().extension() == ".tsrp") {
auto abs_path = std::filesystem::absolute(p.path());
auto abs_path_str = abs_path.string();
try {
auto archive = std::make_shared<libzippp::ZipArchive>(abs_path_str);
archive->open();
auto entries = archive->getEntries();
for (auto& entry : entries) {
if (!entry.isFile()) continue;
std::string name = entry.getName();
NormalizeFileName(name);
if (s_file_index.count(name) > 0 && s_file_index[name] == nullptr) continue;
s_file_index[name] = archive;
}
TsrPrintf("(FS) A %s\n", std::filesystem::relative(p.path(), s_main_dir).string().c_str());
}
catch (...) {
TsrPrintf("Could not open \"%s\"\n", abs_path_str.c_str());
}
}
else {
auto path_str = std::filesystem::relative(p.path(), s_main_dir).string();
NormalizeFileName(path_str);
s_file_index[path_str] = nullptr;
TsrPrintf("(FS) F %s\n", path_str.c_str());
}
}
TsrPrintf("(FS) ---------- FINISHED ----------\n");
}
std::string Filesystem::Read(std::string file_name, bool allow_empty) {
NormalizeFileName(file_name);
if (s_file_index.count(file_name) < 1) {
if (allow_empty)
return std::string();
else
throw std::runtime_error(std::string("(FS) File not found: ") + file_name);
}
auto& archive = s_file_index.at(file_name);
if (archive) { // File is in an archive
auto file = archive->getEntry(file_name, false, false);
if (file.isNull()) throw std::runtime_error("(FS) File is null");
return file.readAsText();
}
else { // File is physical
auto path = s_main_dir / std::filesystem::path(file_name);
std::ifstream t(path, std::ios::binary);
std::stringstream buffer;
buffer << t.rdbuf();
return buffer.str();
}
}
//void TSR::Filesystem::Write(const std::string& name, const std::string& contents) {
// // TODO: implement
//}
void Filesystem::Write(const std::string& name, const std::string& contents) {
std::filesystem::path path = s_main_dir / std::filesystem::path(name);
std::ofstream file(path, std::ios::binary | std::ios::trunc);
if (!file) {
Throw("(FS) Unable to open file for writing: " + name);
}
file << contents;
file.close();
}
std::string Filesystem::CheckFileName(std::string file_name) {
NormalizeFileName(file_name);
auto entry = s_file_index.find(file_name);
if (entry == s_file_index.end() || entry->second != nullptr)
throw std::runtime_error(std::string("(FS) File not found: ") + file_name);
return (s_main_dir / std::filesystem::path(file_name)).string();
}
bool Filesystem::Exists(std::string file_name) {
NormalizeFileName(file_name);
return s_file_index.contains(file_name);
}

32
src/tsr/filesystem.hpp Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include <map>
#include <filesystem>
#include <libzippp/libzippp.h>
#include "tsr.hpp"
namespace TSR {
class Filesystem {
using FileIndex = std::map<std::string, std::shared_ptr<libzippp::ZipArchive>>;
static std::filesystem::path s_main_dir;
static FileIndex s_file_index;
static void NormalizeFileName(std::string& file_name);
public:
static void Init(const std::string& directory);
static const FileIndex& GetFileIndex() {
return s_file_index;
}
static std::string Read(std::string file_name, bool allow_empty = false);
static void Write(const std::string& name, const std::string& contents);
static std::string CheckFileName(std::string file_name);
static bool Exists(std::string file_name);
};
}

159
src/tsr/ia.cpp Normal file
View File

@ -0,0 +1,159 @@
#include "ia.hpp"
using namespace TSR;
class ReadStream {
const char* const m_data;
const char* m_pos;
const char* const m_end;
public:
ReadStream(const char* data, size_t size) : m_data(data), m_pos(data), m_end(m_pos + size) {}
void Seek(size_t pos) {
m_pos = m_data + pos;
if (m_pos > m_end)
throw ParseException("Out of range");
}
template <class T>
const T& Read() {
if (m_pos + sizeof(T) > m_end)
throw ParseException("Out of range");
auto ret_pos = m_pos;
m_pos += sizeof(T);
return *(T*)ret_pos;
}
const void* ReadBlock(size_t size) {
auto start = m_pos;
m_pos += size;
if (m_pos > m_end)
throw ParseException("Out of range");
return start;
}
const char* ReadStr() {
auto start = m_pos;
while (m_pos < m_end) {
if (*(m_pos++) == '\0')
return start;
}
throw ParseException("String not terminated");
}
};
IAData TSR::ParseIA(const std::string& str, std::vector<BoneRef>& bone_list) {
IAData data;
ReadStream rs(str.data(), str.length());
data.is_skeletal = false;
int additional_vertex_size = 0;
auto magic = rs.ReadStr();
if (!strcmp(magic, "IA8"))
data.stride = 8;
else if (!strcmp(magic, "IA2"))
data.stride = 2;
else if (!strcmp(magic, "IA3"))
data.stride = 3;
else if (!strcmp(magic, "SKIA84")) {
data.stride = 8;
data.is_skeletal = true;
additional_vertex_size = 20;
}
else
throw ParseException("Unsupported IA format");
// skip reserved header
rs.Seek(16);
if (data.is_skeletal) {
auto num_bones = rs.Read<uint32_t>();
if (num_bones >= TSR_MAX_BONES)
throw ParseException("Max bones exceeded");
bone_list.resize(num_bones);
for (auto& bone : bone_list) {
bone.name = rs.ReadStr();
bone.offset = rs.Read<glm::mat4>();
}
}
data.num_vertices = rs.Read<uint32_t>();
data.vertices_size = data.num_vertices * (sizeof(float) * data.stride + additional_vertex_size);
data.vertices_ptr = rs.ReadBlock(data.vertices_size);
data.num_indices = rs.Read<uint32_t>();
data.indices_size = data.num_indices * sizeof(uint32_t);
data.indices_ptr = rs.ReadBlock(data.indices_size);
return data;
}
void TSR::ParseSK(const std::string& str, std::vector<BoneInfo>& bone_list) {
ReadStream rs(str.data(), str.length());
auto magic = rs.ReadStr();
if (strcmp(magic, "SK") != 0)
throw ParseException("Unsupported SK format");
// header
rs.Seek(16);
auto num_bones = rs.Read<uint32_t>();
if (num_bones >= TSR_MAX_BONES)
throw ParseException("Max bones exceeded");
bone_list.resize(num_bones);
for (auto& bone : bone_list) {
bone.name = rs.ReadStr();
bone.parent_idx = rs.Read<uint8_t>();
bone.transform = rs.Read<glm::mat4>();
}
}
void TSR::ParseSKAN(const std::string& str, std::vector<SkAnimChannel>& chan_list, size_t& duration, float& tps) {
ReadStream rs(str.data(), str.length());
auto magic = rs.ReadStr();
if (strcmp(magic, "SKAN") != 0)
throw ParseException("Unsupported SKAN format");
// header
rs.Seek(16);
duration = rs.Read<uint32_t>();
tps = rs.Read<float>();
auto num_channels = rs.Read<uint32_t>();
if (num_channels >= TSR_MAX_BONES)
throw ParseException("Max channels exceeded");
chan_list.resize(num_channels);
for (auto& chan : chan_list) {
chan.name = rs.ReadStr();
chan.frames.resize(duration + 1);
for (auto& frame : chan.frames) {
frame.pos = rs.Read<glm::vec3>();
frame.rot = rs.Read<glm::quat>();
frame.scl = rs.Read<glm::vec3>();
}
}
}

57
src/tsr/ia.hpp Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include "tsr.hpp"
// PARSERS
namespace TSR {
class ParseException : public std::exception {
public:
ParseException(const char* what) : std::exception(what) {}
};
struct BoneInfo {
std::string name;
glm::mat4 transform;
int parent_idx;
};
struct BoneRef {
std::string name;
glm::mat4 offset;
};
struct SkAnimFrame {
glm::vec3 pos;
glm::quat rot;
glm::vec3 scl;
};
struct SkAnimChannel {
std::string name;
std::vector<SkAnimFrame> frames;
};
//struct SkAnim {
// std::vector<SkAnimChannel> channels;
// size_t duration;
// float tps;
//};
struct IAData {
size_t stride;
const void* vertices_ptr;
size_t vertices_size;
size_t num_vertices;
const void* indices_ptr;
size_t indices_size;
size_t num_indices;
bool is_skeletal;
};
IAData ParseIA(const std::string& str, std::vector<BoneRef>& bone_list);
void ParseSK(const std::string& str, std::vector<BoneInfo>& bone_list);
void ParseSKAN(const std::string& str, std::vector<SkAnimChannel>& chan_list, size_t& duration, float& tps);
}

128
src/tsr/model.cpp Normal file
View File

@ -0,0 +1,128 @@
#include "model.hpp"
using namespace TSR;
Skeleton::Skeleton(const std::string& name) {
auto sk_str = Filesystem::Read(name);
ParseSK(sk_str, m_bones);
}
int TSR::Skeleton::GetBoneIdByName(const std::string& name) const {
for (int i = 0; i < m_bones.size(); ++i) {
if (m_bones[i].name == name)
return i;
}
return TSR_NO_BONE;
}
SkAnim::SkAnim(const std::string& name) {
auto skan_str = Filesystem::Read(name);
ParseSKAN(skan_str, m_channels, m_duration, m_tps);
}
Model::Model(const std::string& name) {
auto model_str = Filesystem::Read(name);
try {
auto model_json = nlohmann::json::parse(model_str);
if (model_json.contains("skeleton"))
m_skeleton = AssetMap::Get<Skeleton>(model_json.at("skeleton").get<std::string>());
const auto& parts_json = model_json.at("parts"); // .get<std::vector<nlohmann::json>>();
for (const auto& part_json : parts_json) {
std::string type_str("basic");
if (part_json.count("type")) {
const auto& type_json = part_json.at("type");
if (type_json.is_string()) type_json.get_to(type_str);
}
Drawable d;
d.type = RT_BASIC;
d.texture = AssetMap::Get<Texture>(part_json.at("texture").get<std::string>());
d.mesh = AssetMap::Get<Mesh>(part_json.at("mesh").get<std::string>());
d.color = glm::vec3(1.0f);
d.uv_mult = 1.0f;
d.xz_mult = glm::vec2(1.0f);
if (part_json.contains("texture1"))
d.texture1 = AssetMap::Get<Texture>(part_json.at("texture1").get<std::string>());
if (part_json.contains("texture2"))
d.texture2 = AssetMap::Get<Texture>(part_json.at("texture2").get<std::string>());
if (part_json.contains("uv_mult"))
part_json.at("uv_mult").get_to(d.uv_mult);
if (part_json.contains("xz_mult1"))
part_json.at("xz_mult1").get_to(d.xz_mult[0]);
if (part_json.contains("xz_mult2"))
part_json.at("xz_mult2").get_to(d.xz_mult[1]);
// TYPE
if (type_str == "B_DOUBLESIDED") {
d.type = RT_BASIC_DOUBLESIDED;
}
else if (type_str == "UV_TINT_UV") {
d.type = RT_UV_TINT_UV;
}
else if (type_str == "XZ") {
d.type = RT_XZ;
}
else if (type_str == "XZ_XZ_MASK_UV") {
d.type = RT_XZ_XZ_MASK_UV;
}
else if (type_str == "SKELETAL") {
d.type = RT_SKELETAL;
}
// BONE
if (part_json.contains("bone")) {
if (!m_skeleton) Throw("Part is bound to a bone but the model has no skeleton");
d.bone_id = m_skeleton->GetBoneIdByName(part_json.at("bone").get<std::string>());
}
else {
d.bone_id = TSR_NO_BONE;
}
// SKELETAL BONES
if (d.mesh->IsSkeletal()) {
if (!m_skeleton) Throw("Skeletal mesh in a model with no skeleton");
const auto& mesh_bones = d.mesh->GetBones();
for (const auto& bone : mesh_bones) {
d.bone_ids.push_back(m_skeleton->GetBoneIdByName(bone.name));
}
}
m_parts.push_back(d);
if (part_json.contains("name"))
m_part_names.insert({ part_json.at("name").get<std::string>(), m_parts.size() - 1 });
}
const auto& anims_json = model_json.at("animations");
for (const auto& anim_json : anims_json) {
m_animations.push_back(Animation());
auto idx = m_animations.size() - 1;
auto& anim = m_animations[idx];
m_anim_names.insert({ anim_json.at("name").get<std::string>(), idx });
if (anim_json.contains("skel")) {
if (!m_skeleton) Throw("Skeletal animation in a model with no skeleton");
anim.skel = AssetMap::Get<SkAnim>(anim_json.at("skel").get<std::string>());
for (const auto& chan : anim.skel->Channels())
anim.bone_ids.push_back(m_skeleton->GetBoneIdByName(chan.name));
}
// events
}
}
catch (nlohmann::json::exception ex) {
Throw(ex.what());
}
}

65
src/tsr/model.hpp Normal file
View File

@ -0,0 +1,65 @@
#pragma once
#include "assets.hpp"
#include "renderer.hpp"
namespace TSR {
class Skeleton : public Asset {
std::vector<BoneInfo> m_bones;
public:
Skeleton(const std::string& name);
const std::vector<BoneInfo>& Bones() const { return m_bones; }
int GetBoneIdByName(const std::string& name) const;
};
class SkAnim : public Asset {
std::vector<SkAnimChannel> m_channels;
size_t m_duration;
float m_tps;
public:
SkAnim(const std::string& name);
const std::vector<SkAnimChannel>& Channels() const { return m_channels; }
size_t Duration() const { return m_duration; }
float TPS() const { return m_tps; }
};
struct Animation {
AssetPtr<SkAnim> skel;
std::vector<int> bone_ids;
/* events */
};
class Model : public Asset {
AssetPtr<Skeleton> m_skeleton;
std::vector<Drawable> m_parts;
std::map<std::string, int> m_part_names;
std::vector<Animation> m_animations;
std::map<std::string, int> m_anim_names;
public:
Model(const std::string& name);
Model(const Model&) = delete;
Model(Model&&) = delete;
void Draw(Renderer& renderer_ref, const DrawCtx* draw_context_ptr) const {
for (const auto& part : m_parts)
renderer_ref.Add(DrawRef(&part, draw_context_ptr));
}
void DrawInstanced(Renderer& renderer_ref, const DrawCtx* draw_context_ptr) const {
for (const auto& part : m_parts)
renderer_ref.AddInstanced(DrawRef(&part, draw_context_ptr));
}
const Skeleton& GetSkeleton() const { return *m_skeleton; }
int GetAnimId(const std::string& name) { return m_anim_names.at(name); }
const Animation& GetAnim(int id) { return m_animations[id]; }
};
}

585
src/tsr/renderer.cpp Normal file
View File

@ -0,0 +1,585 @@
#include "renderer.hpp"
#include <SOIL2/SOIL2.h>
#include <glm/gtc/type_ptr.hpp>
#include <tuple>
#include "window.hpp"
using namespace TSR;
RenderType Renderer::s_rt_instanced_map[RT_COUNT] = {
RT_NONE, //RT_NONE
RT_BASIC_INSTANCED, //RT_BASIC
RT_BASIC_DOUBLESIDED_INSTANCED, //RT_BASIC_DOUBLESIDED
RT_NONE, //RT_BASIC_INSTANTIATED
RT_NONE, //RT_BASIC_DOUBLESIDED_INSTANTIATED
RT_UV_TINT_UV_INSTANCED, //RT_UV_TINT_UV
RT_NONE, //RT_UV_TINT_UV_INSTANCED
RT_NONE, //RT_XZ
RT_NONE, //RT_XZ_XZ_MASK_UV
RT_NONE, //RT_SKELETAL
RT_NONE, //RT_TRANSLUCENT
};
const char* Shader::s_uniform_names[SU_COUNT] = {
"u_tex", //SU_TEX
"u_tex1", //SU_TEX1
"u_tex2", //SU_TEX2
"u_tex3", //SU_TEX3
"u_tex_pos", //SU_TEX_POS
"u_tex_normal", //SU_TEX_NORMAL
"u_tex_light", //SU_TEX_LIGHT
"u_vp", //SU_VP
"u_mvp", //SU_MVP
"u_model", //SU_MODEL
"u_no_light", //SU_NO_LIGHT
"u_alpha", //SU_ALPHA
"u_sun_color", //SU_SUN_COLOR
"u_sun_direction", //SU_SUN_DIRECTION
"u_ambient_color", //SU_AMBIENT_COLOR
"u_uv_mult", //SU_UV_MULT
"u_xz_mult", //SU_XZ_MULT
"u_bone_transforms",//SU_BONE_TRANSFORMS
};
Texture::Texture(const std::string& name) {
GLint filter_min = GL_LINEAR_MIPMAP_LINEAR;
GLint filter_mag = GL_LINEAR;
GLint wrap_s = GL_REPEAT;
GLint wrap_t = GL_REPEAT;
bool compress = true;
auto config_file = name + ".json";
auto config_string = Filesystem::Read(config_file, true);
if (!config_string.empty()) {
auto j_config = json::parse(config_string);
auto ParseFilterType = [](const std::string& name) {
if (name == "LINEAR")
return GL_LINEAR;
else if (name == "NEAREST")
return GL_NEAREST;
else if (name == "LINEAR_MIPMAP_LINEAR")
return GL_LINEAR_MIPMAP_LINEAR;
else if (name == "LINEAR_MIPMAP_NEAREST")
return GL_LINEAR_MIPMAP_NEAREST;
else if (name == "NEAREST_MIPMAP_LINEAR")
return GL_NEAREST_MIPMAP_LINEAR;
else if (name == "NEAREST_MIPMAP_NEAREST")
return GL_NEAREST_MIPMAP_NEAREST;
else
return GL_LINEAR;
};
if (j_config.contains("filter_min"))
filter_min = ParseFilterType(j_config.at("filter_min").get<std::string>());
if (j_config.contains("filter_mag"))
filter_mag = ParseFilterType(j_config.at("filter_mag").get<std::string>());
if (j_config.contains("dxt_compress"))
j_config.at("dxt_compress").get_to(compress);
if (j_config.contains("repeat_s"))
wrap_s = j_config.at("repeat_s").get<bool>() ? GL_REPEAT : GL_CLAMP_TO_EDGE;
if (j_config.contains("repeat_t"))
wrap_t = j_config.at("repeat_t").get<bool>() ? GL_REPEAT : GL_CLAMP_TO_EDGE;
}
auto image_string = Filesystem::Read(name);
m_id = SOIL_load_OGL_texture_from_memory((const unsigned char*)image_string.c_str(), image_string.size(), SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, compress ? SOIL_FLAG_COMPRESS_TO_DXT : 0);
if (!m_id) throw std::runtime_error("Invalid image format");
glBindTexture(GL_TEXTURE_2D, m_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_min);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_mag);
glGenerateMipmap(GL_TEXTURE_2D);
}
Texture::~Texture() {
glDeleteTextures(1, &m_id);
}
template <class T>
void SetAttribPointer(unsigned int index, int size, size_t stride, const void* pointer) {}
template <>
void SetAttribPointer<GLfloat>(unsigned int index, int size, size_t stride, const void* pointer) {
glVertexAttribPointer(index, size, GL_FLOAT, GL_FALSE, stride, pointer);
}
template <>
void SetAttribPointer<GLubyte>(unsigned int index, int size, size_t stride, const void* pointer) {
glVertexAttribIPointer(index, size, GL_UNSIGNED_BYTE, stride, pointer);
}
template <class... T>
static inline void SetAttribPointersImpl(size_t, size_t, size_t) {}
template <class T, class... T2, class... Size>
static inline void SetAttribPointersImpl(size_t index, size_t offset, size_t stride, size_t size, Size... sizes) {
glEnableVertexAttribArray(index);
SetAttribPointer<T>(index, size, stride, (void*)(offset));
SetAttribPointersImpl<T2...>(index + 1, offset + size * sizeof(T), stride, sizes...);
}
template <class... T, class... Size>
static inline void SetAttribPointers(Size... sizes) {
size_t stride = 0U;
((stride += sizes * sizeof(T)), ...);
SetAttribPointersImpl<T...>(0, 0, stride, sizes...);
}
Mesh::Mesh(const std::string& name) {
auto file_str = Filesystem::Read(name);
auto ia = ParseIA(file_str, m_bones);
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glGenBuffers(1, &m_vbo); // Generate 1 buffer
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, ia.vertices_size, ia.vertices_ptr, GL_STATIC_DRAW);
glGenBuffers(1, &m_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ia.indices_size, ia.indices_ptr, GL_STATIC_DRAW);
m_is_skeletal = ia.is_skeletal;
if (m_is_skeletal) {
if (ia.stride != 8)
Throw("Unsupported SKIA stride");
SetAttribPointers<GLfloat, GLfloat, GLfloat, GLubyte, GLfloat>(3, 2, 3, 4, 4);
}
else {
if (ia.stride == 8)
SetAttribPointers<GLfloat, GLfloat, GLfloat>(3, 2, 3);
else if (ia.stride == 3)
SetAttribPointers<GLfloat>(3);
else if (ia.stride == 2)
SetAttribPointers<GLfloat>(2);
else
Throw("Unsupported IA stride");
}
m_size = ia.num_indices;
}
Mesh::~Mesh() {
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_ebo);
glDeleteVertexArrays(1, &m_vao);
}
InstancedSSBO::InstancedSSBO(const std::vector<BasicDrawCtx>& data) : m_size(data.size()) {
glBindVertexArray(0);
glGenBuffers(1, &m_id);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_id);
glBufferData(GL_SHADER_STORAGE_BUFFER, data.size() * sizeof(BasicDrawCtx), &data[0], GL_STATIC_DRAW);
}
TSR::InstancedSSBO::~InstancedSSBO() {
glDeleteBuffers(1, &m_id);
}
static GLuint CreateShader(const std::string& source_code, GLenum type) {
GLuint id = glCreateShader(type);
const char* c_str = source_code.c_str();
glShaderSource(id, 1, &c_str, NULL);
glCompileShader(id);
GLint is_compiled = 0;
glGetShaderiv(id, GL_COMPILE_STATUS, &is_compiled);
if (is_compiled == GL_FALSE) {
GLint max_length = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &max_length);
std::vector<GLchar> error_log(max_length);
glGetShaderInfoLog(id, max_length, &max_length, &error_log[0]);
glDeleteShader(id);
Throw(std::string("Could not compile shader: " + std::string(error_log.begin(), error_log.end())));
}
return id;
}
static GLuint CreateProgram(GLuint vertex, GLuint fragment) {
GLuint id = glCreateProgram();
glAttachShader(id, vertex);
glAttachShader(id, fragment);
glLinkProgram(id);
GLint is_linked = 0;
glGetProgramiv(id, GL_LINK_STATUS, &is_linked);
if (is_linked == GL_FALSE) {
GLint max_length = 0;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &max_length);
std::vector<GLchar> error_log(max_length);
glGetProgramInfoLog(id, max_length, &max_length, &error_log[0]);
glDeleteProgram(id);
Throw(std::string("Could not link program: " + std::string(error_log.begin(), error_log.end())));
}
return id;
}
Shader::Shader(const std::string& vertex_code, const std::string& fragment_code, const char* nametag) {
GLuint vertex, fragment;
vertex = CreateShader(vertex_code, GL_VERTEX_SHADER);
fragment = CreateShader(fragment_code, GL_FRAGMENT_SHADER);
try {
m_id = CreateProgram(vertex, fragment);
glDeleteShader(vertex);
glDeleteShader(fragment);
}
catch (std::runtime_error& e) {
glDeleteShader(vertex);
glDeleteShader(fragment);
throw;
}
for (int i = 0; i < SU_COUNT; ++i)
m_uniforms[i] = GetUniformLocation(s_uniform_names[i]);
//glBindFragDataLocation(m_id, 0, "FragColor");
TsrPrintf("%s is program %u\n", nametag, m_id);
glUseProgram(0);
}
Shader::~Shader() {
glDeleteProgram(m_id);
}
void FramebuffersWrapper::CreateFramebufferTexture(GLuint& texture, GLint internalformat, GLenum format, GLenum type, GLenum attachment) {
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_width, m_height, 0, format, type, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture, 0);
}
FramebuffersWrapper::FramebuffersWrapper(GLuint width, GLuint height) : m_width(width), m_height(height) {
// G-BUFFER
glGenFramebuffers(1, &m_fb_gb);
glBindFramebuffer(GL_FRAMEBUFFER, m_fb_gb);
CreateFramebufferTexture(m_tex_gb_color, GL_RGBA, GL_RGBA, GL_FLOAT, GL_COLOR_ATTACHMENT0);
CreateFramebufferTexture(m_tex_gb_normal, GL_RGBA16F, GL_RGBA, GL_FLOAT, GL_COLOR_ATTACHMENT1);
CreateFramebufferTexture(m_tex_gb_depth, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH_STENCIL_ATTACHMENT);
const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, buffers);
// Light framebuffer
glGenFramebuffers(1, &m_fb_lights);
glBindFramebuffer(GL_FRAMEBUFFER, m_fb_lights);
CreateFramebufferTexture(m_tex_light_mult, GL_RGBA, GL_RGBA, GL_FLOAT, GL_COLOR_ATTACHMENT0);
//CreateFramebufferTexture(m_tex_light_add, GL_RGBA, GL_RGBA, GL_FLOAT, GL_COLOR_ATTACHMENT1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_tex_gb_depth, 0);
}
FramebuffersWrapper::~FramebuffersWrapper() {
glDeleteTextures(1, &m_tex_gb_color);
glDeleteTextures(1, &m_tex_gb_normal);
glDeleteTextures(1, &m_tex_gb_depth);
glDeleteTextures(1, &m_tex_light_mult);
//glDeleteTextures(1, &m_tex_light_add);
glDeleteFramebuffers(1, &m_fb_gb);
glDeleteFramebuffers(1, &m_fb_lights);
}
Renderer::Renderer() :
m_shader_basic(Filesystem::Read("shaders/basic.vs"), Filesystem::Read("shaders/basic.fs"), "BASIC"),
m_shader_basic_instanced(Filesystem::Read("shaders/basic_instanced.vs"), Filesystem::Read("shaders/basic.fs"), "BASIC_INSTANCED"),
m_shader_uv_tint_uv(Filesystem::Read("shaders/basic.vs"), Filesystem::Read("shaders/uv_tint_uv.fs"), "UV_TINT_UV"),
m_shader_uv_tint_uv_instanced(Filesystem::Read("shaders/basic_instanced.vs"), Filesystem::Read("shaders/uv_tint_uv.fs"), "UV_TINT_UV_INSTANCED"),
m_shader_screen(Filesystem::Read("shaders/deferred_quad.vs"), Filesystem::Read("shaders/deferred_quad.fs"), "SCREEN"),
m_shader_xz(Filesystem::Read("shaders/basic.vs"), Filesystem::Read("shaders/xz.fs"), "XZ"),
m_shader_xz_xz_mask_uv(Filesystem::Read("shaders/basic.vs"), Filesystem::Read("shaders/xz_xz_mask_uv.fs"), "XZ_XZ_MASK_UV"),
m_shader_skeletal(Filesystem::Read("shaders/skeletal.vs"), Filesystem::Read("shaders/skeletal.fs"), "SKELETAL"),
m_proj_matrix(1.0f),
m_view_matrix(1.0f),
m_viewport_buf(AssetMap::Get<Mesh>("viewport.ia2")),
m_last_width(0),
m_last_height(0)
{}
void Renderer::Render(int width, int height) {
if (width && height) {
if (m_last_width != width || m_last_height != height) {
m_fbs.reset();
m_fbs = std::make_unique<FramebuffersWrapper>(width, height);
m_last_width = width;
m_last_height = height;
}
glViewport(0, 0, width, height);
//auto aspect_ratio = (float)width / (float)height;
//glm::vec3 sun_color(0.3f, 0.3f, 0.4f);
//glm::vec3 sun_direction(0.0f, 1.0f, 0.0f);
//glm::vec3 ambient_color = sun_color * 0.6f;//(1.0f, 1.0f, 0.8f);
//glm::vec3 farplane_color(0.1f, 0.1f, 0.2f);
glm::vec3 sun_color(1.0f, 1.0f, 0.8f);
glm::vec3 sun_direction(0.0f, 1.0f, 0.0f);
glm::vec3 ambient_color = sun_color * 0.6f;//(1.0f, 1.0f, 0.8f);
glm::vec3 farplane_color(0.7f, 0.8f, 0.9f);
sun_direction = glm::normalize(glm::vec3(0.5f, 1.0f, 0.7f));
m_fbs->BindGBuffer();
glStencilMask(0xFF);
glClearStencil(0);
glClearColor(farplane_color.r, farplane_color.g, farplane_color.b, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
auto mat_vp = m_proj_matrix * m_view_matrix;
// BASIC & DOUBLESIDED
m_shader_basic.Use();
glUniformMatrix4fv(m_shader_basic.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
glUniform1i(m_shader_basic.U(SU_TEX), 0);
auto DrawListBasic = [&](TSR::RenderType t) {
TSR::Texture* last_texture = nullptr;
glm::mat4 model;
for (const auto& d : m_draw_lists[t]) {
model = d.context->model_matrix;
if (d.drawable->bone_id != TSR_NO_BONE)
model *= d.context->bone_transforms[d.drawable->bone_id];
glUniformMatrix4fv(m_shader_basic.U(SU_MODEL), 1, GL_FALSE, glm::value_ptr(model));
auto texture = d.drawable->texture.get();
if (last_texture != texture) {
glActiveTexture(GL_TEXTURE0);
d.drawable->texture->Bind();
last_texture = texture;
}
d.drawable->mesh->Draw();
}
};
glEnable(GL_CULL_FACE);
DrawListBasic(RT_BASIC);
glDisable(GL_CULL_FACE);
DrawListBasic(RT_BASIC_DOUBLESIDED);
glEnable(GL_CULL_FACE);
// SKELETAL
if (!m_draw_lists[RT_SKELETAL].empty()) {
m_shader_skeletal.Use();
glUniformMatrix4fv(m_shader_skeletal.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
glUniform1i(m_shader_skeletal.U(SU_TEX), 0);
for (const auto& d : m_draw_lists[RT_SKELETAL]) {
glUniformMatrix4fv(m_shader_skeletal.U(SU_MODEL), 1, GL_FALSE, glm::value_ptr(d.context->model_matrix));
const auto& bone_ids = d.drawable->bone_ids;
auto num_bones = bone_ids.size();
const auto& mesh_bones = d.drawable->mesh->GetBones();
m_bone_transforms.resize(num_bones);
for (int i = 0; i < num_bones; ++i) {
m_bone_transforms[i] = d.context->bone_transforms[bone_ids[i]] * mesh_bones[i].offset;
}
glUniformMatrix4fv(m_shader_skeletal.U(SU_BONE_TRANSFORMS), num_bones, GL_FALSE, glm::value_ptr(m_bone_transforms[0]));
auto texture = d.drawable->texture.get();
glActiveTexture(GL_TEXTURE0);
d.drawable->texture->Bind();
d.drawable->mesh->Draw();
}
}
// BASIC & DOUBLESIDED INSTANCED
if (!m_draw_lists[RT_BASIC_INSTANCED].empty() || !m_draw_lists[RT_BASIC_DOUBLESIDED_INSTANCED].empty()) {
m_shader_basic_instanced.Use();
glUniformMatrix4fv(m_shader_basic_instanced.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
glUniform1i(m_shader_basic_instanced.U(SU_TEX), 0);
auto DrawListBasicInstanced = [&](TSR::RenderType t) {
for (const auto& d : m_draw_lists[t]) {
d.context->ssbo->Bind();
glActiveTexture(GL_TEXTURE0);
d.drawable->texture->Bind();
d.drawable->mesh->DrawInstanced(d.context->ssbo->Size());
}
};
glEnable(GL_CULL_FACE);
DrawListBasicInstanced(RT_BASIC_INSTANCED);
glDisable(GL_CULL_FACE);
DrawListBasicInstanced(RT_BASIC_DOUBLESIDED_INSTANCED);
}
glEnable(GL_CULL_FACE);
// UV_TINT_UV
if (!m_draw_lists[RT_UV_TINT_UV].empty()) {
m_shader_uv_tint_uv.Use();
glUniformMatrix4fv(m_shader_uv_tint_uv.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
glUniform1i(m_shader_uv_tint_uv.U(SU_TEX), 0);
glUniform1i(m_shader_uv_tint_uv.U(SU_TEX1), 1);
for (const auto& d : m_draw_lists[RT_UV_TINT_UV]) {
glUniformMatrix4fv(m_shader_basic.U(SU_MODEL), 1, GL_FALSE, glm::value_ptr(d.context->model_matrix));
glUniform1f(m_shader_uv_tint_uv.U(SU_UV_MULT), d.drawable->uv_mult);
glActiveTexture(GL_TEXTURE0);
d.drawable->texture->Bind();
glActiveTexture(GL_TEXTURE1);
d.drawable->texture1->Bind();
d.drawable->mesh->Draw();
}
}
// UV_TINT_UV_INSTANCED
if (!m_draw_lists[RT_UV_TINT_UV_INSTANCED].empty()) {
m_shader_uv_tint_uv_instanced.Use();
glUniformMatrix4fv(m_shader_uv_tint_uv_instanced.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
glUniform1i(m_shader_uv_tint_uv_instanced.U(SU_TEX), 0);
glUniform1i(m_shader_uv_tint_uv_instanced.U(SU_TEX1), 1);
for (const auto& d : m_draw_lists[RT_UV_TINT_UV_INSTANCED]) {
d.context->ssbo->Bind();
glUniform1f(m_shader_uv_tint_uv_instanced.U(SU_UV_MULT), d.drawable->uv_mult);
glActiveTexture(GL_TEXTURE0);
d.drawable->texture->Bind();
glActiveTexture(GL_TEXTURE1);
d.drawable->texture1->Bind();
d.drawable->mesh->DrawInstanced(d.context->ssbo->Size());
}
}
// XZ
if (!m_draw_lists[RT_XZ].empty()) {
m_shader_xz.Use();
glUniformMatrix4fv(m_shader_xz.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
glUniform1i(m_shader_xz.U(SU_TEX), 0);
for (const auto& d : m_draw_lists[RT_XZ]) {
glUniformMatrix4fv(m_shader_basic.U(SU_MODEL), 1, GL_FALSE, glm::value_ptr(d.context->model_matrix));
glUniform2fv(m_shader_xz.U(SU_XZ_MULT), 1, glm::value_ptr(d.drawable->xz_mult));
glActiveTexture(GL_TEXTURE0);
d.drawable->texture->Bind();
d.drawable->mesh->Draw();
}
}
// XZ_XZ_MASK_UV
if (!m_draw_lists[RT_XZ_XZ_MASK_UV].empty()) {
m_shader_xz_xz_mask_uv.Use();
glUniformMatrix4fv(m_shader_xz_xz_mask_uv.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp));
glUniform1i(m_shader_xz_xz_mask_uv.U(SU_TEX), 0);
glUniform1i(m_shader_xz_xz_mask_uv.U(SU_TEX1), 1);
glUniform1i(m_shader_xz_xz_mask_uv.U(SU_TEX2), 2);
for (const auto& d : m_draw_lists[RT_XZ_XZ_MASK_UV]) {
glUniformMatrix4fv(m_shader_basic.U(SU_MODEL), 1, GL_FALSE, glm::value_ptr(d.context->model_matrix));
glUniform2fv(m_shader_xz_xz_mask_uv.U(SU_XZ_MULT), 1, glm::value_ptr(d.drawable->xz_mult));
glActiveTexture(GL_TEXTURE0);
d.drawable->texture->Bind();
glActiveTexture(GL_TEXTURE1);
d.drawable->texture1->Bind();
glActiveTexture(GL_TEXTURE2);
d.drawable->texture2->Bind();
d.drawable->mesh->Draw();
}
}
//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
//glStencilFunc(GL_EQUAL, 0, 0xFF);
//glStencilMask(0x00);
// draw skybox
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
m_shader_screen.Use();
glUniform3f(m_shader_screen.U(SU_AMBIENT_COLOR), ambient_color.r, ambient_color.g, ambient_color.b);
glUniform3f(m_shader_screen.U(SU_SUN_COLOR), sun_color.r, sun_color.g, sun_color.b);
glUniform3f(m_shader_screen.U(SU_SUN_DIRECTION), sun_direction.x, sun_direction.y, sun_direction.z);
glUniform1i(m_shader_screen.U(SU_TEX), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_fbs->GetGBColor());
glUniform1i(m_shader_screen.U(SU_TEX_POS), 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_fbs->GetGBDepth());
glUniform1i(m_shader_screen.U(SU_TEX_NORMAL), 2);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, m_fbs->GetGBNormal());
glUniform1i(m_shader_screen.U(SU_TEX_LIGHT), 3);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, m_fbs->GetLightMult());
m_viewport_buf->Draw();
}
for (int i = 0; i < RT_COUNT; ++i)
m_draw_lists[i].clear();
}

317
src/tsr/renderer.hpp Normal file
View File

@ -0,0 +1,317 @@
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>
#include <memory>
#include "filesystem.hpp"
#include "assets.hpp"
#include "ia.hpp"
namespace TSR {
enum RenderType {
RT_NONE,
RT_BASIC,
RT_BASIC_DOUBLESIDED,
RT_BASIC_INSTANCED,
RT_BASIC_DOUBLESIDED_INSTANCED,
RT_UV_TINT_UV,
RT_UV_TINT_UV_INSTANCED,
RT_XZ,
RT_XZ_XZ_MASK_UV,
RT_SKELETAL,
RT_TRANSLUCENT,
RT_COUNT
};
class Texture : public Asset {
GLuint m_id;
public:
Texture(const std::string& name);
Texture(const Texture&) = delete;
Texture(Texture&&) = delete;
~Texture();
void Bind() const { glBindTexture(GL_TEXTURE_2D, m_id); }
GLuint GetRawId() const { return m_id; }
};
class Mesh : public Asset {
GLuint m_vao;
GLuint m_vbo;
GLuint m_ebo;
GLuint m_size;
bool m_is_skeletal;
std::vector<BoneRef> m_bones;
public:
Mesh(const std::string& name);
Mesh(const Mesh&) = delete;
Mesh(Mesh&&) = delete;
~Mesh();
void Draw() const {
glBindVertexArray(m_vao);
glDrawElements(GL_TRIANGLES, m_size, GL_UNSIGNED_INT, 0);
}
void DrawInstanced(size_t num) const {
glBindVertexArray(m_vao);
glDrawElementsInstanced(GL_TRIANGLES, m_size, GL_UNSIGNED_INT, 0, num);
}
bool IsSkeletal() const {
return m_is_skeletal;
}
const std::vector<BoneRef>& GetBones() const {
return m_bones;
}
};
struct Drawable {
RenderType type;
AssetPtr<Mesh> mesh;
AssetPtr<Texture> texture;
AssetPtr<Texture> texture1;
AssetPtr<Texture> texture2;
glm::vec3 color;
float uv_mult;
glm::vec2 xz_mult;
int bone_id;
std::vector<int> bone_ids;
};
struct BasicDrawCtx {
glm::mat4 model_matrix;
glm::vec4 colors[4];
};
class InstancedSSBO {
GLuint m_id;
size_t m_size;
public:
InstancedSSBO(const std::vector<BasicDrawCtx>& data);
void Bind() const {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_id);
}
size_t Size() const { return m_size; }
~InstancedSSBO();
};
struct DrawCtx : public BasicDrawCtx {
std::unique_ptr<InstancedSSBO> ssbo;
glm::mat4* bone_transforms;
//std::vector<glm::mat4> bone_transforms;
};
struct DrawRef {
const Drawable* drawable;
const DrawCtx* context;
DrawRef(const Drawable* drawable, const DrawCtx* context) : drawable(drawable), context(context) {}
};
enum ShaderUniform {
SU_TEX,
SU_TEX1,
SU_TEX2,
SU_TEX3,
SU_TEX_POS,
SU_TEX_NORMAL,
SU_TEX_LIGHT,
SU_VP,
SU_MVP,
SU_MODEL,
SU_NO_LIGHT,
SU_ALPHA,
SU_SUN_COLOR,
SU_SUN_DIRECTION,
SU_AMBIENT_COLOR,
SU_UV_MULT,
SU_XZ_MULT,
SU_BONE_TRANSFORMS,
SU_COUNT
};
class Shader {
protected:
GLuint m_id;
std::string m_nametag;
static const char* s_uniform_names[SU_COUNT];
GLuint m_uniforms[SU_COUNT];
GLuint GetUniformLocation(const char* name) const {
return glGetUniformLocation(m_id, name);
}
public:
Shader(const std::string& vertex_code, const std::string& fragment_code, const char* nametag = "");
Shader(const Shader&) = delete;
Shader(Shader&&) = delete;
~Shader();
void Use() const {
glUseProgram(m_id);
}
GLuint U(ShaderUniform uni) const {
return m_uniforms[uni];
}
};
//class SceneShader : public Shader {
//public:
// const GLuint u_tex;
// const GLuint u_model;
// const GLuint u_view;
// const GLuint u_proj;
// const GLuint u_no_light;
// const GLuint u_alpha;
// SceneShader(const std::string& vertex_code, const std::string& fragment_code, const char* nametag) :
// Shader(vertex_code, fragment_code, nametag),
// u_tex(GetUniformLocation("u_tex")),
// u_model(GetUniformLocation("u_model")),
// u_view(GetUniformLocation("u_view")),
// u_proj(GetUniformLocation("u_proj")),
// u_no_light(GetUniformLocation("u_no_light")),
// u_alpha(GetUniformLocation("u_alpha"))
// {}
//};
//class ScreenShader : public Shader {
//public:
// const GLuint u_tex;
// const GLuint u_tex_pos;
// const GLuint u_tex_normal;
// const GLuint u_tex_light;
// const GLuint u_sun_color;
// const GLuint u_sun_direction;
// const GLuint u_ambient_color;
// ScreenShader(const std::string& vertex_code, const std::string& fragment_code, const char* nametag) :
// Shader(vertex_code, fragment_code, nametag),
// u_tex(GetUniformLocation("u_tex")),
// u_tex_pos(GetUniformLocation("u_tex_pos")),
// u_tex_normal(GetUniformLocation("u_tex_normal")),
// u_tex_light(GetUniformLocation("u_tex_light")),
// u_sun_color(GetUniformLocation("u_sun_color")),
// u_sun_direction(GetUniformLocation("u_sun_direction")),
// u_ambient_color(GetUniformLocation("u_ambient_color"))
// {}
//};
class FramebuffersWrapper {
const GLuint m_width;
const GLuint m_height;
GLuint m_fb_gb;
GLuint m_tex_gb_color;
GLuint m_tex_gb_normal;
GLuint m_tex_gb_depth;
GLuint m_fb_lights;
GLuint m_tex_light_mult;
GLuint m_tex_light_add;
void CreateFramebufferTexture(GLuint& texture, GLint internalformat, GLenum format, GLenum type, GLenum attachment);
public:
FramebuffersWrapper(GLuint width, GLuint height);
~FramebuffersWrapper();
void BindGBuffer() const {
glBindFramebuffer(GL_FRAMEBUFFER, m_fb_gb);
}
void BindLightBuffer() const {
glBindFramebuffer(GL_FRAMEBUFFER, m_fb_lights);
}
GLuint GetGBColor() const {
return m_tex_gb_color;
}
GLuint GetGBNormal() const {
return m_tex_gb_normal;
}
GLuint GetGBDepth() const {
return m_tex_gb_depth;
}
GLuint GetLightMult() const {
return m_tex_light_mult;
}
};
class Renderer {
static RenderType s_rt_instanced_map[RT_COUNT];
std::vector<DrawRef> m_draw_lists[RT_COUNT];
Shader m_shader_basic;
Shader m_shader_basic_instanced;
Shader m_shader_uv_tint_uv;
Shader m_shader_uv_tint_uv_instanced;
Shader m_shader_xz;
Shader m_shader_xz_xz_mask_uv;
Shader m_shader_screen;
Shader m_shader_skeletal;
//float m_aspect_ratio;
std::unique_ptr<FramebuffersWrapper> m_fbs;
std::shared_ptr<Mesh> m_viewport_buf;
int m_last_width, m_last_height;
std::vector<glm::mat4> m_bone_transforms;
public:
glm::mat4 m_proj_matrix;
glm::mat4 m_view_matrix;
Renderer();
void Add(const DrawRef& draw_ref) {
m_draw_lists[draw_ref.drawable->type].push_back(draw_ref);
}
void AddInstanced(const DrawRef& draw_ref) {
m_draw_lists[s_rt_instanced_map[draw_ref.drawable->type]].push_back(draw_ref);
}
void SetViewMatrix(const glm::mat4& view_matrix) {
m_view_matrix = view_matrix;
}
void SetProjectionMatrix(const glm::mat4& proj_matrix) {
m_proj_matrix = proj_matrix;
}
void SetProjection(float aspect_ratio, float fov, float nearplane, float farplane) {
SetProjectionMatrix(glm::perspective(glm::radians(fov * 0.5f), aspect_ratio, nearplane, farplane));
}
void Render(int width, int height);
};
}

26
src/tsr/rendersystem.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "rendersystem.hpp"
using namespace TSR;
void RenderSystem::Render(TSR::Renderer& renderer) {
//auto v = World::Registry().view<ModelComponent, TransformComponent>();
//for (auto [ent, mesh, render, trans] : v.each()) {
// render.ctx.m_model_matrix = glm::toMat4(trans.rot) * glm::translate(glm::mat4(1.0f), trans.pos);
//
// for (auto& drawable : mesh.parts)
// renderer.Add(TSR::DrawRef(&drawable, &render.ctx));
//}
//entt::view<MeshComponent> v(World::Get().Reg());
//World::Get().Reg()
}

25
src/tsr/rendersystem.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "systems.hpp"
#include <vector>
#include "../tsr/renderer.hpp"
namespace TSR {
struct ModelComponent {
TSR::DrawCtx ctx;
std::vector<glm::mat4> bone_transforms;
};
class RenderSystem {
public:
static void Render(TSR::Renderer& renderer);
};
}

3
src/tsr/systems.hpp Normal file
View File

@ -0,0 +1,3 @@
#pragma once
#include <entt/entt.hpp>
#include "world.hpp"

45
src/tsr/tsr.hpp Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#include <iostream>
#include <string>
#include <stdexcept>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <nlohmann/json.hpp>
// log
#ifdef TSR_ADVANCED_LOG
#define TsrFPrintf(file, format, ...) fprintf(file, "[%s] " format, __func__, __VA_ARGS__)
#define TsrErrorf(format, ...) TsrFPrintf(stderr, format, __VA_ARGS__)
#define TsrPrintf(format, ...) TsrFPrintf(stdout, format, __VA_ARGS__)
#else
#define TsrErrorf printf
#define TsrPrintf printf
#endif
#define TSR_NO_BONE 255
#define TSR_MAX_BONES TSR_NO_BONE
#define U8(_S) (const char*)u8##_S
namespace TSR {
using std::string_literals::operator""s;
using namespace nlohmann;
inline void Throw(const std::string& msg) {
throw std::runtime_error(msg);
}
template <size_t size>
inline glm::vec<size, float> JsonGetVec(json j) {
glm::vec<size, float> ret;
for (int i = 0; i < size; ++i)
ret[i] = j[i];
return ret;
}
}

90
src/tsr/window.cpp Normal file
View File

@ -0,0 +1,90 @@
#include "window.hpp"
#include <stdexcept>
#include "tsr.hpp"
GLFWwindow* TSR::Window::s_window = nullptr;
int TSR::Window::s_window_dimensions[4];
void TSR::Window::Init(const char* title, int width, int height) {
s_window_dimensions[0] = 0;
s_window_dimensions[1] = 0;
s_window_dimensions[2] = width;
s_window_dimensions[3] = height;
TsrPrintf("GLFW init\n");
if (!glfwInit()) Throw("Could not init GLFW!");
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_MAXIMIZED, GL_TRUE);
glfwWindowHint(GLFW_DEPTH_BITS, 0);
//glfwWindowHint(GLFW_DEPTH_BITS, 0);
glfwWindowHint(GLFW_STENCIL_BITS, 0);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
s_window = glfwCreateWindow(width, height, title, nullptr, nullptr);
if (!s_window) {
glfwTerminate();
Throw("Could not create GLFW window!");
}
glfwMakeContextCurrent(s_window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
glfwDestroyWindow(s_window);
glfwTerminate();
Throw("Could not init GLEW!");
}
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param) {
if (type == GL_DEBUG_TYPE_OTHER) return;
printf("GL DEBUG: %s\n", message);
}, nullptr);
glfwSwapInterval(1);
//glfwSetWindowUserPointer(s_window, this);
//glfwSetKeyCallback(m_window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
// ((Window*)glfwGetWindowUserPointer(window))->m_key_cb(key, scancode, action, mods);
//});
//glfwSetCursorPosCallback(m_window, [](GLFWwindow* window, double x, double y) {
// ((Window*)glfwGetWindowUserPointer(window))->m_mouse_cb(x, y);
//});
//glfwSetFramebufferSizeCallback(m_window, [](GLFWwindow* window, int width, int height) {
// ((Window*)glfwGetWindowUserPointer(window))->m_size_cb(width, height);
//});
}
void TSR::Window::Close() {
if (s_window) {
glfwDestroyWindow(s_window);
glfwTerminate();
}
}
void TSR::Window::SwitchFullscreen() {
if (glfwGetWindowMonitor(s_window) != nullptr) {
glfwSetWindowMonitor(s_window, nullptr, s_window_dimensions[0], s_window_dimensions[1], s_window_dimensions[2], s_window_dimensions[3], 0);
}
else {
glfwGetWindowPos(s_window, &s_window_dimensions[0], &s_window_dimensions[1]);
glfwGetWindowSize(s_window, &s_window_dimensions[2], &s_window_dimensions[3]);
const GLFWvidmode* vm = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowMonitor(s_window, glfwGetPrimaryMonitor(), 0, 0, vm->width, vm->height, vm->refreshRate);
}
}
//
//void GLAPIENTRY TSR::Window::DebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param) {
// Tsr()->OnWindowMessage(std::string(message));
//}

72
src/tsr/window.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <functional>
namespace TSR {
class Window {
//using KeyCallback = std::function<void(int, int, int, int)>;
//using MouseCallback = std::function<void(double, double)>;
//using SizeCallback = std::function<void(int, int)>;
static GLFWwindow* s_window;
static int s_window_dimensions[4];
public:
//KeyCallback m_key_cb;
//MouseCallback m_mouse_cb;
//SizeCallback m_size_cb;
//Window(const char* title, int width, int height);
static void Init(const char* title, int width, int height);
static void Close();
static void Show() { glfwShowWindow(s_window); }
static void Hide() { glfwHideWindow(s_window); }
static void SwitchFullscreen();
static bool ShouldClose() { return glfwWindowShouldClose(s_window); }
static void SetShouldClose(int value) { glfwSetWindowShouldClose(s_window, value); }
static bool KeyDown(int key) { return glfwGetKey(s_window, key) == GLFW_PRESS; }
static void SetInputMode(int mode, int value) { glfwSetInputMode(s_window, mode, value); }
static void GetFramebufferSize(int& width, int& height) { glfwGetFramebufferSize(s_window, &width, &height); }
static void GetMousePos(double& x, double& y) { glfwGetCursorPos(s_window, &x, &y); }
static void PollEvents() { glfwPollEvents(); }
static void SwapBuffers() { glfwSwapBuffers(s_window); }
static GLFWwindow* Ptr() { return s_window; }
static GLFWkeyfun SetKeyCallback(GLFWkeyfun callback) { return glfwSetKeyCallback(s_window, callback); }
static GLFWmousebuttonfun SetMouseButtonCallback(GLFWmousebuttonfun callback) { return glfwSetMouseButtonCallback(s_window, callback); }
static GLFWcursorposfun SetCursorPosCallback(GLFWcursorposfun callback) { return glfwSetCursorPosCallback(s_window, callback); }
//static void SetKeyCallback(KeyCallback cb) {
// m_key_cb = cb;
//}
//static void SetMouseCallback(MouseCallback cb) {
// m_mouse_cb = cb;
//}
//static void SetSizeCallback(SizeCallback cb) {
// m_size_cb = cb;
//}
//static void GLAPIENTRY DebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param);
//static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
//static void MouseMoveCallback(GLFWwindow* window, double x, double y);
//static void SizeCallback(GLFWwindow* window, int width, int height);
//Window(Window const&) = delete;
//Window(Window&&) = delete;
//~Window();
};
class WindowWrapper {
public:
WindowWrapper(const char* title, int width, int height) { Window::Init(title, width, height); }
~WindowWrapper() { Window::Close(); }
};
}

6
src/tsr/world.cpp Normal file
View File

@ -0,0 +1,6 @@
#include "world.hpp"
using namespace TSR;
//std::unique_ptr<World> World::s_world;
entt::registry World::s_registry;

33
src/tsr/world.hpp Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/quaternion.hpp>
#include <memory>
#include <entt/entt.hpp>
namespace TSR {
struct TransformComponent {
glm::vec3 pos;
glm::quat rot;
};
class World {
static entt::registry s_registry;
//entt::registry m_reg;
public:
static entt::registry& Registry() {
return s_registry;
}
};
}

143
src/tsrecs.cpp Normal file
View File

@ -0,0 +1,143 @@
#include <iostream>
#include <fstream>
#include "tsr/filesystem.hpp"
#include "tsr/window.hpp"
#include "tsr/renderer.hpp"
#include "tsr/model.hpp"
#include "tsr/camera.hpp"
#include <windows.h>
using namespace TSR;
Camera cam;
int main() {
TsrPrintf("Hello (client)\n");
try {
Filesystem::Init("main");
WindowWrapper ww("TSR test", 640, 480);
////Audio::Init();
Renderer r;
auto model = AssetMap::Get<Model>("models/test_skeletal.mdl.json");
DrawCtx draw_ctx;
draw_ctx.model_matrix = glm::mat4(1.0f);
std::vector<glm::mat4> bone_transforms;
bone_transforms.resize(model->GetSkeleton().Bones().size());
draw_ctx.bone_transforms = &bone_transforms[0];
auto anim_id = model->GetAnimId("ruce");
const auto& anim = model->GetAnim(anim_id);
const auto& skel = model->GetSkeleton();
const auto& sk_bones = skel.Bones();
//glfwSwapInterval(0);
Window::SetInputMode(GLFW_CURSOR, GLFW_CURSOR_DISABLED);
Window::SetCursorPosCallback([](GLFWwindow* window, double xpos, double ypos) {
static float last_mouse_x = 0.0f, last_mouse_y = 0.0f;
double xoffset = xpos - last_mouse_x;
double yoffset = last_mouse_y - ypos; // reversed since y-coordinates range from bottom to top
cam.ProcessMouse(xoffset, yoffset);
last_mouse_x = xpos;
last_mouse_y = ypos;
});
cam.movement_speed *= 0.1f;
Window::Show();
while (!Window::ShouldClose()) {
float time = 1.0f / 75.0f;
if (Window::KeyDown(GLFW_KEY_W))
cam.ProcessMovement(Camera::Movement::FORWARD, time);
if (Window::KeyDown(GLFW_KEY_S))
cam.ProcessMovement(Camera::Movement::BACKWARD, time);
if (Window::KeyDown(GLFW_KEY_A))
cam.ProcessMovement(Camera::Movement::LEFT, time);
if (Window::KeyDown(GLFW_KEY_D))
cam.ProcessMovement(Camera::Movement::RIGHT, time);
if (Window::KeyDown(GLFW_KEY_SPACE))
cam.ProcessMovement(Camera::Movement::UP, time);
if (Window::KeyDown(GLFW_KEY_LEFT_SHIFT))
cam.ProcessMovement(Camera::Movement::DOWN, time);
int w, h;
Window::GetFramebufferSize(w, h);
r.SetProjection((float)w / (float)h, 90.0f, 0.1f, 1000.0f);
//r.SetViewMatrix(glm::lookAt(glm::vec3(-1.0f, 2.0f, 2.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)));
r.SetViewMatrix(cam.GetViewMatrix());
//r.SetViewMatrix(glm::lookAt(glm::vec3(10.0f, 5.0f, 3.0f), glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)));
// reset bones
for (int i = 0; i < bone_transforms.size(); ++i) {
bone_transforms[i] = sk_bones[i].transform;
}
// animation
float cur_frame = glm::mod((float)(glfwGetTime() * anim.skel->TPS()), (float)anim.skel->Duration());
//float cur_frame = glm::mod(1.0f, 3.0f);
for (int i = 0; i < anim.skel->Channels().size(); ++i) {
int fr1 = glm::floor(cur_frame);
int fr2 = glm::ceil(cur_frame);
float t = glm::fract(cur_frame);
const auto& frame1 = anim.skel->Channels()[i].frames[fr1];
const auto& frame2 = anim.skel->Channels()[i].frames[fr2];
auto translation = glm::translate(glm::mat4(1.0f), glm::mix(frame1.pos, frame2.pos, t));
auto rotation = glm::toMat4(glm::normalize(glm::slerp(frame1.rot, frame2.rot, t)));
auto scale = glm::scale(glm::mat4(1.0f), glm::mix(frame1.scl, frame2.scl, t));
bone_transforms[anim.bone_ids[i]] = translation * rotation * scale;
}
// apply parents
for (int i = 0; i < bone_transforms.size(); ++i) {
if (sk_bones[i].parent_idx != TSR_NO_BONE)
bone_transforms[i] = bone_transforms[sk_bones[i].parent_idx] * bone_transforms[i];
}
model->Draw(r, &draw_ctx);
r.Render(w, h);
Window::PollEvents();
Window::SwapBuffers();
}
//Client::Run();
}
catch (std::exception ex) {
TsrPrintf("ERROR: %s\n", ex.what());
MessageBoxA(NULL, ex.what(), "ERROR", MB_ICONERROR);
}
//Audio::Close();
return 0;
}

31
tsrecs.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33829.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tsrecs", "tsrecs.vcxproj", "{636143B5-5296-4E48-813E-6FE5EB883870}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{636143B5-5296-4E48-813E-6FE5EB883870}.Debug|x64.ActiveCfg = Debug|x64
{636143B5-5296-4E48-813E-6FE5EB883870}.Debug|x64.Build.0 = Debug|x64
{636143B5-5296-4E48-813E-6FE5EB883870}.Debug|x86.ActiveCfg = Debug|Win32
{636143B5-5296-4E48-813E-6FE5EB883870}.Debug|x86.Build.0 = Debug|Win32
{636143B5-5296-4E48-813E-6FE5EB883870}.Release|x64.ActiveCfg = Release|x64
{636143B5-5296-4E48-813E-6FE5EB883870}.Release|x64.Build.0 = Release|x64
{636143B5-5296-4E48-813E-6FE5EB883870}.Release|x86.ActiveCfg = Release|Win32
{636143B5-5296-4E48-813E-6FE5EB883870}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {96A7D133-9A25-473C-B402-A0DB0C48E308}
EndGlobalSection
EndGlobal

159
tsrecs.vcxproj Normal file
View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{636143b5-5296-4e48-813e-6fe5eb883870}</ProjectGuid>
<RootNamespace>tsrecs</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\tsr\camera.cpp" />
<ClCompile Include="src\tsr\model.cpp" />
<ClCompile Include="src\tsr\rendersystem.cpp" />
<ClCompile Include="src\tsr\world.cpp" />
<ClCompile Include="src\tsr\assets.cpp" />
<ClCompile Include="src\tsr\filesystem.cpp" />
<ClCompile Include="src\tsr\ia.cpp" />
<ClCompile Include="src\tsr\renderer.cpp" />
<ClCompile Include="src\tsr\window.cpp" />
<ClCompile Include="src\tsrecs.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\tsr\camera.hpp" />
<ClInclude Include="src\tsr\model.hpp" />
<ClInclude Include="src\tsr\rendersystem.hpp" />
<ClInclude Include="src\tsr\systems.hpp" />
<ClInclude Include="src\tsr\world.hpp" />
<ClInclude Include="src\tsr\assets.hpp" />
<ClInclude Include="src\tsr\filesystem.hpp" />
<ClInclude Include="src\tsr\ia.hpp" />
<ClInclude Include="src\tsr\renderer.hpp" />
<ClInclude Include="src\tsr\tsr.hpp" />
<ClInclude Include="src\tsr\window.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

84
tsrecs.vcxproj.filters Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\tsrecs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\renderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\window.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\assets.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\filesystem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\ia.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\world.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\rendersystem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\model.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tsr\camera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\tsr\window.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\renderer.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\ia.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\assets.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\filesystem.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\tsr.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\world.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\rendersystem.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\systems.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\model.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tsr\camera.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>