diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5dcf23f --- /dev/null +++ b/.gitignore @@ -0,0 +1,372 @@ +## 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 +emsdk +emscripten + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +*.tlog/ +Crawler/x64/ +[Rr]eleases/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd +Crawler/Crawler.html +Crawler/Crawler.data +Crawler/Crawler.js +Crawler/Crawler.wasm +Crawler/pixelGameEngine_wasm.o +*.tiled-session +/Crawler/Crawler.tiled-session \ No newline at end of file diff --git a/CppProperties.json b/CppProperties.json new file mode 100644 index 0000000..f598ba5 --- /dev/null +++ b/CppProperties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "inheritEnvironments": [ + "msvc_x64" + ], + "name": "x64-Debug", + "includePath": [ + "${env.INCLUDE}", + "${workspaceRoot}\\**" + ], + "defines": [ + "WIN32", + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "intelliSenseMode": "windows-msvc-x64" + } + ] +} \ No newline at end of file diff --git a/assets/unitcube.obj b/assets/unitcube.obj index 9413c49..8a5f323 100644 --- a/assets/unitcube.obj +++ b/assets/unitcube.obj @@ -12,15 +12,15 @@ vt 0 1 #2 vt 1 0 #3 vt 1 1 #4 -f 1/2 3/1 7/3 #South/0 -f 1/2 7/3 5/4 #1 -f 5/2 7/1 8/3 #East/2 -f 5/2 8/3 6/4 #3 -f 6/2 8/1 4/3 #North/4 -f 6/2 4/3 2/4 #5 -f 2/2 4/1 3/3 #West/6 -f 2/2 3/3 1/4 #7 -f 3/2 4/1 8/3 #Top/8 -f 3/2 8/3 7/4 #9 -f 6/2 2/1 1/3 #Bottom/10 -f 6/2 1/3 5/4 #11 \ No newline at end of file +f 1/2/ 3/1/ 7/3/ #South/0 +f 1/2/ 7/3/ 5/4/ #1 +f 5/2/ 7/1/ 8/3/ #East/2 +f 5/2/ 8/3/ 6/4/ #3 +f 6/2/ 8/1/ 4/3/ #North/4 +f 6/2/ 4/3/ 2/4/ #5 +f 2/2/ 4/1/ 3/3/ #West/6 +f 2/2/ 3/3/ 1/4/ #7 +f 3/2/ 4/1/ 8/3/ #Top/8 +f 3/2/ 8/3/ 7/4/ #9 +f 6/2/ 2/1/ 1/3/ #Bottom/10 +f 6/2/ 1/3/ 5/4/ #11 \ No newline at end of file diff --git a/main.cpp b/main.cpp index 00f644c..b812f7c 100644 --- a/main.cpp +++ b/main.cpp @@ -26,35 +26,11 @@ public: public: bool OnUserCreate() override { - cube.tris = - { - // SOUTH - { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, WHITE }, - { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, WHITE }, - - // EAST - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, WHITE }, - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, WHITE }, - - // NORTH - { 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, WHITE }, - { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, WHITE }, - - // WEST - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, WHITE }, - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, WHITE }, - - // TOP - { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, WHITE }, - { 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, WHITE }, - - // BOTTOM - { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, WHITE }, - { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, WHITE }, - - }; + cube.LoadOBJFile("assets/unitcube.obj"); olc::GFX3D::ConfigureDisplay(); + cubeTex=new Sprite("assets/dirtblock.png"); + renderer.SetProjection(90.0f, (float)ScreenHeight()/(float)ScreenWidth(), 0.1f, 1000.0f, 0.0f, 0.0f, ScreenWidth(), ScreenHeight()); return true; @@ -66,6 +42,8 @@ public: Clear(VERY_DARK_BLUE); + GFX3D::ClearDepth(); + GFX3D::vec3d vLookTarget = GFX3D::Math::Vec_Add(vEye, vLookDir); renderer.SetCamera(vEye, vLookTarget, vUp); @@ -89,18 +67,6 @@ public: } }; -enum Direction{ - RIGHT, - DOWN, - LEFT, - UP -}; - -struct Data{ - int x,y; -}; - - int main() { Graphics3DPGEX_Example demo; diff --git a/olcPGEX_Graphics3D.h b/olcPGEX_Graphics3D.h index b7c4e5f..a0ce20d 100644 --- a/olcPGEX_Graphics3D.h +++ b/olcPGEX_Graphics3D.h @@ -1,64 +1,67 @@ /* - olcPGEX_Graphics3D.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | 3D Rendering - v0.1 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - support for software rendering 3D graphics. - - NOTE!!! This file is under development and may change! - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ©OneLoneCoder 2018 +olcPGEX_Graphics3D.h + ++-------------------------------------------------------------+ +| OneLoneCoder Pixel Game Engine Extension | +| 3D Rendering - v0.4 | ++-------------------------------------------------------------+ + +What is this? +~~~~~~~~~~~~~ +This is an extension to the olcPixelGameEngine, which provides +support for software rendering 3D graphics. + +NOTE!!! This file is under development and may change! + +Big Thanks to MaGetzUb for finding an OOB error, and joshinils +for pointing out sampling inaccuracy. + +License (OLC-3) +~~~~~~~~~~~~~~~ + +Copyright 2018-2019 OneLoneCoder.com + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions or derivations of source code must retain the above +copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions or derivative works in binary form must reproduce +the above copyright notice. This list of conditions and the following +disclaimer must be reproduced in the documentation and/or other +materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Links +~~~~~ +YouTube: https://www.youtube.com/javidx9 +Discord: https://discord.gg/WhwHUMV +Twitter: https://www.twitter.com/javidx9 +Twitch: https://www.twitch.tv/javidx9 +GitHub: https://www.github.com/onelonecoder +Patreon: https://www.patreon.com/javidx9 +Homepage: https://www.onelonecoder.com + +Author +~~~~~~ +David Barr, aka javidx9, �OneLoneCoder 2018 */ @@ -68,9 +71,14 @@ #include #include #include +#include +#include +#include #undef min #undef max +//#include + namespace olc { // Container class for Advanced 2D Drawing functions @@ -98,7 +106,7 @@ namespace olc { vec3d p[3]; vec2d t[3]; - olc::Pixel col; + olc::Pixel col[3]; }; struct mat4x4 @@ -109,37 +117,59 @@ namespace olc struct mesh { std::vector tris; + bool LoadOBJFile(std::string sFilename, bool bHasTexture = false); }; + /*class MipMap : public olc::Sprite + { + public: + MipMap(); + MipMap(std::string sImageFile); + MipMap(std::string sImageFile, olc::ResourcePack *pack); + MipMap(int32_t w, int32_t h); + ~MipMap(); + + public: + olc::rcode LoadFromFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); + olc::rcode LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); + Pixel Sample(float x, float y, float z); + Pixel SampleBL(float u, float v, float z); + + private: + int GenerateMipLevels(); + std::vector vecMipMaps; + + };*/ + class Math { public: - inline Math(); + Math(); public: - inline static vec3d Mat_MultiplyVector(mat4x4 &m, vec3d &i); - inline static mat4x4 Mat_MultiplyMatrix(mat4x4 &m1, mat4x4 &m2); - inline static mat4x4 Mat_MakeIdentity(); - inline static mat4x4 Mat_MakeRotationX(float fAngleRad); - inline static mat4x4 Mat_MakeRotationY(float fAngleRad); - inline static mat4x4 Mat_MakeRotationZ(float fAngleRad); - inline static mat4x4 Mat_MakeScale(float x, float y, float z); - inline static mat4x4 Mat_MakeTranslation(float x, float y, float z); - inline static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); - inline static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up); - inline static mat4x4 Mat_QuickInverse(mat4x4 &m); // Only for Rotation/Translation Matrices - inline static mat4x4 Mat_Inverse(olc::GFX3D::mat4x4 &m); - - inline static vec3d Vec_Add(vec3d &v1, vec3d &v2); - inline static vec3d Vec_Sub(vec3d &v1, vec3d &v2); - inline static vec3d Vec_Mul(vec3d &v1, float k); - inline static vec3d Vec_Div(vec3d &v1, float k); - inline static float Vec_DotProduct(vec3d &v1, vec3d &v2); - inline static float Vec_Length(vec3d &v); - inline static vec3d Vec_Normalise(vec3d &v); - inline static vec3d Vec_CrossProduct(vec3d &v1, vec3d &v2); - inline static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t); - - inline static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2); + static vec3d Mat_MultiplyVector(mat4x4 &m, vec3d &i); + static mat4x4 Mat_MultiplyMatrix(mat4x4 &m1, mat4x4 &m2); + static mat4x4 Mat_MakeIdentity(); + static mat4x4 Mat_MakeRotationX(float fAngleRad); + static mat4x4 Mat_MakeRotationY(float fAngleRad); + static mat4x4 Mat_MakeRotationZ(float fAngleRad); + static mat4x4 Mat_MakeScale(float x, float y, float z); + static mat4x4 Mat_MakeTranslation(float x, float y, float z); + static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); + static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up); + static mat4x4 Mat_QuickInverse(mat4x4 &m); // Only for Rotation/Translation Matrices + static mat4x4 Mat_Inverse(olc::GFX3D::mat4x4 &m); + + static vec3d Vec_Add(vec3d &v1, vec3d &v2); + static vec3d Vec_Sub(vec3d &v1, vec3d &v2); + static vec3d Vec_Mul(vec3d &v1, float k); + static vec3d Vec_Div(vec3d &v1, float k); + static float Vec_DotProduct(vec3d &v1, vec3d &v2); + static float Vec_Length(vec3d &v); + static vec3d Vec_Normalise(vec3d &v); + static vec3d Vec_CrossProduct(vec3d &v1, vec3d &v2); + static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t); + + static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2); }; enum RENDERFLAGS @@ -150,8 +180,17 @@ namespace olc RENDER_CULL_CW = 0x08, RENDER_CULL_CCW = 0x10, RENDER_DEPTH = 0x20, + RENDER_LIGHTS = 0x40, + }; + + enum LIGHTS + { + LIGHT_DISABLED, + LIGHT_AMBIENT, + LIGHT_DIRECTIONAL, + LIGHT_POINT }; - + class PipeLine { @@ -163,38 +202,59 @@ namespace olc void SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up); void SetTransform(olc::GFX3D::mat4x4 &transform); void SetTexture(olc::Sprite *texture); - void SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col); + //void SetMipMapTexture(olc::GFX3D::MipMap *texture); + void SetLightSource(uint32_t nSlot, uint32_t nType, olc::Pixel col, olc::GFX3D::vec3d pos, olc::GFX3D::vec3d dir = { 0.0f, 0.0f, 1.0f }, float fParam = 0.0f); uint32_t Render(std::vector &triangles, uint32_t flags = RENDER_CULL_CW | RENDER_TEXTURED | RENDER_DEPTH); + uint32_t Render(std::vector &triangles, uint32_t flags, int nOffset, int nCount); + uint32_t RenderLine(olc::GFX3D::vec3d &p1, olc::GFX3D::vec3d &p2, olc::Pixel col = olc::WHITE); + uint32_t RenderCircleXZ(olc::GFX3D::vec3d &p1, float r, olc::Pixel col = olc::WHITE); private: olc::GFX3D::mat4x4 matProj; olc::GFX3D::mat4x4 matView; olc::GFX3D::mat4x4 matWorld; olc::Sprite *sprTexture; + //olc::GFX3D::MipMap *sprMipMap; + //bool bUseMipMap; float fViewX; float fViewY; float fViewW; float fViewH; + + struct sLight + { + uint32_t type; + olc::GFX3D::vec3d pos; + olc::GFX3D::vec3d dir; + olc::Pixel col; + float param; + } lights[4]; }; - + public: //static const int RF_TEXTURE = 0x00000001; //static const int RF_ = 0x00000002; - inline static void ConfigureDisplay(); - inline static void ClearDepth(); - inline static void AddTriangleToScene(olc::GFX3D::triangle &tri); - inline static void RenderScene(); + static void ConfigureDisplay(); + static void ClearDepth(); + static void AddTriangleToScene(olc::GFX3D::triangle &tri); + static void RenderScene(); - inline static void DrawTriangleFlat(olc::GFX3D::triangle &tri); - inline static void DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col = olc::WHITE); - inline static void DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr); - inline static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1, + static void DrawTriangleFlat(olc::GFX3D::triangle &tri); + static void DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col = olc::WHITE); + static void DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr); + static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1, int x2, int y2, float u2, float v2, float w2, int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr); + static void RasterTriangle(int x1, int y1, float u1, float v1, float w1, olc::Pixel c1, + int x2, int y2, float u2, float v2, float w2, olc::Pixel c2, + int x3, int y3, float u3, float v3, float w3, olc::Pixel c3, + olc::Sprite* spr, + uint32_t nFlags); + // Draws a sprite with the transform applied //inline static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform); @@ -203,8 +263,11 @@ namespace olc }; } +#endif +#ifdef OLC_PGEX_GRAPHICS3D +#undef OLC_PGEX_GRAPHICS3D namespace olc { @@ -354,7 +417,7 @@ namespace olc olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_Inverse(olc::GFX3D::mat4x4 &m) { double det; - + mat4x4 matInv; @@ -376,7 +439,7 @@ namespace olc matInv.m[3][3] = m.m[0][0] * m.m[1][1] * m.m[2][2] - m.m[0][0] * m.m[1][2] * m.m[2][1] - m.m[1][0] * m.m[0][1] * m.m[2][2] + m.m[1][0] * m.m[0][2] * m.m[2][1] + m.m[2][0] * m.m[0][1] * m.m[1][2] - m.m[2][0] * m.m[0][2] * m.m[1][1]; det = m.m[0][0] * matInv.m[0][0] + m.m[0][1] * matInv.m[1][0] + m.m[0][2] * matInv.m[2][0] + m.m[0][3] * matInv.m[3][0]; - // if (det == 0) return false; + // if (det == 0) return false; det = 1.0 / det; @@ -443,7 +506,7 @@ namespace olc olc::GFX3D::vec3d lineToIntersect = Vec_Mul(lineStartToEnd, t); return Vec_Add(lineStart, lineToIntersect); } - + int olc::GFX3D::Math::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2) { @@ -521,7 +584,9 @@ namespace olc // the plane, the triangle simply becomes a smaller triangle // Copy appearance info to new triangle - out_tri1.col = olc::MAGENTA;// in_tri.col; + out_tri1.col[0] = in_tri.col[0]; + out_tri1.col[1] = in_tri.col[1]; + out_tri1.col[2] = in_tri.col[2]; // The inside point is valid, so keep that... out_tri1.p[0] = *inside_points[0]; @@ -550,9 +615,13 @@ namespace olc // represent a quad with two new triangles // Copy appearance info to new triangles - out_tri1.col = olc::GREEN;// in_tri.col; - out_tri2.col = olc::RED;// in_tri.col; - + out_tri1.col[0] = in_tri.col[0]; + out_tri2.col[0] = in_tri.col[0]; + out_tri1.col[1] = in_tri.col[1]; + out_tri2.col[1] = in_tri.col[1]; + out_tri1.col[2] = in_tri.col[2]; + out_tri2.col[2] = in_tri.col[2]; + // The first triangle consists of the two inside points and a new // point determined by the location where one side of the triangle // intersects with the plane @@ -587,19 +656,193 @@ namespace olc void GFX3D::DrawTriangleFlat(olc::GFX3D::triangle &tri) { - pge->FillTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, tri.col); + pge->FillTriangle((int32_t)tri.p[0].x, (int32_t)tri.p[0].y, (int32_t)tri.p[1].x, (int32_t)tri.p[1].y, (int32_t)tri.p[2].x, (int32_t)tri.p[2].y, tri.col[0]); } void GFX3D::DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col) { - pge->DrawTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, col); + pge->DrawTriangle((int32_t)tri.p[0].x, (int32_t)tri.p[0].y, (int32_t)tri.p[1].x, (int32_t)tri.p[1].y, (int32_t)tri.p[2].x, (int32_t)tri.p[2].y, col); } void GFX3D::TexturedTriangle(int x1, int y1, float u1, float v1, float w1, int x2, int y2, float u2, float v2, float w2, int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr) + + { + if (y2 < y1) + { + std::swap(y1, y2); + std::swap(x1, x2); + std::swap(u1, u2); + std::swap(v1, v2); + std::swap(w1, w2); + } + + if (y3 < y1) + { + std::swap(y1, y3); + std::swap(x1, x3); + std::swap(u1, u3); + std::swap(v1, v3); + std::swap(w1, w3); + } + + if (y3 < y2) + { + std::swap(y2, y3); + std::swap(x2, x3); + std::swap(u2, u3); + std::swap(v2, v3); + std::swap(w2, w3); + } + + int dy1 = y2 - y1; + int dx1 = x2 - x1; + float dv1 = v2 - v1; + float du1 = u2 - u1; + float dw1 = w2 - w1; + + int dy2 = y3 - y1; + int dx2 = x3 - x1; + float dv2 = v3 - v1; + float du2 = u3 - u1; + float dw2 = w3 - w1; + + float tex_u, tex_v, tex_w; + + float dax_step = 0, dbx_step = 0, + du1_step = 0, dv1_step = 0, + du2_step = 0, dv2_step = 0, + dw1_step = 0, dw2_step = 0; + + if (dy1) dax_step = dx1 / (float)abs(dy1); + if (dy2) dbx_step = dx2 / (float)abs(dy2); + + if (dy1) du1_step = du1 / (float)abs(dy1); + if (dy1) dv1_step = dv1 / (float)abs(dy1); + if (dy1) dw1_step = dw1 / (float)abs(dy1); + + if (dy2) du2_step = du2 / (float)abs(dy2); + if (dy2) dv2_step = dv2 / (float)abs(dy2); + if (dy2) dw2_step = dw2 / (float)abs(dy2); + + if (dy1) + { + for (int i = y1; i <= y2; i++) + { + int ax = int(x1 + (float)(i - y1) * dax_step); + int bx = int(x1 + (float)(i - y1) * dbx_step); + + float tex_su = u1 + (float)(i - y1) * du1_step; + float tex_sv = v1 + (float)(i - y1) * dv1_step; + float tex_sw = w1 + (float)(i - y1) * dw1_step; + + float tex_eu = u1 + (float)(i - y1) * du2_step; + float tex_ev = v1 + (float)(i - y1) * dv2_step; + float tex_ew = w1 + (float)(i - y1) * dw2_step; + + if (ax > bx) + { + std::swap(ax, bx); + std::swap(tex_su, tex_eu); + std::swap(tex_sv, tex_ev); + std::swap(tex_sw, tex_ew); + } + + tex_u = tex_su; + tex_v = tex_sv; + tex_w = tex_sw; + + float tstep = 1.0f / ((float)(bx - ax)); + float t = 0.0f; + + for (int j = ax; j < bx; j++) + { + tex_u = (1.0f - t) * tex_su + t * tex_eu; + tex_v = (1.0f - t) * tex_sv + t * tex_ev; + tex_w = (1.0f - t) * tex_sw + t * tex_ew; + if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) + { + /*if (bMipMap) + pge->Draw(j, i, ((olc::GFX3D::MipMap*)spr)->Sample(tex_u / tex_w, tex_v / tex_w, tex_w)); + else*/ + if(pge->Draw(j, i, spr != nullptr ? spr->Sample(tex_u / tex_w, tex_v / tex_w) : olc::GREY)) + m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; + } + t += tstep; + } + + } + } + + dy1 = y3 - y2; + dx1 = x3 - x2; + dv1 = v3 - v2; + du1 = u3 - u2; + dw1 = w3 - w2; + + if (dy1) dax_step = dx1 / (float)abs(dy1); + if (dy2) dbx_step = dx2 / (float)abs(dy2); + + du1_step = 0, dv1_step = 0; + if (dy1) du1_step = du1 / (float)abs(dy1); + if (dy1) dv1_step = dv1 / (float)abs(dy1); + if (dy1) dw1_step = dw1 / (float)abs(dy1); + + if (dy1) + { + for (int i = y2; i <= y3; i++) + { + int ax = int(x2 + (float)(i - y2) * dax_step); + int bx = int(x1 + (float)(i - y1) * dbx_step); + + float tex_su = u2 + (float)(i - y2) * du1_step; + float tex_sv = v2 + (float)(i - y2) * dv1_step; + float tex_sw = w2 + (float)(i - y2) * dw1_step; + + float tex_eu = u1 + (float)(i - y1) * du2_step; + float tex_ev = v1 + (float)(i - y1) * dv2_step; + float tex_ew = w1 + (float)(i - y1) * dw2_step; + + if (ax > bx) + { + std::swap(ax, bx); + std::swap(tex_su, tex_eu); + std::swap(tex_sv, tex_ev); + std::swap(tex_sw, tex_ew); + } + + tex_u = tex_su; + tex_v = tex_sv; + tex_w = tex_sw; + + float tstep = 1.0f / ((float)(bx - ax)); + float t = 0.0f; + + for (int j = ax; j < bx; j++) + { + tex_u = (1.0f - t) * tex_su + t * tex_eu; + tex_v = (1.0f - t) * tex_sv + t * tex_ev; + tex_w = (1.0f - t) * tex_sw + t * tex_ew; + + if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) + { + /*if(bMipMap) + pge->Draw(j, i, ((olc::GFX3D::MipMap*)spr)->Sample(tex_u / tex_w, tex_v / tex_w, tex_w)); + else*/ + if(pge->Draw(j, i, spr != nullptr ? spr->Sample(tex_u / tex_w, tex_v / tex_w) : olc::GREY)) + m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; + } + t += tstep; + } + } + } + } + + + void GFX3D::DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr) { - pge->FillTexturedTriangle({{float(x1),float(y1)},{float(x2),float(y2)},{float(x3),float(y3)}},{{u1,v1},{u2,v2},{u3,v3}},{WHITE,WHITE,WHITE},spr); + } float* GFX3D::m_DepthBuffer = nullptr; @@ -615,14 +858,123 @@ namespace olc memset(m_DepthBuffer, 0, pge->ScreenWidth() * pge->ScreenHeight() * sizeof(float)); } - + bool GFX3D::mesh::LoadOBJFile(std::string sFilename, bool bHasTexture) + { + std::ifstream f(sFilename); + if (!f.is_open()) return false; + + // Local cache of verts + std::vector verts; + std::vector norms; + std::vector texs; + + while (!f.eof()) + { + char line[128]; + f.getline(line, 128); + + std::stringstream s; + s << line; + + char junk; + + if (line[0] == 'v') + { + if (line[1] == 't') + { + vec2d v; + s >> junk >> junk >> v.x >> v.y; + //v.x = 1.0f - v.x; + v.y = 1.0f - v.y; + texs.push_back(v); + } + else if (line[1] == 'n') + { + vec3d v; + s >> junk >> junk >> v.x >> v.y >> v.z; + norms.push_back(v); + } + else + { + vec3d v; + s >> junk >> v.x >> v.y >> v.z; + verts.push_back(v); + } + } + + + /*if (!bHasTexture) + { + if (line[0] == 'f') + { + int f[3]; + s >> junk >> f[0] >> f[1] >> f[2]; + tris.push_back({ verts[f[0] - 1], verts[f[1] - 1], verts[f[2] - 1] }); + } + } + else*/ + { + if (line[0] == 'f') + { + s >> junk; + + std::string tokens[9]; + int nTokenCount = -1; + while (!s.eof()) + { + char c = s.get(); + if (c == ' ' || c == '/') + { + if (tokens[nTokenCount].size() > 0) + { + nTokenCount++; + } + } + else + tokens[nTokenCount].append(1, c); + } + + tokens[nTokenCount].pop_back(); + + int stride = 1; + if (!texs.empty()) stride++; + if (!norms.empty()) stride++; + + if (!texs.empty()) + { + tris.push_back({ + verts[stoi(tokens[0 * stride]) - 1], + verts[stoi(tokens[1 * stride]) - 1], + verts[stoi(tokens[2 * stride]) - 1], + texs[stoi(tokens[0 * stride + 1]) - 1], + texs[stoi(tokens[1 * stride + 1]) - 1], + texs[stoi(tokens[2 * stride + 1]) - 1], + olc::WHITE, olc::WHITE, olc::WHITE}); + } + else + { + tris.push_back({ + verts[stoi(tokens[0 * stride]) - 1], + verts[stoi(tokens[1 * stride]) - 1], + verts[stoi(tokens[2 * stride]) - 1], + olc::GFX3D::vec2d{0,0,0}, + olc::GFX3D::vec2d{0,0,0}, + olc::GFX3D::vec2d{0,0,0}, + olc::WHITE, olc::WHITE, olc::WHITE }); + + } + } + } + } + return true; + } GFX3D::PipeLine::PipeLine() { - + //bUseMipMap = false; } - + void GFX3D::PipeLine::SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight) { matProj = GFX3D::Math::Mat_MakeProjection(fFovDegrees, fAspectRatio, fNear, fFar); @@ -646,14 +998,114 @@ namespace olc void GFX3D::PipeLine::SetTexture(olc::Sprite *texture) { sprTexture = texture; + //bUseMipMap = false; } - void GFX3D::PipeLine::SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col) + /*void GFX3D::PipeLine::SetMipMapTexture(olc::GFX3D::MipMap *texture) { + sprMipMap = texture; + bUseMipMap = true; + }*/ + void GFX3D::PipeLine::SetLightSource(uint32_t nSlot, uint32_t nType, olc::Pixel col, olc::GFX3D::vec3d pos, olc::GFX3D::vec3d dir, float fParam) + { + if (nSlot < 4) + { + lights[nSlot].type = nType; + lights[nSlot].pos = pos; + lights[nSlot].dir = dir; + lights[nSlot].col = col; + lights[nSlot].param = fParam; + } } uint32_t GFX3D::PipeLine::Render(std::vector &triangles, uint32_t flags) + { + return Render(triangles, flags, 0, triangles.size()); + } + + uint32_t GFX3D::PipeLine::RenderLine(olc::GFX3D::vec3d &p1, olc::GFX3D::vec3d &p2, olc::Pixel col) + { + // Coordinates are assumed to be in world space + olc::GFX3D::vec3d t1, t2; + + // Transform into view + t1 = GFX3D::Math::Mat_MultiplyVector(matView, p1); + t2 = GFX3D::Math::Mat_MultiplyVector(matView, p2); + + // Project onto screen + t1 = GFX3D::Math::Mat_MultiplyVector(matProj, t1); + t2 = GFX3D::Math::Mat_MultiplyVector(matProj, t2); + + // Project + t1.x = t1.x / t1.w; + t1.y = t1.y / t1.w; + t1.z = t1.z / t1.w; + + t2.x = t2.x / t2.w; + t2.y = t2.y / t2.w; + t2.z = t2.z / t2.w; + + vec3d vOffsetView = { 1,1,0 }; + t1 = Math::Vec_Add(t1, vOffsetView); + t2 = Math::Vec_Add(t2, vOffsetView); + + t1.x *= 0.5f * fViewW; + t1.y *= 0.5f * fViewH; + t2.x *= 0.5f * fViewW; + t2.y *= 0.5f * fViewH; + + vOffsetView = { fViewX,fViewY,0 }; + t1 = Math::Vec_Add(t1, vOffsetView); + t2 = Math::Vec_Add(t2, vOffsetView); + + pge->DrawLine((int32_t)t1.x, (int32_t)t1.y, (int32_t)t2.x, (int32_t)t2.y, col); + + return 0; + } + + uint32_t GFX3D::PipeLine::RenderCircleXZ(olc::GFX3D::vec3d &p1, float r, olc::Pixel col) + { + // Coordinates are assumed to be in world space + olc::GFX3D::vec3d t1; + olc::GFX3D::vec3d t2 = { p1.x + r, p1.y, p1.z }; + + // Transform into view + t1 = GFX3D::Math::Mat_MultiplyVector(matView, p1); + t2 = GFX3D::Math::Mat_MultiplyVector(matView, t2); + + // Project onto screen + t1 = GFX3D::Math::Mat_MultiplyVector(matProj, t1); + t2 = GFX3D::Math::Mat_MultiplyVector(matProj, t2); + + // Project + t1.x = t1.x / t1.w; + t1.y = t1.y / t1.w; + t1.z = t1.z / t1.w; + + t2.x = t2.x / t2.w; + t2.y = t2.y / t2.w; + t2.z = t2.z / t2.w; + + vec3d vOffsetView = { 1,1,0 }; + t1 = Math::Vec_Add(t1, vOffsetView); + t2 = Math::Vec_Add(t2, vOffsetView); + + t1.x *= 0.5f * fViewW; + t1.y *= 0.5f * fViewH; + t2.x *= 0.5f * fViewW; + t2.y *= 0.5f * fViewH; + + vOffsetView = { fViewX,fViewY,0 }; + t1 = Math::Vec_Add(t1, vOffsetView); + t2 = Math::Vec_Add(t2, vOffsetView); + + pge->FillCircle((int32_t)t1.x, (int32_t)t1.y, (int32_t)fabs(t2.x - t1.x), col); + + return 0; + } + + uint32_t GFX3D::PipeLine::Render(std::vector &triangles, uint32_t flags, int nOffset, int nCount) { // Calculate Transformation Matrix mat4x4 matWorldView = Math::Mat_MultiplyMatrix(matWorld, matView); @@ -665,8 +1117,13 @@ namespace olc int nTriangleDrawnCount = 0; // Process Triangles - for (auto &tri : triangles) + //for (auto &tri : triangles) + // omp_set_dynamic(0); + // omp_set_num_threads(4); + //#pragma omp parallel for schedule(static) + for(int tx = nOffset; tx < nOffset+nCount; tx++) { + GFX3D::triangle &tri = triangles[tx]; GFX3D::triangle triTransformed; // Just copy through texture coordinates @@ -674,6 +1131,11 @@ namespace olc triTransformed.t[1] = { tri.t[1].x, tri.t[1].y, tri.t[1].z }; triTransformed.t[2] = { tri.t[2].x, tri.t[2].y, tri.t[2].z }; // Think! + // Dont forget vertex colours + triTransformed.col[0] = tri.col[0]; + triTransformed.col[1] = tri.col[1]; + triTransformed.col[2] = tri.col[2]; + // Transform Triangle from object into projected space triTransformed.p[0] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[0]); triTransformed.p[1] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[1]); @@ -689,15 +1151,75 @@ namespace olc // Cull triangles that face away from viewer if (flags & RENDER_CULL_CW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) > 0.0f) continue; if (flags & RENDER_CULL_CCW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) < 0.0f) continue; - + // If Lighting, calculate shading - triTransformed.col = olc::WHITE; + if (flags & RENDER_LIGHTS) + { + olc::Pixel ambient_clamp = { 0,0,0 }; + olc::Pixel light_combined = { 0,0,0 }; + uint32_t nLightSources = 0; + float nLightR = 0, nLightG = 0, nLightB = 0; + + for (int i = 0; i < 4; i++) + { + switch (lights[i].type) + { + case LIGHT_DISABLED: + break; + case LIGHT_AMBIENT: + ambient_clamp = lights[i].col; + break; + case LIGHT_DIRECTIONAL: + { + nLightSources++; + GFX3D::vec3d light_dir = GFX3D::Math::Vec_Normalise(lights[i].dir); + float light = GFX3D::Math::Vec_DotProduct(light_dir, normal); + if (light > 0) + { + int j = 0; + } + + light = std::max(light, 0.0f); + nLightR += light * (lights[i].col.r/255.0f); + nLightG += light * (lights[i].col.g/255.0f); + nLightB += light * (lights[i].col.b/255.0f); + } + break; + case LIGHT_POINT: + break; + } + } + + //nLightR /= nLightSources; + //nLightG /= nLightSources; + //nLightB /= nLightSources; + + nLightR = std::max(nLightR, ambient_clamp.r / 255.0f); + nLightG = std::max(nLightG, ambient_clamp.g / 255.0f); + nLightB = std::max(nLightB, ambient_clamp.b / 255.0f); + + triTransformed.col[0] = olc::Pixel(uint8_t(nLightR * triTransformed.col[0].r), uint8_t(nLightG * triTransformed.col[0].g), uint8_t(nLightB * triTransformed.col[0].b)); + triTransformed.col[1] = olc::Pixel(uint8_t(nLightR * triTransformed.col[1].r), uint8_t(nLightG * triTransformed.col[1].g), uint8_t(nLightB * triTransformed.col[1].b)); + triTransformed.col[2] = olc::Pixel(uint8_t(nLightR * triTransformed.col[2].r), uint8_t(nLightG * triTransformed.col[2].g), uint8_t(nLightB * triTransformed.col[2].b)); + + + + /*GFX3D::vec3d light_dir = { 1,1,1 }; + light_dir = GFX3D::Math::Vec_Normalise(light_dir); + float light = GFX3D::Math::Vec_DotProduct(light_dir, normal); + if (light < 0) light = 0; + triTransformed.col[0] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f); + triTransformed.col[1] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f); + triTransformed.col[2] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f);*/ + } + //else + // triTransformed.col = olc::WHITE; // Clip triangle against near plane int nClippedTriangles = 0; - triangle clipped[2]; + GFX3D::triangle clipped[2]; nClippedTriangles = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triTransformed, clipped[0], clipped[1]); - + // This may yield two new triangles for (int n = 0; n < nClippedTriangles; n++) { @@ -738,9 +1260,9 @@ namespace olc // Clip triangles against all four screen edges, this could yield // a bunch of triangles, so create a queue that we traverse to // ensure we only test new triangles generated against planes - triangle sclipped[2]; - std::list listTriangles; - + GFX3D::triangle sclipped[2]; + std::list listTriangles; + // Add initial triangle listTriangles.push_back(triProjected); @@ -805,25 +1327,39 @@ namespace olc // For now, just draw triangle - if (flags & RENDER_TEXTURED) - { - TexturedTriangle( - triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, - triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, - triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, - sprTexture); - } + //if (flags & RENDER_TEXTURED) + //{/* + // TexturedTriangle( + // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, + // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, + // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, + // sprTexture);*/ + + // RasterTriangle( + // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col, + // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col, + // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col, + // sprTexture, nFlags); + + //} if (flags & RENDER_WIRE) { DrawTriangleWire(triRaster, olc::RED); } - - if (flags & RENDER_FLAT) + else { - DrawTriangleFlat(triRaster); + RasterTriangle( + (int)triRaster.p[0].x,(int)triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col[0], + (int)triRaster.p[1].x,(int)triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col[1], + (int)triRaster.p[2].x,(int)triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col[2], + sprTexture, flags); + } + + + nTriangleDrawnCount++; } } @@ -831,6 +1367,359 @@ namespace olc return nTriangleDrawnCount; } + + void GFX3D::RasterTriangle(int x1, int y1, float u1, float v1, float w1, olc::Pixel c1, + int x2, int y2, float u2, float v2, float w2, olc::Pixel c2, + int x3, int y3, float u3, float v3, float w3, olc::Pixel c3, + olc::Sprite* spr, + uint32_t nFlags) + + { + if (y2 < y1) + { + std::swap(y1, y2); std::swap(x1, x2); std::swap(u1, u2); std::swap(v1, v2); std::swap(w1, w2); std::swap(c1, c2); + } + + if (y3 < y1) + { + std::swap(y1, y3); std::swap(x1, x3); std::swap(u1, u3); std::swap(v1, v3); std::swap(w1, w3); std::swap(c1, c3); + } + + if (y3 < y2) + { + std::swap(y2, y3); std::swap(x2, x3); std::swap(u2, u3); std::swap(v2, v3); std::swap(w2, w3); std::swap(c2, c3); + } + + int dy1 = y2 - y1; + int dx1 = x2 - x1; + float dv1 = v2 - v1; + float du1 = u2 - u1; + float dw1 = w2 - w1; + int dcr1 = c2.r - c1.r; + int dcg1 = c2.g - c1.g; + int dcb1 = c2.b - c1.b; + int dca1 = c2.a - c1.a; + + int dy2 = y3 - y1; + int dx2 = x3 - x1; + float dv2 = v3 - v1; + float du2 = u3 - u1; + float dw2 = w3 - w1; + int dcr2 = c3.r - c1.r; + int dcg2 = c3.g - c1.g; + int dcb2 = c3.b - c1.b; + int dca2 = c3.a - c1.a; + + float tex_u, tex_v, tex_w; + float col_r, col_g, col_b, col_a; + + float dax_step = 0, dbx_step = 0, + du1_step = 0, dv1_step = 0, + du2_step = 0, dv2_step = 0, + dw1_step = 0, dw2_step = 0, + dcr1_step = 0, dcr2_step = 0, + dcg1_step = 0, dcg2_step = 0, + dcb1_step = 0, dcb2_step = 0, + dca1_step = 0, dca2_step = 0; + + if (dy1) dax_step = dx1 / (float)abs(dy1); + if (dy2) dbx_step = dx2 / (float)abs(dy2); + + if (dy1) du1_step = du1 / (float)abs(dy1); + if (dy1) dv1_step = dv1 / (float)abs(dy1); + if (dy1) dw1_step = dw1 / (float)abs(dy1); + + if (dy2) du2_step = du2 / (float)abs(dy2); + if (dy2) dv2_step = dv2 / (float)abs(dy2); + if (dy2) dw2_step = dw2 / (float)abs(dy2); + + if (dy1) dcr1_step = dcr1 / (float)abs(dy1); + if (dy1) dcg1_step = dcg1 / (float)abs(dy1); + if (dy1) dcb1_step = dcb1 / (float)abs(dy1); + if (dy1) dca1_step = dca1 / (float)abs(dy1); + + if (dy2) dcr2_step = dcr2 / (float)abs(dy2); + if (dy2) dcg2_step = dcg2 / (float)abs(dy2); + if (dy2) dcb2_step = dcb2 / (float)abs(dy2); + if (dy2) dca2_step = dca2 / (float)abs(dy2); + + float pixel_r = 0.0f; + float pixel_g = 0.0f; + float pixel_b = 0.0f; + float pixel_a = 1.0f; + + if (dy1) + { + for (int i = y1; i <= y2; i++) + { + int ax = int(x1 + (float)(i - y1) * dax_step); + int bx = int(x1 + (float)(i - y1) * dbx_step); + + float tex_su = u1 + (float)(i - y1) * du1_step; + float tex_sv = v1 + (float)(i - y1) * dv1_step; + float tex_sw = w1 + (float)(i - y1) * dw1_step; + + float tex_eu = u1 + (float)(i - y1) * du2_step; + float tex_ev = v1 + (float)(i - y1) * dv2_step; + float tex_ew = w1 + (float)(i - y1) * dw2_step; + + float col_sr = c1.r + (float)(i - y1) * dcr1_step; + float col_sg = c1.g + (float)(i - y1) * dcg1_step; + float col_sb = c1.b + (float)(i - y1) * dcb1_step; + float col_sa = c1.a + (float)(i - y1) * dca1_step; + + float col_er = c1.r + (float)(i - y1) * dcr2_step; + float col_eg = c1.g + (float)(i - y1) * dcg2_step; + float col_eb = c1.b + (float)(i - y1) * dcb2_step; + float col_ea = c1.a + (float)(i - y1) * dca2_step; + + if (ax > bx) + { + std::swap(ax, bx); + std::swap(tex_su, tex_eu); + std::swap(tex_sv, tex_ev); + std::swap(tex_sw, tex_ew); + std::swap(col_sr, col_er); + std::swap(col_sg, col_eg); + std::swap(col_sb, col_eb); + std::swap(col_sa, col_ea); + } + + tex_u = tex_su; + tex_v = tex_sv; + tex_w = tex_sw; + col_r = col_sr; + col_g = col_sg; + col_b = col_sb; + col_a = col_sa; + + float tstep = 1.0f / ((float)(bx - ax)); + float t = 0.0f; + + for (int j = ax; j < bx; j++) + { + tex_u = (1.0f - t) * tex_su + t * tex_eu; + tex_v = (1.0f - t) * tex_sv + t * tex_ev; + tex_w = (1.0f - t) * tex_sw + t * tex_ew; + col_r = (1.0f - t) * col_sr + t * col_er; + col_g = (1.0f - t) * col_sg + t * col_eg; + col_b = (1.0f - t) * col_sb + t * col_eb; + col_a = (1.0f - t) * col_sa + t * col_ea; + + pixel_r = col_r; + pixel_g = col_g; + pixel_b = col_b; + pixel_a = col_a; + + if (nFlags & GFX3D::RENDER_TEXTURED) + { + if (spr != nullptr) + { + olc::Pixel sample = spr->Sample(tex_u / tex_w, tex_v / tex_w); + pixel_r *= sample.r / 255.0f; + pixel_g *= sample.g / 255.0f; + pixel_b *= sample.b / 255.0f; + pixel_a *= sample.a / 255.0f; + } + } + + if (nFlags & GFX3D::RENDER_DEPTH) + { + if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) + if (pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f)))) + m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; + } + else + { + pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f))); + } + + t += tstep; + } + } + } + + dy1 = y3 - y2; + dx1 = x3 - x2; + dv1 = v3 - v2; + du1 = u3 - u2; + dw1 = w3 - w2; + dcr1 = c3.r - c2.r; + dcg1 = c3.g - c2.g; + dcb1 = c3.b - c2.b; + dca1 = c3.a - c2.a; + + if (dy1) dax_step = dx1 / (float)abs(dy1); + if (dy2) dbx_step = dx2 / (float)abs(dy2); + + du1_step = 0; dv1_step = 0; + if (dy1) du1_step = du1 / (float)abs(dy1); + if (dy1) dv1_step = dv1 / (float)abs(dy1); + if (dy1) dw1_step = dw1 / (float)abs(dy1); + + dcr1_step = 0; dcg1_step = 0; dcb1_step = 0; dca1_step = 0; + if (dy1) dcr1_step = dcr1 / (float)abs(dy1); + if (dy1) dcg1_step = dcg1 / (float)abs(dy1); + if (dy1) dcb1_step = dcb1 / (float)abs(dy1); + if (dy1) dca1_step = dca1 / (float)abs(dy1); + + if (dy1) + { + for (int i = y2; i <= y3; i++) + { + int ax = int(x2 + (float)(i - y2) * dax_step); + int bx = int(x1 + (float)(i - y1) * dbx_step); + + float tex_su = u2 + (float)(i - y2) * du1_step; + float tex_sv = v2 + (float)(i - y2) * dv1_step; + float tex_sw = w2 + (float)(i - y2) * dw1_step; + + float tex_eu = u1 + (float)(i - y1) * du2_step; + float tex_ev = v1 + (float)(i - y1) * dv2_step; + float tex_ew = w1 + (float)(i - y1) * dw2_step; + + float col_sr = c2.r + (float)(i - y2) * dcr1_step; + float col_sg = c2.g + (float)(i - y2) * dcg1_step; + float col_sb = c2.b + (float)(i - y2) * dcb1_step; + float col_sa = c2.a + (float)(i - y2) * dca1_step; + + float col_er = c1.r + (float)(i - y1) * dcr2_step; + float col_eg = c1.g + (float)(i - y1) * dcg2_step; + float col_eb = c1.b + (float)(i - y1) * dcb2_step; + float col_ea = c1.a + (float)(i - y1) * dca2_step; + + if (ax > bx) + { + std::swap(ax, bx); + std::swap(tex_su, tex_eu); + std::swap(tex_sv, tex_ev); + std::swap(tex_sw, tex_ew); + std::swap(col_sr, col_er); + std::swap(col_sg, col_eg); + std::swap(col_sb, col_eb); + std::swap(col_sa, col_ea); + } + + tex_u = tex_su; + tex_v = tex_sv; + tex_w = tex_sw; + col_r = col_sr; + col_g = col_sg; + col_b = col_sb; + col_a = col_sa; + + float tstep = 1.0f / ((float)(bx - ax)); + float t = 0.0f; + + for (int j = ax; j < bx; j++) + { + tex_u = (1.0f - t) * tex_su + t * tex_eu; + tex_v = (1.0f - t) * tex_sv + t * tex_ev; + tex_w = (1.0f - t) * tex_sw + t * tex_ew; + col_r = (1.0f - t) * col_sr + t * col_er; + col_g = (1.0f - t) * col_sg + t * col_eg; + col_b = (1.0f - t) * col_sb + t * col_eb; + col_a = (1.0f - t) * col_sa + t * col_ea; + + pixel_r = col_r; + pixel_g = col_g; + pixel_b = col_b; + pixel_a = col_a; + + if (nFlags & GFX3D::RENDER_TEXTURED) + { + if (spr != nullptr) + { + olc::Pixel sample = spr->Sample(tex_u / tex_w, tex_v / tex_w); + pixel_r *= sample.r / 255.0f; + pixel_g *= sample.g / 255.0f; + pixel_b *= sample.b / 255.0f; + pixel_a *= sample.a / 255.0f; + } + } + + if (nFlags & GFX3D::RENDER_DEPTH) + { + if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) + if (pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f)))) + m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; + } + else + { + pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f))); + } + + t += tstep; + } + } + } + } + + + + //GFX3D::MipMap::MipMap() : olc::Sprite(){} + //GFX3D::MipMap::MipMap(std::string sImageFile) : olc::Sprite(sImageFile) + //{ + // GenerateMipLevels(); + //} + //GFX3D::MipMap::MipMap(std::string sImageFile, olc::ResourcePack *pack) : olc::Sprite(sImageFile, pack){} + //GFX3D::MipMap::MipMap(int32_t w, int32_t h) : olc::Sprite(w, h) {} + + //int GFX3D::MipMap::GenerateMipLevels() + //{ + // int nLevelsW = 0; + // int nLevelsH = 0; + // int w = width; + // int h = height; + // while (w > 1) { w >>= 1; nLevelsW++; } + // while (h > 1) { h >>= 1; nLevelsH++; } + + // int nLevels = std::min(nLevelsW, nLevelsH); + + // w = width >> 1; + // h = height >> 1; + + // vecMipMaps.emplace_back(w, h); // Level 0 + // memcpy(vecMipMaps[0].GetData(), GetData(), w*h*sizeof(uint32_t)); + + // for (int i = 1; i < nLevels; i++) + // { + // vecMipMaps.emplace_back(w, h); + // pge->SetDrawTarget(&vecMipMaps[i]); + // for (int x = 0; x < w; x++) + // for (int y = 0; y < h; y++) + // pge->Draw(x, y, vecMipMaps[i-1].SampleBL((float)x / (float)w, (float)y / (float)h)); + // w >>= 1; h >>= 1; + // } + + // pge->SetDrawTarget(nullptr); + // return nLevels; + //} + // + //olc::rcode GFX3D::MipMap::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack) + //{ + // olc::rcode r = olc::Sprite::LoadFromFile(sImageFile, pack); + // if (r == olc::FAIL) return r; + // GenerateMipLevels(); + // return r; + //} + + //olc::rcode GFX3D::MipMap::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack) + //{ + // olc::rcode r = olc::Sprite::LoadFromPGESprFile(sImageFile, pack); + // if (r == olc::FAIL) return r; + // GenerateMipLevels(); + // return r; + //} + // + //olc::Pixel GFX3D::MipMap::Sample(float x, float y, float z) + //{ + // int nLevel = (int)(z * (float)vecMipMaps.size()); + // return vecMipMaps[nLevel].Sample(x, y); + //} + + //olc::Pixel GFX3D::MipMap::SampleBL(float u, float v, float z); + } #endif \ No newline at end of file diff --git a/olcPGEX_Graphics3D_Test.sln b/olcPGEX_Graphics3D_Test.sln new file mode 100644 index 0000000..6d0c1f9 --- /dev/null +++ b/olcPGEX_Graphics3D_Test.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33516.290 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "olcPGEX_Graphics3D_Test", "olcPGEX_Graphics3D_Test.vcxproj", "{C8A1786A-8F64-46B4-A126-B3FDC522679D}" +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 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Debug|x64.ActiveCfg = Debug|x64 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Debug|x64.Build.0 = Debug|x64 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Debug|x86.ActiveCfg = Debug|Win32 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Debug|x86.Build.0 = Debug|Win32 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Release|x64.ActiveCfg = Release|x64 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Release|x64.Build.0 = Release|x64 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Release|x86.ActiveCfg = Release|Win32 + {C8A1786A-8F64-46B4-A126-B3FDC522679D}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E0993727-6757-42CE-AB38-B80437781E32} + EndGlobalSection +EndGlobal diff --git a/olcPGEX_Graphics3D_Test.vcxproj b/olcPGEX_Graphics3D_Test.vcxproj new file mode 100644 index 0000000..97a8a22 --- /dev/null +++ b/olcPGEX_Graphics3D_Test.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + {C8A1786A-8F64-46B4-A126-B3FDC522679D} + Win32Proj + + + + Application + true + v143 + + + Application + false + v143 + + + Application + true + v143 + + + Application + false + v143 + + + + + + + + + + + + + + + + + + + + + true + + + true + + + + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + + + MachineX86 + true + Console + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + MachineX86 + true + Console + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/olcPGEX_Graphics3D_Test.vcxproj.filters b/olcPGEX_Graphics3D_Test.vcxproj.filters new file mode 100644 index 0000000..7f4c36c --- /dev/null +++ b/olcPGEX_Graphics3D_Test.vcxproj.filters @@ -0,0 +1,34 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + + + + + \ No newline at end of file