diff --git a/win/.gitignore b/win/.gitignore
new file mode 100644
index 0000000..296f0ee
--- /dev/null
+++ b/win/.gitignore
@@ -0,0 +1,362 @@
+## 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/
+[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
\ No newline at end of file
diff --git a/win/README.md b/win/README.md
new file mode 100644
index 0000000..73f1ecc
--- /dev/null
+++ b/win/README.md
@@ -0,0 +1,49 @@
+
+# TinyEngine - Windows Port
+Tiny OpenGL3 based 2D/3D Engine / Wrapper in C++
+This port will allow you to compile TinyEngine and its examples on Windows.
+
+## About
+The original TinyEngine source remains unchanged for the Windows port as it was already written in a portable manner. The exception to this is TinyEngine.h which has 3 #include's added to fix compile errors. The original TinyEngine.h is untouched and the modified copy is in the "win/TinyEngineWin" directory.
+
+All 11 example projects (as of 01/12/2020) have been included in one Visual Studio solution file, with each example in its own project. An extra template project (x_Name Template) is included and can easily be duplicated and renamed to create a new project with the minimum number of files needed to compile. In most instances the example code was copied verbatim, with only changes to relative include paths necessary. 6_Tree required some extra work to fix a vector subscript out of range error, but only differs by around 10 lines.
+
+All examples were built with Visual Studio Community 2019, version 16.8.2, against the C++ 17 compiler.
+
+## Preparing your environment
+
+As I have been away from C++ for a while I thought now would be a good time to try vcpkg. I was impressed by how easy it was to use and recommend utilising it to set up your environment. The following steps will walk you through the process of installing vcpkg and the necessary dependencies.
+
+### Installing vcpkg
+Follow the instructions at https://docs.microsoft.com/en-us/cpp/build/vcpkg?view=msvc-160#installation to clone the vcpkg repository and bootstrap it.
+
+Make sure to follow the integration instructions at https://docs.microsoft.com/en-us/cpp/build/vcpkg?view=msvc-160#installation on a per-user basis so that include paths are resolved automagically.
+
+### Installing dependencies
+The following packages need to be installed to compile TinyEngine and the examples. This can be done from a Developer Power Shell in Visual Studio. Make sure you change to the directory where the vcpkg binary resides.
+
+#### SDL2:
+ ./vcpkg install sdl2:x86-windows
+ ./vcpkg install sdl2-image:x86-windows
+ ./vcpkg install sdl2-ttf:x86-windows
+ ./vcpkg install sdl2-mixer:x86-windows
+
+#### GLEW
+ ./vcpkg install glew:x86-windows
+
+#### GLM
+ ./vcpkg install glm:x86-windows
+
+#### Boost Filesystem
+ ./vcpkg install boost-filesystem:x86-windows
+
+#### Libnoise
+ ./vcpkg install libnoise:x86-windows
+
+### SDL2 path environment variable
+The Visual Studio project makes use of an environment variable named SDL2_DIR. You'll either need to set this environment variable or the projects will fail to link. SDL2 was installed into the vcpkg directory in a previous step, the path will be something similar to
+
+ C:\vcpkg\packages\sdl2_x86-windows
+
+## Trying out the examples
+Open the TinyEngineWin.sln solution file in the "win/TinyEngineWin" directory, set whichever example you want to launch as your startup project, then build and run. If you have any issues please open an issue and I'll do my best to help you resolve it.
\ No newline at end of file
diff --git a/win/TinyEngineWin/0_Empty/0_Empty.vcxproj b/win/TinyEngineWin/0_Empty/0_Empty.vcxproj
new file mode 100644
index 0000000..47fd449
--- /dev/null
+++ b/win/TinyEngineWin/0_Empty/0_Empty.vcxproj
@@ -0,0 +1,184 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {2abad29b-e604-4684-8308-c7f8ab4f5930}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/0_Empty/0_Empty.vcxproj.filters b/win/TinyEngineWin/0_Empty/0_Empty.vcxproj.filters
new file mode 100644
index 0000000..bb0f3dd
--- /dev/null
+++ b/win/TinyEngineWin/0_Empty/0_Empty.vcxproj.filters
@@ -0,0 +1,69 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/0_Empty/main.cpp b/win/TinyEngineWin/0_Empty/main.cpp
new file mode 100644
index 0000000..77ee64b
--- /dev/null
+++ b/win/TinyEngineWin/0_Empty/main.cpp
@@ -0,0 +1,28 @@
+#include "../TinyEngine.h"
+
+int main( int argc, char* args[] ) {
+
+ //Initialize a Window
+ Tiny::window("Example Window", 600, 400);
+
+ //Add the Event Handler
+ Tiny::event.handler = [&](){
+ };
+
+ //Set up an ImGUI Interface here
+ Tiny::view.interface = [&](){
+ };
+
+ //Define the rendering pipeline
+ Tiny::view.pipeline = [&](){
+ };
+
+ //Execute the render loop
+ Tiny::loop([&](){
+ //Do any additional stuff in here
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/10_Audio/10_Audio.vcxproj b/win/TinyEngineWin/10_Audio/10_Audio.vcxproj
new file mode 100644
index 0000000..e8be37e
--- /dev/null
+++ b/win/TinyEngineWin/10_Audio/10_Audio.vcxproj
@@ -0,0 +1,184 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {598C5B6E-B616-4D90-B945-E00140B498B3}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/10_Audio/10_Audio.vcxproj.filters b/win/TinyEngineWin/10_Audio/10_Audio.vcxproj.filters
new file mode 100644
index 0000000..bb0f3dd
--- /dev/null
+++ b/win/TinyEngineWin/10_Audio/10_Audio.vcxproj.filters
@@ -0,0 +1,69 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/10_Audio/acoustic.wav b/win/TinyEngineWin/10_Audio/acoustic.wav
new file mode 100644
index 0000000..78e90df
Binary files /dev/null and b/win/TinyEngineWin/10_Audio/acoustic.wav differ
diff --git a/win/TinyEngineWin/10_Audio/main.cpp b/win/TinyEngineWin/10_Audio/main.cpp
new file mode 100644
index 0000000..a0910b2
--- /dev/null
+++ b/win/TinyEngineWin/10_Audio/main.cpp
@@ -0,0 +1,16 @@
+#include "../TinyEngine.h"
+
+int main( int argc, char* args[] ) {
+
+ Tiny::audio.init();
+ Tiny::audio.load({"acoustic.wav"});
+ Tiny::audio.play("acoustic.wav");
+
+ Tiny::loop([&](){
+ //This waits until the program quits...
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/11_Voronoi/11_Voronoi.vcxproj b/win/TinyEngineWin/11_Voronoi/11_Voronoi.vcxproj
new file mode 100644
index 0000000..c2d6bdd
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/11_Voronoi.vcxproj
@@ -0,0 +1,188 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/11_Voronoi/11_Voronoi.vcxproj.filters b/win/TinyEngineWin/11_Voronoi/11_Voronoi.vcxproj.filters
new file mode 100644
index 0000000..432adc6
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/11_Voronoi.vcxproj.filters
@@ -0,0 +1,75 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/11_Voronoi/imgui.ini b/win/TinyEngineWin/11_Voronoi/imgui.ini
new file mode 100644
index 0000000..6315809
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/imgui.ini
@@ -0,0 +1,10 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
+[Window][Controller]
+Pos=50,470
+Size=480,260
+Collapsed=0
+
diff --git a/win/TinyEngineWin/11_Voronoi/main.cpp b/win/TinyEngineWin/11_Voronoi/main.cpp
new file mode 100644
index 0000000..138346d
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/main.cpp
@@ -0,0 +1,179 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/color.h"
+#include "../../../include/helpers/image.h"
+
+#include "poisson.h"
+#include "model.h"
+#include
+#include
+
+/*
+
+~ GPU Accelerated Voronoi Map ~
+
+Possible OpenGL Implementations (2 Types):
+
+ (A) Naive Parallel On-Screen Clustering:
+ -> Pass all centroids as uniform, cluster in shader
+
+ (B) Depth Test Clustering:
+ -> Instanced render with centroids, distance is depth, color computed in shader
+
+ Here I implemented the second version.
+
+ Additional Optimizations:
+ -> Don't draw entire quad when points are placed using poisson disc, only a small quad
+ This reduces fragment waste because we can assume cones of a certain size.
+ 2-3 Orders of Magnitude Speed Boost
+ -> Don't pass a matrix, just the centroid. Scale in the vertex shader.
+ -> Render to texture, then render quad to screen
+
+ Applications:
+ -> Dynamic Run-Time Mosaic Filters in a Shader
+ -> Dynamic Run-Time Bubble Filter
+
+ -> Dynamic Run-Time Mosaic Effects with Particles (e.g. Lava-, Cloud-Flow)
+ -> Voronoi Painter using Directional Poisson Disc Sampling
+ -> "Clustered Convection" by Centroid (Particle) Motion
+ -> ???
+
+ Extensions:
+ -> Rendering to Sphere using Cubemaps (trivial to extend)
+*/
+
+#define SIZE 768
+
+int main( int argc, char* args[] ) {
+
+ //Setup Window
+ Tiny::view.vsync = false;
+ Tiny::window("GPU Accelerated Voronoise", SIZE, SIZE);
+
+ Tiny::event.handler = [](){}; //eventHandler;
+ Tiny::view.interface = interfaceFunc;
+
+ srand(time(NULL));
+
+ //Generate Set of Centroids
+ sample::disc(centroids, K, glm::vec2(-1), glm::vec2(1));
+ offset = centroids;
+
+ //Utility Classes
+ Square2D flat;
+ Shader voronoi({"shader/voronoi.vs", "shader/voronoi.fs"}, {"in_Quad", "in_Tex", "in_Centroid"});
+
+ Billboard billboard(SIZE, SIZE);
+ Shader billboardshader({"shader/billboard.vs", "shader/billboard.fs"}, {"in_Quad", "in_Tex"});
+
+ //Filter Effects
+ Shader bubble({"shader/bubble.vs", "shader/bubble.fs"}, {"in_Quad", "in_Tex", "in_Centroid"}, {"centroids"});
+ Shader mosaic({"shader/mosaic.vs", "shader/mosaic.fs"}, {"in_Quad", "in_Tex", "in_Centroid"}, {"centroids"});
+
+ //SSBO Centroids into Filters
+ bubble.buffer("centroids", centroids);
+ mosaic.buffer("centroids", centroids);
+
+ //Prepare instance render of flat, per-centroid
+ Instance instance(&flat);
+ instance.addBuffer(centroids);
+
+ Texture tex(image::load("starry_night.png")); //Load Texture with Image
+
+ //Prepare Noise for jiggling the centroids
+ noise::module::Perlin perlin;
+ perlin.SetOctaveCount(4);
+ perlin.SetFrequency(1.0);
+ perlin.SetPersistence(0.5);
+
+ int n = 0;
+ float us = 0.0; //Rolling average execution time calculation in microseconds (us)
+
+ Tiny::view.pipeline = [&](){
+
+ auto start = std::chrono::high_resolution_clock::now(); //Start Timer
+
+ billboard.target(color::black);
+ voronoi.use();
+ voronoi.uniform("R", R);
+ voronoi.uniform("drawcenter", drawcenter);
+ voronoi.uniform("style", drawstyle);
+ voronoi.uniform("metric", metric);
+ voronoi.uniform("twist", twist);
+ instance.render();
+
+ glFlush(); //Finish Pass
+
+ auto stop = std::chrono::high_resolution_clock::now(); //TIME!
+ auto duration = std::chrono::duration_cast(stop - start);
+
+ //Rolling Average
+ us = (float)((us*n+duration.count())/(n+1));
+ n++;
+
+ std::cout<<"Average Execution Time: "< centroids;
+std::vector offset;
+
+float K = 64;
+float R = 2.0f*sqrt(4.0f/3.14159265f/K);
+
+std::function interfaceFunc = [&](){
+
+
+ ImGui::SetNextWindowSize(ImVec2(480, 260), ImGuiCond_Once);
+ ImGui::SetNextWindowPos(ImVec2(50, 470), ImGuiCond_Once);
+
+ ImGui::Begin("Controller", NULL, ImGuiWindowFlags_NoResize);
+
+ ImGui::Checkbox("Animate", &animate); ImGui::SameLine();
+ ImGui::Checkbox("Centroids", &drawcenter); ImGui::SameLine();
+ ImGui::Checkbox("Non-Static", &translate);
+
+ static int e;
+ ImGui::RadioButton("Pick", &e, 0); ImGui::SameLine();
+ ImGui::RadioButton("Depth", &e, 1); ImGui::SameLine();
+ ImGui::RadioButton("Mosaic", &e, 2); ImGui::SameLine();
+ ImGui::RadioButton("Bubble", &e, 3);
+ drawstyle = e;
+
+ static int f;
+ ImGui::RadioButton("L1", &f, 0); ImGui::SameLine();
+ ImGui::RadioButton("L2", &f, 1); ImGui::SameLine();
+ ImGui::RadioButton("LTwist", &f, 2);
+ metric = f;
+
+ ImGui::SliderFloat("Centroids", &K, 256, 16*1024);
+ if(ImGui::Button("Re-Seed")){
+ centroids.clear();
+ offset.clear();
+ sample::disc(centroids, K, glm::vec2(-1), glm::vec2(1));
+ offset = centroids;
+ R = 2.0f*sqrt(4.0f/3.14159265f/K);
+ updated = true;
+ }
+
+ ImGui::SliderFloat("Twist", &twist, 0.0, 6.0);
+
+ ImGui::End();
+
+};
diff --git a/win/TinyEngineWin/11_Voronoi/poisson.h b/win/TinyEngineWin/11_Voronoi/poisson.h
new file mode 100644
index 0000000..2365fd4
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/poisson.h
@@ -0,0 +1,169 @@
+#include
+#include
+
+namespace sample{
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_real_distribution<> dis(0.0, 1.0);
+
+ float uniform(){
+ return dis(gen);
+ }
+
+ float uniform(float a, float b){
+ return dis(gen)*(a-b)+b;
+ }
+
+ //Single point at position towards p with radius R
+ bool disc(std::vector& set, float R, glm::vec2 p, glm::vec2 a, glm::vec2 b){
+
+ if(set.empty()){
+ set.push_back(p);
+ return true;
+ }
+
+ const float length = R/sqrt(2);
+ const int NX = ceil((b.x-a.x)/length);
+ const int NY = ceil((b.y-a.y)/length);
+ int* grid = new int[NX*NY];
+ memset(grid, 0, NX*NY*sizeof(int));
+
+ std::function addGrid = [&](glm::vec2 s, int val){
+ glm::ivec2 ind = glm::vec2(NX, NY)*(s-a)/(b-a); //Indices
+ grid[ind.x*NY+ind.y] = val; //Set Indices in Neighborhood
+ };
+
+ //Set is Not Empty - Fill Grid
+ for(unsigned int i = 0; i < set.size(); i++)
+ addGrid(set[i], i+1);
+
+ //Find the Nearest Guy - Attempt to Place Nearby
+ int near = 0; float dist = glm::distance(a, b);
+ for(unsigned int i = 0; i < set.size(); i++){
+ if(glm::distance(set[i], p) < dist){
+ dist = glm::distance(set[i], p);
+ near = i;
+ }
+ }
+
+ //Generate Nearby Point
+ int tries = 16;
+ while(tries > 0){
+ tries--;
+
+ float nr = uniform(R, 2*R);
+ float nt = uniform(0, 2*3.14159265);
+
+ glm::vec2 npos = set[near]+nr*glm::vec2(cos(nt), sin(nt));
+ if(glm::any(glm::lessThan(npos, glm::vec2(a))) || glm::any(glm::greaterThanEqual(npos, glm::vec2(b))))
+ continue;
+
+ glm::ivec2 ind = glm::vec2(NX, NY)*(npos-a)/(b-a); //Indices
+
+ bool free = true;
+ for(int i = ind.x-2; i <= ind.x+2 && free; i++){
+ for(int j = ind.y-2; j <= ind.y+2 && free; j++){
+
+ if(i < 0 || i >= NX || j < 0 || j >= NY)
+ continue;
+
+ //Non-Zero Entry,and Too Close
+ if(grid[i*NY+j] > 0){
+ if(glm::distance(set[grid[i*NY+j]-1], npos) < R){
+ free = false;
+ continue;
+ }
+ }
+ }
+ }
+
+ if(free){
+ set.push_back(npos);
+ addGrid(set.back(), set.size());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //Sample Set of Points in Region
+ void disc(std::vector& set, int K, glm::vec2 a, glm::vec2 b){
+
+ float r = sqrt(glm::dot(b-a, b-a)/3.14159265f/K);
+ const float length = r/sqrt(2); //Edge Length
+ const int NX = ceil((b.x-a.x)/length);
+ const int NY = ceil((b.y-a.y)/length);
+ int* grid = new int[NX*NY];
+ memset(grid, 0, NX*NY*sizeof(int));
+
+ //Grid Addition Function
+ std::function addGrid = [&](glm::vec2 s, int val){
+ glm::ivec2 ind = glm::vec2(NX, NY)*(s-a)/(b-a); //Indices
+ grid[ind.x*NY+ind.y] = val; //Set Indices in Neighborhood
+ };
+
+ //Setup Grid
+ if(set.empty()){
+ set.push_back(0.5f*(a+b)); //Center
+ addGrid(set.back(), set.size());
+ K--;
+ }
+ else for(unsigned int i = 0; i < set.size(); i++)
+ addGrid(set[i], i+1);
+
+ //Now Generate New Samples by Iterating over the Set
+ int tries = 0;
+
+ while(K > 0){
+
+ if(tries > set.size())
+ break;
+
+ //Sample Uniformly from Set
+ int n = uniform(0, set.size());
+
+ //Generate Sample Surrounding It
+ float nr = uniform(r, 2*r);
+ float nt = uniform(0, 2*3.14159265);
+
+ //New Sample Position, Grid Index
+ glm::vec2 npos = set[n]+nr*glm::vec2(cos(nt), sin(nt));
+ if(glm::any(glm::lessThan(npos, glm::vec2(a))) || glm::any(glm::greaterThanEqual(npos, glm::vec2(b))))
+ continue;
+
+ glm::ivec2 ind = glm::vec2(NX, NY)*(npos-a)/(b-a); //Indices
+
+ bool free = true;
+ for(int i = ind.x-2; i <= ind.x+2 && free; i++){
+ for(int j = ind.y-2; j <= ind.y+2 && free; j++){
+
+ if(i < 0 || i >= NX || j < 0 || j >= NY)
+ continue;
+
+ //Non-Zero Entry,and Too Close
+ if(grid[i*NY+j] > 0){
+ if(glm::distance(set[grid[i*NY+j]-1], npos) < r){
+ free = false;
+ continue;
+ }
+ }
+ }
+ }
+
+ if(!free){
+ tries++;
+ continue;
+ }
+
+ //Place Point
+ set.push_back(npos);
+ addGrid(set.back(), set.size());
+ tries = 0;
+ K--;
+ }
+ delete[] grid;
+ }
+
+ //Those functions could probably be improved. Not sure how right now. Recursiveness?
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/billboard.fs b/win/TinyEngineWin/11_Voronoi/shader/billboard.fs
new file mode 100644
index 0000000..3071b3a
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/billboard.fs
@@ -0,0 +1,9 @@
+#version 330 core
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+uniform sampler2D imageTexture;
+
+void main(){
+ fragColor = texture(imageTexture, ex_Tex);
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/billboard.vs b/win/TinyEngineWin/11_Voronoi/shader/billboard.vs
new file mode 100644
index 0000000..6b7b7f7
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/billboard.vs
@@ -0,0 +1,11 @@
+#version 330 core
+layout (location = 0) in vec2 in_Quad;
+layout (location = 1) in vec2 in_Tex;
+out vec2 ex_Tex;
+
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, 1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/bubble.fs b/win/TinyEngineWin/11_Voronoi/shader/bubble.fs
new file mode 100644
index 0000000..7c7e351
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/bubble.fs
@@ -0,0 +1,26 @@
+#version 430 core
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+layout (std430, binding = 0) buffer centroids {
+ vec2 c[];
+};
+
+uniform sampler2D voronoi;
+uniform sampler2D image;
+
+uniform float R;
+
+int index(vec3 a){
+ a = a*255.0f;
+ return int((a.x + a.y*256 + a.z*256*256));
+}
+
+void main(){
+ int i = index(texture(voronoi, ex_Tex).rgb);
+
+ //Direction
+ vec2 dir = (2*ex_Tex-1) - c[i]; //Direction to the Centroid
+ float d = length(dir)/R; //Distance divided by R
+ fragColor = mix(texture(image, ex_Tex+dir*d), vec4(vec3(0), 1), d*d);
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/bubble.vs b/win/TinyEngineWin/11_Voronoi/shader/bubble.vs
new file mode 100644
index 0000000..286c048
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/bubble.vs
@@ -0,0 +1,13 @@
+#version 430 core
+layout (location = 0) in vec2 in_Quad;
+layout (location = 1) in vec2 in_Tex;
+layout (location = 2) in vec2 in_Centroid;
+
+out vec2 ex_Tex;
+
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, 1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/mosaic.fs b/win/TinyEngineWin/11_Voronoi/shader/mosaic.fs
new file mode 100644
index 0000000..e40604a
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/mosaic.fs
@@ -0,0 +1,22 @@
+#version 430 core
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+layout (std430, binding = 3) buffer centroids {
+ vec2 c[];
+};
+
+uniform sampler2D voronoi;
+uniform sampler2D image;
+
+uniform int NCOLOR;
+
+int index(vec3 a){
+ a = a*255.0f;
+ return int((a.x + a.y*256 + a.z*256*256));
+}
+
+void main(){
+ int i = index(texture(voronoi, ex_Tex).rgb);
+ fragColor = texture(image, 0.5*(c[i]+1.0));
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/mosaic.vs b/win/TinyEngineWin/11_Voronoi/shader/mosaic.vs
new file mode 100644
index 0000000..286c048
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/mosaic.vs
@@ -0,0 +1,13 @@
+#version 430 core
+layout (location = 0) in vec2 in_Quad;
+layout (location = 1) in vec2 in_Tex;
+layout (location = 2) in vec2 in_Centroid;
+
+out vec2 ex_Tex;
+
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, 1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/voronoi.fs b/win/TinyEngineWin/11_Voronoi/shader/voronoi.fs
new file mode 100644
index 0000000..9bf273f
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/voronoi.fs
@@ -0,0 +1,81 @@
+#version 330 core
+
+in vec2 ex_Quad;
+in vec2 ex_Centroid;
+flat in vec3 ex_Color;
+out vec4 fragColor;
+
+uniform float R;
+
+uniform bool drawcenter;
+uniform int metric;
+uniform float twist;
+uniform int style;
+
+float L1(vec2 a, vec2 b){
+ return (abs(a.x-b.x)+abs(a.y-b.y));
+}
+
+float L2(vec2 a, vec2 b){
+ return length(a-b);
+}
+
+float Ltwist(vec2 a, vec2 b){
+ vec2 dir = b-a;
+ float d = length(dir);
+
+
+ float PI = 3.14159265f;
+
+// dir.x = sin(theta);
+// dir.y = cos(theta);
+
+ //dir.
+
+ float theta = atan(dir.y/dir.x);
+ if(dir.x < 0) theta += PI;
+ //if(dir.x < 0) theta = theta-2*PI;
+// if(dir.y < 0)
+// theta = 2*PI-theta;
+
+ //atan(dir.y/dir.x);
+ //if(dir.x < 0) theta = -theta;
+
+ /*
+ I want a sine wave around the radius with a certain period.
+ Meaning that as I go around, I have a signal strength going up and down.
+
+ I want to compute the angle of the vector.
+
+ 1. Compute Angle of Vector
+ 2. Multiply with a sine wave squared of a certain frequency to get tentacle effect.
+ 3. But add a phase shift that is proportional to the distance from the center.
+ 4. That is the distance function!
+
+ */
+
+ float k = twist;
+ float m = 5;
+ return d+0.05*sin(k*theta+m*d/R)*sin(k*theta+m*d/R);//(abs(a.x-b.x)+abs(a.y-b.y));
+}
+
+void main(){
+
+ if(metric == 0)
+ gl_FragDepth = L1(ex_Quad, ex_Centroid);
+ else if(metric == 1){
+ gl_FragDepth = L2(ex_Quad, ex_Centroid);
+ if(gl_FragDepth > R) discard; //Make them Round
+ }
+ else{
+ gl_FragDepth = Ltwist(ex_Quad, ex_Centroid);
+ }
+
+ if(style == 1)
+ fragColor = vec4(vec3(gl_FragDepth/R), 1.0);
+ else
+ fragColor = vec4(ex_Color, 1.0);
+
+ if(gl_FragDepth < 0.1*R && drawcenter)
+ fragColor = vec4(1.0);
+}
diff --git a/win/TinyEngineWin/11_Voronoi/shader/voronoi.vs b/win/TinyEngineWin/11_Voronoi/shader/voronoi.vs
new file mode 100644
index 0000000..cd0881e
--- /dev/null
+++ b/win/TinyEngineWin/11_Voronoi/shader/voronoi.vs
@@ -0,0 +1,23 @@
+#version 330 core
+layout (location = 0) in vec2 in_Quad;
+layout (location = 2) in vec2 in_Centroid;
+
+out vec2 ex_Quad;
+flat out vec3 ex_Color;
+out vec2 ex_Centroid;
+
+uniform float R;
+
+vec3 color(int i){
+ float r = ((i >> 0) & 0xff)/255.0f;
+ float g = ((i >> 8) & 0xff)/255.0f;
+ float b = ((i >> 16) & 0xff)/255.0f;
+ return vec3(r,g,b);
+}
+
+void main(){
+ ex_Centroid = in_Centroid;
+ ex_Color = color(gl_InstanceID);
+ ex_Quad = R*in_Quad+in_Centroid;
+ gl_Position = vec4(ex_Quad, 0.0, 1.0);
+}
diff --git a/win/TinyEngineWin/11_Voronoi/starry_night.png b/win/TinyEngineWin/11_Voronoi/starry_night.png
new file mode 100644
index 0000000..56fd436
Binary files /dev/null and b/win/TinyEngineWin/11_Voronoi/starry_night.png differ
diff --git a/win/TinyEngineWin/1_Image/1_Image.vcxproj b/win/TinyEngineWin/1_Image/1_Image.vcxproj
new file mode 100644
index 0000000..39f5421
--- /dev/null
+++ b/win/TinyEngineWin/1_Image/1_Image.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/1_Image/1_Image.vcxproj.filters b/win/TinyEngineWin/1_Image/1_Image.vcxproj.filters
new file mode 100644
index 0000000..7252c25
--- /dev/null
+++ b/win/TinyEngineWin/1_Image/1_Image.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/1_Image/canyon.png b/win/TinyEngineWin/1_Image/canyon.png
new file mode 100644
index 0000000..fed75f2
Binary files /dev/null and b/win/TinyEngineWin/1_Image/canyon.png differ
diff --git a/win/TinyEngineWin/1_Image/effects.h b/win/TinyEngineWin/1_Image/effects.h
new file mode 100644
index 0000000..582512f
--- /dev/null
+++ b/win/TinyEngineWin/1_Image/effects.h
@@ -0,0 +1,15 @@
+/*
+ Effects File. Contains all Parameters for effects.
+*/
+
+int ind = 0; //Effect Index
+int res = 100; //Pixelate Effect
+int bits = 4; //Bitreduce Effect
+
+Handle interfaceFunc = [&](){
+ /* Do Something */
+ ImGui::Text("Shader Effects");
+ ImGui::DragInt("Effect", &ind, 1, 0, 2);
+ ImGui::DragInt("Resolution", &res, 1, 1, 400);
+ ImGui::DragInt("Bits", &bits, 1, 1, 16);
+};
diff --git a/win/TinyEngineWin/1_Image/imgui.ini b/win/TinyEngineWin/1_Image/imgui.ini
new file mode 100644
index 0000000..5e7278e
--- /dev/null
+++ b/win/TinyEngineWin/1_Image/imgui.ini
@@ -0,0 +1,5 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
diff --git a/win/TinyEngineWin/1_Image/main.cpp b/win/TinyEngineWin/1_Image/main.cpp
new file mode 100644
index 0000000..9e0aacd
--- /dev/null
+++ b/win/TinyEngineWin/1_Image/main.cpp
@@ -0,0 +1,40 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/image.h"
+#include "../../../include/helpers/color.h"
+
+#include "effects.h"
+
+int main( int argc, char* args[] ) {
+
+ Tiny::window("Shader Effects Example", 1200, 800);
+
+ Tiny::event.handler = [](){ /* ... */ };
+
+ Tiny::view.interface = interfaceFunc;
+
+ Texture tex(image::load("canyon.png")); //Load Texture with Image
+ Square2D flat; //Create Primitive Model
+ Shader effect({"shader/effect.vs", "shader/effect.fs"}, {"in_Quad", "in_Tex"});
+
+ Tiny::view.pipeline = [&](){
+
+ Tiny::view.target(color::black); //Target Main Screen
+
+ effect.use(); //Use Effect Shader
+ effect.uniform("index", ind); //Define Uniforms
+ effect.uniform("res", res);
+ effect.uniform("bits", bits);
+ effect.texture("imageTexture", tex); //Load Texture
+ effect.uniform("model", flat.model); //Add Model Matrix
+ flat.render(); //Render Primitive
+
+ };
+
+ Tiny::loop([&](){
+ /* Absolutely Nothing! */
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/1_Image/shader/effect.fs b/win/TinyEngineWin/1_Image/shader/effect.fs
new file mode 100644
index 0000000..62cf65a
--- /dev/null
+++ b/win/TinyEngineWin/1_Image/shader/effect.fs
@@ -0,0 +1,30 @@
+#version 130
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+uniform sampler2D imageTexture;
+
+//Effect Parameters
+uniform int index;
+uniform int res;
+uniform int bits;
+
+vec4 none(){
+ return texture(imageTexture, ex_Tex);
+}
+
+vec4 pixelate(){
+ return texture(imageTexture, floor(ex_Tex*vec2(res))/vec2(res));
+}
+
+vec4 bitreduce(){
+ vec4 color = texture(imageTexture, ex_Tex);
+ return vec4(round(color.xyz*vec3(bits))/vec3(bits), 1.0);
+}
+
+void main(){
+ //Get the fragment color from the effect choice
+ if(index == 1) fragColor = pixelate();
+ else if(index == 2) fragColor = bitreduce();
+ else fragColor = none();
+}
diff --git a/win/TinyEngineWin/1_Image/shader/effect.vs b/win/TinyEngineWin/1_Image/shader/effect.vs
new file mode 100644
index 0000000..d90e341
--- /dev/null
+++ b/win/TinyEngineWin/1_Image/shader/effect.vs
@@ -0,0 +1,12 @@
+#version 130
+in vec2 in_Quad;
+in vec2 in_Tex;
+out vec2 ex_Tex;
+
+//Position the Billboard in space!
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, -1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/2_Heightmap/2_Heightmap.vcxproj b/win/TinyEngineWin/2_Heightmap/2_Heightmap.vcxproj
new file mode 100644
index 0000000..3bd26b0
--- /dev/null
+++ b/win/TinyEngineWin/2_Heightmap/2_Heightmap.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/2_Heightmap/2_Heightmap.vcxproj.filters b/win/TinyEngineWin/2_Heightmap/2_Heightmap.vcxproj.filters
new file mode 100644
index 0000000..8aae4d6
--- /dev/null
+++ b/win/TinyEngineWin/2_Heightmap/2_Heightmap.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/2_Heightmap/imgui.ini b/win/TinyEngineWin/2_Heightmap/imgui.ini
new file mode 100644
index 0000000..5e7278e
--- /dev/null
+++ b/win/TinyEngineWin/2_Heightmap/imgui.ini
@@ -0,0 +1,5 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
diff --git a/win/TinyEngineWin/2_Heightmap/main.cpp b/win/TinyEngineWin/2_Heightmap/main.cpp
new file mode 100644
index 0000000..ff3111a
--- /dev/null
+++ b/win/TinyEngineWin/2_Heightmap/main.cpp
@@ -0,0 +1,36 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/color.h"
+
+#include "model.h"
+
+int main( int argc, char* args[] ) {
+
+ Tiny::window("Heightmap Render", WIDTH, HEIGHT); //Open Window
+ Tiny::event.handler = eventHandler; //Event Handler
+ Tiny::view.interface = [&](){ /* ... */ }; //No Interface
+
+ setup(); //Prepare Model Stuff
+
+ Model mesh(_construct); //Construct a Mesh
+ mesh.shift(glm::vec3(-32.0, -15.0, -32.0)); //Translate Mesh
+ Shader defaultShader({"shader/default.vs", "shader/default.fs"}, {"in_Position", "in_Normal"});
+
+ Tiny::view.pipeline = [&](){ //Setup Drawing Pipeline
+
+ Tiny::view.target(color::black); //Target Screen
+
+ defaultShader.use(); //Prepare Shader
+ defaultShader.uniform("model", mesh.model); //Set Model Matrix
+ defaultShader.uniform("vp", projection*camera); //View Projection Matrix
+ mesh.render(GL_LINES); //Render Model with Lines
+
+ };
+
+ Tiny::loop([&](){ //Autorotate Camera
+ camera = glm::rotate(camera, glm::radians(0.1f), glm::vec3(0.0f, 1.0f, 0.0f));
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/2_Heightmap/model.h b/win/TinyEngineWin/2_Heightmap/model.h
new file mode 100644
index 0000000..8e475a1
--- /dev/null
+++ b/win/TinyEngineWin/2_Heightmap/model.h
@@ -0,0 +1,142 @@
+#include
+
+//Model Stuff
+int SEED = 10;
+double scale = 30.0;
+double heightmap[64][64] = {0.0};
+glm::vec2 dim = glm::vec2(64);
+noise::module::Perlin perlin;
+
+//View Stuff
+const int WIDTH = 1200;
+const int HEIGHT = 800;
+glm::vec3 viewPos = glm::vec3(50, 1, 50);
+float zoom = 0.05;
+float zoomInc = 0.001;
+float rotation = 0.0f;
+glm::vec3 cameraPos = glm::vec3(50, 50, 50);
+glm::vec3 lookPos = glm::vec3(0, 0, 0);
+glm::mat4 camera = glm::lookAt(cameraPos, lookPos, glm::vec3(0,1,0));
+glm::mat4 projection;
+
+void setup(){
+ //Random Seed
+ srand(time(NULL));
+ SEED = rand();
+
+ //Projection Matrix (Orthographic)
+ projection = glm::ortho(-(float)Tiny::view.WIDTH*zoom, (float)Tiny::view.WIDTH*zoom, -(float)Tiny::view.HEIGHT*zoom, (float)Tiny::view.HEIGHT*zoom, -800.0f, 500.0f);
+
+ perlin.SetOctaveCount(8);
+ perlin.SetFrequency(1.0);
+ perlin.SetPersistence(0.6);
+
+ float min = 0.0;
+ float max = 0.0;
+ for(int i = 0; i < dim.x; i++){
+ for(int j = 0; j < dim.y; j++){
+ heightmap[i][j] = perlin.GetValue(i*(1.0/dim.x), j*(1.0/dim.y), SEED);
+ if(heightmap[i][j] > max) max = heightmap[i][j];
+ if(heightmap[i][j] < min) min = heightmap[i][j];
+ }
+ }
+
+ //Normalize
+ for(int i = 0; i < dim.x; i++){
+ for(int j = 0; j < dim.y; j++){
+ //Normalize to (0, 1) scale.
+ heightmap[i][j] = (heightmap[i][j] - min)/(max - min);
+ }
+ }
+};
+
+// Event Handler
+std::function eventHandler = [&](){
+
+ if(Tiny::event.scroll.posy && zoom <= 0.3){
+ zoom += zoomInc;
+ projection = glm::ortho(-(float)WIDTH*zoom, (float)WIDTH*zoom, -(float)HEIGHT*zoom, (float)HEIGHT*zoom, -800.0f, 500.0f);
+ }
+ if(Tiny::event.scroll.negy && zoom > 0.005){
+ zoom -= zoomInc;
+ projection = glm::ortho(-(float)WIDTH*zoom, (float)WIDTH*zoom, -(float)HEIGHT*zoom, (float)HEIGHT*zoom, -800.0f, 500.0f);
+ }
+ if(Tiny::event.scroll.posx){
+ rotation += 1.5f;
+ if(rotation < 0.0) rotation = 360.0 + rotation;
+ else if(rotation > 360.0) rotation = rotation - 360.0;
+ camera = glm::rotate(camera, glm::radians(1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
+ }
+ if(Tiny::event.scroll.negx){
+ rotation -= 1.5f;
+ if(rotation < 0.0) rotation = 360.0 + rotation;
+ else if(rotation > 360.0) rotation = rotation - 360.0;
+ camera = glm::rotate(camera, glm::radians(-1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
+ }
+
+};
+
+// Model Constructing Function
+std::function _construct = [&](Model* h){
+ //Loop over all positions and add the triangles!
+ for(int i = 0; i < dim.x-1; i++){
+ for(int j = 0; j < dim.y-1; j++){
+
+ //Add to Position Vector
+ glm::vec3 a = glm::vec3(i, scale*heightmap[i][j], j);
+ glm::vec3 b = glm::vec3(i+1, scale*heightmap[i+1][j], j);
+ glm::vec3 c = glm::vec3(i, scale*heightmap[i][j+1], j+1);
+ glm::vec3 d = glm::vec3(i+1, scale*heightmap[i+1][j+1], j+1);
+
+ //UPPER TRIANGLE
+
+ //Add Indices
+ h->indices.push_back(h->positions.size()/3+0);
+ h->indices.push_back(h->positions.size()/3+1);
+ h->indices.push_back(h->positions.size()/3+2);
+ h->indices.push_back(h->positions.size()/3+0);
+
+ h->positions.push_back(a.x);
+ h->positions.push_back(a.y);
+ h->positions.push_back(a.z);
+ h->positions.push_back(b.x);
+ h->positions.push_back(b.y);
+ h->positions.push_back(b.z);
+ h->positions.push_back(c.x);
+ h->positions.push_back(c.y);
+ h->positions.push_back(c.z);
+
+ glm::vec3 n1 = glm::cross(a-b, c-b);
+
+ for(int i = 0; i < 3; i++){
+ h->normals.push_back(n1.x);
+ h->normals.push_back(n1.y);
+ h->normals.push_back(n1.z);
+ }
+
+ //Lower Triangle
+ h->indices.push_back(h->positions.size()/3+0);
+ h->indices.push_back(h->positions.size()/3+1);
+ h->indices.push_back(h->positions.size()/3+2);
+ h->indices.push_back(h->positions.size()/3+0);
+
+ h->positions.push_back(d.x);
+ h->positions.push_back(d.y);
+ h->positions.push_back(d.z);
+ h->positions.push_back(c.x);
+ h->positions.push_back(c.y);
+ h->positions.push_back(c.z);
+ h->positions.push_back(b.x);
+ h->positions.push_back(b.y);
+ h->positions.push_back(b.z);
+
+ glm::vec3 n2 = glm::cross(d-c, b-c);
+
+ for(int i = 0; i < 3; i++){
+ h->normals.push_back(n2.x);
+ h->normals.push_back(n2.y);
+ h->normals.push_back(n2.z);
+ }
+ }
+ }
+};
diff --git a/win/TinyEngineWin/2_Heightmap/shader/default.fs b/win/TinyEngineWin/2_Heightmap/shader/default.fs
new file mode 100644
index 0000000..598661b
--- /dev/null
+++ b/win/TinyEngineWin/2_Heightmap/shader/default.fs
@@ -0,0 +1,11 @@
+#version 130
+
+in vec4 ex_Color;
+in vec3 ex_Normal;
+in vec3 ex_FragPos;
+
+out vec4 fragColor;
+
+void main(void) {
+ fragColor = ex_Color; //Pass Color to Fragment
+}
diff --git a/win/TinyEngineWin/2_Heightmap/shader/default.vs b/win/TinyEngineWin/2_Heightmap/shader/default.vs
new file mode 100644
index 0000000..4411c1e
--- /dev/null
+++ b/win/TinyEngineWin/2_Heightmap/shader/default.vs
@@ -0,0 +1,23 @@
+#version 130
+
+in vec3 in_Position;
+in vec3 in_Normal;
+
+uniform mat4 model;
+uniform mat4 vp;
+
+out vec4 ex_Color;
+out vec3 ex_Normal;
+out vec3 ex_FragPos;
+
+void main(void) {
+ //Fragment Position in Model Space
+ ex_FragPos = (model * vec4(in_Position, 1.0f)).xyz;
+ ex_Normal = in_Normal; //Pass Normal
+
+ //Fragment in Screen Space
+ gl_Position = vp * vec4(ex_FragPos, 1.0f);
+
+ //Color from Normal Vector
+ ex_Color = vec4(normalize(in_Normal), 1.0);
+}
diff --git a/win/TinyEngineWin/3_Automata/3_Automata.vcxproj b/win/TinyEngineWin/3_Automata/3_Automata.vcxproj
new file mode 100644
index 0000000..28c4972
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/3_Automata.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/3_Automata/3_Automata.vcxproj.filters b/win/TinyEngineWin/3_Automata/3_Automata.vcxproj.filters
new file mode 100644
index 0000000..8aae4d6
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/3_Automata.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/3_Automata/main.cpp b/win/TinyEngineWin/3_Automata/main.cpp
new file mode 100644
index 0000000..c3e436a
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/main.cpp
@@ -0,0 +1,68 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/image.h"
+#include "../../../include/helpers/color.h"
+
+#include "model.h"
+
+int main( int argc, char* args[] ) {
+
+ Tiny::view.vsync = false; //Turn off VSYNC before opening window
+
+ Tiny::window("GPU Accelerated Cellular Automata Example", WIDTH, HEIGHT); //Open Window
+ Tiny::event.handler = eventHandler; //Define Event Handler
+ Tiny::view.interface = [](){ /* ... */ }; //No Interface
+
+ setup(); //Setup Model Data
+
+ //Construct a billboard, using a texture generated from the raw data
+ Billboard targetA(image::make(glm::vec2(WIDTH, HEIGHT), data, [](bool t){
+ if(t) return glm::vec4(1.0, 1.0, 1.0, 1.0);
+ else return glm::vec4(0.0, 0.0, 0.0, 1.0);
+ }));
+ Billboard targetB(WIDTH, HEIGHT, true, false); //color, no depth
+ bool flip = true;
+
+ Square2D flat; //Flat square primitive for drawing billboard to screen
+
+ //Shader for drawing billboard to screen and for doing an automata step
+ Shader shader({"shader/billboard.vs", "shader/billboard.fs"}, {"in_Quad", "in_Tex"});
+ Shader automata({"shader/automata.vs", "shader/automata.fs"}, {"in_Quad", "in_Tex"});
+
+ Tiny::view.pipeline = [&](){
+
+ if(!paused){
+ if(flip){
+ targetB.target(false); //Use target as the render target (no clearing)!
+ automata.use(); //Use the Automata Shader
+ automata.texture("imageTexture", targetA.texture); //Target texture!
+ automata.uniform("model", flat.model);
+ flat.render(); //Render target texture to itself using primitive and automata shader
+ }
+ else{
+ targetA.target(false); //Use target as the render target (no clearing)!
+ automata.use(); //Use the Automata Shader
+ automata.texture("imageTexture", targetB.texture); //Target texture!
+ automata.uniform("model", flat.model);
+ flat.render(); //Render target texture to itself using primitive and automata shader
+ }
+ flip = !flip;
+ }
+
+ Tiny::view.target(color::black); //Target screen
+ shader.use(); //Setup Shader
+ if(flip) shader.texture("imageTexture", targetB.texture);
+ else shader.texture("imageTexture", targetA.texture);
+ shader.texture("imageTexture", targetA.texture);
+ shader.uniform("model", flat.model);
+ flat.render(); //Render Objects
+
+ };
+
+ Tiny::loop([&](){
+ /* Absolutely Nothing! */
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/3_Automata/model.h b/win/TinyEngineWin/3_Automata/model.h
new file mode 100644
index 0000000..5d24e3e
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/model.h
@@ -0,0 +1,24 @@
+//Data
+const int SIZE = 100;
+const int WIDTH = 1200, HEIGHT = 800;
+bool data[WIDTH*HEIGHT] = {false};
+bool paused = true;
+
+//Setup of Data
+void setup(){
+ //Generate Random Data!
+ srand(time(NULL));
+ for(int i = 0; i < WIDTH*HEIGHT; i++){
+ data[i] = (rand()%2 == 0)?1:0;
+ }
+};
+
+// Event Handler
+std::function eventHandler = [&](){
+
+ // Pause and Unpause
+ if(!Tiny::event.press.empty())
+ if(Tiny::event.press.back() == SDLK_p)
+ paused = !paused;
+
+};
diff --git a/win/TinyEngineWin/3_Automata/shader/automata.fs b/win/TinyEngineWin/3_Automata/shader/automata.fs
new file mode 100644
index 0000000..4f742a0
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/shader/automata.fs
@@ -0,0 +1,32 @@
+#version 330 core
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+uniform sampler2D imageTexture;
+
+vec3 live = vec3(0.0, 0.0, 0.0);
+vec3 dead = vec3(1.0, 1.0, 1.0);
+
+//Conways Game of Life
+vec3 rule(){
+ vec2 p = ex_Tex*(1.0, 1.0); //Scale
+ bool s = (texture(imageTexture, p).xyz == live); //Self
+
+ int n = 0; //Neighbors
+ n += (textureOffset(imageTexture, p, ivec2( 1, 0)).xyz == live)?1:0;
+ n += (textureOffset(imageTexture, p, ivec2(-1, 0)).xyz == live)?1:0;
+ n += (textureOffset(imageTexture, p, ivec2( 0, 1)).xyz == live)?1:0;
+ n += (textureOffset(imageTexture, p, ivec2( 0,-1)).xyz == live)?1:0;
+ n += (textureOffset(imageTexture, p, ivec2( 1, 1)).xyz == live)?1:0;
+ n += (textureOffset(imageTexture, p, ivec2(-1,-1)).xyz == live)?1:0;
+ n += (textureOffset(imageTexture, p, ivec2(-1, 1)).xyz == live)?1:0;
+ n += (textureOffset(imageTexture, p, ivec2( 1,-1)).xyz == live)?1:0;
+
+ if(s && (n == 2 || n == 3)) return live;
+ if(!s && n == 3) return live;
+ return dead;
+}
+
+void main(){
+ fragColor = vec4(rule(), 1.0);
+}
diff --git a/win/TinyEngineWin/3_Automata/shader/automata.vs b/win/TinyEngineWin/3_Automata/shader/automata.vs
new file mode 100644
index 0000000..8f36079
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/shader/automata.vs
@@ -0,0 +1,12 @@
+#version 330 core
+in vec2 in_Quad;
+in vec2 in_Tex;
+out vec2 ex_Tex;
+
+//Position the Billboard in space!
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, 1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/3_Automata/shader/billboard.fs b/win/TinyEngineWin/3_Automata/shader/billboard.fs
new file mode 100644
index 0000000..ff446f2
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/shader/billboard.fs
@@ -0,0 +1,9 @@
+#version 130
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+uniform sampler2D imageTexture;
+
+void main(){
+ fragColor = texture(imageTexture, ex_Tex);
+}
diff --git a/win/TinyEngineWin/3_Automata/shader/billboard.vs b/win/TinyEngineWin/3_Automata/shader/billboard.vs
new file mode 100644
index 0000000..0f93710
--- /dev/null
+++ b/win/TinyEngineWin/3_Automata/shader/billboard.vs
@@ -0,0 +1,13 @@
+#version 130
+in vec2 in_Quad;
+in vec2 in_Tex;
+out vec2 ex_Tex;
+
+//Position the Billboard in space!
+uniform mat4 model;
+
+void main(){
+ //Set Ex-Tex:
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, 1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/4_Julia/4_Julia.vcxproj b/win/TinyEngineWin/4_Julia/4_Julia.vcxproj
new file mode 100644
index 0000000..543d838
--- /dev/null
+++ b/win/TinyEngineWin/4_Julia/4_Julia.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/4_Julia/4_Julia.vcxproj.filters b/win/TinyEngineWin/4_Julia/4_Julia.vcxproj.filters
new file mode 100644
index 0000000..8aae4d6
--- /dev/null
+++ b/win/TinyEngineWin/4_Julia/4_Julia.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/4_Julia/imgui.ini b/win/TinyEngineWin/4_Julia/imgui.ini
new file mode 100644
index 0000000..2134e47
--- /dev/null
+++ b/win/TinyEngineWin/4_Julia/imgui.ini
@@ -0,0 +1,10 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
+[Window][Julia Set Controller]
+Pos=69,307
+Size=480,260
+Collapsed=0
+
diff --git a/win/TinyEngineWin/4_Julia/main.cpp b/win/TinyEngineWin/4_Julia/main.cpp
new file mode 100644
index 0000000..9e0024b
--- /dev/null
+++ b/win/TinyEngineWin/4_Julia/main.cpp
@@ -0,0 +1,52 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/color.h"
+
+#include "model.h"
+
+int main( int argc, char* args[] ) {
+ srand(time(NULL)); //SEED
+
+ Tiny::view.vsync = true;
+
+ Tiny::window("Julia Set Explorer", 1000, 1000); //Open Window
+
+ Tiny::event.handler = eventHandler; //Set Event Handler
+ Tiny::view.interface = interfaceFunc; //Set Interface Function
+
+ Square2D flat; //Flat geometry primitive
+ Shader julia({"shader/julia.vs", "shader/julia.fs"}, {"in_Quad", "in_Tex"});
+
+ Tiny::view.pipeline = [&](){
+
+ Tiny::view.target(color::black); //Target Screen
+
+ julia.use(); //Prepare Shader
+ julia.uniform("maxiter", res);
+ julia.uniform("radius", radius);
+ julia.uniform("zoom", zoom);
+ julia.uniform("order", order);
+ julia.uniform("converge", glm::vec4(cc[0], cc[1], cc[2], cc[3]));
+ julia.uniform("diverge", glm::vec4(dc[0], dc[1], dc[2], dc[3]));
+ julia.uniform("bias", glm::vec2(bias[0], bias[1]));
+ julia.uniform("offset", glm::vec2(px, py));
+ julia.uniform("model", flat.model);
+ flat.render(); //Draw onto Flat Geometry
+
+ };
+
+ Tiny::loop([&](){ //Extra Stuff (every tick)
+ t += rate; //Cycle
+ if(t > 1.0) t -= 1.0;
+
+ if(!active) return; //Pause
+
+ //Animate
+ if(appear) radius = appearAmp*pow(sin(2*PI*t), 2);
+ if(movex) bias[0] = center[0]+amplitude[0]*sin(2*PI*(t+phase[0]));
+ if(movey) bias[1] = center[1]+amplitude[1]*sin(2*PI*(t+phase[1]));
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/4_Julia/model.h b/win/TinyEngineWin/4_Julia/model.h
new file mode 100644
index 0000000..eb06488
--- /dev/null
+++ b/win/TinyEngineWin/4_Julia/model.h
@@ -0,0 +1,118 @@
+//Data
+const int SIZE = 500;
+int data[SIZE*SIZE] = {0};
+bool paused = true;
+float PI = 3.14159265;
+
+//Resolution
+int res = 25;
+float radius = 2.0;
+float bias[2] = {0.0};
+double zoom = 1.5;
+int order = 2;
+double px = 0.0;
+double py = 0.0;
+
+float cc[4] = {0.070, 0.086, 0.211, 1.0};
+float dc[4] = {0.882, 0.157, 0.204, 1.0};
+
+bool active = false;
+bool appear = false;
+float appearAmp = 1.0;
+bool movex = false;
+bool movey = false;
+float phase[2] = {0.0, 0.0};
+float amplitude[2] = {1.0, 1.0};
+float center[2] = {0.0, 0.0};
+float rate = 0.01;
+float t = 0.0;
+
+// Event Handler
+std::function eventHandler = [&](){
+
+ if(Tiny::event.scroll.posy)
+ zoom *= 0.9;
+ if(Tiny::event.scroll.negy)
+ zoom /= 0.9;
+
+ if(Tiny::event.active[SDLK_w])
+ py -= 0.05*zoom;
+
+ if(Tiny::event.active[SDLK_a])
+ px += 0.05*zoom;
+
+ if(Tiny::event.active[SDLK_s])
+ py += 0.05*zoom;
+
+ if(Tiny::event.active[SDLK_d])
+ px -= 0.05*zoom;
+
+};
+
+//Interface Function
+Handle interfaceFunc = [&](){
+ //Window Size
+ ImGui::SetNextWindowSize(ImVec2(480, 260), ImGuiCond_Once);
+ ImGui::SetNextWindowPos(ImVec2(50, 470), ImGuiCond_Once);
+
+ //Open Window
+ ImGui::Begin("Julia Set Controller", NULL, ImGuiWindowFlags_NoResize);
+
+ if(ImGui::BeginTabBar("Tab Bar", ImGuiTabBarFlags_None)){
+ //Current Position Information
+ if(ImGui::BeginTabItem("Info")){
+ ImGui::Text("Position:"); ImGui::SameLine();
+ ImGui::Text("( %f,", px); ImGui::SameLine();
+ ImGui::Text(" %f )", py);
+ ImGui::Text("Zoom: "); ImGui::SameLine();
+ ImGui::Text("%f", zoom);
+ if(ImGui::Button("Randomize")){ //Randomize
+ t = 0.0; //Reset Time
+ radius = 1.0;
+ active = true;
+ appearAmp = 1.0+(float)(rand()%200)/1000.0;
+ rate = 0.002;
+ order = rand()%4+2; //2-6
+ appear = rand()%2;
+ movex = rand()%2;
+ movey = rand()%2;
+ res = rand()%15+10;
+ center[0] = (float)(rand()%2000)/1000.0-1.0;
+ center[1] = (float)(rand()%2000)/1000.0-1.0;
+ phase[0] = (float)(rand()%2000)/1000.0-1.0;
+ phase[1] = (float)(rand()%2000)/1000.0-1.0;
+ amplitude[0] = (float)(rand()%800)/1000.0+0.2;
+ amplitude[1] = (float)(rand()%800)/1000.0+0.2;
+ }
+ ImGui::EndTabItem();
+ }
+ if(ImGui::BeginTabItem("Control")){
+ ImGui::DragInt("Order", &order, 1, 0, 10);
+ ImGui::DragInt("Resolution", &res, 1, 0, 500);
+ ImGui::DragFloat("Convergence", &radius, 0.01f, 0.0f, 2.0f);
+ ImGui::DragFloat2("Bias", bias, 0.005f, -10.0f, 10.0f);
+ ImGui::EndTabItem();
+ }
+ if(ImGui::BeginTabItem("Visual")){
+ ImGui::ColorEdit3("Converge Color", cc);
+ ImGui::ColorEdit3("Diverge Color", dc);
+ ImGui::EndTabItem();
+ }
+ if(ImGui::BeginTabItem("Animate")){
+ ImGui::DragFloat("Rate", &rate, 0.0001f, 0.001f, 0.01f);
+ ImGui::SameLine(); ImGui::Checkbox("Run", &active);
+ ImGui::Checkbox("Appear", &appear); ImGui::SameLine();
+ ImGui::Checkbox("Move X", &movex); ImGui::SameLine();
+ ImGui::Checkbox("Move Y", &movey);
+ ImGui::DragFloat2("Phase", phase, 0.001f, -1.0f, 1.0f);
+ ImGui::DragFloat2("Amplitude", amplitude, 0.01f, 0.0f, 10.0f);
+ ImGui::DragFloat2("Center", center, 0.001f, -10.0f, 10.0f);
+ ImGui::DragFloat("Appear Amplitude", &appearAmp, 0.01f, 0.0f, 2.0f); ImGui::SameLine();
+
+ ImGui::EndTabItem();
+ }
+ ImGui::EndTabBar();
+ }
+
+ ImGui::End();
+};
diff --git a/win/TinyEngineWin/4_Julia/shader/julia.fs b/win/TinyEngineWin/4_Julia/shader/julia.fs
new file mode 100644
index 0000000..a372cb1
--- /dev/null
+++ b/win/TinyEngineWin/4_Julia/shader/julia.fs
@@ -0,0 +1,49 @@
+#version 130
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+//Uniform Parameters
+uniform int maxiter;
+uniform float radius;
+uniform vec2 bias;
+uniform float zoom;
+uniform int order;
+uniform vec2 offset;
+
+//Colors
+uniform vec4 converge;
+uniform vec4 diverge;
+
+//Complex Product
+vec2 cprod(vec2 a, vec2 b){
+ return vec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
+}
+
+//Complex Power
+vec2 cpow(vec2 a, int n){
+ vec2 b = a;
+ if(n == 0) return vec2(1, 0);
+ for(int i = 1; i < n; i++)
+ b = cprod(b, a);
+ return b;
+}
+
+vec4 julia(vec2 p){
+ //Move the Image
+ p = (p*2-vec2(1.0))*zoom-offset;
+
+ //Find the Convergence Behavior
+ int iter = 0;
+ while(length(p) < radius && iter < maxiter){
+ p = 2*cpow(p, order)+4*cpow(p, order+1)-3*cpow(p, order+2)+bias;
+ iter++;
+ }
+
+ //Pick the Pixel Color
+ if(iter == maxiter) return converge;
+ else return mix(diverge, converge, float(iter)/float(maxiter));
+}
+
+void main(){
+ fragColor = julia(ex_Tex);
+}
diff --git a/win/TinyEngineWin/4_Julia/shader/julia.vs b/win/TinyEngineWin/4_Julia/shader/julia.vs
new file mode 100644
index 0000000..d90e341
--- /dev/null
+++ b/win/TinyEngineWin/4_Julia/shader/julia.vs
@@ -0,0 +1,12 @@
+#version 130
+in vec2 in_Quad;
+in vec2 in_Tex;
+out vec2 ex_Tex;
+
+//Position the Billboard in space!
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, -1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/5_Particles/5_Particles.vcxproj b/win/TinyEngineWin/5_Particles/5_Particles.vcxproj
new file mode 100644
index 0000000..125d925
--- /dev/null
+++ b/win/TinyEngineWin/5_Particles/5_Particles.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/5_Particles/5_Particles.vcxproj.filters b/win/TinyEngineWin/5_Particles/5_Particles.vcxproj.filters
new file mode 100644
index 0000000..8aae4d6
--- /dev/null
+++ b/win/TinyEngineWin/5_Particles/5_Particles.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/5_Particles/dot.png b/win/TinyEngineWin/5_Particles/dot.png
new file mode 100644
index 0000000..7e082b4
Binary files /dev/null and b/win/TinyEngineWin/5_Particles/dot.png differ
diff --git a/win/TinyEngineWin/5_Particles/imgui.ini b/win/TinyEngineWin/5_Particles/imgui.ini
new file mode 100644
index 0000000..5e7278e
--- /dev/null
+++ b/win/TinyEngineWin/5_Particles/imgui.ini
@@ -0,0 +1,5 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
diff --git a/win/TinyEngineWin/5_Particles/main.cpp b/win/TinyEngineWin/5_Particles/main.cpp
new file mode 100644
index 0000000..bce590c
--- /dev/null
+++ b/win/TinyEngineWin/5_Particles/main.cpp
@@ -0,0 +1,46 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/image.h"
+#include "../../../include/helpers/color.h"
+
+#include "model.h"
+
+int main( int argc, char* args[] ) {
+
+ Tiny::window("Particle System", WIDTH, HEIGHT);
+ Tiny::event.handler = eventHandler;
+ Tiny::view.interface = [&](){ /* ... */ }; //No Interface
+
+ setup(); //Prepare Model Stuff
+
+ Square3D model; //Model we want to instance render!
+
+ std::vector models;
+ for(int i = 0; i < 1000; i++){ //Generate random model matrices
+ glm::mat4 model = glm::translate(glm::mat4(1.0), glm::vec3(rand()%101-50, rand()%101-50, rand()%101-50));
+ models.push_back(glm::rotate(model, 2.0f*3.14159265f*(float)(rand()%360)/360.0f, glm::vec3(0.0, 1.0, 0.0)));
+ }
+ Instance particle(&model); //Particle system based on this model
+ particle.addBuffer(models); //Update particle system
+
+ Texture tex(image::load("dot.png")); //Texture to draw onto the model
+ Shader particleShader({"shader/particle.vs", "shader/particle.fs"}, {"in_Quad", "in_Tex", "in_Model"});
+
+ Tiny::view.pipeline = [&](){
+
+ Tiny::view.target(color::black);
+
+ particleShader.use();
+ particleShader.texture("spriteTexture", tex);
+ particleShader.uniform("projectionCamera", projection*camera);
+ particle.render();
+
+ };
+
+ Tiny::loop([&](){ //Autorotate Camera
+ camera = glm::rotate(camera, glm::radians(0.1f), glm::vec3(0.0f, 1.0f, 0.0f));
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/5_Particles/model.h b/win/TinyEngineWin/5_Particles/model.h
new file mode 100644
index 0000000..9e9e9c1
--- /dev/null
+++ b/win/TinyEngineWin/5_Particles/model.h
@@ -0,0 +1,40 @@
+
+const int WIDTH = 800;
+const int HEIGHT = 800;
+
+float zoom = 0.05;
+float zoomInc = 0.001;
+float rotation = 0.0f;
+glm::vec3 cameraPos = glm::vec3(50, 50, 50);
+glm::vec3 lookPos = glm::vec3(0, 0, 0);
+glm::mat4 camera = glm::lookAt(cameraPos, lookPos, glm::vec3(0,1,0));
+glm::mat4 projection;
+
+void setup(){
+ projection = glm::ortho(-(float)Tiny::view.WIDTH*zoom, (float)Tiny::view.WIDTH*zoom, -(float)Tiny::view.HEIGHT*zoom, (float)Tiny::view.HEIGHT*zoom, -800.0f, 500.0f);
+};
+
+std::function eventHandler = [&](){
+
+ if(Tiny::event.scroll.posy && zoom <= 0.3){
+ zoom += zoomInc;
+ projection = glm::ortho(-(float)WIDTH*zoom, (float)WIDTH*zoom, -(float)HEIGHT*zoom, (float)HEIGHT*zoom, -800.0f, 500.0f);
+ }
+ if(Tiny::event.scroll.negy && zoom > 0.005){
+ zoom -= zoomInc;
+ projection = glm::ortho(-(float)WIDTH*zoom, (float)WIDTH*zoom, -(float)HEIGHT*zoom, (float)HEIGHT*zoom, -800.0f, 500.0f);
+ }
+ if(Tiny::event.scroll.posx){
+ rotation += 1.5f;
+ if(rotation < 0.0) rotation = 360.0 + rotation;
+ else if(rotation > 360.0) rotation = rotation - 360.0;
+ camera = glm::rotate(camera, glm::radians(1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
+ }
+ if(Tiny::event.scroll.negx){
+ rotation -= 1.5f;
+ if(rotation < 0.0) rotation = 360.0 + rotation;
+ else if(rotation > 360.0) rotation = rotation - 360.0;
+ camera = glm::rotate(camera, glm::radians(-1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
+ }
+
+};
diff --git a/win/TinyEngineWin/5_Particles/shader/particle.fs b/win/TinyEngineWin/5_Particles/shader/particle.fs
new file mode 100644
index 0000000..e779d33
--- /dev/null
+++ b/win/TinyEngineWin/5_Particles/shader/particle.fs
@@ -0,0 +1,13 @@
+#version 130
+
+in vec2 ex_Tex;
+
+uniform sampler2D spriteTexture;
+
+out vec4 fragColor;
+
+void main(void) {
+ vec4 color = texture(spriteTexture, ex_Tex);
+ if(color.a == 0.0) discard;
+ else fragColor = color;
+}
diff --git a/win/TinyEngineWin/5_Particles/shader/particle.vs b/win/TinyEngineWin/5_Particles/shader/particle.vs
new file mode 100644
index 0000000..ba446ad
--- /dev/null
+++ b/win/TinyEngineWin/5_Particles/shader/particle.vs
@@ -0,0 +1,18 @@
+#version 130
+
+in vec3 in_Quad;
+in vec2 in_Tex;
+in mat4 in_Model;
+
+uniform mat4 projectionCamera;
+
+out vec2 ex_Tex;
+out vec3 ex_Color;
+
+void main(void) {
+ //Pass Texture Coordinates
+ ex_Tex = in_Tex;
+
+ //Actual Position in Space
+ gl_Position = projectionCamera * in_Model * vec4(in_Quad, 1.0f);
+}
diff --git a/win/TinyEngineWin/6_Tree/6_Tree.vcxproj b/win/TinyEngineWin/6_Tree/6_Tree.vcxproj
new file mode 100644
index 0000000..3fb4f72
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/6_Tree.vcxproj
@@ -0,0 +1,188 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/6_Tree/6_Tree.vcxproj.filters b/win/TinyEngineWin/6_Tree/6_Tree.vcxproj.filters
new file mode 100644
index 0000000..bf0444e
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/6_Tree.vcxproj.filters
@@ -0,0 +1,75 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/6_Tree/imgui.ini b/win/TinyEngineWin/6_Tree/imgui.ini
new file mode 100644
index 0000000..0ab8e49
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/imgui.ini
@@ -0,0 +1,10 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
+[Window][Tree Controller]
+Pos=20,10
+Size=443,591
+Collapsed=0
+
diff --git a/win/TinyEngineWin/6_Tree/instance_.cpp b/win/TinyEngineWin/6_Tree/instance_.cpp
new file mode 100644
index 0000000..c7a46ce
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/instance_.cpp
@@ -0,0 +1,96 @@
+class Instance{
+public:
+
+ Instance(Primitive* _m){
+ m = _m;
+ };
+
+ ~Instance(){
+ for(auto& b: instances){
+ glDeleteBuffers(1, &b);
+ }
+ }
+
+ Primitive* m; //Instanced Render Model (must be derived from primitive)
+ std::vector instances; //Instance VBO Pointers
+ unsigned int SIZE; //Number of Instances
+
+ template void addBuffer(std::vector& buf);
+ template void updateBuffer(std::vector& buf, int index);
+ template void configBuffer(GLuint instance);
+
+ void render(GLenum mode = GL_TRIANGLE_STRIP); //Default because of primitive models
+};
+
+template
+void Instance::addBuffer(std::vector& buf){
+ GLuint instance;
+ glGenBuffers(1, &instance);
+ SIZE = buf.size(); //Update the Number of Instances
+
+ glBindVertexArray(m->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, instance); //Bind Instance Buffer and Data
+
+#if _DEBUG
+ /*
+ Required for Windows Debug builds only.
+ Leaving the data field as &buf[0] casues an array index error and
+ crashes the program. Passing NULL indicates to OpenGL that there is
+ no data to be copied. I don't know what Visual Studio changes in the
+ release build that prevents this.
+ */
+ if (buf.size() == 0)
+ glBufferData(GL_ARRAY_BUFFER, SIZE * sizeof(D), NULL, GL_STATIC_DRAW);
+ else
+#endif
+ glBufferData(GL_ARRAY_BUFFER, SIZE*sizeof(D), &buf[0], GL_STATIC_DRAW);
+
+ configBuffer(instance);
+}
+
+template
+void Instance::configBuffer(GLuint instance){
+ glEnableVertexAttribArray(m->vbo.size()+instances.size());
+ glVertexAttribPointer(m->vbo.size()+instances.size(), sizeof(D)/sizeof(GLfloat), GL_FLOAT, GL_FALSE, 0, (void*)0);
+ glVertexAttribDivisor(m->vbo.size()+instances.size(), 1);
+ instances.push_back(instance);
+}
+
+template<> //For Matrices - Special Procedure
+void Instance::configBuffer(GLuint instance){
+ for(int i = 0; i < 4; i++){
+ glEnableVertexAttribArray(m->vbo.size()+instances.size());
+ glVertexAttribPointer(m->vbo.size()+instances.size(), 4, GL_FLOAT, GL_FALSE, 4*sizeof(glm::vec4), (void*)(i*sizeof(glm::vec4)));
+ glVertexAttribDivisor(m->vbo.size()+instances.size(), 1);
+ instances.push_back(instance);
+ }
+}
+
+template
+void Instance::updateBuffer(std::vector& buf, int index){
+ glBindVertexArray(m->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, instances[index]); //Bind Instance Buffer and Data
+
+ if(buf.size() != SIZE)
+ glBufferData(GL_ARRAY_BUFFER, buf.size()*sizeof(D), &buf[0], GL_STATIC_DRAW);
+#if _DEBUG
+ else if (buf.size() == 0)
+ /*
+ Required for Windows Debug builds only.
+ Leaving the data field as &buf[0] casues an array index error and
+ crashes the program. Passing NULL indicates to OpenGL that there is
+ no data to be copied. I don't know what Visual Studio changes in the
+ release build that prevents this.
+ */
+ glBufferSubData(GL_ARRAY_BUFFER, 0, SIZE * sizeof(D), NULL);
+#endif
+ else
+ glBufferSubData(GL_ARRAY_BUFFER, 0, SIZE*sizeof(D), &buf[0]);
+
+ SIZE = buf.size();
+}
+
+void Instance::render(GLenum mode){
+ glBindVertexArray(m->vao);
+ glDrawArraysInstanced(mode, 0, m->SIZE, SIZE); //Instanced render
+}
diff --git a/win/TinyEngineWin/6_Tree/leaf.png b/win/TinyEngineWin/6_Tree/leaf.png
new file mode 100644
index 0000000..a01ef26
Binary files /dev/null and b/win/TinyEngineWin/6_Tree/leaf.png differ
diff --git a/win/TinyEngineWin/6_Tree/main.cpp b/win/TinyEngineWin/6_Tree/main.cpp
new file mode 100644
index 0000000..5b176d7
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/main.cpp
@@ -0,0 +1,178 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/image.h"
+#include "../../../include/helpers/color.h"
+#include "../../../include/helpers/helper.h"
+
+#include
+
+#include "model.h"
+
+/*
+* This function is necessary for Windows debug builds when
+* compiling with Visual Studio 2019. It adds one 4x4 zero
+* matrix to a vector of glm::mat4. Without this a vector of size 0
+* passed to glBufferData and glBufferSubData will throw an array
+* subscript error when trying to read the value of element 0.
+*
+* This doesn't happen on release builds, though I'm not sure
+* why. Perhaps something to do with how the memory is initialised
+* (or not initialised) for release builds.
+*
+* Also not sure why when this program is compiled with g++ on
+* Linux the problem doesn't occur if the empty vector is passed in.
+*/
+void initLeaves(std::vector& leaves)
+{
+ float vals[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+ glm::mat4 newMat4 = glm::make_mat4(vals);
+ leaves.push_back(newMat4);
+}
+
+int main( int argc, char* args[] ) {
+
+ Tiny::view.lineWidth = 1.0f;
+
+ Tiny::window("Procedural Tree", WIDTH, HEIGHT);
+ Tiny::event.handler = eventHandler;
+ Tiny::view.interface = interfaceFunc;
+
+ setup(); //Prepare Model Stuff
+
+ Model treemesh(_construct); //Construct a Mesh
+
+ Square3D flat; //Geometry for Particle System
+
+ std::vector leaves;
+ addLeaves(leaves, true); //Generate the model matrices
+
+ Instance particle(&flat); //Make Particle System
+
+#if _DEBUG
+ initLeaves(leaves); // Necessary for windows debug builds
+#endif
+ particle.addBuffer(leaves); //Add Matrices
+
+ Texture tex(image::load("leaf.png"));
+
+ Shader particleShader({"shader/particle.vs", "shader/particle.fs"}, {"in_Quad", "in_Tex", "in_Model"});
+ Shader defaultShader({"shader/default.vs", "shader/default.fs"}, {"in_Position", "in_Normal"});
+ Shader depth({"shader/depth.vs", "shader/depth.fs"}, {"in_Position"});
+ Shader particledepth({"shader/particledepth.vs", "shader/particledepth.fs"}, {"in_Quad", "in_Tex", "in_Model"});
+ Billboard shadow(1600, 1600, false); //No Color Buffer
+
+ Model floor(construct_floor);
+ floor.move(glm::vec3(0), 0, glm::vec3(1000)); //So we can cast shadows
+
+ Tiny::view.pipeline = [&](){ //Setup Drawing Pipeline
+
+ shadow.target();
+ if(drawshadow){
+ depth.use();
+ depth.uniform("dvp", lproj*lview);
+ defaultShader.uniform("model", treemesh.model);
+ treemesh.render(GL_TRIANGLES);
+ }
+ if(leafshadow){
+ particledepth.use();
+ particledepth.uniform("dvp", lproj*lview);
+ particledepth.texture("spriteTexture", tex);
+ addLeaves(leaves, false); //Generate the model matrices
+
+#if _DEBUG
+ if (leaves.size() == 0)
+ initLeaves(leaves); // Necessary for windows debug builds
+#endif
+ particle.updateBuffer(leaves, 0);
+
+ particle.render(GL_TRIANGLE_STRIP); //Render Particle System
+ }
+
+ //Prepare Render Target
+ Tiny::view.target(glm::vec3(backcolor[0], backcolor[1], backcolor[2]));
+
+ if(drawwire || drawtree){
+ defaultShader.use();
+ defaultShader.uniform("model", treemesh.model);
+ defaultShader.uniform("projectionCamera", projection*camera);
+ defaultShader.uniform("lightcolor", lightcolor);
+ defaultShader.uniform("lookDir", lookPos - cameraPos);
+ defaultShader.uniform("lightDir", lightpos);
+
+ defaultShader.uniform("drawshadow", drawshadow);
+ if(drawshadow){
+ defaultShader.uniform("dbvp", bias*lproj*lview);
+ defaultShader.texture("shadowMap", shadow.depth);
+ defaultShader.uniform("light", lightpos);
+ }
+
+ defaultShader.uniform("drawfloor", true);
+ defaultShader.uniform("drawcolor", glm::vec4(backcolor[0],backcolor[1],backcolor[2],1));
+ defaultShader.uniform("model", floor.model);
+ floor.render();
+ defaultShader.uniform("drawfloor", false);
+
+ defaultShader.uniform("model", treemesh.model);
+
+ if(drawtree){
+ defaultShader.uniform("drawcolor", glm::vec4(treecolor[0], treecolor[1], treecolor[2], treeopacity));
+ defaultShader.uniform("wireframe", false);
+ treemesh.render(GL_TRIANGLES);
+ }
+
+ if(drawwire){
+ defaultShader.uniform("drawcolor", glm::vec4(wirecolor[0], wirecolor[1], wirecolor[2], 1.0));
+ defaultShader.uniform("wireframe", true);
+ treemesh.render(GL_LINES);
+ }
+ }
+
+ if(drawleaf){
+ particleShader.use();
+ particleShader.texture("spriteTexture", tex);
+ particleShader.uniform("projectionCamera", projection*camera);
+ particleShader.uniform("leafcolor", glm::vec4(leafcolor[0], leafcolor[1], leafcolor[2], leafopacity));
+ particleShader.uniform("lightcolor", lightcolor);
+
+ particleShader.uniform("selfshadow", selfshadow);
+ if(selfshadow){
+ particleShader.uniform("dbvp", bias*lproj*lview);
+ particleShader.texture("shadowMap", shadow.depth);
+ particleShader.uniform("light", lightpos);
+ }
+
+ particleShader.uniform("lookDir", lookPos - cameraPos);
+ addLeaves(leaves, true);
+
+#if _DEBUG
+ if (leaves.size() == 0)
+ initLeaves(leaves); // Necessary for windows debug builds
+#endif
+ particle.updateBuffer(leaves, 0);
+ particle.render(GL_TRIANGLE_STRIP); //Render Particle System
+ }
+ };
+
+ //Loop over Stuff
+ Tiny::loop([&](){ /* ... */
+
+ if(autorotate){
+ camera = glm::rotate(camera, glm::radians(0.5f), glm::vec3(0.0f, 1.0f, 0.0f));
+ rotation += 0.5f;
+ }
+
+ if(!paused)
+ root->grow(growthrate);
+
+ //Update Rendering Structures
+ treemesh.construct(_construct);
+ particle.updateBuffer(leaves, 0);
+
+ });
+
+ //Get rid of this thing!
+ delete root;
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/6_Tree/model.h b/win/TinyEngineWin/6_Tree/model.h
new file mode 100644
index 0000000..e0a610d
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/model.h
@@ -0,0 +1,222 @@
+//Parameters
+#define PI 3.14159265f
+
+const int WIDTH = 1200;
+const int HEIGHT = 800;
+
+float zoom = 0.5;
+float zoomInc = 0.99;
+float rotation = 0.0f;
+glm::vec3 cameraPos = glm::vec3(50, 200, 50);
+glm::vec3 lookPos = glm::vec3(0, 180, 0);
+glm::mat4 camera = glm::lookAt(cameraPos, lookPos, glm::vec3(0,1,0));
+glm::mat4 projection;
+
+bool paused = false;
+bool autorotate = true;
+bool drawwire = false;
+bool drawtree = true;
+bool drawleaf = true;
+
+float leafcolor[3] = {0.82, 0.13, 0.23};
+float treecolor[3] = {1.00, 1.00, 1.00};
+float wirecolor[3] = {0.00, 0.00, 0.00};
+float backcolor[3] = {0.80, 0.80, 0.80};
+float lightcolor[3] = {1.00, 1.00, 1.00};
+float leafopacity = 0.9;
+int leafmindepth = 8;
+float treeopacity = 1.0;
+float treescale[2] = {15.0f, 5.0f};
+
+int ringsize = 12;
+int leafcount = 10;
+float leafsize = 5.0;
+float taper = 0.6;
+float leafspread[3] = {50.0, 50.0, 50.0};
+
+float growthrate = 1.0;
+float passratio = 0.3;
+float splitdecay = 1E-2;
+float directedness = 0.5;
+int localdepth = 2;
+bool conservearea = true;
+
+bool drawshadow = true;
+bool selfshadow = true;
+bool leafshadow = true;
+glm::vec3 lightpos = glm::vec3(50);
+glm::mat4 bias = glm::mat4(
+ 0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0
+);
+glm::mat4 lproj = glm::ortho(-300.0f, 300.0f, -300.0f, 400.0f, -200.0f, 800.0f);
+glm::mat4 lview = glm::lookAt(lightpos, glm::vec3(0), glm::vec3(0,1,0));
+
+#include "tree.h"
+
+void setup(){
+ projection = glm::ortho(-(float)Tiny::view.WIDTH*zoom, (float)Tiny::view.WIDTH*zoom, -(float)Tiny::view.HEIGHT*zoom, (float)Tiny::view.HEIGHT*zoom, -500.0f, 800.0f);
+ srand(time(NULL));
+ root = new Branch({0.6, 0.45, 2.5}); //Create Root
+}
+
+// Event Handler
+std::function eventHandler = [&](){
+
+ if(Tiny::event.scroll.posy){
+ zoom /= zoomInc;
+ projection = glm::ortho(-(float)Tiny::view.WIDTH*zoom, (float)Tiny::view.WIDTH*zoom, -(float)Tiny::view.HEIGHT*zoom, (float)Tiny::view.HEIGHT*zoom, -500.0f, 800.0f);
+ }
+ if(Tiny::event.scroll.negy){
+ zoom *= zoomInc;
+ projection = glm::ortho(-(float)Tiny::view.WIDTH*zoom, (float)Tiny::view.WIDTH*zoom, -(float)Tiny::view.HEIGHT*zoom, (float)Tiny::view.HEIGHT*zoom, -500.0f, 800.0f);
+ }
+ if(Tiny::event.scroll.posx){
+ rotation += 1.5f;
+ if(rotation < 0.0) rotation = 360.0 + rotation;
+ else if(rotation > 360.0) rotation = rotation - 360.0;
+ camera = glm::rotate(camera, glm::radians(1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
+ }
+ if(Tiny::event.scroll.negx){
+ rotation -= 1.5f;
+ if(rotation < 0.0) rotation = 360.0 + rotation;
+ else if(rotation > 360.0) rotation = rotation - 360.0;
+ camera = glm::rotate(camera, glm::radians(-1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
+ }
+
+ //Pause Toggle
+ if(!Tiny::event.press.empty()){
+ if(Tiny::event.press.back() == SDLK_p)
+ paused = !paused;
+ else if(Tiny::event.press.back() == SDLK_a)
+ autorotate = !autorotate;
+
+ //Regrow
+ else if(Tiny::event.press.back() == SDLK_r){
+ Branch* newroot = new Branch(root, true);
+ delete(root);
+ root = newroot;
+ }
+ }
+
+};
+
+//Interface Function
+Handle interfaceFunc = [&](){
+ //Window Size
+ ImGui::SetNextWindowSize(ImVec2(360, 400), ImGuiCond_Once);
+ ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_Once);
+
+ //Open Window
+ ImGui::Begin("Tree Controller", NULL, ImGuiWindowFlags_None);
+ if(ImGui::BeginTabBar("Tab Bar", ImGuiTabBarFlags_None)){
+ if(ImGui::BeginTabItem("Info")){
+
+ ImGui::Checkbox("Pause [P]", &paused);
+ ImGui::Checkbox("Auto-Rotate [A]", &autorotate);
+
+ ImGui::ColorEdit3("Background", backcolor);
+// ImGui::ColorEdit3("Light Color", lightcolor);
+
+ ImGui::Text("Made by Nicholas McDonald");
+ ImGui::EndTabItem();
+
+ }
+
+ if(ImGui::BeginTabItem("Growth")){
+
+ if(ImGui::Button("Re-Grow [R]")){
+ Branch* newroot = new Branch(root, true);
+ delete(root);
+ root = newroot;
+ }
+
+ ImGui::Text("Growth Behavior");
+ ImGui::DragFloat("Growth Rate", &growthrate, 0.01f, 0.0f, 5.0f);
+ ImGui::Checkbox("Conserve Crossectional Area", &conservearea);
+ if(!conservearea)
+ ImGui::DragFloat("Pass Ratio", &passratio, 0.01f, 0.0f, 1.0f);
+
+ ImGui::Text("Split Behavior");
+ ImGui::DragFloat("Ratio", &root->ratio, 0.01f, 0.0f, 1.0f);
+ ImGui::DragFloat("Size", &root->splitsize, 0.1f, 0.1f, 5.0f);
+ ImGui::DragFloat("Decay", &splitdecay, 0.001f, 0.0f, 1.0f);
+
+ ImGui::Text("Growth Direction");
+ ImGui::DragFloat("Spread", &root->spread, 0.01f, 0.0f, 5.0f);
+ ImGui::DragFloat("Directedness", &directedness, 0.01f, 0.0f, 1.0f);
+ ImGui::DragInt("Local Depth", &localdepth, 1, 0, 15);
+
+ ImGui::EndTabItem();
+ }
+
+ if(ImGui::BeginTabItem("Leaf")){
+ ImGui::ColorEdit3("Color", leafcolor);
+ ImGui::DragFloat("Opacity", &leafopacity, 0.01f, 0.0f, 1.0f);
+ ImGui::DragInt("Count", &leafcount, 1, 0, 30);
+ ImGui::DragInt("Minimum Depth", &leafmindepth, 1, 0, 15);
+ ImGui::DragFloat3("Spread", leafspread, 0.1f, 0.0f, 250.0f);
+ ImGui::DragFloat("Size", &leafsize, 0.1f, 0.0f, 25.0f);
+ ImGui::Checkbox("Draw", &drawleaf); ImGui::SameLine();
+ ImGui::Checkbox("Shade", &leafshadow); ImGui::SameLine();
+ ImGui::Checkbox("Self-Shade", &selfshadow);
+
+ ImGui::EndTabItem();
+ }
+
+ if(ImGui::BeginTabItem("Tree")){
+ ImGui::ColorEdit3("Fill", treecolor);
+ ImGui::ColorEdit3("Wire", wirecolor);
+ ImGui::DragFloat("Opacity", &treeopacity, 0.01f, 0.0f, 1.0f);
+ ImGui::DragFloat2("Scale", treescale, 0.01f, 0.1f, 50.0f);
+ ImGui::DragFloat("Taper", &taper, 0.01f, 0.0f, 1.0f);
+
+ ImGui::Checkbox("Draw", &drawtree); ImGui::SameLine();
+ ImGui::Checkbox("Wire", &drawwire); ImGui::SameLine();
+ ImGui::Checkbox("Shade", &drawshadow);
+
+ ImGui::DragInt("Mesh", &ringsize, 1, 3, 12);
+
+ ImGui::EndTabItem();
+ }
+ ImGui::EndTabBar();
+ }
+
+ ImGui::End();
+};
+
+std::function construct_floor = [&](Model* h){
+
+ float floor[24] = {
+ -1.0, 0.0, -1.0,
+ -1.0, 0.0, 1.0,
+ 1.0, 0.0, -1.0,
+ 1.0, 0.0, 1.0,
+ };
+
+ for(int i = 0; i < 12; i++)
+ h->positions.push_back(floor[i]);
+
+ h->indices.push_back(0);
+ h->indices.push_back(1);
+ h->indices.push_back(2);
+
+ h->indices.push_back(1);
+ h->indices.push_back(3);
+ h->indices.push_back(2);
+
+ glm::vec3 floorcolor = glm::vec3(0.65, 0.5, 0.3);
+
+ for(int i = 0; i < 4; i++){
+ h->normals.push_back(0.0);
+ h->normals.push_back(1.0);
+ h->normals.push_back(0.0);
+
+ h->colors.push_back(floorcolor.x);
+ h->colors.push_back(floorcolor.y);
+ h->colors.push_back(floorcolor.z);
+ h->colors.push_back(1.0);
+ }
+};
diff --git a/win/TinyEngineWin/6_Tree/screenshots/Redtree.png b/win/TinyEngineWin/6_Tree/screenshots/Redtree.png
new file mode 100644
index 0000000..778bfed
Binary files /dev/null and b/win/TinyEngineWin/6_Tree/screenshots/Redtree.png differ
diff --git a/win/TinyEngineWin/6_Tree/screenshots/Yellowtree.png b/win/TinyEngineWin/6_Tree/screenshots/Yellowtree.png
new file mode 100644
index 0000000..a230be5
Binary files /dev/null and b/win/TinyEngineWin/6_Tree/screenshots/Yellowtree.png differ
diff --git a/win/TinyEngineWin/6_Tree/shader/default.fs b/win/TinyEngineWin/6_Tree/shader/default.fs
new file mode 100644
index 0000000..fb1e9cf
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/default.fs
@@ -0,0 +1,62 @@
+#version 130
+
+in vec4 ex_Color;
+in vec3 ex_Normal;
+in vec3 ex_FragPos;
+in vec4 ex_Shadow;
+
+out vec4 fragColor;
+
+uniform vec4 drawcolor;
+
+uniform bool wireframe;
+uniform bool drawfloor;
+
+uniform vec3 light;
+
+uniform sampler2D shadowMap;
+
+float gridSample(int size){
+ float shadow = 0.0;
+ float cur = ex_Shadow.z;
+
+ float m = 1 - dot(ex_Normal, normalize(light));
+ float bias = mix(0.005, 0.001*m, pow(m, 5));
+
+ for(int x = -size; x <= size; ++x){
+ for(int y = -size; y <= size; ++y){
+ float near = texture(shadowMap, ex_Shadow.xy + vec2(x, y) / textureSize(shadowMap, 0)).r;
+ shadow += cur-bias > near ? 1.0 : 0.0;
+ }
+ }
+
+ float norm = (2*size+1)*(2*size+1);
+ return shadow/norm;
+}
+
+float shade(){
+ float shadow = 0.0;
+ int size = 1;
+
+ if(greaterThanEqual(ex_Shadow.xy, vec2(0.0f)) == bvec2(true) && lessThanEqual(ex_Shadow.xy, vec2(1.0f)) == bvec2(true))
+ shadow = gridSample(size);
+
+ return shadow;
+}
+
+uniform vec3 lightcolor;
+
+vec4 directionalLight(){
+ float orthoshade = 0.5*shade();
+ return vec4((1.0-orthoshade)*lightcolor, 1.0);
+}
+
+uniform bool drawshadow;
+
+void main(void) {
+ vec4 _light = vec4(1.0);
+ if(drawshadow) _light = directionalLight();
+ if(drawfloor) fragColor = _light*drawcolor;
+ else if(!wireframe) fragColor = _light*drawcolor;
+ else fragColor = drawcolor;
+}
diff --git a/win/TinyEngineWin/6_Tree/shader/default.vs b/win/TinyEngineWin/6_Tree/shader/default.vs
new file mode 100644
index 0000000..538ab63
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/default.vs
@@ -0,0 +1,28 @@
+#version 130
+
+in vec3 in_Position;
+in vec3 in_Normal;
+in vec4 in_Color;
+
+uniform mat4 model;
+uniform mat4 projectionCamera;
+uniform mat4 dbvp;
+
+out vec4 ex_Color;
+out vec3 ex_Normal;
+out vec3 ex_FragPos;
+out vec4 ex_Shadow;
+
+
+void main(void) {
+ //Fragment Position in Model Space
+ ex_FragPos = (model * vec4(in_Position, 1.0f)).xyz;
+ ex_Normal = in_Normal; //Pass Normal
+ ex_Shadow = dbvp* vec4(ex_FragPos, 1.0f);
+
+ //Fragment in Screen Space
+ gl_Position = projectionCamera * vec4(ex_FragPos, 1.0f);
+
+ //Color from Normal Vector
+ ex_Color = in_Color;//vec4(normalize(in_Normal), 1.0);
+}
diff --git a/win/TinyEngineWin/6_Tree/shader/depth.fs b/win/TinyEngineWin/6_Tree/shader/depth.fs
new file mode 100644
index 0000000..dbf2c4b
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/depth.fs
@@ -0,0 +1,3 @@
+#version 330 core
+void main() {
+}
diff --git a/win/TinyEngineWin/6_Tree/shader/depth.vs b/win/TinyEngineWin/6_Tree/shader/depth.vs
new file mode 100644
index 0000000..b2253bf
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/depth.vs
@@ -0,0 +1,9 @@
+#version 330 core
+in vec3 in_Position;
+uniform mat4 model;
+uniform mat4 dvp;
+
+void main(void) {
+ // Set the position to the one defined in our vertex array
+ gl_Position = dvp * model * vec4(in_Position, 1.0f);
+}
diff --git a/win/TinyEngineWin/6_Tree/shader/particle.fs b/win/TinyEngineWin/6_Tree/shader/particle.fs
new file mode 100644
index 0000000..91072bf
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/particle.fs
@@ -0,0 +1,65 @@
+#version 130
+
+in vec2 ex_Tex;
+
+uniform sampler2D spriteTexture;
+uniform vec4 leafcolor;
+
+
+in vec4 ex_Shadow;
+
+
+uniform vec3 light;
+uniform vec3 lightcolor;
+
+uniform sampler2D shadowMap;
+
+float gridSample(int size){
+ float shadow = 0.0;
+ float cur = ex_Shadow.z;
+
+ vec3 normal = -light;
+
+ float m = 1 - dot(normal, normalize(light));
+ float bias = 0.001;//mix(0.005, 0.001*m, pow(m, 5));
+
+ for(int x = -size; x <= size; ++x){
+ for(int y = -size; y <= size; ++y){
+ float near = texture(shadowMap, ex_Shadow.xy + vec2(x, y) / textureSize(shadowMap, 0)).r;
+ shadow += cur-bias > near ? 1.0 : 0.0;
+ }
+ }
+
+ float norm = (2*size+1)*(2*size+1);
+ return shadow/norm;
+}
+
+float shade(){
+ float shadow = 0.0;
+ int size = 0;
+
+ if(greaterThanEqual(ex_Shadow.xy, vec2(0.0f)) == bvec2(true) && lessThanEqual(ex_Shadow.xy, vec2(1.0f)) == bvec2(true))
+ shadow = gridSample(size);
+
+ return shadow;
+}
+
+vec4 directionalLight(){
+ float orthoshade = 0.5*shade();
+ return vec4((1.0-orthoshade)*lightcolor, 1.0);
+}
+
+uniform bool selfshadow;
+
+out vec4 fragColor;
+
+void main(void) {
+
+ vec4 color = texture(spriteTexture, ex_Tex);
+ if(color.a == 0.0) discard;
+
+ vec4 _light = vec4(1.0);
+ if(selfshadow) _light = directionalLight();
+ fragColor = _light*leafcolor;
+
+}
diff --git a/win/TinyEngineWin/6_Tree/shader/particle.vs b/win/TinyEngineWin/6_Tree/shader/particle.vs
new file mode 100644
index 0000000..9baca92
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/particle.vs
@@ -0,0 +1,21 @@
+#version 130
+
+in vec3 in_Quad;
+in vec2 in_Tex;
+in mat4 in_Model;
+
+uniform mat4 projectionCamera;
+uniform mat4 dbvp;
+
+out vec2 ex_Tex;
+out vec3 ex_Color;
+out vec4 ex_Shadow;
+
+void main(void) {
+ //Pass Texture Coordinates
+ ex_Tex = in_Tex;
+
+ //Actual Position in Space
+ gl_Position = projectionCamera * in_Model * vec4(in_Quad, 1.0f);
+ ex_Shadow = dbvp * in_Model * vec4(in_Quad, 1.0f);
+}
diff --git a/win/TinyEngineWin/6_Tree/shader/particledepth.fs b/win/TinyEngineWin/6_Tree/shader/particledepth.fs
new file mode 100644
index 0000000..205cc5b
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/particledepth.fs
@@ -0,0 +1,9 @@
+#version 330 core
+in vec2 ex_Tex;
+
+uniform sampler2D spriteTexture;
+
+void main() {
+ vec4 color = texture(spriteTexture, ex_Tex);
+ if(color.a == 0.0) discard;
+}
diff --git a/win/TinyEngineWin/6_Tree/shader/particledepth.vs b/win/TinyEngineWin/6_Tree/shader/particledepth.vs
new file mode 100644
index 0000000..1af0440
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/shader/particledepth.vs
@@ -0,0 +1,13 @@
+#version 330 core
+in vec3 in_Quad;
+in vec2 in_Tex;
+in mat4 in_Model;
+
+out vec2 ex_Tex;
+
+uniform mat4 dvp;
+
+void main(void) {
+ ex_Tex = in_Tex;
+ gl_Position = dvp * in_Model * vec4(in_Quad, 1.0f);
+}
diff --git a/win/TinyEngineWin/6_Tree/tree.h b/win/TinyEngineWin/6_Tree/tree.h
new file mode 100644
index 0000000..1c90545
--- /dev/null
+++ b/win/TinyEngineWin/6_Tree/tree.h
@@ -0,0 +1,253 @@
+struct Branch{
+
+ int ID = 0; //For Leaf Hashing
+ bool leaf = true;
+
+ Branch *A, *B, *P; //Child A, B and Parent
+
+ //Parameters
+ float ratio, spread, splitsize;
+ int depth = 0;
+
+ //Constructors
+ Branch(float r, float s, float ss):
+ ratio {r},
+ spread {s},
+ splitsize {ss}
+ {};
+
+ Branch(Branch* b, bool root):
+ ratio {b->ratio},
+ spread {b->spread},
+ splitsize {b->splitsize}
+ {
+ if(root) return;
+ depth = b->depth+1;
+ P = b; //Set Parent
+ };
+
+ ~Branch(){
+ if(leaf) return;
+ delete(A);
+ delete(B);
+ }
+
+ //Size / Direction Data
+ glm::vec3 dir = glm::vec3(0.0, 1.0, 0.0);
+ float length = 0.0, radius = 0.0, area = 0.1;
+
+ void grow(double _size);
+ void split();
+
+ //Compute Direction to Highest Local Leaf Density
+ glm::vec3 leafdensity(int searchdepth);
+};
+
+void Branch::grow(double feed){
+
+ radius = sqrt(area/PI); //Current Radius
+
+ if(leaf){
+ length += cbrt(feed); //Grow in Length
+ feed -= cbrt(feed) * area; //Reduce Feed
+ area += feed/length; //Grow In Area
+
+ //Split Condition
+ if(length > splitsize * exp(-splitdecay * depth))
+ split(); //Split Behavior
+
+ return;
+ }
+
+ double pass = passratio;
+
+ if(conservearea) //Feedback Control for Area Conservation
+ pass = (A->area+B->area)/(A->area+B->area+area);
+
+ area += pass * feed / length; //Grow in Girth
+ feed *= ( 1.0 - pass ); //Reduce Feed
+
+ if(feed < 1E-5) return; //Prevent Over-Branching
+
+ A->grow(feed*ratio); //Grow Children
+ B->grow(feed*(1.0-ratio));
+}
+
+void Branch::split(){
+
+ leaf = false;
+
+ //Add Child Branches
+ A = new Branch(this, false);
+ B = new Branch(this, false);
+ A->ID = 2 * ID + 0; //Every Leaf ID is Unique (because binary!)
+ B->ID = 2 * ID + 1;
+
+ /* Ideal Growth Direction:
+ Perpendicular to direction with highest leaf density! */
+
+ glm::vec3 D = leafdensity(localdepth); //Direction of Highest Density
+ glm::vec3 N = glm::normalize(glm::cross(dir, D)); //Normal Vector
+ glm::vec3 M = -1.0f*N; //Reflection
+
+ float flip = (rand()%2)?1.0:-1.0; //Random Direction Flip
+ A->dir = glm::normalize( glm::mix(flip*spread*N, dir, ratio) );
+ B->dir = glm::normalize( glm::mix(flip*spread*M, dir, 1.0-ratio) );
+
+}
+
+glm::vec3 Branch::leafdensity(int searchdepth){
+
+ //Random Vector! (for noise)
+ glm::vec3 r = glm::vec3(rand()%100,rand()%100,rand()%100)/glm::vec3(100)-glm::vec3(0.5);
+
+ if(depth == 0) return r;
+
+ /*
+ General Idea: Branches grow away from areas with a high leaf density!
+
+ Therefore, if we can compute a vector that points towards the area with
+ the locally highest leaf density, we can use that to compute our normal
+ for branching.
+
+ Locally high density is determined by descending the tree to some maximum
+ search depth (finding an ancestor node), and computing some leaf-density
+ metric over the descendant node leaves. This is implemented recursively.
+
+ Metric 1: Uniform Weights in Space.
+ Problem: Causes strange spiral artifacts at high-search depths, because it
+ computes the average leaf position of the entire tree. Therefore,
+ the tree grows in a strange way, away from the center.
+
+ Metric 2: Distance weighted average position (i.e. relative vector)
+ Problem: This causes strange cone artifacts when using a sufficiently large
+ search depth. This is also more expensive to compute, and wonky because
+ we compute the distance-weighted average distance (what?? exactly).
+
+ Since both metrics give similar results at a small search-depth (e.g. 2),
+ meaning we only search locally, I will use the one that is simpler to compute.
+ That is Method 1.
+
+ I did throw in a weighting by the branch ratio though, just because I can.
+ That means that the tree should tend to grow away from branches with the most
+ growth potential.
+
+ */
+
+ Branch* C = this; //Ancestor node
+ glm::vec3 rel = glm::vec3(0); //Relative position to start node
+ while(C->depth > 0 && searchdepth-- >= 0){ //Descend tree
+ rel += C->length*C->dir; //Add relative position
+ C = C->P; //Move to parent
+ }
+
+ std::function leafaverage = [&](Branch* b)->glm::vec3{
+ if(b->leaf) return b->length*b->dir;
+ return b->length*b->dir + ratio*leafaverage(b->A) + (1.0f-ratio)*leafaverage(b->B);
+ };
+
+ //Average relative to ancestor, shifted by rel ( + Noise )
+ return directedness*glm::normalize(leafaverage(C) - rel) + (1.0f-directedness)*r;
+}
+
+Branch* root;
+
+// Model Constructing Function for Tree
+std::function _construct = [&](Model* h){
+
+ //Basically Add Lines for the Tree!
+ std::function addBranch = [&](Branch* b, glm::vec3 p){
+
+ glm::vec3 start = p;
+ glm::vec3 end = p + glm::vec3(b->length*treescale[0])*b->dir;
+
+ //Get Some Normal Vector
+ glm::vec3 x = glm::normalize(b->dir + glm::vec3(1.0, 1.0, 1.0));
+ glm::vec4 n = glm::vec4(glm::normalize(glm::cross(b->dir, x)), 1.0);
+
+ //Add the Correct Number of Indices
+ glm::mat4 r = glm::rotate(glm::mat4(1.0), PI/ringsize, b->dir);
+
+ //Index Buffer
+ int _b = h->positions.size()/3;
+
+ //GL TRIANGLES
+ for(int i = 0; i < ringsize; i++){
+ //Bottom Triangle
+ h->indices.push_back(_b+i*2+0);
+ h->indices.push_back(_b+(i*2+2)%(2*ringsize));
+ h->indices.push_back(_b+i*2+1);
+ //Upper Triangle
+ h->indices.push_back(_b+(i*2+2)%(2*ringsize));
+ h->indices.push_back(_b+(i*2+3)%(2*ringsize));
+ h->indices.push_back(_b+i*2+1);
+ }
+
+ for(int i = 0; i < ringsize; i++){
+
+ h->positions.push_back(start.x + b->radius*treescale[1]*n.x);
+ h->positions.push_back(start.y + b->radius*treescale[1]*n.y);
+ h->positions.push_back(start.z + b->radius*treescale[1]*n.z);
+ h->normals.push_back(n.x);
+ h->normals.push_back(n.y);
+ h->normals.push_back(n.z);
+ n = r*n;
+
+ h->positions.push_back(end.x + taper*b->radius*treescale[1]*n.x);
+ h->positions.push_back(end.y + taper*b->radius*treescale[1]*n.y);
+ h->positions.push_back(end.z + taper*b->radius*treescale[1]*n.z);
+ h->normals.push_back(n.x);
+ h->normals.push_back(n.y);
+ h->normals.push_back(n.z);
+ n = r*n;
+
+ }
+
+ //No Leaves
+ if(b->leaf) return;
+
+ addBranch(b->A, end);
+ addBranch(b->B, end);
+ };
+
+ //Recursive add Branches
+ addBranch(root, glm::vec3(0.0));
+};
+
+//Construct Leaf Particle System from Tree Data
+std::function&, bool)> addLeaves = [&](std::vector& p, bool face){
+ p.clear();
+
+ //Explore the Tree and Add Leaves!
+ std::function addLeaf = [&](Branch* b, glm::vec3 pos){
+
+ if(b->leaf){
+
+ if(b->depth < leafmindepth) return;
+
+ for(int i = 0; i < leafcount; i++){
+ //Hashed Random Displace
+ glm::vec3 d = glm::vec3(hashrand(b->ID+i), hashrand(b->ID+i+leafcount), hashrand(b->ID+i+2*leafcount))-glm::vec3(0.5);
+ d = d * glm::vec3(leafspread[0], leafspread[1], leafspread[2]);
+
+ //Rotate Towards Camera (or not) and Scale
+ glm::mat4 model = glm::translate(glm::mat4(1.0), pos+d);
+
+ if(face) model = glm::rotate(model, glm::radians(45.0f-rotation), glm::vec3(0.0, 1.0, 0.0));
+ else model = glm::rotate(model, glm::radians(45.0f), glm::vec3(0.0, 1.0, 0.0));
+
+ p.push_back(glm::scale(model, glm::vec3(leafsize)));
+
+ }
+
+ return;
+ }
+
+ //Otherwise get other leaves!
+ glm::vec3 end = pos + glm::vec3(b->length*treescale[0])*b->dir;
+ addLeaf(b->A, end);
+ addLeaf(b->B, end);
+ };
+
+ addLeaf(root, glm::vec3(0.0));
+};
diff --git a/win/TinyEngineWin/7_SDF/7_SDF.vcxproj b/win/TinyEngineWin/7_SDF/7_SDF.vcxproj
new file mode 100644
index 0000000..377f6ac
--- /dev/null
+++ b/win/TinyEngineWin/7_SDF/7_SDF.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/7_SDF/7_SDF.vcxproj.filters b/win/TinyEngineWin/7_SDF/7_SDF.vcxproj.filters
new file mode 100644
index 0000000..8aae4d6
--- /dev/null
+++ b/win/TinyEngineWin/7_SDF/7_SDF.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/7_SDF/imgui.ini b/win/TinyEngineWin/7_SDF/imgui.ini
new file mode 100644
index 0000000..bb627a3
--- /dev/null
+++ b/win/TinyEngineWin/7_SDF/imgui.ini
@@ -0,0 +1,10 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
+[Window][2D Signed Distance Field Controller]
+Pos=116,220
+Size=480,260
+Collapsed=0
+
diff --git a/win/TinyEngineWin/7_SDF/main.cpp b/win/TinyEngineWin/7_SDF/main.cpp
new file mode 100644
index 0000000..bd8ebc9
--- /dev/null
+++ b/win/TinyEngineWin/7_SDF/main.cpp
@@ -0,0 +1,41 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/color.h"
+
+#include "model.h"
+
+int main( int argc, char* args[] ) {
+ srand(time(NULL)); //SEED
+
+ Tiny::view.vsync = true;
+
+ Tiny::window("2D Signed Distance Field", 1000, 1000); //Open Window
+
+ Tiny::event.handler = eventHandler; //Set Event Handler
+ Tiny::view.interface = interfaceFunc; //Set Interface Function
+
+ Square2D flat; //Flat geometry primitive
+ Shader sdf({"shader/sdf.vs", "shader/sdf.fs"}, {"in_Quad", "in_Tex"});
+
+ Tiny::view.pipeline = [&](){
+
+ Tiny::view.target(color::black); //Target Screen
+
+ sdf.use(); //Use the Shader
+ sdf.uniform("zoom", zoom);
+ sdf.uniform("converge", glm::vec4(cc[0], cc[1], cc[2], cc[3]));
+ sdf.uniform("diverge", glm::vec4(dc[0], dc[1], dc[2], dc[3]));
+ sdf.uniform("offset", glm::vec2(px, py));
+ sdf.uniform("drawlines", drawlines);
+ sdf.uniform("thickness", thickness);
+ sdf.uniform("density", density);
+ sdf.uniform("model", flat.model);
+ flat.render(); //Render with Flat Geometry
+
+ };
+
+ Tiny::loop([&](){}); //Do Nothing
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/7_SDF/model.h b/win/TinyEngineWin/7_SDF/model.h
new file mode 100644
index 0000000..ec9c38c
--- /dev/null
+++ b/win/TinyEngineWin/7_SDF/model.h
@@ -0,0 +1,55 @@
+//Resolution
+double zoom = 1.5;
+double px = 0.0;
+double py = 0.0;
+
+float cc[4] = {0.070, 0.086, 0.211, 1.0};
+float dc[4] = {0.882, 0.157, 0.204, 1.0};
+
+float density = 0.1;
+float thickness = 0.05;
+bool drawlines = true;
+
+// Event Handler
+std::function eventHandler = [&](){
+
+ if(Tiny::event.scroll.posy)
+ zoom *= 0.9;
+ if(Tiny::event.scroll.negy)
+ zoom /= 0.9;
+
+ if(Tiny::event.active[SDLK_w])
+ py += 0.05*zoom;
+
+ if(Tiny::event.active[SDLK_a])
+ px += 0.05*zoom;
+
+ if(Tiny::event.active[SDLK_s])
+ py -= 0.05*zoom;
+
+ if(Tiny::event.active[SDLK_d])
+ px -= 0.05*zoom;
+
+};
+
+//Interface Function
+Handle interfaceFunc = [&](){
+ //Window Size
+ ImGui::SetNextWindowSize(ImVec2(480, 260), ImGuiCond_Once);
+ ImGui::SetNextWindowPos(ImVec2(50, 470), ImGuiCond_Once);
+
+ //Open Window
+ ImGui::Begin("2D Signed Distance Field Controller", NULL, ImGuiWindowFlags_NoResize);
+ ImGui::ColorEdit3("Negative Color", dc);
+ ImGui::ColorEdit3("Positive Color", cc);
+ ImGui::Text("Position:"); ImGui::SameLine();
+ ImGui::Text("( %f,", px); ImGui::SameLine();
+ ImGui::Text(" %f )", py);
+ ImGui::Text("Zoom: "); ImGui::SameLine();
+ ImGui::Text("%f", zoom);
+ ImGui::Checkbox("Draw Isolines", &drawlines);
+ ImGui::SliderFloat("Thickness", &thickness, 0.01f, 1.0f);
+ ImGui::SliderFloat("Density", &density, 0.02f, 1.0f);
+
+ ImGui::End();
+};
diff --git a/win/TinyEngineWin/7_SDF/shader/sdf.fs b/win/TinyEngineWin/7_SDF/shader/sdf.fs
new file mode 100644
index 0000000..ac5b688
--- /dev/null
+++ b/win/TinyEngineWin/7_SDF/shader/sdf.fs
@@ -0,0 +1,46 @@
+#version 330 core
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+uniform float zoom;
+uniform vec2 offset;
+
+uniform vec4 converge;
+uniform vec4 diverge;
+
+//Signed Distance Field Functions
+float circ(vec2 p, float r){
+ return length(p) - r;
+}
+
+float box(vec2 p, vec2 b){
+ vec2 q = abs(p) - b;
+ return length(max(q,0.0)) + min(max(q.x,q.y),0.0);
+}
+
+uniform bool drawlines;
+uniform float thickness;
+uniform float density;
+
+bool isoline(float a, float b){
+ return (abs(b-a) < 0.01);
+}
+
+float sdf(vec2 p){
+ p = (p*2-vec2(1.0))*zoom-offset;
+ float c = circ(p+vec2(0.5), 0.5);
+ float b = box(p-vec2(0.5), vec2(0.5));
+ if(isoline(b, c)) return 0.0;
+ return min(b, c);
+}
+
+vec4 sdfcol(float t){
+ if(mod(abs(t), density) < thickness && drawlines) return vec4(vec3(0.0), 1.0);
+
+ if(t > 0) return converge;
+ else return diverge;
+}
+
+void main(){
+ fragColor = sdfcol(sdf(ex_Tex));//julia(ex_Tex);
+}
diff --git a/win/TinyEngineWin/7_SDF/shader/sdf.vs b/win/TinyEngineWin/7_SDF/shader/sdf.vs
new file mode 100644
index 0000000..d90e341
--- /dev/null
+++ b/win/TinyEngineWin/7_SDF/shader/sdf.vs
@@ -0,0 +1,12 @@
+#version 130
+in vec2 in_Quad;
+in vec2 in_Tex;
+out vec2 ex_Tex;
+
+//Position the Billboard in space!
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, -1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/8_Raymarch/8_Raymarch.vcxproj b/win/TinyEngineWin/8_Raymarch/8_Raymarch.vcxproj
new file mode 100644
index 0000000..5da49b4
--- /dev/null
+++ b/win/TinyEngineWin/8_Raymarch/8_Raymarch.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/8_Raymarch/8_Raymarch.vcxproj.filters b/win/TinyEngineWin/8_Raymarch/8_Raymarch.vcxproj.filters
new file mode 100644
index 0000000..8aae4d6
--- /dev/null
+++ b/win/TinyEngineWin/8_Raymarch/8_Raymarch.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/8_Raymarch/imgui.ini b/win/TinyEngineWin/8_Raymarch/imgui.ini
new file mode 100644
index 0000000..c247a63
--- /dev/null
+++ b/win/TinyEngineWin/8_Raymarch/imgui.ini
@@ -0,0 +1,10 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
+[Window][Raymarching Controller]
+Pos=127,116
+Size=480,260
+Collapsed=0
+
diff --git a/win/TinyEngineWin/8_Raymarch/main.cpp b/win/TinyEngineWin/8_Raymarch/main.cpp
new file mode 100644
index 0000000..27de2d0
--- /dev/null
+++ b/win/TinyEngineWin/8_Raymarch/main.cpp
@@ -0,0 +1,41 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/color.h"
+
+#include "model.h"
+
+int main( int argc, char* args[] ) {
+ srand(time(NULL)); //SEED
+
+ Tiny::view.vsync = true;
+
+ Tiny::window("3D Signed Distance Field", 1000, 1000);
+
+ Tiny::event.handler = eventHandler;
+ Tiny::view.interface = interfaceFunc;
+
+ Shader sdf({"shader/sdf.vs", "shader/sdf.fs"}, {"in_Quad", "in_Tex"});
+ Square2D flat; //Flat geometry primitive
+
+ Tiny::view.pipeline = [&](){
+
+ Tiny::view.target(color::black); //Target Screen
+
+ sdf.use();
+ sdf.uniform("camerapos", camerapos);
+ sdf.uniform("lookpos", lookpos);
+ sdf.uniform("zoom", zoom);
+ sdf.uniform("converge", glm::vec4(cc[0], cc[1], cc[2], cc[3]));
+ sdf.uniform("diverge", glm::vec4(dc[0], dc[1], dc[2], dc[3]));
+ sdf.uniform("model", flat.model);
+ flat.render();
+
+ };
+
+ Tiny::loop([&](){
+
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/8_Raymarch/model.h b/win/TinyEngineWin/8_Raymarch/model.h
new file mode 100644
index 0000000..15a3a4c
--- /dev/null
+++ b/win/TinyEngineWin/8_Raymarch/model.h
@@ -0,0 +1,59 @@
+//Data
+const int SIZE = 500;
+int data[SIZE*SIZE] = {0};
+bool paused = true;
+float PI = 3.14159265;
+
+//Resolution
+int res = 25;
+float radius = 2.0;
+float bias[2] = {0.0};
+double zoom = 1.5;
+int order = 2;
+
+float cc[4] = {0.070, 0.086, 0.211, 1.0};
+float dc[4] = {0.882, 0.157, 0.204, 1.0};
+
+bool active = false;
+bool appear = false;
+float appearAmp = 1.0;
+bool movex = false;
+bool movey = false;
+float phase[2] = {0.0, 0.0};
+float amplitude[2] = {1.0, 1.0};
+float center[2] = {0.0, 0.0};
+float rate = 0.01;
+float t = 0.0;
+glm::vec3 up = glm::vec3(0,1,0);
+
+glm::vec3 camerapos = glm::vec3(5.0);
+glm::vec3 lookpos = glm::vec3(0.0);
+
+// Event Handler
+std::function eventHandler = [&](){
+
+ if(Tiny::event.scroll.posy)
+ zoom /= 0.9;
+ if(Tiny::event.scroll.negy)
+ zoom *= 0.9;
+ if(Tiny::event.scroll.posx)
+ camerapos = glm::rotate(glm::mat4(1), 0.05f, up)*glm::vec4(camerapos, 1.0);
+ if(Tiny::event.scroll.negx)
+ camerapos = glm::rotate(glm::mat4(1), -0.05f, up)*glm::vec4(camerapos, 1.0);
+
+};
+
+//Interface Function
+Handle interfaceFunc = [&](){
+ //Window Size
+ ImGui::SetNextWindowSize(ImVec2(480, 260), ImGuiCond_Once);
+ ImGui::SetNextWindowPos(ImVec2(50, 470), ImGuiCond_Once);
+
+ //Open Window
+ ImGui::Begin("Raymarching Controller", NULL, ImGuiWindowFlags_NoResize);
+
+ ImGui::ColorEdit3("Intersect Color", cc);
+ ImGui::ColorEdit3("Miss Color", dc);
+
+ ImGui::End();
+};
diff --git a/win/TinyEngineWin/8_Raymarch/shader/sdf.fs b/win/TinyEngineWin/8_Raymarch/shader/sdf.fs
new file mode 100644
index 0000000..58191fe
--- /dev/null
+++ b/win/TinyEngineWin/8_Raymarch/shader/sdf.fs
@@ -0,0 +1,80 @@
+#version 330 core
+in vec2 ex_Tex;
+out vec4 fragColor;
+
+uniform float zoom;
+uniform vec2 offset;
+
+uniform vec4 converge;
+uniform vec4 diverge;
+
+uniform vec3 camerapos;
+uniform vec3 lookpos;
+
+vec3 lightpos = vec3(1, 2, 3);
+vec3 lightcol = vec3(1);
+
+//Signed Distance Field Functions
+float circ(vec3 p, float r){
+ return length(p) - r;
+}
+
+float box(vec3 p, vec3 b){
+ vec3 q = abs(p) - b;
+ return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
+}
+
+float sdf(vec3 p){
+ float a = box(p+0.5, vec3(1.0));
+ float b = circ(p-0.5, 1.0);
+ //return max(a, -b);
+ return min(a, b);
+}
+
+vec3 ray(vec3 start, vec3 dir, float mind, float maxd){
+ vec3 p = start;
+ float d = sdf(p);
+ while(length(p - start) < maxd && d > mind)
+ d = sdf((p += 0.5*d*dir));
+ return p;
+}
+
+vec3 sdfnormal(vec3 p){
+ float d = 0.01;
+ float gx = (sdf(p + d*vec3(1,0,0)) - sdf(p - d*vec3(1,0,0)))/(2*d);
+ float gy = (sdf(p + d*vec3(0,1,0)) - sdf(p - d*vec3(0,1,0)))/(2*d);
+ float gz = (sdf(p + d*vec3(0,0,1)) - sdf(p - d*vec3(0,0,1)))/(2*d);
+ return normalize(vec3(gx, gy, gz));
+}
+
+vec4 light(vec3 p){
+ vec3 n = sdfnormal(p);
+ float diffuse = 0.5*dot(n, lightpos);
+ float specular = 0.1*pow(max(0.0, dot(reflect(normalize(lightpos), n), normalize(p - camerapos))), 64);
+ float ambient = 1.0;
+ return vec4(vec3(diffuse+specular+ambient)*lightcol, 1.0);
+}
+
+float shade(vec3 p){
+ vec3 dir = normalize(p - lightpos);
+ vec3 e = ray(lightpos, dir, 0.01, length(p-lightpos));
+ if(length(e - p) < 0.1) return 1.0;
+ else return 0.9;
+}
+
+void main(){
+ vec3 dir = normalize(lookpos - camerapos); //Look Direction
+ vec3 nx = normalize(cross(dir, vec3(0,1,0))); //Normal Vector Sideways
+ vec3 ny = normalize(cross(dir, nx)); //Normal Vector Up
+
+ vec2 t = (ex_Tex*2-vec2(1.0))*zoom; //Fragment Position
+ vec3 s = camerapos + t.x*nx + t.y*ny; //Starting Position
+
+ float maxd = 15.0;
+ float mind = 0.001;
+ vec3 e = ray(s, dir, mind, maxd);
+ float d = length(e - s)/maxd;
+
+ if(d < 1.0) fragColor = shade(e)*light(e)*converge;
+ else fragColor = diverge;
+}
diff --git a/win/TinyEngineWin/8_Raymarch/shader/sdf.vs b/win/TinyEngineWin/8_Raymarch/shader/sdf.vs
new file mode 100644
index 0000000..d90e341
--- /dev/null
+++ b/win/TinyEngineWin/8_Raymarch/shader/sdf.vs
@@ -0,0 +1,12 @@
+#version 130
+in vec2 in_Quad;
+in vec2 in_Tex;
+out vec2 ex_Tex;
+
+//Position the Billboard in space!
+uniform mat4 model;
+
+void main(){
+ ex_Tex = in_Tex;
+ gl_Position = model*vec4(in_Quad, -1.0, 1.0);
+}
diff --git a/win/TinyEngineWin/9_Scene/9_Scene.vcxproj b/win/TinyEngineWin/9_Scene/9_Scene.vcxproj
new file mode 100644
index 0000000..0ff8902
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/9_Scene.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/9_Scene/9_Scene.vcxproj.filters b/win/TinyEngineWin/9_Scene/9_Scene.vcxproj.filters
new file mode 100644
index 0000000..8aae4d6
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/9_Scene.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+ Header Files
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/9_Scene/imgui.ini b/win/TinyEngineWin/9_Scene/imgui.ini
new file mode 100644
index 0000000..fa04b5f
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/imgui.ini
@@ -0,0 +1,10 @@
+[Window][Debug##Default]
+Pos=60,60
+Size=400,400
+Collapsed=0
+
+[Window][Point Light Scene Controller]
+Pos=50,470
+Size=480,260
+Collapsed=0
+
diff --git a/win/TinyEngineWin/9_Scene/main.cpp b/win/TinyEngineWin/9_Scene/main.cpp
new file mode 100644
index 0000000..3bcc8e2
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/main.cpp
@@ -0,0 +1,99 @@
+#include "../TinyEngine.h"
+#include "../../../include/helpers/color.h"
+#include "../../../include/helpers/object.h"
+
+#include "model.h"
+
+int main( int argc, char* args[] ) {
+
+ Tiny::view.vsync = true;
+ Tiny::window("Lighting Scene Test", 1200, 800);
+
+ setup();
+
+ Tiny::event.handler = eventHandler;
+ Tiny::view.interface = interfaceFunc;
+
+ Shader shader({"shader/default.vs", "shader/default.fs"}, {"in_Position", "in_Normal", "in_Color"});
+ Shader cubedepth({"shader/cubedepth.vs", "shader/cubedepth.gs", "shader/cubedepth.fs"}, {"in_Position"});
+
+ std::string path = "object/";
+ Model lamp(obj::load, path+"Lamp");
+ Model table(obj::load, path+"Table");
+ Model chair(obj::load, path+"Chair");
+ Model shelf(obj::load, path+"Shelf");
+ Model frame(obj::load, path+"Frame");
+ table.shift(glm::vec3(0, 0, 2));
+ chair.shift(glm::vec3(0, 0, -2));
+ lamp.shift(glm::vec3(2, 5, 2));
+ shelf.shift(glm::vec3( 24, 0, 0));
+ frame.shift(glm::vec3(-25, 15, 0), 90);
+
+ Model room(construct_room);
+ room.move(glm::vec3(0), 0, glm::vec3(25)); //Scale Floor
+
+ //Shadow Map
+ Cubemap pointshadow(1000, 1000, false); //No Color Buffer
+
+ Tiny::view.pipeline = [&](){
+
+ //Point Shadow Map
+ if(lightupdate){ //Only do it if necessary
+ pointshadow.target();
+ cubedepth.use();
+ cubedepth.uniform("vp", views);
+ cubedepth.uniform("proj", pointproj);
+ cubedepth.uniform("lightPos", plightpos);
+ cubedepth.uniform("far", pointfar);
+ cubedepth.uniform("model", lamp.model);
+ lamp.render();
+ cubedepth.uniform("model", table.model);
+ table.render();
+ cubedepth.uniform("model", chair.model);
+ chair.render();
+ cubedepth.uniform("model", shelf.model);
+ shelf.render();
+ cubedepth.uniform("model", frame.model);
+ frame.render();
+ lightupdate = false;
+ }
+
+ //Render Scene
+ Tiny::view.target(color::black); //Target Screen
+
+ shader.use();
+ shader.uniform("vp", proj*view);
+ shader.uniform("camera", pos);
+
+ //Point Shadow
+ shader.texture("pointshadowMap", pointshadow.depth);
+ shader.uniform("pointlightpos", plightpos);
+ shader.uniform("pointlightfar", pointfar);
+ shader.uniform("pointlighton", on);
+ shader.uniform("pointlightcolor", lightcolor);
+ shader.uniform("brightness", brightness);
+ shader.uniform("attenuation", attenuation);
+
+ //Draw Models
+ shader.uniform("model", room.model);
+ room.render();
+ shader.uniform("model", lamp.model);
+ lamp.render();
+ shader.uniform("model", table.model);
+ table.render();
+ shader.uniform("model", chair.model);
+ chair.render();
+ shader.uniform("model", shelf.model);
+ shelf.render();
+ shader.uniform("model", frame.model);
+ frame.render();
+ };
+
+ Tiny::loop([&](){
+
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/9_Scene/model.h b/win/TinyEngineWin/9_Scene/model.h
new file mode 100644
index 0000000..5766328
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/model.h
@@ -0,0 +1,250 @@
+//Camera Data
+glm::vec3 pos = glm::vec3(20);
+glm::vec3 up = glm::vec3(0, 1, 0);
+glm::vec3 look = glm::vec3(0,10,0);
+glm::mat4 proj;
+glm::mat4 view;
+float scale = 20.0;
+
+//Pointlight Data
+float pointnear = 0.1f;
+float pointfar = 60.0f;
+std::vector views;
+glm::mat4 pointproj;
+glm::vec3 plightpos = glm::vec3(0, 5, 17);
+bool lightupdate = true;
+
+//Pointlight Properties
+bool on = true;
+float lightcolor[3] = {1.0, 0.9, 0.8};
+float brightness = 1.0;
+float attenuation[3] = {0.5, 1.0, 5.0};
+
+//Compute Matrices
+void setup(){
+ proj = glm::ortho(-(float)Tiny::view.WIDTH/scale, (float)Tiny::view.WIDTH/scale, -(float)Tiny::view.HEIGHT/scale, (float)Tiny::view.HEIGHT/scale, -50.0f, 300.0f);
+ view = glm::lookAt(pos, look, up);
+
+ pointproj = glm::perspective(glm::radians(90.0f), 1.0f, pointnear, pointfar);
+ views.clear();
+ views.push_back(pointproj*glm::lookAt(plightpos, plightpos+glm::vec3( 1.0, 0.0, 0.0), glm::vec3(0.0,-1.0, 0.0)));
+ views.push_back(pointproj*glm::lookAt(plightpos, plightpos+glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0,-1.0, 0.0)));
+ views.push_back(pointproj*glm::lookAt(plightpos, plightpos+glm::vec3( 0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0)));
+ views.push_back(pointproj*glm::lookAt(plightpos, plightpos+glm::vec3( 0.0,-1.0, 0.0), glm::vec3(0.0, 0.0,-1.0)));
+ views.push_back(pointproj*glm::lookAt(plightpos, plightpos+glm::vec3( 0.0, 0.0, 1.0), glm::vec3(0.0,-1.0, 0.0)));
+ views.push_back(pointproj*glm::lookAt(plightpos, plightpos+glm::vec3( 0.0, 0.0,-1.0), glm::vec3(0.0,-1.0, 0.0)));
+}
+
+// Event Handler
+std::function eventHandler = [&](){
+
+ if(Tiny::event.scroll.posy)
+ scale *= 0.9;
+ if(Tiny::event.scroll.negy)
+ scale /= 0.9;
+ if(Tiny::event.scroll.posx)
+ pos = glm::rotate(glm::mat4(1), glm::radians(2.5f), up)*glm::vec4(pos, 1.0);
+ if(Tiny::event.scroll.negx)
+ pos = glm::rotate(glm::mat4(1), -glm::radians(2.5f), up)*glm::vec4(pos, 1.0);
+
+ setup(); //Recompute (I know this shouldn't be called all the time, whatever lol)
+};
+
+//Interface Function
+Handle interfaceFunc = [&](){
+ //Window Size
+ ImGui::SetNextWindowSize(ImVec2(480, 260), ImGuiCond_Once);
+ ImGui::SetNextWindowPos(ImVec2(50, 470), ImGuiCond_Once);
+
+ ImGui::Begin("Point Light Scene Controller", NULL, ImGuiWindowFlags_NoResize);
+
+ ImGui::ColorEdit3("Light Color", lightcolor);
+ ImGui::SliderFloat3("Attenuation", attenuation, 0.0f, 25.0f);
+ ImGui::Checkbox("On Switch", &on);
+ ImGui::SliderFloat("Brightness", &brightness, 0.0f, 1.0f);
+ ImGui::SliderFloat3("Position", &plightpos[0], -25.0f, 25.0f);
+ lightupdate = true;
+
+ ImGui::End();
+};
+
+std::function construct_room = [&](Model* h){
+
+ float room[24] = {
+ -1.0, 0.0, -1.0,
+ -1.0, 0.0, 1.0,
+ 1.0, 0.0, -1.0,
+ 1.0, 0.0, 1.0,
+ -1.0, 1.0, -1.0,
+ -1.0, 1.0, 1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, 1.0, 1.0
+ };
+
+ for(int i = 0; i < 24; i++)
+ h->positions.push_back(room[i]);
+
+ h->indices.push_back(0);
+ h->indices.push_back(1);
+ h->indices.push_back(2);
+
+ h->indices.push_back(1);
+ h->indices.push_back(3);
+ h->indices.push_back(2);
+
+ h->indices.push_back(4);
+ h->indices.push_back(6);
+ h->indices.push_back(5);
+
+ h->indices.push_back(5);
+ h->indices.push_back(6);
+ h->indices.push_back(7);
+
+ //Ceiling
+
+ glm::vec3 floorcolor = glm::vec3(0.65, 0.5, 0.3);
+ glm::vec3 ceilingcolor = glm::vec3(0.9, 0.9, 0.8);
+
+ for(int i = 0; i < 4; i++){
+ h->normals.push_back(0.0);
+ h->normals.push_back(1.0);
+ h->normals.push_back(0.0);
+
+ h->colors.push_back(floorcolor.x);
+ h->colors.push_back(floorcolor.y);
+ h->colors.push_back(floorcolor.z);
+ h->colors.push_back(1.0);
+ }
+
+ for(int i = 0; i < 4; i++){
+ h->normals.push_back(0.0);
+ h->normals.push_back(-1.0);
+ h->normals.push_back(0.0);
+
+ h->colors.push_back(ceilingcolor.x);
+ h->colors.push_back(ceilingcolor.y);
+ h->colors.push_back(ceilingcolor.z);
+ h->colors.push_back(1.0);
+ }
+
+ float wallA[12] = {
+ -1.0, 0.0, -1.0,
+ 1.0, 0.0, -1.0,
+ -1.0, 1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ };
+
+ //Walls
+ int P = h->positions.size()/3;
+ h->indices.push_back(P);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+2);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+3);
+ h->indices.push_back(P+2);
+
+ for(int i = 0; i < 12; i++)
+ h->positions.push_back(wallA[i]);
+
+ for(int i = 0; i < 4; i++){
+ h->normals.push_back(0.0);
+ h->normals.push_back(0.0);
+ h->normals.push_back(1.0);
+
+ h->colors.push_back(ceilingcolor.x);
+ h->colors.push_back(ceilingcolor.y);
+ h->colors.push_back(ceilingcolor.z);
+ h->colors.push_back(1.0);
+ }
+
+ float wallB[12] = {
+ -1.0, 0.0, 1.0,
+ 1.0, 0.0, 1.0,
+ -1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ };
+
+ //Walls
+ P = h->positions.size()/3;
+ h->indices.push_back(P);
+ h->indices.push_back(P+2);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+2);
+ h->indices.push_back(P+3);
+
+ for(int i = 0; i < 12; i++)
+ h->positions.push_back(wallB[i]);
+
+ for(int i = 0; i < 4; i++){
+ h->normals.push_back( 0.0);
+ h->normals.push_back( 0.0);
+ h->normals.push_back(-1.0);
+
+ h->colors.push_back(ceilingcolor.x);
+ h->colors.push_back(ceilingcolor.y);
+ h->colors.push_back(ceilingcolor.z);
+ h->colors.push_back(1.0);
+ }
+
+
+ float wallC[12] = {
+ -1.0, 0.0,-1.0,
+ -1.0, 0.0, 1.0,
+ -1.0, 1.0,-1.0,
+ -1.0, 1.0, 1.0,
+ };
+
+ //Walls
+ P = h->positions.size()/3;
+ h->indices.push_back(P);
+ h->indices.push_back(P+2);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+2);
+ h->indices.push_back(P+3);
+
+ for(int i = 0; i < 12; i++)
+ h->positions.push_back(wallC[i]);
+
+ for(int i = 0; i < 4; i++){
+ h->normals.push_back( 1.0);
+ h->normals.push_back( 0.0);
+ h->normals.push_back( 0.0);
+
+ h->colors.push_back(ceilingcolor.x);
+ h->colors.push_back(ceilingcolor.y);
+ h->colors.push_back(ceilingcolor.z);
+ h->colors.push_back(1.0);
+ }
+
+ float wallD[12] = {
+ 1.0, 0.0,-1.0,
+ 1.0, 0.0, 1.0,
+ 1.0, 1.0,-1.0,
+ 1.0, 1.0, 1.0,
+ };
+
+ //Walls
+ P = h->positions.size()/3;
+ h->indices.push_back(P);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+2);
+ h->indices.push_back(P+1);
+ h->indices.push_back(P+3);
+ h->indices.push_back(P+2);
+
+ for(int i = 0; i < 12; i++)
+ h->positions.push_back(wallD[i]);
+
+ for(int i = 0; i < 4; i++){
+ h->normals.push_back(-1.0);
+ h->normals.push_back( 0.0);
+ h->normals.push_back( 0.0);
+
+ h->colors.push_back(ceilingcolor.x);
+ h->colors.push_back(ceilingcolor.y);
+ h->colors.push_back(ceilingcolor.z);
+ h->colors.push_back(1.0);
+ }
+};
diff --git a/win/TinyEngineWin/9_Scene/object/Chair.mtl b/win/TinyEngineWin/9_Scene/object/Chair.mtl
new file mode 100644
index 0000000..0c43d89
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/object/Chair.mtl
@@ -0,0 +1,12 @@
+# Blender MTL File: 'Scene2.blend'
+# Material Count: 1
+
+newmtl Material.003
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.780000 0.660000 0.440000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
diff --git a/win/TinyEngineWin/9_Scene/object/Frame.mtl b/win/TinyEngineWin/9_Scene/object/Frame.mtl
new file mode 100644
index 0000000..f9d8d8d
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/object/Frame.mtl
@@ -0,0 +1,22 @@
+# Blender MTL File: 'Scene2.blend'
+# Material Count: 2
+
+newmtl Material.003
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.780000 0.660000 0.440000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.017
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
diff --git a/win/TinyEngineWin/9_Scene/object/Lamp.mtl b/win/TinyEngineWin/9_Scene/object/Lamp.mtl
new file mode 100644
index 0000000..3a1fb79
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/object/Lamp.mtl
@@ -0,0 +1,12 @@
+# Blender MTL File: 'Scene2.blend'
+# Material Count: 1
+
+newmtl Material.013
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.500000 0.500000 0.500000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
diff --git a/win/TinyEngineWin/9_Scene/object/Shelf.mtl b/win/TinyEngineWin/9_Scene/object/Shelf.mtl
new file mode 100644
index 0000000..31e2284
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/object/Shelf.mtl
@@ -0,0 +1,180 @@
+# Blender MTL File: 'Scene2.blend'
+# Material Count: 18
+
+newmtl Material.001
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.128242 0.077101 0.001733
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.005
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.190181 0.008746 0.000000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.006
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.009811 0.233019 0.003475
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.007
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.005542 0.005359 0.178865
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.008
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.226587 0.012994 0.225870
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.009
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.010352 0.167949 0.000000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.010
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.603822 0.000000 0.027389
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.011
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.018222 0.420029 0.374053
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.012
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.310817 0.051999 0.306036
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.013
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.000000 0.000000 0.000000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.014
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.054970 0.054970 0.054970
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.015
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.476995 0.385327 0.101934
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.016
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.673854 0.602496 0.015054
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.017
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.018
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.022153 0.000000 0.527724
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.019
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.091460 0.000000 0.486902
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl Material.020
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.100088 0.000000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+
+newmtl None
+Ns 500
+Ka 0.8 0.8 0.8
+Kd 0.8 0.8 0.8
+Ks 0.8 0.8 0.8
+d 1
+illum 2
diff --git a/win/TinyEngineWin/9_Scene/object/Table.mtl b/win/TinyEngineWin/9_Scene/object/Table.mtl
new file mode 100644
index 0000000..7d65432
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/object/Table.mtl
@@ -0,0 +1,10 @@
+# Blender MTL File: 'Scene2.blend'
+# Material Count: 1
+
+newmtl None
+Ns 500
+Ka 0.8 0.8 0.8
+Kd 0.427 0.29 0.02
+Ks 0.8 0.8 0.8
+d 1
+illum 2
diff --git a/win/TinyEngineWin/9_Scene/shader/cubedepth.fs b/win/TinyEngineWin/9_Scene/shader/cubedepth.fs
new file mode 100644
index 0000000..3e5384c
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/shader/cubedepth.fs
@@ -0,0 +1,9 @@
+#version 330 core
+in vec4 FragPos;
+
+uniform vec3 lightPos;
+uniform float far;
+
+void main(){
+ gl_FragDepth = length(FragPos.xyz - lightPos)/far;
+}
diff --git a/win/TinyEngineWin/9_Scene/shader/cubedepth.gs b/win/TinyEngineWin/9_Scene/shader/cubedepth.gs
new file mode 100644
index 0000000..718109e
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/shader/cubedepth.gs
@@ -0,0 +1,23 @@
+#version 330 core
+
+layout (triangles) in;
+layout (triangle_strip, max_vertices=18) out;
+
+uniform mat4 vp[6];
+uniform mat4 proj;
+
+out vec4 FragPos; // FragPos from GS (output per emitvertex)
+
+void main(){
+
+ for(int face = 0; face < 6; ++face){
+ gl_Layer = face; // built-in variable that specifies to which face we render.
+ for(int i = 0; i < 3; ++i){ // for each triangle vertex
+ FragPos = gl_in[i].gl_Position;
+ gl_Position = vp[face]*FragPos;
+ EmitVertex();
+ }
+ EndPrimitive();
+ }
+
+}
diff --git a/win/TinyEngineWin/9_Scene/shader/cubedepth.vs b/win/TinyEngineWin/9_Scene/shader/cubedepth.vs
new file mode 100644
index 0000000..3b2ee75
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/shader/cubedepth.vs
@@ -0,0 +1,8 @@
+#version 330 core
+layout (location = 0) in vec3 in_Position;
+
+uniform mat4 model;
+
+void main(){
+ gl_Position = model * vec4(in_Position, 1.0);
+}
diff --git a/win/TinyEngineWin/9_Scene/shader/default.fs b/win/TinyEngineWin/9_Scene/shader/default.fs
new file mode 100644
index 0000000..13061d6
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/shader/default.fs
@@ -0,0 +1,69 @@
+#version 330 core
+
+in vec4 ex_Color;
+in vec3 ex_Normal;
+
+in vec3 ex_Model; //Model Space
+in vec4 ex_Frag;
+
+out vec4 fragColor;
+
+uniform vec3 camera;
+
+//Pointlight
+uniform vec3 pointlightpos;
+uniform float pointlightfar;
+uniform samplerCube pointshadowMap;
+uniform vec3 attenuation;
+uniform bool pointlighton;
+uniform float brightness;
+uniform vec3 pointlightcolor;
+
+float pointShadow(samplerCube cube, vec3 pos, float _far){
+ float shadow = 0.0;
+
+ vec3 dir = ex_Model - pos;
+ float m = 1.0-dot(ex_Normal, -normalize(dir));
+ float bias = max(0.001, 0.01*m);
+
+ const float samples = 4.0;
+ const float offset = 0.5;
+
+ for(float x = -offset; x < offset; x += offset / (samples * 0.5)){
+ for(float y = -offset; y < offset; y += offset / (samples * 0.5)){
+ for(float z = -offset; z < offset; z += offset / (samples * 0.5)){
+
+ float near = texture(cube, dir+vec3(x,y,z)).r;
+ float cur = length(dir)/_far;
+ if(cur > 1.0) shadow += 1.0;
+ else shadow += (cur - bias > near) ? 1.0:0.0;
+
+ }
+ }
+ }
+ return shadow / (samples * samples * samples);
+}
+
+vec4 pointLight(){
+ vec3 dir = normalize(pointlightpos-ex_Model);
+ vec3 cdir = normalize(camera-ex_Model);
+ vec3 hdir = normalize(cdir + dir); //Blinn-Phong Modification
+
+ float dist = length(dir)/pointlightfar;
+ float A = 1.0/(attenuation.x + attenuation.y*dist + attenuation.z*dist*dist);
+
+ float ambient = 0.1;
+ float diffuse = 0.2*max(dot(ex_Normal, normalize(dir)), 0.0);
+ float specular = 0.2*pow(max(dot(hdir, ex_Normal), 0.0), 8);
+
+ float cubeshade = pointShadow(pointshadowMap, pointlightpos, pointlightfar);
+
+ return brightness*vec4(A*(ambient+(1.0-cubeshade)*(diffuse+specular))*pointlightcolor, 1.0);
+}
+
+void main(void) {
+ vec4 light = vec4(0); //Compute Lighting
+ if(pointlighton)
+ light += pointLight();
+ fragColor = light*ex_Color; //Set Color
+}
diff --git a/win/TinyEngineWin/9_Scene/shader/default.vs b/win/TinyEngineWin/9_Scene/shader/default.vs
new file mode 100644
index 0000000..f9b709b
--- /dev/null
+++ b/win/TinyEngineWin/9_Scene/shader/default.vs
@@ -0,0 +1,23 @@
+#version 330 core
+
+layout(location = 0) in vec3 in_Position;
+layout(location = 1) in vec3 in_Normal;
+layout(location = 2) in vec4 in_Color;
+
+uniform mat4 model;
+uniform mat4 vp;
+uniform mat4 dbvp;
+
+out vec4 ex_Color;
+out vec3 ex_Normal;
+out vec3 ex_Model; //Model Space
+out vec4 ex_Shadow; //Shadow Space
+out vec4 ex_Frag;
+
+void main(void) {
+ ex_Model = (model * vec4(in_Position, 1.0f)).xyz;
+ ex_Normal = in_Normal;
+ ex_Shadow = dbvp * vec4(ex_Model, 1.0f);
+ gl_Position = vp * vec4(ex_Model, 1.0f);
+ ex_Color = in_Color;
+}
diff --git a/win/TinyEngineWin/TinyEngine.h b/win/TinyEngineWin/TinyEngine.h
new file mode 100644
index 0000000..7c894d4
--- /dev/null
+++ b/win/TinyEngineWin/TinyEngine.h
@@ -0,0 +1,109 @@
+#include
+#include
+
+// Extra includes needed to get Windows build to compile
+#include
+#include
+#include
+
+using Handle = std::function;
+using slist = std::initializer_list;
+
+#include "../../include/imgui/imgui.h" //Interface Dependencies
+#include "../../include/imgui/imgui_impl_sdl.h"
+#include "../../include/imgui/imgui_impl_opengl3.h"
+
+#include //Rendering Dependencies
+#include
+#include
+#include
+#include
+#include
+#include "glm/gtc/matrix_transform.hpp"
+
+#include //File / Console IO
+#include
+#include
+#include
+#include
+
+#include "../../include/utility/texture.cpp" //Utility Classes
+#include "../../include/utility/shader.cpp"
+#include "../../include/utility/model.cpp"
+#include "../../include/utility/instance.cpp"
+#include "../../include/utility/target.cpp"
+
+#include "../../include/view.cpp"
+#include "../../include/event.cpp"
+#include "../../include/audio.cpp"
+
+#include
+
+/* TINY ENGINE */
+
+namespace Tiny {
+
+static View view; //Window and Interface (Requires Initialization)
+static Event event; //Event Handler
+static Audio audio; //Audio Processor (Requires Initialization)
+
+bool window(std::string windowName, int width, int height){ //Open a window
+ if( SDL_Init( SDL_INIT_VIDEO ) < 0 ){
+ printf( "SDL could not initialize! Error: %s\n", SDL_GetError() );
+ return false;
+ }
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+
+ if( !( IMG_Init( IMG_INIT_PNG ) & IMG_INIT_PNG ) ){
+ printf( "SDL_Image could not initialize! Error: %s\n", IMG_GetError() );
+ return false;
+ }
+
+ if( TTF_Init() == -1 ){ //for some reason this is -1
+ printf( "SDL_ttf could not initialize! Error: %s\n", TTF_GetError() );
+ return false;
+ }
+
+ if(!view.init(windowName, width, height)){ //Start the View Class
+ std::cout<<"Failed to launch visual interface."<
+void loop(F function, Args&&... args){
+ while(!event.quit){
+
+ if(Tiny::view.enabled){
+ event.input(); //Get Input
+ event.handle(view); //Call the event-handling system
+ }
+
+ if(Tiny::audio.enabled) audio.process(); //Audio Processor
+
+ function(args...); //User-defined Game Loop
+
+ if(Tiny::view.enabled) view.render(); //Render View
+
+ }
+}
+
+}
diff --git a/win/TinyEngineWin/TinyEngineWin.sln b/win/TinyEngineWin/TinyEngineWin.sln
new file mode 100644
index 0000000..47dcbde
--- /dev/null
+++ b/win/TinyEngineWin/TinyEngineWin.sln
@@ -0,0 +1,141 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30711.63
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "0_Empty", "0_Empty\0_Empty.vcxproj", "{2ABAD29B-E604-4684-8308-C7F8AB4F5930}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "3_Automata", "3_Automata\3_Automata.vcxproj", "{3D01050A-BFD8-4583-A632-B7697BB9B70D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "4_Julia", "4_Julia\4_Julia.vcxproj", "{81736DB9-E589-4761-B8AF-77CC244B8DDC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "5_Particles", "5_Particles\5_Particles.vcxproj", "{C7B6C8E2-616C-4C16-A278-2DB914EE84C9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "6_Tree", "6_Tree\6_Tree.vcxproj", "{979CD189-C98B-4FD8-9716-F4D8D3430A16}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7_SDF", "7_SDF\7_SDF.vcxproj", "{9835EAC7-ACE9-41D8-8A02-52716575B6E3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8_Raymarch", "8_Raymarch\8_Raymarch.vcxproj", "{96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "9_Scene", "9_Scene\9_Scene.vcxproj", "{BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "10_Audio", "10_Audio\10_Audio.vcxproj", "{598C5B6E-B616-4D90-B945-E00140B498B3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "11_Voronoi", "11_Voronoi\11_Voronoi.vcxproj", "{21B654A5-62AF-4A22-9DAB-324058FB0615}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "2_Heightmap", "2_Heightmap\2_Heightmap.vcxproj", "{B2ED7E97-065D-4D09-A910-624B9AE506A8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "1_Image", "1_Image\1_Image.vcxproj", "{367E6A04-D0F5-4091-BEE5-A9AC56F3881D}"
+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
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Debug|x64.ActiveCfg = Debug|x64
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Debug|x64.Build.0 = Debug|x64
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Debug|x86.ActiveCfg = Debug|Win32
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Debug|x86.Build.0 = Debug|Win32
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Release|x64.ActiveCfg = Release|x64
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Release|x64.Build.0 = Release|x64
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Release|x86.ActiveCfg = Release|Win32
+ {2ABAD29B-E604-4684-8308-C7F8AB4F5930}.Release|x86.Build.0 = Release|Win32
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Debug|x64.ActiveCfg = Debug|x64
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Debug|x64.Build.0 = Debug|x64
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Debug|x86.ActiveCfg = Debug|Win32
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Debug|x86.Build.0 = Debug|Win32
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Release|x64.ActiveCfg = Release|x64
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Release|x64.Build.0 = Release|x64
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Release|x86.ActiveCfg = Release|Win32
+ {3D01050A-BFD8-4583-A632-B7697BB9B70D}.Release|x86.Build.0 = Release|Win32
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Debug|x64.ActiveCfg = Debug|x64
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Debug|x64.Build.0 = Debug|x64
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Debug|x86.ActiveCfg = Debug|Win32
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Debug|x86.Build.0 = Debug|Win32
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Release|x64.ActiveCfg = Release|x64
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Release|x64.Build.0 = Release|x64
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Release|x86.ActiveCfg = Release|Win32
+ {81736DB9-E589-4761-B8AF-77CC244B8DDC}.Release|x86.Build.0 = Release|Win32
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Debug|x64.ActiveCfg = Debug|x64
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Debug|x64.Build.0 = Debug|x64
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Debug|x86.ActiveCfg = Debug|Win32
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Debug|x86.Build.0 = Debug|Win32
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Release|x64.ActiveCfg = Release|x64
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Release|x64.Build.0 = Release|x64
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Release|x86.ActiveCfg = Release|Win32
+ {C7B6C8E2-616C-4C16-A278-2DB914EE84C9}.Release|x86.Build.0 = Release|Win32
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Debug|x64.ActiveCfg = Debug|x64
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Debug|x64.Build.0 = Debug|x64
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Debug|x86.ActiveCfg = Debug|Win32
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Debug|x86.Build.0 = Debug|Win32
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Release|x64.ActiveCfg = Release|x64
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Release|x64.Build.0 = Release|x64
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Release|x86.ActiveCfg = Release|Win32
+ {979CD189-C98B-4FD8-9716-F4D8D3430A16}.Release|x86.Build.0 = Release|Win32
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Debug|x64.ActiveCfg = Debug|x64
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Debug|x64.Build.0 = Debug|x64
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Debug|x86.ActiveCfg = Debug|Win32
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Debug|x86.Build.0 = Debug|Win32
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Release|x64.ActiveCfg = Release|x64
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Release|x64.Build.0 = Release|x64
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Release|x86.ActiveCfg = Release|Win32
+ {9835EAC7-ACE9-41D8-8A02-52716575B6E3}.Release|x86.Build.0 = Release|Win32
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Debug|x64.ActiveCfg = Debug|x64
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Debug|x64.Build.0 = Debug|x64
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Debug|x86.ActiveCfg = Debug|Win32
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Debug|x86.Build.0 = Debug|Win32
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Release|x64.ActiveCfg = Release|x64
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Release|x64.Build.0 = Release|x64
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Release|x86.ActiveCfg = Release|Win32
+ {96172AFA-E1FD-428B-BC2B-F0B8F0F3D732}.Release|x86.Build.0 = Release|Win32
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Debug|x64.ActiveCfg = Debug|x64
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Debug|x64.Build.0 = Debug|x64
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Debug|x86.ActiveCfg = Debug|Win32
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Debug|x86.Build.0 = Debug|Win32
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Release|x64.ActiveCfg = Release|x64
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Release|x64.Build.0 = Release|x64
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Release|x86.ActiveCfg = Release|Win32
+ {BB9C4B80-0CBA-4099-8E6C-3FABCE5ECDAB}.Release|x86.Build.0 = Release|Win32
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Debug|x64.ActiveCfg = Debug|x64
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Debug|x64.Build.0 = Debug|x64
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Debug|x86.ActiveCfg = Debug|Win32
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Debug|x86.Build.0 = Debug|Win32
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Release|x64.ActiveCfg = Release|x64
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Release|x64.Build.0 = Release|x64
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Release|x86.ActiveCfg = Release|Win32
+ {598C5B6E-B616-4D90-B945-E00140B498B3}.Release|x86.Build.0 = Release|Win32
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Debug|x64.ActiveCfg = Debug|x64
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Debug|x64.Build.0 = Debug|x64
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Debug|x86.ActiveCfg = Debug|Win32
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Debug|x86.Build.0 = Debug|Win32
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Release|x64.ActiveCfg = Release|x64
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Release|x64.Build.0 = Release|x64
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Release|x86.ActiveCfg = Release|Win32
+ {21B654A5-62AF-4A22-9DAB-324058FB0615}.Release|x86.Build.0 = Release|Win32
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Debug|x64.ActiveCfg = Debug|x64
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Debug|x64.Build.0 = Debug|x64
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Debug|x86.ActiveCfg = Debug|Win32
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Debug|x86.Build.0 = Debug|Win32
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Release|x64.ActiveCfg = Release|x64
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Release|x64.Build.0 = Release|x64
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Release|x86.ActiveCfg = Release|Win32
+ {B2ED7E97-065D-4D09-A910-624B9AE506A8}.Release|x86.Build.0 = Release|Win32
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Debug|x64.ActiveCfg = Debug|x64
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Debug|x64.Build.0 = Debug|x64
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Debug|x86.ActiveCfg = Debug|Win32
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Debug|x86.Build.0 = Debug|Win32
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Release|x64.ActiveCfg = Release|x64
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Release|x64.Build.0 = Release|x64
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Release|x86.ActiveCfg = Release|Win32
+ {367E6A04-D0F5-4091-BEE5-A9AC56F3881D}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8E446AF0-3FD9-4FB0-A0DC-FB4B7A2C72A4}
+ EndGlobalSection
+EndGlobal
diff --git a/win/TinyEngineWin/x_Name Template/main.cpp b/win/TinyEngineWin/x_Name Template/main.cpp
new file mode 100644
index 0000000..bf48fc3
--- /dev/null
+++ b/win/TinyEngineWin/x_Name Template/main.cpp
@@ -0,0 +1,35 @@
+#include "../TinyEngine.h"
+
+/*
+* This project is a copy of 0_Empty and can be
+* used to quickly create a new project with all
+* the correct settings to build an example on
+* Windows.
+*/
+
+int main( int argc, char* args[] ) {
+
+ //Initialize a Window
+ Tiny::window("Example Window", 600, 400);
+
+ //Add the Event Handler
+ Tiny::event.handler = [&](){
+ };
+
+ //Set up an ImGUI Interface here
+ Tiny::view.interface = [&](){
+ };
+
+ //Define the rendering pipeline
+ Tiny::view.pipeline = [&](){
+ };
+
+ //Execute the render loop
+ Tiny::loop([&](){
+ //Do any additional stuff in here
+ });
+
+ Tiny::quit();
+
+ return 0;
+}
diff --git a/win/TinyEngineWin/x_Name Template/x_Name.vcxproj b/win/TinyEngineWin/x_Name Template/x_Name.vcxproj
new file mode 100644
index 0000000..0f7e29f
--- /dev/null
+++ b/win/TinyEngineWin/x_Name Template/x_Name.vcxproj
@@ -0,0 +1,184 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {E4F2F0CE-3CF6-4E48-8824-95677215DCD9}
+ My0Empty
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ false
+ $(ProjectDir)$(Configuration)\
+ $(ProjectDir)$(Configuration)\
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2d.lib;SDL2main.lib;%(AdditionalDependencies)
+ msvcrt.lib
+
+
+
+
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ %SDL2_DIR%\lib\;%SDL2_DIR%\lib\manual-link;%(AdditionalLibraryDirectories)
+ opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/win/TinyEngineWin/x_Name Template/x_Name.vcxproj.filters b/win/TinyEngineWin/x_Name Template/x_Name.vcxproj.filters
new file mode 100644
index 0000000..bb0f3dd
--- /dev/null
+++ b/win/TinyEngineWin/x_Name Template/x_Name.vcxproj.filters
@@ -0,0 +1,69 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {bdfdabfc-0a6f-4a38-96ea-1029e776ae29}
+
+
+ {863e8ba3-8fbf-409f-b5d8-23bc70f8b1a0}
+
+
+ {49038325-f945-4b5a-8b43-dc43f021eb72}
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ TinyEngine
+
+
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imgui
+
+
+ imguin_impl
+
+
+ imguin_impl
+
+
+ Source Files
+
+
+
\ No newline at end of file