Compare commits
217 Commits
Release-12
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
7498390180 | |||
4ac28a2c10 | |||
61c1c3245c | |||
cb9fe4e5c9 | |||
c7e7aa6fb5 | |||
1261321992 | |||
6d1ddad428 | |||
eae3c794fa | |||
db7a37d647 | |||
26600915db | |||
7bc87d00ef | |||
5e65f17a90 | |||
426498d53c | |||
28bdc7f667 | |||
|
e8bfa7b6f0 | ||
d60620ef7c | |||
8cb470ad1c | |||
575a4a0f9b | |||
e9bdaf54b6 | |||
7b2f7de032 | |||
e8245c4442 | |||
bd918aa351 | |||
a0cc8524d9 | |||
1964aeae86 | |||
b84e2ee2c5 | |||
1597662e2e | |||
0823730e82 | |||
6cbd369d51 | |||
926ae06834 | |||
d5fd68eba8 | |||
08b2dfbecc | |||
e33a51b7d4 | |||
7f5ee5cf0c | |||
401e2c0883 | |||
e5bdc441d1 | |||
392375e56c | |||
b007c78cfe | |||
512dc3cb1a | |||
a22a83d2f8 | |||
76cd48c9b7 | |||
38bb1b22ce | |||
122644a013 | |||
|
641f2de8d0 | ||
6618aa5e6b | |||
3970aa2718 | |||
fb5ca55fda | |||
bcca6285af | |||
f8395726cd | |||
ca7abb3044 | |||
14c45ab0f1 | |||
1ca5e5a694 | |||
25fc3f8698 | |||
a836fc7b32 | |||
e6dcc9d61e | |||
6dff2f97c1 | |||
dbcc3e11e1 | |||
b2bc1170df | |||
5d7fe84bd0 | |||
627a047a9b | |||
f0e2cd151f | |||
bf60c14d5e | |||
83a9baea34 | |||
|
95de887499 | ||
81ebc175e2 | |||
82669b43bc | |||
779f212a29 | |||
0cc18cfdad | |||
da35075735 | |||
d29ea018c3 | |||
72c256f907 | |||
7687c0d873 | |||
ad34e9ffc0 | |||
5a9716af02 | |||
ce5c4d4eb1 | |||
0302c43f5d | |||
9a5554e447 | |||
7dada0e51f | |||
807eef59bc | |||
4d97c6dead | |||
686a4be0c9 | |||
68ba438433 | |||
e4a4f01b28 | |||
aa4a29961c | |||
55b67ab850 | |||
68e98e6c43 | |||
4e9645436e | |||
ea99a96e64 | |||
6866ba828b | |||
4893233301 | |||
7b5ef6045b | |||
5998bec833 | |||
0f4ada563e | |||
b9bae43cf3 | |||
7f1794e48f | |||
cc504c65ec | |||
bb4a80e36d | |||
5d981e64fc | |||
5b19d26b79 | |||
8e834f9c5a | |||
dbdb4f7ec1 | |||
39c7c7ac0d | |||
e155d272bb | |||
2ee5015d61 | |||
4484fd482f | |||
97573e28a9 | |||
0417c37460 | |||
0a757407d8 | |||
308b0dc854 | |||
5f367efc28 | |||
b4c29315f4 | |||
|
a568faa701 | ||
9d89abb2b8 | |||
6e8185e2cd | |||
8fcfbddd44 | |||
4d761e874e | |||
131ce4c78e | |||
e712a5aaa3 | |||
b86377a092 | |||
5fc4914180 | |||
58e432b9c3 | |||
41fa634da1 | |||
9d6d256e80 | |||
0e22bc721a | |||
881d031f3c | |||
9e3e0c949f | |||
1526a101c3 | |||
f6e8875eb9 | |||
9903fc19c9 | |||
e809b1b665 | |||
d15b3f660d | |||
ff2a8ab787 | |||
55160044b6 | |||
04a4cbd54d | |||
f96a3851a1 | |||
4996288163 | |||
f3c2fd5e93 | |||
6650af4fc4 | |||
1d8823b046 | |||
c0b65818c8 | |||
32de87229e | |||
3759affa5d | |||
8ce9a08951 | |||
ec964dbee1 | |||
91baa826fa | |||
c2446763ad | |||
6286b62998 | |||
4de44ba1e2 | |||
166db43f2e | |||
2a1085df2d | |||
240fa7ddbc | |||
d89f79e70e | |||
7bf30f6f39 | |||
2a70981bf0 | |||
0147245325 | |||
15dcb79479 | |||
50895153f5 | |||
9688854533 | |||
0005c036b4 | |||
af42d8fd25 | |||
ff4d014739 | |||
9dda4bebc5 | |||
a5bfb4972a | |||
4348f2708a | |||
32dd2b54ca | |||
e8b601aa25 | |||
d5fd3e1a49 | |||
f593a0beac | |||
0b7af6fd31 | |||
eca4309e85 | |||
4be97f52d9 | |||
613a13618c | |||
4150c93c85 | |||
9dee59fd45 | |||
b6b2ca1bfe | |||
4eca3311c8 | |||
54711355c4 | |||
8bddf3e0a7 | |||
26d17dae38 | |||
4ff8d8ff07 | |||
162732e4b7 | |||
289157ab8a | |||
3a658b1096 | |||
480502f89e | |||
d28f680cd0 | |||
2d1e42c23b | |||
abd691b648 | |||
e261b610c2 | |||
8625c52ee9 | |||
74a4705e44 | |||
ae327b96a5 | |||
eb3e037c96 | |||
672a363c53 | |||
6a16c3f87e | |||
23d3d1f378 | |||
523806f9ef | |||
d118ae2f8e | |||
5979ae41fc | |||
652626b2e4 | |||
a8145cb926 | |||
0914b496e7 | |||
c62b58aa16 | |||
11ce9ac5fe | |||
7310825ddd | |||
513dc1e332 | |||
63bbb8794e | |||
178f328728 | |||
1c74ee9c71 | |||
608e9e29f5 | |||
c53fa52f6f | |||
7fa75cac54 | |||
|
d5f9eaa5a8 | ||
dead018993 | |||
|
e9a339182b | ||
|
076398b290 | ||
cf72d92c28 | |||
5d99f8ec1f | |||
a388ee8021 |
22
.gitea/workflows/buildtest.yml
Normal file
22
.gitea/workflows/buildtest.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Run ReCI Build Test
|
||||
run-name: Run ReCI Build Test For ${{ gitea.repository }}.
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
Explore-Gitea-Actions:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
RECI_GIT: https://git.redacted.cc/maxine/ReCI
|
||||
RECI: /RECI
|
||||
steps:
|
||||
- run: echo "The job was automatically triggered by a ${{ gitea.event_name }} event."
|
||||
- run: echo "This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
||||
- run: echo "The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- run: echo "The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||
- run: echo "The workflow is now ready to run your tests on the runner."
|
||||
- run: echo "Install toolchain and run ReCI build test"
|
||||
- run: apt-get update && apt-get install -y lua5.3 git libxrandr-dev libvulkan-dev && git clone $RECI_GIT $RECI
|
||||
- run: lua $RECI/reci.lua -f $RECI/scripts/buildtools.reci -f reci/scripts/builddeps.reci -f $RECI/scripts/buildtest.reci
|
||||
- run: echo "This job's status is ${{ job.status }}."
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
/cmake-build-debug
|
||||
/.idea
|
||||
|
||||
/assets/test_files
|
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
cmake_minimum_required(VERSION 3.18..3.27)
|
||||
project(JGL
|
||||
VERSION 1.0
|
||||
LANGUAGES CXX
|
||||
@@ -9,50 +9,89 @@ if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
if (WIN32)
|
||||
set(CMAKE_CXX_FLAGS "-municode")
|
||||
endif(WIN32)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
|
||||
# Enable Package Managers
|
||||
include(cmake/CPM.cmake)
|
||||
|
||||
|
||||
CPMAddPackage(
|
||||
NAME mcolor
|
||||
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-5.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME J3ML
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/Release-6.zip
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/3.4.5.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ReWindow
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/vA0.2.30.zip
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-32.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME GLAD
|
||||
URL https://git.redacted.cc/Redacted/glad/archive/v2.1.zip
|
||||
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo_depthtexture_shadow.zip
|
||||
)
|
||||
file(COPY "assets" DESTINATION "${PROJECT_BINARY_DIR}")
|
||||
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp")
|
||||
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp" )
|
||||
file(GLOB_RECURSE ASSETS "assets/*")
|
||||
|
||||
add_library(JGL SHARED ${SOURCES})
|
||||
CPMAddPackage(
|
||||
NAME jlog
|
||||
URL https://git.redacted.cc/josh/jlog/Prerelease-16.zip
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
CPMAddPackage(
|
||||
NAME freetype
|
||||
URL https://github.com/freetype/freetype/archive/refs/tags/VER-2-13-2.zip
|
||||
)
|
||||
endif()
|
||||
|
||||
#set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
|
||||
|
||||
file(COPY "assets" DESTINATION "${PROJECT_BINARY_DIR}")
|
||||
file(GLOB_RECURSE ASSETS "assets/*")
|
||||
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp" )
|
||||
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp" "src/*.h")
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(Freetype REQUIRED)
|
||||
add_library(JGL SHARED ${SOURCES})
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
add_library(JGL STATIC ${SOURCES})
|
||||
endif()
|
||||
|
||||
set_target_properties(JGL PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
#Don't expose these ones.
|
||||
include_directories(
|
||||
${ReWindow_SOURCE_DIR}/include
|
||||
${Event_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_include_directories(JGL PUBLIC
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${mcolor_SOURCE_DIR}/include
|
||||
${J3ML_SOURCE_DIR}/include
|
||||
${jlog_SOURCE_DIR}/include
|
||||
${glad_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
add_executable(JGL_Demo main.cpp)
|
||||
set_target_properties(JGL_Demo PROPERTIES LINK_FLAGS "-Wl,-rpath,./lib")
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
include_directories(${OPENGL_INCLUDE_DIRS})
|
||||
include_directories(${J3ML_SOURCE_DIR}/include)
|
||||
include_directories(${ReWindow_SOURCE_DIR}/include)
|
||||
include_directories(${glad_SOURCE_DIR}/include)
|
||||
#set_target_properties(JGL_Demo PROPERTIES LINK_FLAGS "-Wl,-rpath,./lib")
|
||||
|
||||
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS})
|
||||
target_link_libraries(JGL PRIVATE ${FREETYPE_LIBRARIES})
|
||||
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS})
|
||||
target_link_libraries(JGL_Demo PUBLIC JGL ${OPENGL_LIBRARIES} J3ML ReWindowLibrary glad)
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS} )
|
||||
target_link_libraries(JGL PRIVATE ${FREETYPE_LIBRARIES})
|
||||
target_link_libraries(JGL PUBLIC mcolor J3ML jlog glad)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_include_directories(JGL PRIVATE ${freetype_SOURCE_DIR}/include)
|
||||
target_link_libraries(JGL PRIVATE freetype)
|
||||
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog glad)
|
||||
endif()
|
||||
|
||||
target_link_libraries(JGL_Demo PUBLIC JGL ReWindow Event glad)
|
||||
|
89
README.md
89
README.md
@@ -1,11 +1,82 @@
|
||||
# Josh Graphics Library
|
||||
# Josh's Graphics Library
|
||||
|
||||
# Goals
|
||||
* Provide single-function-calls to render various graphics primitives in 2D and 3D.
|
||||
* Integrated directly with our other toolkits (ReWindow, J3ML)
|
||||
* Quick Rendering of Debug Text, Geometric Widgets, Textures, and so forth.
|
||||
Yet Another C++ Rendering Toolkit
|
||||
|
||||
# Non-Goals
|
||||
* Full Rendering Engine
|
||||
* OpenGL/Vulkan Wrapper
|
||||
* Asset Loading & Management
|
||||
[](http://unlicense.org/) 
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* Modern C++ (20).
|
||||
* Cross Platform (Linux & Windows 10 1909 or newer).
|
||||
* Provides single-function-calls to render various graphics in 2D and 3D.
|
||||
* Integrates right into an existing OpenGL rendering system.
|
||||
* Quick Rendering of Text, Shapes, Sprites / Textures, etc.
|
||||
* High-performance text rendering.
|
||||
* Little-to-no overhead.
|
||||
|
||||
## API Overview
|
||||
|
||||
### J2D
|
||||
* DrawPoint
|
||||
* DrawLine / DrawGradientLine / DrawDottedLine / DrawDashedLine / DrawLines
|
||||
* DrawSprite / DrawPartialSprite
|
||||
* DrawRenderTarget / DrawPartialRenderTarget
|
||||
* OutlineRect / OutlineRoundedRect / OutlineChamferRect
|
||||
* FillRect / FillGradientRect / FillRoundedRect / FillChamferRect
|
||||
* OutlineCircle / FillCircle
|
||||
* OutlineTriangle / FillTriangle / FillGradientTriangle
|
||||
* DrawString
|
||||
* DrawCubicBezierCurve
|
||||
* DrawArc
|
||||
* OutlineEllipse / FillEllipse
|
||||
|
||||
### J3D
|
||||
* DrawLine
|
||||
* DrawString
|
||||
* DrawMatrixGizmo (WIP)
|
||||
* DrawAxisAngleGizmo (WIP)
|
||||
* DrawQuaternionGizmo (WIP)
|
||||
|
||||
### Types
|
||||
* RenderTarget
|
||||
* VRamList
|
||||
* Texture
|
||||
* Font
|
||||
|
||||
## Usage
|
||||
```cpp
|
||||
// Makes sure the glViewport will be the correct size.
|
||||
// Typically done once per frame.
|
||||
JGL::Update(window_size);
|
||||
|
||||
JGL::J2D::Begin();
|
||||
JGL::J2D::FillRect(Colors::Blue, {0,0}, {16,16});
|
||||
JGL::J2D::End();
|
||||
|
||||
// See the example program in main.cpp for more in-depth usage.
|
||||
```
|
||||
## Requirements
|
||||
|
||||
An OpenGL 2.1 or newer accelerator with at-least two texture mappers that supports the `GL_ARB_framebuffer_object` extension or
|
||||
an implementation that can provide those features through alternative means (common on ArmSoC and Risc-V).
|
||||
|
||||
## Compatability
|
||||
|
||||
* AMD ✓
|
||||
* NVIDIA ✓
|
||||
* Intel ✓
|
||||
* Zink (OpenGL-on-Vulkan) ✓
|
||||
* GL4ES ✓
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation is available [here](https://doc.redacted.cc/JGL/d3/dcc/md__r_e_a_d_m_e.html).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions to JGL are welcome! If you find a bug, have a feature request, or would like to contribute code, please submit an issue or pull request to our repository!
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
JGL is developed and maintained by Josh O'Leary @ Co from Redacted Software and contributors. Special thanks to Redacted.
|
164
assets/models/cone.obj
Normal file
164
assets/models/cone.obj
Normal file
@@ -0,0 +1,164 @@
|
||||
# Blender v3.6.4 OBJ File: ''
|
||||
# www.blender.org
|
||||
o Cone
|
||||
v 0.000000 -1.000000 -1.000000
|
||||
v 0.195090 -1.000000 -0.980785
|
||||
v 0.382683 -1.000000 -0.923880
|
||||
v 0.555570 -1.000000 -0.831470
|
||||
v 0.707107 -1.000000 -0.707107
|
||||
v 0.831470 -1.000000 -0.555570
|
||||
v 0.923880 -1.000000 -0.382683
|
||||
v 0.980785 -1.000000 -0.195090
|
||||
v 1.000000 -1.000000 0.000000
|
||||
v 0.980785 -1.000000 0.195090
|
||||
v 0.923880 -1.000000 0.382683
|
||||
v 0.831470 -1.000000 0.555570
|
||||
v 0.707107 -1.000000 0.707107
|
||||
v 0.555570 -1.000000 0.831470
|
||||
v 0.382683 -1.000000 0.923880
|
||||
v 0.195090 -1.000000 0.980785
|
||||
v 0.000000 -1.000000 1.000000
|
||||
v -0.195090 -1.000000 0.980785
|
||||
v -0.382683 -1.000000 0.923880
|
||||
v -0.555570 -1.000000 0.831470
|
||||
v -0.707107 -1.000000 0.707107
|
||||
v -0.831470 -1.000000 0.555570
|
||||
v -0.923880 -1.000000 0.382683
|
||||
v -0.980785 -1.000000 0.195090
|
||||
v -1.000000 -1.000000 0.000000
|
||||
v -0.980785 -1.000000 -0.195090
|
||||
v -0.923880 -1.000000 -0.382683
|
||||
v -0.831470 -1.000000 -0.555570
|
||||
v -0.707107 -1.000000 -0.707107
|
||||
v -0.555570 -1.000000 -0.831470
|
||||
v -0.382683 -1.000000 -0.923880
|
||||
v -0.195090 -1.000000 -0.980785
|
||||
v 0.000000 1.000000 0.000000
|
||||
vt 0.250000 0.490000
|
||||
vt 0.250000 0.250000
|
||||
vt 0.296822 0.485388
|
||||
vt 0.341844 0.471731
|
||||
vt 0.383337 0.449553
|
||||
vt 0.419706 0.419706
|
||||
vt 0.449553 0.383337
|
||||
vt 0.471731 0.341844
|
||||
vt 0.485388 0.296822
|
||||
vt 0.490000 0.250000
|
||||
vt 0.485388 0.203178
|
||||
vt 0.471731 0.158156
|
||||
vt 0.449553 0.116663
|
||||
vt 0.419706 0.080294
|
||||
vt 0.383337 0.050447
|
||||
vt 0.341844 0.028269
|
||||
vt 0.296822 0.014612
|
||||
vt 0.250000 0.010000
|
||||
vt 0.203178 0.014612
|
||||
vt 0.158156 0.028269
|
||||
vt 0.116663 0.050447
|
||||
vt 0.080294 0.080294
|
||||
vt 0.050447 0.116663
|
||||
vt 0.028269 0.158156
|
||||
vt 0.014612 0.203178
|
||||
vt 0.010000 0.250000
|
||||
vt 0.014612 0.296822
|
||||
vt 0.028269 0.341844
|
||||
vt 0.050447 0.383337
|
||||
vt 0.080294 0.419706
|
||||
vt 0.116663 0.449553
|
||||
vt 0.158156 0.471731
|
||||
vt 0.796822 0.014612
|
||||
vt 0.514612 0.203178
|
||||
vt 0.703178 0.485388
|
||||
vt 0.203178 0.485388
|
||||
vt 0.750000 0.490000
|
||||
vt 0.796822 0.485388
|
||||
vt 0.841844 0.471731
|
||||
vt 0.883337 0.449553
|
||||
vt 0.919706 0.419706
|
||||
vt 0.949553 0.383337
|
||||
vt 0.971731 0.341844
|
||||
vt 0.985388 0.296822
|
||||
vt 0.990000 0.250000
|
||||
vt 0.985388 0.203178
|
||||
vt 0.971731 0.158156
|
||||
vt 0.949553 0.116663
|
||||
vt 0.919706 0.080294
|
||||
vt 0.883337 0.050447
|
||||
vt 0.841844 0.028269
|
||||
vt 0.750000 0.010000
|
||||
vt 0.703178 0.014612
|
||||
vt 0.658156 0.028269
|
||||
vt 0.616663 0.050447
|
||||
vt 0.580294 0.080294
|
||||
vt 0.550447 0.116663
|
||||
vt 0.528269 0.158156
|
||||
vt 0.510000 0.250000
|
||||
vt 0.514612 0.296822
|
||||
vt 0.528269 0.341844
|
||||
vt 0.550447 0.383337
|
||||
vt 0.580294 0.419706
|
||||
vt 0.616663 0.449553
|
||||
vt 0.658156 0.471731
|
||||
s off
|
||||
f 1/1 33/2 2/3
|
||||
f 2/3 33/2 3/4
|
||||
f 3/4 33/2 4/5
|
||||
f 4/5 33/2 5/6
|
||||
f 5/6 33/2 6/7
|
||||
f 6/7 33/2 7/8
|
||||
f 7/8 33/2 8/9
|
||||
f 8/9 33/2 9/10
|
||||
f 9/10 33/2 10/11
|
||||
f 10/11 33/2 11/12
|
||||
f 11/12 33/2 12/13
|
||||
f 12/13 33/2 13/14
|
||||
f 13/14 33/2 14/15
|
||||
f 14/15 33/2 15/16
|
||||
f 15/16 33/2 16/17
|
||||
f 16/17 33/2 17/18
|
||||
f 17/18 33/2 18/19
|
||||
f 18/19 33/2 19/20
|
||||
f 19/20 33/2 20/21
|
||||
f 20/21 33/2 21/22
|
||||
f 21/22 33/2 22/23
|
||||
f 22/23 33/2 23/24
|
||||
f 23/24 33/2 24/25
|
||||
f 24/25 33/2 25/26
|
||||
f 25/26 33/2 26/27
|
||||
f 26/27 33/2 27/28
|
||||
f 27/28 33/2 28/29
|
||||
f 28/29 33/2 29/30
|
||||
f 29/30 33/2 30/31
|
||||
f 30/31 33/2 31/32
|
||||
f 16/33 24/34 32/35
|
||||
f 31/32 33/2 32/36
|
||||
f 32/36 33/2 1/1
|
||||
f 32/35 1/37 2/38
|
||||
f 2/38 3/39 4/40
|
||||
f 4/40 5/41 6/42
|
||||
f 6/42 7/43 8/44
|
||||
f 8/44 9/45 10/46
|
||||
f 10/46 11/47 12/48
|
||||
f 12/48 13/49 14/50
|
||||
f 14/50 15/51 16/33
|
||||
f 16/33 17/52 18/53
|
||||
f 18/53 19/54 20/55
|
||||
f 20/55 21/56 22/57
|
||||
f 22/57 23/58 24/34
|
||||
f 24/34 25/59 26/60
|
||||
f 26/60 27/61 28/62
|
||||
f 28/62 29/63 30/64
|
||||
f 30/64 31/65 32/35
|
||||
f 32/35 2/38 8/44
|
||||
f 2/38 4/40 8/44
|
||||
f 4/40 6/42 8/44
|
||||
f 8/44 10/46 16/33
|
||||
f 10/46 12/48 16/33
|
||||
f 12/48 14/50 16/33
|
||||
f 16/33 18/53 24/34
|
||||
f 18/53 20/55 24/34
|
||||
f 20/55 22/57 24/34
|
||||
f 24/34 26/60 32/35
|
||||
f 26/60 28/62 32/35
|
||||
f 28/62 30/64 32/35
|
||||
f 32/35 8/44 16/33
|
46
assets/models/cube.amo
Normal file
46
assets/models/cube.amo
Normal file
@@ -0,0 +1,46 @@
|
||||
ao Cube 1
|
||||
v 8
|
||||
1.000000 1.000000 1.000000
|
||||
1.000000 1.000000 -1.000000
|
||||
1.000000 -1.000000 1.000000
|
||||
1.000000 -1.000000 -1.000000
|
||||
-1.000000 1.000000 1.000000
|
||||
-1.000000 1.000000 -1.000000
|
||||
-1.000000 -1.000000 1.000000
|
||||
-1.000000 -1.000000 -1.000000
|
||||
vt 14
|
||||
0.625000 0.500000
|
||||
0.875000 0.500000
|
||||
0.875000 0.750000
|
||||
0.625000 0.750000
|
||||
0.375000 0.750000
|
||||
0.625000 1.000000
|
||||
0.375000 1.000000
|
||||
0.375000 0.000000
|
||||
0.625000 0.000000
|
||||
0.625000 0.250000
|
||||
0.375000 0.250000
|
||||
0.125000 0.500000
|
||||
0.375000 0.500000
|
||||
0.125000 0.750000
|
||||
vn 6
|
||||
0.000000 0.000000 1.000000
|
||||
0.000000 -1.000000 0.000000
|
||||
-1.000000 0.000000 0.000000
|
||||
0.000000 0.000000 -1.000000
|
||||
1.000000 0.000000 0.000000
|
||||
0.000000 1.000000 0.000000
|
||||
f 12
|
||||
2 0 0 0 1 0 4 2 0
|
||||
7 3 1 3 4 1 2 3 1
|
||||
5 5 2 7 6 2 6 7 2
|
||||
7 8 3 5 9 3 1 10 3
|
||||
3 11 4 1 12 4 0 4 4
|
||||
1 13 5 5 12 5 4 0 5
|
||||
2 0 0 4 1 0 6 2 0
|
||||
7 3 1 2 4 1 6 3 1
|
||||
5 5 2 6 6 2 4 7 2
|
||||
7 8 3 1 9 3 3 10 3
|
||||
3 11 4 0 12 4 2 4 4
|
||||
1 13 5 4 12 5 0 0 5
|
||||
end
|
38
assets/models/cube.obj
Normal file
38
assets/models/cube.obj
Normal file
@@ -0,0 +1,38 @@
|
||||
# Blender v3.6.4 OBJ File: ''
|
||||
# www.blender.org
|
||||
o Cube
|
||||
v 1.000000 1.000000 -1.000000
|
||||
v 1.000000 -1.000000 -1.000000
|
||||
v 1.000000 1.000000 1.000000
|
||||
v 1.000000 -1.000000 1.000000
|
||||
v -1.000000 1.000000 -1.000000
|
||||
v -1.000000 -1.000000 -1.000000
|
||||
v -1.000000 1.000000 1.000000
|
||||
v -1.000000 -1.000000 1.000000
|
||||
vt 0.875000 0.500000
|
||||
vt 0.625000 0.750000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.375000 1.000000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.625000 0.000000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.375000 0.000000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.125000 0.750000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.875000 0.750000
|
||||
vt 0.625000 1.000000
|
||||
s off
|
||||
f 5/1 3/2 1/3
|
||||
f 3/2 8/4 4/5
|
||||
f 7/6 6/7 8/8
|
||||
f 2/9 8/10 6/11
|
||||
f 1/3 4/5 2/9
|
||||
f 5/12 2/9 6/7
|
||||
f 5/1 7/13 3/2
|
||||
f 3/2 7/14 8/4
|
||||
f 7/6 5/12 6/7
|
||||
f 2/9 4/5 8/10
|
||||
f 1/3 3/2 4/5
|
||||
f 5/12 1/3 2/9
|
5
assets/shader_programs/test_fragment.glsl
Normal file
5
assets/shader_programs/test_fragment.glsl
Normal file
@@ -0,0 +1,5 @@
|
||||
#version 120
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(1, 1, 1, 1);
|
||||
}
|
7
assets/shader_programs/test_vertex.glsl
Normal file
7
assets/shader_programs/test_vertex.glsl
Normal file
@@ -0,0 +1,7 @@
|
||||
#version 120
|
||||
|
||||
attribute vec2 position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position.x, position.y, 1.0, 1.0);
|
||||
}
|
BIN
assets/sprites/Re3D.png
Normal file
BIN
assets/sprites/Re3D.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
assets/sprites/alpha_mask.png
Normal file
BIN
assets/sprites/alpha_mask.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 942 B |
BIN
assets/sprites/alpha_mask_2.png
Normal file
BIN
assets/sprites/alpha_mask_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <JGL/Color4.h>
|
||||
#include <J3ML/J3ML.h>
|
||||
|
||||
namespace JGL
|
||||
{
|
||||
using namespace J3ML;
|
||||
struct Color3 {
|
||||
u8 r;
|
||||
u8 g;
|
||||
u8 b;
|
||||
|
||||
Color3 Lerp(const Color3& rhs, float alpha) const;
|
||||
Color4 WithAlphaChannel(float alpha = 1) const;
|
||||
Color3(u8 R, u8 G, u8 B) : r(R), g(G), b(B) {}
|
||||
Color3(const Color4& c)
|
||||
{
|
||||
this->r = c.r;
|
||||
this->g = c.g;
|
||||
this->b = c.b;
|
||||
}
|
||||
u8 RedChannel () const { return r; }
|
||||
u8 GreenChannel() const { return g; }
|
||||
u8 BlueChannel () const { return b; }
|
||||
float RedChannelNormalized () const { return static_cast<float>(r) / 255.f;}
|
||||
float BlueChannelNormalized() const { return static_cast<float>(b) / 255.f;}
|
||||
float GreenChannelNormalized() const { return static_cast<float>(g) / 255.f;}
|
||||
};
|
||||
|
||||
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace JGL
|
||||
{
|
||||
struct Color4{
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
int a;
|
||||
};
|
||||
}
|
@@ -1,178 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <JGL/Color3.h>
|
||||
|
||||
namespace JGL
|
||||
{
|
||||
namespace Colors {
|
||||
namespace Primary {
|
||||
static const Color3 Red{255, 0, 0};
|
||||
static const Color3 Green{0, 255, 0};
|
||||
static const Color3 Blue{0, 0, 255};
|
||||
static const Color3 White{255, 255, 255};
|
||||
static const Color3 Black{0, 0, 0};
|
||||
static const Color3 Gray{128, 128, 128};
|
||||
static const Color3 DarkGray{192, 192, 192};
|
||||
static const Color3 LightGray{64, 64, 64};
|
||||
static const Color3 Yellow{255, 255, 0};
|
||||
}
|
||||
using namespace Primary;
|
||||
namespace Reds {
|
||||
static const Color3 Fuchsia {255, 0, 255};
|
||||
static const Color3 LightSalmon{255, 160, 122};
|
||||
static const Color3 Salmon{250, 128, 114};
|
||||
static const Color3 DarkSalmon{233, 150, 122};
|
||||
static const Color3 LightCoral{240, 128, 128};
|
||||
static const Color3 IndianRed{205, 92, 92};
|
||||
static const Color3 Crimson{220, 20, 60};
|
||||
static const Color3 Firebrick{178, 34, 34};
|
||||
static const Color3 DarkRed{139, 0, 0};
|
||||
}
|
||||
namespace Oranges {
|
||||
static const Color3 Coral{255, 127, 80};
|
||||
static const Color3 Tomato{255, 99, 71};
|
||||
static const Color3 OrangeRed{255, 69, 0};
|
||||
static const Color3 Gold{255, 215, 0};
|
||||
static const Color3 Orange{255, 165, 0};
|
||||
static const Color3 DarkOrange{255, 140, 0};
|
||||
}
|
||||
namespace Yellows {
|
||||
static const Color3 LightYellow{255, 255, 224};
|
||||
static const Color3 LemonChiffon{255, 250, 205};
|
||||
static const Color3 LightGoldenrodYellow{250, 250, 210};
|
||||
static const Color3 PapayaWhip{255, 239, 213};
|
||||
static const Color3 Moccasin{255, 228, 181};
|
||||
static const Color3 PeachPuff{255, 218, 185};
|
||||
static const Color3 PaleGoldenrod{238, 232, 170};
|
||||
static const Color3 Khaki{240, 230, 140};
|
||||
static const Color3 DarkKhaki{189, 183, 107};
|
||||
}
|
||||
namespace Greens {
|
||||
static const Color3 LawnGreen{124, 252, 0};
|
||||
static const Color3 Chartreuse{127, 255, 0};
|
||||
static const Color3 LimeGreen{50, 205, 50};
|
||||
static const Color3 ForestGreen{34, 139, 34};
|
||||
static const Color3 DarkGreen{0, 100, 0};
|
||||
static const Color3 GreenYellow{173, 255, 47};
|
||||
static const Color3 YellowGreen{154, 205, 50};
|
||||
static const Color3 SpringGreen{0, 255, 127};
|
||||
static const Color3 MediumSpringGreen{0, 250, 154};
|
||||
static const Color3 LightGreen{144, 238, 144};
|
||||
static const Color3 PaleGreen{152, 251, 152};
|
||||
static const Color3 DarkSeaGreen{143, 188, 143};
|
||||
static const Color3 MediumSeaGreen{60, 179, 113};
|
||||
static const Color3 SeaGreen{46, 139, 87};
|
||||
static const Color3 DarkOliveGreen{85, 107, 47};
|
||||
static const Color3 OliveDrab{107, 142, 35};
|
||||
static const Color3 Lime{0, 255, 0};
|
||||
static const Color3 Olive{128, 128, 0};
|
||||
}
|
||||
namespace Cyans {
|
||||
static const Color3 LightCyan{224, 255, 255};
|
||||
static const Color3 Cyan{0, 255, 255};
|
||||
static const Color3 Aqua{0, 255, 255};
|
||||
static const Color3 Aquamarine{127, 255, 212};
|
||||
static const Color3 MediumAquamarine{102, 205, 170};
|
||||
static const Color3 PaleTurquoise{175, 238, 238};
|
||||
static const Color3 Turquoise{64, 224, 208};
|
||||
static const Color3 MediumTurquoise{72, 209, 204};
|
||||
static const Color3 DarkTurquoise{0, 206, 209};
|
||||
static const Color3 LightSeaGreen{32, 178, 170};
|
||||
static const Color3 CadetBlue{95, 158, 160};
|
||||
static const Color3 DarkCyan{0, 139, 139};
|
||||
static const Color3 Teal{0, 128, 128};
|
||||
}
|
||||
namespace Blues {
|
||||
static const Color3 PowderBlue{176, 224, 230};
|
||||
static const Color3 LightBlue{173, 216, 230};
|
||||
static const Color3 LightSkyBlue{135, 206, 250};
|
||||
static const Color3 SkyBlue{135, 206, 235};
|
||||
static const Color3 DeepSkyBlue{0, 191, 255};
|
||||
static const Color3 LightSteelBlue{176, 196, 222};
|
||||
static const Color3 DodgerBlue{30, 144, 255};
|
||||
static const Color3 CornflowerBlue{100, 149, 237};
|
||||
static const Color3 SteelBlue{70, 130, 180};
|
||||
static const Color3 RoyalBlue{65, 105, 225};
|
||||
static const Color3 MediumBlue{0, 0, 205};
|
||||
static const Color3 DarkBlue{0, 0, 139};
|
||||
static const Color3 Navy{0, 0, 128};
|
||||
static const Color3 MidnightBlue{25, 25, 112};
|
||||
static const Color3 MediumSlateBlue{123, 104, 238};
|
||||
static const Color3 SlateBlue{106, 90, 205};
|
||||
static const Color3 DarkSlateBlue{72, 61, 139};
|
||||
}
|
||||
|
||||
|
||||
namespace Purples {
|
||||
static const Color3 Lavender{230, 230, 250};
|
||||
static const Color3 Thistle{216, 191, 216};
|
||||
static const Color3 Plum{221, 160, 221};
|
||||
static const Color3 Violet{238, 160, 221};
|
||||
static const Color3 Orchid{218, 112, 214};
|
||||
static const Color3 Fuchsia{255, 0, 255};
|
||||
static const Color3 Magenta{255, 0, 255};
|
||||
static const Color3 MediumOrchid{186, 85, 211};
|
||||
static const Color3 MediumPurple{147, 112, 219};
|
||||
static const Color3 BlueViolet{138, 43, 226};
|
||||
static const Color3 DarkViolet{148, 0, 211};
|
||||
static const Color3 DarkOrchid{153, 50, 204};
|
||||
static const Color3 DarkMagenta{139, 0, 128};
|
||||
static const Color3 Purple{128, 0, 128};
|
||||
static const Color3 Indigo{75, 0, 130};
|
||||
}
|
||||
namespace Pinks {
|
||||
static const Color3 Pink{255, 129, 203};
|
||||
static const Color3 LightPink{255, 182, 193};
|
||||
static const Color3 HotPink{255, 105, 180};
|
||||
static const Color3 DeepPink{255, 20, 147};
|
||||
static const Color3 PaleVioletRed{219, 112, 147};
|
||||
static const Color3 MediumVioletRed{199, 21, 133};
|
||||
}
|
||||
namespace Whites {
|
||||
static const Color3 Snow{255, 250, 250};
|
||||
static const Color3 Honeydew{240, 255, 240};
|
||||
static const Color3 MintCream{245, 255, 250};
|
||||
static const Color3 Azure{240, 255, 255};
|
||||
static const Color3 AliceBlue{240, 248, 255};
|
||||
static const Color3 GhostWhite{248, 248, 255};
|
||||
static const Color3 WhiteSmoke{245, 245, 245};
|
||||
static const Color3 SeaShell{255, 245, 238};
|
||||
static const Color3 Beige{245, 245, 220};
|
||||
static const Color3 OldLace{253, 245, 230};
|
||||
static const Color3 FloralWhite{255, 250, 240};
|
||||
static const Color3 Ivory{255, 255, 240};
|
||||
static const Color3 AntiqueWhite{250, 240, 215};
|
||||
static const Color3 Linen{250, 240, 230};
|
||||
static const Color3 LavenderBlush{255, 240, 245};
|
||||
static const Color3 MistyRose{255, 228, 255};
|
||||
}
|
||||
namespace Grays {
|
||||
static const Color3 Gainsboro{220, 220, 220};
|
||||
static const Color3 LightGray{211, 211, 211};
|
||||
static const Color3 Silver{192, 192, 192};
|
||||
static const Color3 DimGray{105, 105, 105};
|
||||
static const Color3 LightSlateGray{119, 136, 153};
|
||||
static const Color3 SlateGray{112, 128, 144};
|
||||
static const Color3 DarkSlateGray{47, 79, 79};
|
||||
}
|
||||
namespace Browns {
|
||||
static const Color3 CornSilk{255, 248, 220};
|
||||
static const Color3 BlanchedAlmond{255, 235, 205};
|
||||
static const Color3 Bisque{255, 228, 196};
|
||||
static const Color3 NavajoWhite{255, 222, 173};
|
||||
static const Color3 Wheat{254, 222, 179};
|
||||
static const Color3 BurlyWood{222, 184, 135};
|
||||
static const Color3 Tan{210, 180, 140};
|
||||
static const Color3 RosyBrown{188, 143, 143};
|
||||
static const Color3 SandyBrown{244, 164, 96};
|
||||
static const Color3 GoldenRod{218, 165, 32};
|
||||
static const Color3 Peru{205, 133, 63};
|
||||
static const Color3 Chocolate{210, 105, 30};
|
||||
static const Color3 SaddleBrown{139, 69, 19};
|
||||
static const Color3 Sienna{160, 82, 45};
|
||||
static const Color3 Brown{164, 42, 42};
|
||||
static const Color3 Maroon{128, 0, 0};
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,99 +1,698 @@
|
||||
//
|
||||
// Created by dawsh on 1/17/24.
|
||||
//
|
||||
/// Josh's Graphics Library
|
||||
/// A C++20 Library for rendering 2D and 3D primitives in an OpenGL context.
|
||||
/// Developed and Maintained by Josh O'Leary @ Redacted Software.
|
||||
/// Special Thanks to William Tomasine II and Maxine Hayes.
|
||||
/// (c) 2024 Redacted Software
|
||||
/// This work is dedicated to the public domain.
|
||||
|
||||
/// @file JGL.h
|
||||
/// @desc All JGL usable functions are defined here. This is the public API.
|
||||
/// @edit 2024-10-24
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||
#include <J3ML/LinearAlgebra/Vector3.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <JGL/Color3.h>
|
||||
#include <J3ML/Geometry/Sphere.h>
|
||||
#include <J3ML/Geometry/OBB.h>
|
||||
#include <J3ML/Geometry/Capsule.h>
|
||||
#include <J3ML/Geometry/Plane.h>
|
||||
#include <J3ML/Geometry/TriangleMesh.h>
|
||||
#include <Color4.hpp>
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <JGL/types/Enums.h>
|
||||
#include <JGL/types/FontCache.h>
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/types/Light.h>
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/Geometry/Sphere.hpp>
|
||||
#include <J3ML/Geometry/Capsule.hpp>
|
||||
#include <J3ML/Geometry/Triangle2D.hpp>
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/VRamList.h>
|
||||
#include <JGL/types/VertexArray.h>
|
||||
|
||||
// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
|
||||
// Fonts that are included by default.
|
||||
namespace JGL::Fonts {
|
||||
void Init();
|
||||
// Built in fonts.
|
||||
inline Font Jupiteroid;
|
||||
}
|
||||
|
||||
// Simple shapes that are pre-computed and used in some draw functions.
|
||||
namespace JGL::ShapeCache {
|
||||
inline VRamList* cube_vertex_data = nullptr;
|
||||
inline VRamList* cube_index_data = nullptr;
|
||||
inline VRamList* cube_normal_data = nullptr;
|
||||
// Facing straight out.
|
||||
inline VRamList* j2d_default_normal_data = nullptr;
|
||||
inline VRamList* square_origin_topleft_vertex_data = nullptr;
|
||||
void Init();
|
||||
}
|
||||
|
||||
/// OpenGL Wrapper for rendering 2D & 3D graphics in both a 2D and 3D context.
|
||||
namespace JGL {
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
using namespace J3ML::Geometry;
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using J3ML::LinearAlgebra::Vector3;
|
||||
using J3ML::LinearAlgebra::Matrix3x3;
|
||||
using J3ML::LinearAlgebra::Matrix4x4;
|
||||
using J3ML::LinearAlgebra::AxisAngle;
|
||||
using J3ML::LinearAlgebra::Quaternion;
|
||||
[[nodiscard]] bool Init(const Vector2i& window_size, float fovY, float far_plane);
|
||||
void Update(const Vector2i& window_size);
|
||||
inline void PurgeFontCache() { JGL::fontCache.purgeCache(); }
|
||||
|
||||
using J3ML::Geometry::Sphere;
|
||||
using J3ML::Geometry::OBB;
|
||||
using J3ML::Geometry::Capsule;
|
||||
using J3ML::Geometry::TriangleMesh;
|
||||
using J3ML::Geometry::Plane;
|
||||
|
||||
struct HSV {
|
||||
float hue;
|
||||
float saturation;
|
||||
float value;
|
||||
};
|
||||
std::array<GLfloat, 16> OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far);
|
||||
|
||||
struct Triangle2D
|
||||
{
|
||||
Vector2 A;
|
||||
Vector2 B;
|
||||
Vector2 C;
|
||||
};
|
||||
/// @returns true if the graphics driver meets the requirements (GL Version & Extensions).
|
||||
bool MeetsRequirements();
|
||||
}
|
||||
|
||||
struct Triangle3D
|
||||
{
|
||||
Vector3 A;
|
||||
Vector3 B;
|
||||
Vector3 C;
|
||||
};
|
||||
/// Drawing functions for 2D objects.
|
||||
namespace JGL::J2D {
|
||||
/// Open a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
|
||||
/// @note This call may not strictly be necessary on some setups, but is provided to keep the API constant.
|
||||
/// It is recommended to always open a JGL 2D context to render your content, then close when completed.
|
||||
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 3D content in between our calls.
|
||||
/// @param render_target
|
||||
/// @param clear_buffers
|
||||
void Begin(RenderTarget* render_target = nullptr, bool clear_buffers = false);
|
||||
|
||||
bool InitTextEngine();
|
||||
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
|
||||
/// @see Begin().
|
||||
void End();
|
||||
|
||||
// TODO: implement correct coloring
|
||||
/// Provide a list of lights to be used in 2D space. Typically directly after J2D::Begin();
|
||||
/// 8 lights maximum for now. Some kind of light sorting will eventually be needed per j2d element.
|
||||
void OptionalLights(const LightBase** lights, const size_t& light_count);
|
||||
|
||||
namespace J2D {
|
||||
void DrawPixel2D(const Color3 &color, const Vector2 &coordinates);
|
||||
void DrawPixel2D(const Color3 &color, float x, float y);
|
||||
void DrawLine2D(const Color3 &color, const Vector2 &A, const Vector2 &B, float thickness = 1);
|
||||
void DrawLine2D(const Color3 &color, float x, float y, float w, float h, float thickness = 1);
|
||||
void DrawCubicBezierCurve2D();
|
||||
void OutlineCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions,
|
||||
float thickness = 1);
|
||||
void FillCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions);
|
||||
void OutlineTriangle2D(const Color3 &color, const Triangle2D &tri);
|
||||
void FillTriangle2D(const Color3 &color, const Triangle2D &tri);
|
||||
void FillTexturedTriangle2D();
|
||||
void FillTexturedPolygon2D();
|
||||
void DrawSprite2D();
|
||||
void DrawPartialSprite2D();
|
||||
void DrawString2D(const Color3& color, std::string text, float x, float y, float scale, u32 size = 16);
|
||||
void FillRect2D(const Color3 &color, const Vector2 &pos, const Vector2 &size);
|
||||
void OutlineRect2D ( const Color3& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||
void FillRoundedRect2D (const Color3& color, const Vector2& pos, const Vector2& size, float radius);
|
||||
void OutlineRoundedRect2D(const Color3& color, const Vector2& pos, const Vector2& size, float radius, float thickness = 1);
|
||||
void OutlinePolygon2D (const Color3& color, std::vector<Vector2> points);
|
||||
void FillPolygon2D (const Color3& color, std::vector<Vector2> points, float thickness = 1);
|
||||
void GradientFillRect2D ();
|
||||
}
|
||||
namespace J3D {
|
||||
void DrawLine3D(const Color3& color, const Vector3 &A, const Vector3 &B, float thickness = 1);
|
||||
void FillSphere3D(const Color3& color, const Sphere& sphere);
|
||||
void WireframeSphere3D(const Color3& color, const Sphere& sphere, float thickness = 1);
|
||||
void FillOBB3D(const Color3& color, const OBB& obb);
|
||||
void WireframeOBB3D(const Color3& color, const OBB& obb, float thickness = 1);
|
||||
void FillCapsule3D(const Color3& color, const Capsule& capsule);
|
||||
void WireframeCapsule3D(const Color3& color, const Capsule& cap, float thickness = 1);
|
||||
void FillTriangleMesh3D(const Color3& color, const TriangleMesh& mesh);
|
||||
void WireframeTriangleMesh3D(const Color3& color, const TriangleMesh& mesh, float thickness = 1);
|
||||
void DrawString3D(const Color3& color, const std::string& text, const Vector3& pos, float scale, u32 size = 12);
|
||||
/// Specifies a light which is required for every object in the scene.
|
||||
void RequiredLight(const LightBase* light);
|
||||
|
||||
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
|
||||
void DrawMatrixGizmo (const Matrix4x4&);
|
||||
void DrawAxisAngleGizmo (const AxisAngle&, const Vector3&);
|
||||
void DrawQuaternionGizmo (const Quaternion&, const Vector3&);
|
||||
}
|
||||
/// Plots a single pixel on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param coordinates The pixel-point on-screen at which to plot the pixel.
|
||||
/// @param radius The size of the point to plot. By default, a single pixel.
|
||||
void DrawPoint(const Color4& color, const Vector2& coordinates, float radius = 1.f);
|
||||
void DrawPoint(const Color4& color, float x, float y, float radius = 1.f);
|
||||
|
||||
/// Plots a series of pixel-points on the screen, in a batch.
|
||||
/// @note This is more performant for multiple points than plotting them individually.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param points A set of x,y points to render.
|
||||
/// @param radius The size of the point to plot. By default, a single pixel.
|
||||
void DrawPoints(const Color4& color, const Vector2* points, int point_count, float radius = 1.f);
|
||||
|
||||
/// Plots a line (segment) on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
|
||||
/// @param A The starting point of the line segment.
|
||||
/// @param B The end point of the line segment.
|
||||
/// @param thickness The width at which to render the line.
|
||||
void DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness = 1);
|
||||
void DrawLine(const Color4& color, float x1, float y1, float x2, float y2, float thickness = 1);
|
||||
|
||||
/// Plots several line segments defined by a series of points to be connected together.
|
||||
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
|
||||
/// @param points pointer to the first point in the list.
|
||||
/// @param point_count the number of points to draw.
|
||||
/// @param thickness The width at which to render the line.
|
||||
void DrawLines(const Color4& color, const Vector2* points, const size_t& point_count, float thickness = 1);
|
||||
|
||||
/// Plots a line segment using a series of points separated by a given distance.
|
||||
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
|
||||
/// @param A The starting point of the line segment.
|
||||
/// @param B The end point of the line segment.
|
||||
/// @param spacing The distance between each point (px)
|
||||
/// @param thickness The width at which to render the line.
|
||||
/// @note With diagonal lines, the distance between points can differ by one px.
|
||||
void DrawDottedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing = 1.f, float thickness = 1.f);
|
||||
void DrawDottedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing = 1.f, float thickness = 1.f);
|
||||
|
||||
/// Plots a line segment using a series of points separated by a given distance.
|
||||
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
|
||||
/// @param A The starting point of the line segment.
|
||||
/// @param B The end point of the line segment.
|
||||
/// @param spacing The distance between each point (px)
|
||||
/// @param dash_length The length of each dash making up the line.
|
||||
/// @param thickness The width at which to render the line.
|
||||
/// @note With diagonal lines, the distance between dashes can differ by one px.
|
||||
void DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing = 4.f, float dash_length = 6.f, float thickness = 1.f);
|
||||
void DrawDashedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing = 4.f, float dash_length = 6.f, float thickness = 1.f);
|
||||
|
||||
/// Draws a line with a color gradient that transitions across it.
|
||||
/// @param color_a A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param color_b A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param A The starting point of the line segment.
|
||||
/// @param B The end point of the line segment.
|
||||
/// @param thickness The width at which to render the line.
|
||||
void DrawGradientLine(const Color4& color_a, const Color4& color_b, const Vector2& A, const Vector2& B, float thickness = 1);
|
||||
void DrawGradientLine(const Color4& color_a, const Color4& color_b, float x1, float y1, float x2, float y2, float thickness = 1);
|
||||
|
||||
/// Draws an outline of a rectangle on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
/// @param thickness The width at which to render the lines.
|
||||
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||
|
||||
/// Draws an outline of a rectangle with rounded corners onto the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
/// @param radius The corner-rounding radius (in radians).
|
||||
/// @param thickness The width at which to render the lines.
|
||||
void OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, float thickness = 1);
|
||||
|
||||
/// Draws an outline of a rectangle with chamfered corners onto the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
/// @param radius The corner-rounding radius (in radians).
|
||||
/// @param thickness The width at which to render the lines.
|
||||
void OutlineChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, float thickness = 1);
|
||||
|
||||
/// Draws a filled rectangle on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
/// @see FillRoundedRect, FillGradientRect, FillChamferRect.
|
||||
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
|
||||
|
||||
/// Draws a filled rectangle where the color transitions across it.
|
||||
/// @param color1 A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param color2 A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param gradient See enum Direction
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
void FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size);
|
||||
|
||||
/// Draws a filled rectangle with rounded corners on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
/// @param radius The corner-rounding radius (in radians).
|
||||
/// @param subdivisions The amount of sub-divisions (and calculations) to be performed per-arc rounding corner.
|
||||
void FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
|
||||
|
||||
/// Draws a filled rectangle with chamfered (beveled) corners on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
/// @param radius The corner-rounding radius (in radians).
|
||||
void FillChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5);
|
||||
|
||||
/// Draws a render-target (runtime-modifiable texture) to the screen.
|
||||
/// @param render_target A RenderTarget instance to be displayed.
|
||||
/// @param position The position at which to render this object from it's center-point, defined by the origin parameter.
|
||||
/// @param rad_rotation The amount of radians to rotate this render-target about it's center-point.
|
||||
/// @param origin The center-point in the image to use for rendering, rotation, and scaling. Top-left is {0,0} and bottom right is {1, 1}.
|
||||
/// @param scale The amount (in both x, and y axis) to scale the image, with {1,1} being default scaling.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param inversion @see Direction
|
||||
void DrawRenderTarget(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawRenderTarget(const RenderTarget* render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
void DrawPartialRenderTarget(const RenderTarget&, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
|
||||
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawPartialRenderTarget(const RenderTarget*, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
|
||||
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
/// Draws a sprite (technically, actually a render target) to the screen.
|
||||
/// @note This similar overload exists because we expect someone will be an idiot and turn all of their sprites into RenderTargets. ~william
|
||||
/// @param render_target A RenderTarget instance to be displayed.
|
||||
/// @param position The position at which to render this object from it's center-point, defined by the origin parameter.
|
||||
/// @param rad_rotation The amount of radians to rotate this render-target about it's center-point.
|
||||
/// @param origin The center-point in the image to use for rendering, rotation, and scaling. Top-left is {0,0} and bottom right is {1, 1}.
|
||||
/// @param scale The amount (in both x, and y axis) to scale the image, with {1,1} being default scaling.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param inversion @see Direction
|
||||
/// @see DrawSprite
|
||||
void DrawSprite(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const RenderTarget* render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
|
||||
/// @param texture A texture instance to be displayed.
|
||||
/// @param position The point at which to draw the sprite (from the top-left down).
|
||||
/// @param origin The center point around which the image should have all transformations applied to it.
|
||||
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
|
||||
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param inversion @see Direction
|
||||
/// @see class Texture
|
||||
void DrawSprite(const Texture& texture, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
|
||||
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture* texture, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
|
||||
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture& texture, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
|
||||
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture* texture, float positionX, float positionY, float rad_rotation = 0,
|
||||
float originX = 0, float originY = 0,float scaleX = 1, float scaleY = 1,
|
||||
const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
|
||||
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
|
||||
/// @param texture A texture instance to be displayed.
|
||||
/// @param alpha_mask A texture which determines how much of the sprite you can see. Grayscale image exported as "8bpc RGBA".
|
||||
/// @param position The point at which to draw the sprite (from the top-left down).
|
||||
/// @param origin The center point around which the image should have all transformations applied to it.
|
||||
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
|
||||
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param inversion @see Direction
|
||||
/// @see class Texture
|
||||
void DrawSprite(const Texture& texture, const Texture& alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
|
||||
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture* texture, const Texture* alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
|
||||
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture& texture, const Texture& alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
|
||||
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture* texture, const Texture* alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
|
||||
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
/// Draws a piece of a sprite to the screen, similar to DrawSprite.
|
||||
/// @param texture A texture instance to be displayed.
|
||||
/// @param position The point at which to draw the sprite (from the top-left down).
|
||||
/// @param sub_texture_position The top left corner of the sub-texture to be drawn.
|
||||
/// @param sub_texture_size The size of the sub-texture in px.
|
||||
/// @param origin The center point around which the image should have all transformations applied to it.
|
||||
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param inversion @see Direction
|
||||
void DrawPartialSprite(const Texture& texture, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
|
||||
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawPartialSprite(const Texture* texture, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
|
||||
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawPartialSprite(const Texture& texture, float positionX, float positionY, float sub_texture_positionX, float sub_texture_positionY, unsigned int sub_texture_sizeX, unsigned int sub_texture_sizeY,
|
||||
float rad_rotation = 0, float originX = 0, float originY = 0, float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawPartialSprite(const Texture* texture, float positionX, float positionY, float sub_texture_positionX, float sub_texture_positionY, unsigned int sub_texture_sizeX, unsigned int sub_texture_sizeY,
|
||||
float rad_rotation = 0, float originX = 0, float originY = 0, float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
/// To save v-ram, Use if a sprite would be identical if mirrored horizontally, vertically, or both. For example, a circle.
|
||||
/// Assumes the input texture is the top left quadrant. You can use "SoftwareTexture" to invert it correctly so that's the case.
|
||||
/// @param texture A texture instance to be displayed.
|
||||
/// @param position The point at which to draw the sprite (from the top-left down).
|
||||
/// @param mirror_axis The axes to mirror across, Vertical and Horizontal or both only.
|
||||
/// @param rad_rotation The rotation of the final result.
|
||||
/// @param origin The point at which transformations are done about.
|
||||
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
void DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis = Direction::Horizontal | Direction::Vertical, float rad_rotation = 0, const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White);
|
||||
void DrawMirrorSprite(const Texture* texture, const Vector2& position, Direction mirror_axis = Direction::Horizontal | Direction::Vertical, float rad_rotation = 0, const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White);
|
||||
|
||||
/// Draws an outline of a circle on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param center The point in cartesian space at which to draw the circle. This will by-definition be the centroid of this circle.
|
||||
/// @param radius The radius of the circle to be drawn. AKA Half the diameter.
|
||||
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
|
||||
/// @param thickness The line-width of the circle to be rendered at.
|
||||
void OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
|
||||
|
||||
/// Draws a filled circle on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param center The point in cartesian space at which to draw the circle. This will by-definition be the centroid of this circle.
|
||||
/// @param radius The radius of the circle to be drawn. AKA Half the diameter.
|
||||
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
|
||||
void FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 8);
|
||||
|
||||
/// Draws an outline of a triangle on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param tri The triangle defined by its vertices (A, B, and C).
|
||||
/// @param thickness The line-width of the triangle to be rendered at.
|
||||
void OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness = 1);
|
||||
void OutlineTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC, float thickness = 1);
|
||||
|
||||
/// Draws a filled triangle on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param tri The triangle defined by its vertices (A, B, and C).
|
||||
void FillTriangle(const Color4& color, const Triangle2D& tri);
|
||||
void FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC);
|
||||
|
||||
/// Fills a triangle defined by the provided vertices with a gradient that transitions smoothly between the three specified colors at each corner.
|
||||
/// @param a_color The color at vertex A of the triangle.
|
||||
/// @param b_color The color at vertex B of the triangle.
|
||||
/// @param c_color The color at vertex C of the triangle.
|
||||
/// @param tri The triangle defined by its vertices (A, B, and C).
|
||||
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri);
|
||||
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Vector2& tri_a, const Vector2& tri_b, const Vector2& tri_c);
|
||||
|
||||
/// Draws a smooth, curved line segment between two control points, with the curve controlled by the two inner points.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param controlA The first control point, which can be considered the start of the line.
|
||||
/// @param pointA The first inner point, which controls the contour of the curve.
|
||||
/// @param pointB The second inner point, which controls the contour of the curve.
|
||||
/// @param controlB The second control point, which can be considered the end of the line.
|
||||
/// @param subdivisions The accuracy of the approximation of the curve, measured in iteration steps taken.
|
||||
/// @param thickness The line-width to draw the curve with.
|
||||
/// @see J3ML::Algorithm::Bezier
|
||||
void DrawCubicBezierCurve(const Color4& color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
|
||||
int subdivisions = 10, float thickness = 1);
|
||||
|
||||
/// Draws a series of points where the last point always connects to the first point.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param points The array of vector2's to draw as a polygon.
|
||||
/// @param point_count The number of points
|
||||
/// @param thickness The line-width of the polygon
|
||||
void OutlinePolygon(const Color4& color, const Vector2* points, int point_count, float thickness = 1);
|
||||
|
||||
/// Draws a text string on the screen with a given point-size and font.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param text The text to be rendered.
|
||||
/// @param x The position on the screen at which to draw the text, from the top-left.
|
||||
/// @param y The position on the screen at which to draw the text, from the top-left.
|
||||
/// @param scale The value (in both axes) to scale the text by. Defaults to {1,1}.
|
||||
/// @param size The point-size at which to render the font out. Re-using the same point-size allows efficient glyph caching.
|
||||
/// @param font The font to use for rendering. @see Font.
|
||||
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font = Fonts::Jupiteroid);
|
||||
|
||||
|
||||
/// Draws an Arc (section of a circle) to the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param center The point in cartesian space at which to draw the arc. This will by-definition be the centroid of this partial circle.
|
||||
/// @param radius The radius of the partial circle to be drawn. AKA Half the diameter.
|
||||
/// @param arc_begin The point (0 - 2pi) around a unit-circle of which to start the arc.
|
||||
/// @param arc_end The point (0 - 2pi) around a unit-circle of which to start the arc.
|
||||
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
|
||||
/// @param thickness The line-width to draw the arc with.
|
||||
void DrawArc(const Color4& color, const Vector2& center, float radius, float arc_begin, float arc_end,
|
||||
unsigned int subdivisions, float thickness);
|
||||
|
||||
|
||||
/// TODO Implement the following. These ones are going to be extremely annoying.
|
||||
void FillPolygon(const Color4& color, const std::vector<Vector2>& points);
|
||||
void OutlineEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, float thickness = 1, int subdivisions = 8);
|
||||
void FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions = 8);
|
||||
|
||||
void BatchFillRect(const Color4* colors, const Vector2* positions, const Vector2* sizes, const size_t& rect_count);
|
||||
|
||||
void BatchFillCircle(const Color4 *colors, const Vector2* positions, float* radii, unsigned int subdivisions, const size_t& circle_count);
|
||||
}
|
||||
|
||||
/// Drawing functions for 3D objects.
|
||||
namespace JGL::J3D {
|
||||
/// A light for this 3D render that should never be culled out. up-to 8.
|
||||
/// The more you put here, The less we will solve for if you're also using LightArray.
|
||||
/// @note More than 8 lights will cause an error to be printed.
|
||||
void RequiredLight(const LightBase* light);
|
||||
|
||||
/// When each 3D object is drawn, We'll do our best to determine which lights would effect it the most and use those ones.
|
||||
void OptionalLights(const LightBase** lights, const size_t& light_count);
|
||||
|
||||
/// Helper function to conveniently change the Field-Of-View.
|
||||
void ChangeFOV(float fov);
|
||||
|
||||
/// Helper function to change the far-plane, which is the cutoff distance for rendering.
|
||||
void ChangeFarPlane(float far_plane);
|
||||
|
||||
/// Open a 3-D rendering context with the underlying graphics system (In this case& by default OpenGL).
|
||||
/// It is recommended to always open a JGL 3D context to render your content, then close when completed.
|
||||
/// @param two_pass Whether or not we'll use two-pass rendering for occlusion.
|
||||
void Begin(bool two_pass = false);
|
||||
|
||||
/// Closes a 3-D rendering context with the underlying graphics system (In this case& by default OpenGL).
|
||||
/// @see Begin().
|
||||
void End();
|
||||
|
||||
void SetMatrix(const std::vector<GLfloat>& matrix, const Vector2& window_size);
|
||||
|
||||
/// Draws a line in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param A The start-point of the line segment.
|
||||
/// @param B The end-point of the line segment.
|
||||
/// @param thickness The line-width to draw the line segment with.
|
||||
void DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness = 1.f);
|
||||
|
||||
/// Draws a smooth, curved line segment between two control points, with the curve controlled by the two inner points.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param controlA The first control point, which can be considered the start of the line.
|
||||
/// @param pointA The first inner point, which controls the contour of the curve.
|
||||
/// @param pointB The second inner point, which controls the contour of the curve.
|
||||
/// @param controlB The second control point, which can be considered the end of the line.
|
||||
/// @param subdivisions The accuracy of the approximation of the curve, measured in iteration steps taken.
|
||||
/// @param thickness The line-width to draw the curve with.
|
||||
/// @see J3ML::Algorithm::Bezier
|
||||
void DrawCubicBezierCurve(const Color4& color, const Vector3& controlA, const Vector3& pointA, const Vector3& pointB, const Vector3& controlB,
|
||||
int subdivisions = 10, float thickness = 1);
|
||||
|
||||
/// Draws the outline of an Icosahedron in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Icosahedron.
|
||||
/// @param radius The size to draw the Icosahedron at.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
void WireframeIcosahedron(const Color4& color, const Vector3& position, float radius, float thickness = 1.f);
|
||||
|
||||
/// Draws a solid Icosahedron in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Icosahedron.
|
||||
/// @param radius The size to draw the Icosahedron at.
|
||||
void FillIcosahedron(const Color4& color, const Vector3& position, float radius);
|
||||
|
||||
/// Draws the outline of a Sphere in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Sphere.
|
||||
/// @param radius The size to draw the Sphere at.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
|
||||
void WireframeSphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int sectors = 10, unsigned int stacks = 10);
|
||||
|
||||
/// Draws the outline of a Sphere in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param sphere The mathematically-defined sphere object to be rendered.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
|
||||
void WireframeSphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int sectors = 10, unsigned int stacks = 10);
|
||||
|
||||
/// Draws outlines of multiple spheres in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param spheres The mathematically-defined sphere objects to be rendered.
|
||||
/// @param sphere_count The number of spheres.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
|
||||
/// @note The "Position" of the spheres is expected to be in world space.
|
||||
void BatchWireframeSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness = 1.f, unsigned int sectors = 10, unsigned int stacks = 10);
|
||||
|
||||
/// Draws outlines of a sphere in 3D space. Calculates a cross section and revolves it around the center.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Sphere.
|
||||
/// @param radius The size to draw the Sphere at.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param revolutions The number of times to revolve the cross section about the center.
|
||||
/// @param draw_stacks Whether or not to draw the stacks of the sphere.
|
||||
void WireframeRevoSphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int sectors = 10, unsigned int revolutions = 10, bool draw_stacks = false);
|
||||
|
||||
/// Draws the outline of a Sphere in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param sphere The mathematically-defined sphere object to be rendered.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param revolutions The number of times to revolve the cross section about the center.
|
||||
/// @param draw_stacks Whether or not to draw the stacks of the sphere.
|
||||
void WireframeRevoSphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int sectors = 10, unsigned int revolutions = 10, bool draw_stacks = false);
|
||||
|
||||
/// Draws outlines of multiple spheres in 3D space. Calculates a cross section and revolves it around the center.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param spheres The mathematically-defined sphere objects to be rendered.
|
||||
/// @param sphere_count The number of spheres.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param revolutions The number of times to revolve the cross section about the center.
|
||||
/// @param draw_stacks Whether or not to draw the stacks of the sphere.
|
||||
/// @note The "Position" of the spheres is expected to be in world space.
|
||||
/// @note This method of drawing a sphere is *probably* the fastest out of all of them.
|
||||
void BatchWireframeRevoSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness = 1.f, unsigned int sectors = 10, unsigned int revolutions = 10, bool draw_stacks = false);
|
||||
|
||||
/// Draws the outline of an Icosphere in 3D space.
|
||||
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Sphere.
|
||||
/// @param radius The size to draw the Sphere at.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
/// @param subdivisions The accuracy of the approximation of the Icosphere, measured in iteration steps taken.
|
||||
void WireframeIcosphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws the outline of an Icosphere in 3D space.
|
||||
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param sphere The mathematically-defined sphere object to be rendered.
|
||||
/// @param thickness The line-width to draw the Icosphere outline with.
|
||||
/// @param subdivisions The accuracy of the approximation of the Icosphere, measured in iteration steps taken.
|
||||
void WireframeIcosphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws the outline of a Cubesphere in 3D space.
|
||||
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Sphere.
|
||||
/// @param radius The size to draw the Sphere at.
|
||||
/// @param thickness The line-width to draw the Cubesphere outline with.
|
||||
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
|
||||
void WireframeCubesphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws the outline of a Cubesphere in 3D space.
|
||||
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param sphere The mathematically-defined sphere object to be rendered.
|
||||
/// @param thickness The line-width to draw the Cubesphere outline with.
|
||||
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
|
||||
void WireframeCubesphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws a solid Sphere in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Sphere.
|
||||
/// @param radius The size to draw the Sphere at.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
|
||||
void FillSphere(const Color4& color, const Vector3& position, float radius, unsigned int sectors = 10, unsigned int stacks = 10);
|
||||
|
||||
/// Draws a solid Sphere in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param sphere The mathematically-defined sphere object to be rendered.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
|
||||
void FillSphere(const Color4& color, const Sphere& sphere, unsigned int sectors = 10, unsigned int stacks = 10);
|
||||
|
||||
/// Draws multiple solid Spheres in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param spheres The mathematically-defined sphere objects to be rendered.
|
||||
/// @param sphere_count The number of spheres to be rendered.
|
||||
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
|
||||
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
|
||||
void BatchFillSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, unsigned int sectors = 10, unsigned int stacks = 10);
|
||||
|
||||
/// Draws a solid Icosphere in 3D space.
|
||||
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Sphere.
|
||||
/// @param radius The size to draw the Sphere at.
|
||||
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
|
||||
void FillIcosphere(const Color4& color, const Vector3& position, float radius, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws a solid Icosphere in 3D space.
|
||||
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param sphere The mathematically-defined sphere object to be rendered.
|
||||
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
|
||||
void FillIcosphere(const Color4& color, const Sphere& sphere, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws a solid Cubesphere in 3D space.
|
||||
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space at which to draw the Sphere.
|
||||
/// @param radius The size to draw the Sphere at.
|
||||
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
|
||||
void FillCubesphere(const Color4& color, const Vector3& position, float radius, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws a solid Cubesphere in 3D space.
|
||||
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param sphere The mathematically-defined sphere object to be rendered.
|
||||
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
|
||||
void FillCubesphere(const Color4& color, const Sphere& sphere, unsigned int subdivisions = 10);
|
||||
|
||||
/// Draws an outline of an axis-aligned bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The point in 3D space that is the center of the AABB.
|
||||
/// @param radii The radii along x,y,z axes to size the bounding box.
|
||||
/// @param thickness The line-width to draw the Icosphere outline with.
|
||||
void WireframeAABB(const Color4& color, const Vector3& pos, const Vector3& radii, float thickness = 1.f);
|
||||
|
||||
/// Draws an outline of an axis-aligned bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param aabb The AABB object to render.
|
||||
/// @param thickness The line-width to draw the Icosphere outline with.
|
||||
void WireframeAABB(const Color4& color, const AABB& aabb, float thickness = 1.f);
|
||||
|
||||
/// Draws outlines of multiple axis-aligned bounding-boxes in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param boxes The boxes to be drawn.
|
||||
/// @param box_count The number of boxes to be drawn.
|
||||
/// @param thickness The line-width to draw the Icosahedron outline with.
|
||||
void BatchWireframeAABB(const Color4& color, const AABB* boxes, const size_t& box_count, float thickness = 1.f);
|
||||
|
||||
/// Draws a solid axis-aligned bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The point in 3D space that is the center of the AABB.
|
||||
/// @param radii The radii along x,y,z axes to size the bounding box.
|
||||
void FillAABB(const Color4& color, const Vector3& pos, const Vector3& radii);
|
||||
|
||||
/// Draws a solid axis-aligned bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param aabb The AABB object to visualize.
|
||||
void FillAABB(const Color4& color, const AABB& aabb);
|
||||
|
||||
/// Draws solid axis-aligned bounding boxes in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param aabb The AABB objects to visualize.
|
||||
/// @param box_count The number of AABBs to draw.
|
||||
void BatchFillAABB(const Color4& color, const AABB* boxes, const size_t& box_count);
|
||||
|
||||
/// Draws an outline of an oriented bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The point in 3D space that is the center of the AABB.
|
||||
/// @param radii The radii along x,y,z axes to size the bounding box.
|
||||
/// @param orientation The rotation in 3D space of the OBB.
|
||||
/// @param thickness The line-width to draw the OBB outline with.
|
||||
void WireframeOBB(const Color4& color, const Vector3& position, const Vector3& radii, const Matrix3x3& orientation, float thickness = 1.f);
|
||||
|
||||
/// Draws an outline of an oriented bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param obb The OBB object to visualize.
|
||||
/// @param thickness The line-width to draw the OBB outline with.
|
||||
void WireframeOBB(const Color4& color, const OBB& obb, float thickness = 1.f);
|
||||
|
||||
void BatchWireframeOBB(const Color4& color, const OBB* boxes, const size_t& box_count, float thickness = 1.f);
|
||||
|
||||
/// Draws a solid oriented bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param position The center-position of the oriented bounding box.
|
||||
/// @param radii The radii along x,y,z axes to size the bounding box.
|
||||
/// @param orientation The rotation in 3D space of the OBB.
|
||||
void FillOBB(const Color4& color, const Vector3& position, const Vector3& radii, const EulerAngleXYZ& orientation);
|
||||
|
||||
/// Draws a solid oriented bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param obb The oriented-bounding-box object to visualize.
|
||||
void FillOBB(const Color4& color, const OBB& obb);
|
||||
|
||||
void WireframeCylinder();
|
||||
void FillCylinder();
|
||||
void WireframePrism();
|
||||
void FillPrism();
|
||||
void WireframePipe();
|
||||
void FillPipe();
|
||||
void WireframeCone();
|
||||
void FillCone();
|
||||
void WireframeTorus();
|
||||
void FillTorus();
|
||||
|
||||
void FillCapsule(const Color3& color, const Capsule& capsule);
|
||||
void WireframeCapsule(const Color3& color, const Capsule& cap, float thickness = 1.f);
|
||||
void FillTriangleMesh(const Color3& color, const TriangleMesh& mesh);
|
||||
void WireframeTriangleMesh(const Color3& color, const TriangleMesh& mesh, float thickness = 1.f);
|
||||
|
||||
/// Draws a string of text in 3D space, with an arbitrary rotation.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param text The content to display on the screen.
|
||||
/// @param pos The position in 3D space to display the text.
|
||||
/// @param scale The scaling factor to render the text with, 1 being default. TODO: Vector2 scaling?
|
||||
/// @param size The pixel size to rasterize the font with.
|
||||
/// @param font The font object to use when drawing.
|
||||
/// @param angle The orientation in 3D space.
|
||||
/// @param draw_back_face
|
||||
void DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font = Fonts::Jupiteroid, const EulerAngleXYZ& angle = {0, 0, 0}, bool draw_back_face = false);
|
||||
|
||||
void DrawVertexArray(const Color4& color, const VertexArray& vertex_array, const Vector3& position);
|
||||
/// Draws a string of text in 3D space that is always facing the exact direction of the camera projection.
|
||||
void DrawBillboardString();
|
||||
|
||||
/// Draws a texture sprite in 3D space that is always facing the exact direction of the camera projection.
|
||||
void DrawBillboardSprite();
|
||||
|
||||
void DrawSprite();
|
||||
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
|
||||
void DrawMatrixGizmo (const Matrix4x4&);
|
||||
void DrawAxisAngleGizmo (const AxisAngle&, const Vector3&);
|
||||
void DrawQuaternionGizmo (const Quaternion&, const Vector3&);
|
||||
}
|
12
include/JGL/logger/logger.h
Normal file
12
include/JGL/logger/logger.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <jlog/Logger.hpp>
|
||||
|
||||
namespace JGL::Logger {
|
||||
using namespace jlog;
|
||||
|
||||
extern GenericLogger Fatal;
|
||||
extern GenericLogger Debug;
|
||||
extern GenericLogger Error;
|
||||
|
||||
}
|
90
include/JGL/types/Enums.h
Normal file
90
include/JGL/types/Enums.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
namespace JGL {
|
||||
enum class Direction : u8 {
|
||||
None = 0,
|
||||
Vertical = 1,
|
||||
Horizontal = 2,
|
||||
Diagonal_NWSE = 3, // North West -> South East.
|
||||
Diagonal_SWNE = 4 // South West -> North East.
|
||||
};
|
||||
|
||||
inline Direction operator|(Direction a, Direction b) {
|
||||
return static_cast<Direction>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
|
||||
inline bool operator&(Direction a, Direction b) {
|
||||
return (u8)a & (u8)b;
|
||||
}
|
||||
|
||||
static std::string to_string(const JGL::Direction& direction) {
|
||||
switch (direction) {
|
||||
case JGL::Direction::None:
|
||||
return "None";
|
||||
case JGL::Direction::Vertical:
|
||||
return "Vertical";
|
||||
case JGL::Direction::Horizontal:
|
||||
return "Horizontal";
|
||||
case JGL::Direction::Diagonal_NWSE:
|
||||
return "Diagonal_NWSE";
|
||||
case JGL::Direction::Diagonal_SWNE:
|
||||
return "Diagonal_SWNE";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
enum class MSAA_SAMPLE_RATE : u8 {
|
||||
MSAA_NONE = 0,
|
||||
MSAA_2X = 1,
|
||||
MSAA_4X = 2,
|
||||
MSAA_8X = 3
|
||||
};
|
||||
|
||||
enum class FilteringMode : u8 {
|
||||
NEAREST = 0, // Fastest for 2D, Sometimes causes graphical issues.
|
||||
BILINEAR = 1, // Fast and pretty, The best for 2D.
|
||||
|
||||
MIPMAP_NEAREST = 2, // Nearest with mipmaps. The fastest for 3D, Sometimes causes graphical issues. Uses more vram.
|
||||
MIPMAP_BILINEAR = 3, // Bilinear with mipmaps, Fast and pretty. Uses more vram.
|
||||
MIPMAP_TRILINEAR = 4 // The prettiest. Still decent speed. Uses more vram.
|
||||
};
|
||||
|
||||
enum class WrappingMode : u8 {
|
||||
REPEAT = 0,
|
||||
MIRRORED_REPEAT = 1,
|
||||
CLAMP_TO_EDGE = 2,
|
||||
CLAMP_TO_BORDER = 3 // Effectively the same as clamp_to_edge
|
||||
};
|
||||
|
||||
enum class ColorFormat : bool { RGB = false, RGBA = true };
|
||||
|
||||
static std::string to_string(const JGL::MSAA_SAMPLE_RATE& sample_rate) {
|
||||
switch (sample_rate) {
|
||||
case MSAA_SAMPLE_RATE::MSAA_NONE:
|
||||
return "No MSAA";
|
||||
case MSAA_SAMPLE_RATE::MSAA_2X:
|
||||
return "MSAA 2x";
|
||||
case MSAA_SAMPLE_RATE::MSAA_4X:
|
||||
return "MSAA 4x";
|
||||
case MSAA_SAMPLE_RATE::MSAA_8X:
|
||||
return "MSAA 8x";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
static int to_int(const JGL::MSAA_SAMPLE_RATE& sample_rate) {
|
||||
switch (sample_rate) {
|
||||
case MSAA_SAMPLE_RATE::MSAA_NONE:
|
||||
return 0;
|
||||
case MSAA_SAMPLE_RATE::MSAA_2X:
|
||||
return 2;
|
||||
case MSAA_SAMPLE_RATE::MSAA_4X:
|
||||
return 4;
|
||||
case MSAA_SAMPLE_RATE::MSAA_8X:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
39
include/JGL/types/Font.h
Normal file
39
include/JGL/types/Font.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
/// Defines external C references to FreeType Data Structures
|
||||
extern "C" typedef struct FT_FaceRec_* FT_Face;
|
||||
extern "C" typedef struct FT_LibraryRec_* FT_Library;
|
||||
|
||||
namespace JGL
|
||||
{
|
||||
bool InitTextEngine();
|
||||
|
||||
/// A Font class implementation.
|
||||
/// Wraps the font's FreeType asset handle and provides helper functions.
|
||||
class Font {
|
||||
public:
|
||||
/// Default constructor does not initialize any members
|
||||
Font() = default;
|
||||
explicit Font(const std::filesystem::path& path);
|
||||
Font(const unsigned char* data, const size_t& size);
|
||||
/// Destructor handles freeing of the underlying asset handle.
|
||||
~Font();
|
||||
static Font LoadTTF(const std::filesystem::path& filepath);
|
||||
static std::vector<Font> GetLoadedFonts();
|
||||
/// Returns the bounding-box the given string would occupy at the given point-size, assuming normal (1) scaling.
|
||||
/// @param text The string to measure.
|
||||
/// @param ptSize The font size at which to measure.
|
||||
/// @return The size-in-pixels that would contain the entire text.
|
||||
Vector2 MeasureString(const std::string& text, unsigned int ptSize);
|
||||
public:
|
||||
int index = 0;
|
||||
FT_Face face = nullptr;
|
||||
};
|
||||
}
|
70
include/JGL/types/FontCache.h
Normal file
70
include/JGL/types/FontCache.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
/// TODO: FontCache mechanism works amazing, but makes no fucking sense
|
||||
/// Let's document and reorganize it to be a little nicer on the mental :)
|
||||
|
||||
namespace JGL {
|
||||
class CachedGlyph;
|
||||
class CachedFont;
|
||||
class FontCache;
|
||||
}
|
||||
|
||||
/// Represents a single font-character "glyph", that has been cached in-memory for fast retrieval.
|
||||
class JGL::CachedGlyph {
|
||||
private:
|
||||
char character;
|
||||
std::array<GLfloat, 12> texcoords;
|
||||
public:
|
||||
int x2offset = 0, y2offset = 0, w = 0, h = 0;
|
||||
float advanceX = 0, advanceY = 0;
|
||||
|
||||
//CachedGlyph(GLuint texture_id, char c);
|
||||
CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2o, float y2o, float w, float h, float advX, float advY);
|
||||
char getCharacter() const;
|
||||
[[nodiscard]] std::array<GLfloat, 12> getTexCoords() const;
|
||||
};
|
||||
|
||||
/// Represents a Font object as it exists in the font-cache.
|
||||
class JGL::CachedFont {
|
||||
private:
|
||||
std::unordered_map<char, CachedGlyph*> glyphs;
|
||||
GLuint texture = 0;
|
||||
GLsizei texture_width = 0, texture_height = 0;
|
||||
unsigned int font_size = 0;
|
||||
unsigned int font_index = 0;
|
||||
void Erase();
|
||||
public:
|
||||
void appendGlyph(CachedGlyph* glyph);
|
||||
unsigned int getFontSize() const;
|
||||
unsigned int getFontIndex() const;
|
||||
CachedGlyph* getGlyph(char c);
|
||||
std::unordered_map<char, CachedGlyph*> getGlyphs();
|
||||
const GLuint* getTextureHandle();
|
||||
[[nodiscard]] GLsizei getTextureWidth() const;
|
||||
[[nodiscard]] GLsizei getTextureHeight() const;
|
||||
public:
|
||||
CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
|
||||
~CachedFont();
|
||||
};
|
||||
|
||||
class JGL::FontCache {
|
||||
private:
|
||||
std::vector<CachedFont*> cachedFonts{};
|
||||
public:
|
||||
std::vector<CachedFont*> getFonts();
|
||||
CachedFont* getFont(unsigned int font_size, unsigned int font_index);
|
||||
void appendFont(CachedFont* font);
|
||||
void newFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
|
||||
void eraseFont(CachedFont* font);
|
||||
void purgeCache();
|
||||
};
|
||||
|
||||
namespace JGL {
|
||||
inline FontCache fontCache;
|
||||
}
|
70
include/JGL/types/Light.h
Normal file
70
include/JGL/types/Light.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/DirectionVector.hpp>
|
||||
#include <J3ML/Geometry/Frustum.hpp>
|
||||
#include <Color4.hpp>
|
||||
|
||||
namespace JGL {
|
||||
class LightBase;
|
||||
class PointLight;
|
||||
class SpotLight;
|
||||
}
|
||||
|
||||
// TODO this can be consolidated.
|
||||
class JGL::LightBase {
|
||||
protected:
|
||||
/* The 4th number represents whether the light is a positional light.
|
||||
* In OpenGL, You can have positional lights, Like Point Lights or Spot Lights,
|
||||
* Or global lights, Like the sun. */
|
||||
Vector4 position = {0, 0, 0, 1};
|
||||
Color4 ambient = {0, 0, 0, 0};
|
||||
Color4 diffuse = {0, 0, 0, 0};
|
||||
Color4 specular = {0, 0, 0, 0};
|
||||
|
||||
float constant_attenuation = 1;
|
||||
float linear_attenuation = 0;
|
||||
float quadratic_attenuation = 0;
|
||||
public:
|
||||
[[nodiscard]] Vector4 GetPosition() const;
|
||||
[[nodiscard]] Color4 GetAmbient() const;
|
||||
[[nodiscard]] Color4 GetDiffuse() const;
|
||||
[[nodiscard]] Color4 GetSpecular() const;
|
||||
|
||||
[[nodiscard]] float GetConstantAttenuation() const;
|
||||
[[nodiscard]] float GetLinearAttenuation() const;
|
||||
[[nodiscard]] float GetQuadraticAttenuation() const;
|
||||
public:
|
||||
/// Runs a calculation to determine the lights influence on a given point in 3D space.
|
||||
/// @note 0 would be no impact, 1 would be the light is at the same position.
|
||||
[[nodiscard]] virtual float GetAttenuationAtPosition(const Vector3& pos) const { return 0; }
|
||||
public:
|
||||
virtual ~LightBase() = default;
|
||||
};
|
||||
|
||||
/// Omni-directional lights.
|
||||
class JGL::PointLight : public LightBase {
|
||||
public:
|
||||
[[nodiscard]] float GetAttenuationAtPosition(const Vector3& pos) const final;
|
||||
public:
|
||||
PointLight(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation = 1, float linear_attenuation = 0, float quadratic_attenuation = 0);
|
||||
};
|
||||
|
||||
/// Lights which only effect things in a given cone.
|
||||
// TODO get attenuation at position for this.
|
||||
class JGL::SpotLight : public LightBase {
|
||||
protected:
|
||||
Matrix3x3 orientation;
|
||||
float exponent;
|
||||
float cut;
|
||||
public:
|
||||
/// Create a spotlight in 3D space.
|
||||
/// @param position The position of the light in 3D space.
|
||||
/// @param ro_mat Orientation of the light in 3D space.
|
||||
/// @param cone_size_degrees The size of the cone.
|
||||
/// @param exponent How focused the beam should be, Higher is more focused, Lower is less.
|
||||
/// @param ambient How much this light should effect the ambient light of the scene.
|
||||
/// @param diffuse
|
||||
/// @param specular How much this light should effect specular highlights of objects being influenced by it.
|
||||
SpotLight(const Vector3& position, const Matrix3x3& ro_mat, float cone_size_degrees, float exponent, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation = 1, float linear_attenuation = 0, float quadratic_attenuation = 0);
|
||||
};
|
19
include/JGL/types/Material.h
Normal file
19
include/JGL/types/Material.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/// A simple wrapper for OpenGL materials. Lets you set things such as the "shininess" of your elements.
|
||||
|
||||
#include <Color4.hpp>
|
||||
#include <glad/glad.h>
|
||||
namespace JGL {
|
||||
class Material;
|
||||
}
|
||||
class JGL::Material {
|
||||
public:
|
||||
Color4 ambient_ref;
|
||||
Color4 diffuse_ref;
|
||||
Color4 specular_ref;
|
||||
Color4 emission;
|
||||
float shininess;
|
||||
public:
|
||||
Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine);
|
||||
/// @param material Material to use.
|
||||
static void SetActiveMaterial(const Material& material);
|
||||
};
|
126
include/JGL/types/RenderTarget.h
Normal file
126
include/JGL/types/RenderTarget.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
#include <Color4.hpp>
|
||||
#include <Colors.hpp>
|
||||
#include <JGL/types/Enums.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
|
||||
namespace JGL {
|
||||
class RenderTarget;
|
||||
class Texture;
|
||||
}
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2i;
|
||||
class JGL::RenderTarget {
|
||||
private:
|
||||
Color4 clear_color{0,0,0,0};
|
||||
Vector2i size{0, 0};
|
||||
bool using_depth = false;
|
||||
bool texture_created_by_us = false;
|
||||
GLuint framebuffer_object = 0;
|
||||
GLuint depth_buffer = 0;
|
||||
const Texture* texture = nullptr;
|
||||
MSAA_SAMPLE_RATE msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
GLuint msaa_framebuffer_object = 0;
|
||||
GLuint msaa_depth_buffer = 0;
|
||||
GLuint msaa_render_buffer = 0;
|
||||
void Erase();
|
||||
public:
|
||||
/// @returns The Render Target currently in use by OpenGL.
|
||||
/// @note Zero is the screen.
|
||||
static GLuint GetActiveGLFramebufferHandle();
|
||||
|
||||
/// Changes the Render Target that OpenGL will draw on.
|
||||
/// @param render_target The new Render Target for OpenGL to draw on.
|
||||
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
|
||||
|
||||
/// Changes the size of the renderable area of this Render Target.
|
||||
/// @param new_size new width & height in pixels.
|
||||
/// @note The data stored in this Render Target will be lost.
|
||||
void Resize(const Vector2i& new_size);
|
||||
|
||||
/// Sets the MSAA mode for this Render Target.
|
||||
/// @returns false if the mode isn't available, true for success.
|
||||
[[nodiscard]] bool SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
|
||||
|
||||
/// If you're using MSAA and not using J2D || J3D Begin & End you must do this.
|
||||
void MSAABlit() const;
|
||||
|
||||
void RegenerateMipMaps();
|
||||
/// Copy one Render Target onto another. Will break if they're not the same size.
|
||||
// TODO support different sizes. If the destination is too small fix it for them but log a warning.
|
||||
static void Blit(const RenderTarget& source, RenderTarget* destination, const Vector2i& position = {0, 0});
|
||||
|
||||
/// Plots a single pixel onto a Render Target.
|
||||
/// @param color The color to render.
|
||||
/// @param position The position in the destination to draw the pixel.
|
||||
/// @param destination The destination RenderTarget.
|
||||
static void Blit(const Color4& color, const Vector2i& position, RenderTarget* destination);
|
||||
|
||||
/// Blit an input texture onto this render target at the given position.
|
||||
/// @param source Source texture.
|
||||
/// @param destination Render Target to draw on.
|
||||
/// @param position Where in the destination to draw.
|
||||
static void Blit(const Texture* source, RenderTarget* destination, const Vector2i& position = {0, 0});
|
||||
|
||||
/// @returns Whether or not this Render Target created it's Texture.
|
||||
[[nodiscard]] bool OwnsTexture() const;
|
||||
public:
|
||||
/// @returns the size of the renderable area.
|
||||
[[nodiscard]] Vector2i GetDimensions() const;
|
||||
|
||||
/// @returns The currently selected MSAA Sample Rate.
|
||||
[[nodiscard]] MSAA_SAMPLE_RATE GetMSAASampleRate() const;
|
||||
|
||||
/// @returns Whether or not this Render Target is using MSAA.
|
||||
[[nodiscard]] bool MSAAEnabled() const;
|
||||
|
||||
/// @returns The JGL texture this Render Target draws on.
|
||||
[[nodiscard]] const Texture* GetTexture() const;
|
||||
|
||||
/// @returns The OpenGL handle for the texture this Render Target draws on.
|
||||
[[nodiscard]] GLuint GetTextureHandle() const;
|
||||
|
||||
/// @returns The OpenGL handle for this Render Target.
|
||||
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
|
||||
|
||||
/// @returns The handle to the OpenGL buffer containing depth information
|
||||
/// @note Only valid if this Render Target is being used for 3D.
|
||||
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
|
||||
|
||||
/// @returns The color that should be used to clear this Render Target.
|
||||
[[nodiscard]] Color4 GetClearColor() const;
|
||||
|
||||
/// @returns The color information for this Render Target.
|
||||
/// @note The CPU thread this is called from & the GPU cannot do anything while this takes place. It's very slow.
|
||||
[[nodiscard]] std::vector<GLfloat> GetPixels() const;
|
||||
|
||||
[[nodiscard]] static Vector2i MaximumSize();
|
||||
public:
|
||||
/// Create a Render Target from a Render Target that already exists.
|
||||
/** @note Render Targets that are copies of another will copy the Texture.
|
||||
* This is so that deleting the copy doesn't delete the Texture of the original.
|
||||
*/
|
||||
RenderTarget(const RenderTarget& rhs);
|
||||
|
||||
/// Create a Render Target for a texture that already exists.
|
||||
/// @param texture The Texture that using this Render Target would draw on.
|
||||
/// @param clear_color The color to be used if you want to clear the Render Target.
|
||||
/// @note For Render Targets created this way, The destructor will not delete the texture.
|
||||
explicit RenderTarget(const Texture* texture, const Color4& clear_color = Colors::Transparent);
|
||||
|
||||
/// Create a Render Target with a new texture.
|
||||
/// @param size The width & height the Render Target should have.
|
||||
/// @param clear_color The color to be used if you want to clear the Render Target.
|
||||
/// @param use_depth Whether or not this Render Target will have depth information.
|
||||
/// @param sample_rate The MSAA sample rate this Render Target will use.
|
||||
explicit RenderTarget(const Vector2i& size, const Color4& clear_color = Colors::Transparent, bool use_depth = false,
|
||||
MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE, FilteringMode filteirng_mode = FilteringMode::NEAREST);
|
||||
|
||||
/// Deletes this Render Target.
|
||||
/** @note If this Render Target was made with a Texture that already existed
|
||||
* the Texture will not be deleted. */
|
||||
~RenderTarget();
|
||||
|
||||
};
|
18
include/JGL/types/ShadowMap.h
Normal file
18
include/JGL/types/ShadowMap.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/types/Light.h>
|
||||
|
||||
namespace JGL {
|
||||
class ShadowMap;
|
||||
}
|
||||
|
||||
/// You render your scene with all the static objects from the perspective of each static light to a ShadowMap.
|
||||
/// Then, for shadow casters which move. Or lights that move. You only redraw that object from the perspective of each light.
|
||||
/// Some of the approaches I saw for this were disgusting - Redacted.
|
||||
|
||||
class JGL::ShadowMap {
|
||||
private:
|
||||
RenderTarget shadow_map;
|
||||
private:
|
||||
void Create(const LightBase* Light);
|
||||
};
|
124
include/JGL/types/Skeleton.h
Normal file
124
include/JGL/types/Skeleton.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace JGL {
|
||||
class Bone;
|
||||
class SkeletalVertexAttribute;
|
||||
class Skeleton;
|
||||
class KeyFrame;
|
||||
class Animation;
|
||||
class AnimationState;
|
||||
}
|
||||
|
||||
class JGL::SkeletalVertexAttribute {
|
||||
private:
|
||||
std::array<int, 4> bone_ids = { 0, 0, 0, 0 };
|
||||
std::array<float, 4> bone_weights = { 0, 0, 0, 0 };
|
||||
public:
|
||||
[[nodiscard]] std::array<int, 4> GetAffectingBoneIDs() const;
|
||||
[[nodiscard]] std::array<float, 4> GetAffectingBoneWeights() const;
|
||||
public:
|
||||
SkeletalVertexAttribute() = default;
|
||||
/// These cannpt be longer than 4.
|
||||
SkeletalVertexAttribute(const std::vector<int>& ids, const std::vector<float>& weights);
|
||||
};
|
||||
|
||||
class JGL::Bone {
|
||||
private:
|
||||
int id = 0;
|
||||
// Not every gltf2 model includes names, but I'll still include it.
|
||||
std::string name;
|
||||
Matrix4x4 inverse_bind_matrix = Matrix4x4::Identity;
|
||||
Matrix4x4 offset_matrix = Matrix4x4::Identity;
|
||||
Matrix4x4 final_transform = Matrix4x4::Identity;
|
||||
int parent_id = -1;
|
||||
std::vector<int> children{};
|
||||
public:
|
||||
[[nodiscard]] int GetID() const;
|
||||
[[nodiscard]] std::string GetName() const;
|
||||
[[nodiscard]] Matrix4x4 GetInverseBindMatrix() const;
|
||||
[[nodiscard]] Matrix4x4 GetOffsetMatrix() const;
|
||||
[[nodiscard]] Matrix4x4 GetFinalTransform() const;
|
||||
[[nodiscard]] bool IsRootBone() const;
|
||||
public:
|
||||
[[nodiscard]] int GetParentID() const;
|
||||
[[nodiscard]] std::vector<int> GetChildren() const;
|
||||
public:
|
||||
void SetParent(int parent_id);
|
||||
void AppendChild(int new_child);
|
||||
void SetID(int numeric_id);
|
||||
void SetName(const std::string& string_id);
|
||||
void SetInverseBindMatrix(const Matrix4x4& inverse_bind);
|
||||
void SetOffsetMatrix(const Matrix4x4& offset);
|
||||
void SetFinalTransformMatrix(const Matrix4x4& final);
|
||||
public:
|
||||
~Bone() = default;
|
||||
Bone() = default;
|
||||
explicit Bone(int numeric_id, const std::string& string_id = "", int parent_id = -1, const std::vector<int>& children_ids = {},
|
||||
const Matrix4x4& inverse_bind = Matrix4x4::Identity, const Matrix4x4& offset = Matrix4x4::Identity, const Matrix4x4& final = Matrix4x4::Identity);
|
||||
};
|
||||
|
||||
class JGL::Skeleton {
|
||||
private:
|
||||
Bone root;
|
||||
std::vector<Bone> bones;
|
||||
public:
|
||||
[[nodiscard]] Bone* GetRootBone();
|
||||
[[nodiscard]] Bone* FindBone(int id);
|
||||
[[nodiscard]] Bone* FindBone(const std::string& string_id);
|
||||
public:
|
||||
void AppendBone(const Bone& bone);
|
||||
public:
|
||||
explicit Skeleton(const Bone& root_bone, const std::vector<Bone>& children = {});
|
||||
~Skeleton() = default;
|
||||
Skeleton() = default;
|
||||
};
|
||||
|
||||
class JGL::KeyFrame {
|
||||
private:
|
||||
float time_stamp = 0;
|
||||
Skeleton pose;
|
||||
public:
|
||||
[[nodiscard]] float GetTimeStamp() const;
|
||||
[[nodiscard]] Skeleton GetSkeleton() const;
|
||||
public:
|
||||
KeyFrame(const Skeleton& pose, float time_stamp);
|
||||
};
|
||||
|
||||
class JGL::Animation {
|
||||
private:
|
||||
int id = -1;
|
||||
// Not all animations have names.
|
||||
std::string name;
|
||||
float length = 0;
|
||||
std::vector<KeyFrame> key_frames;
|
||||
std::vector<SkeletalVertexAttribute> vertex_attributes{};
|
||||
public:
|
||||
[[nodiscard]] float GetDuratrion() const;
|
||||
[[nodiscard]] std::vector<KeyFrame> GetKeyFrames() const;
|
||||
[[nodiscard]] int GetID() const;
|
||||
[[nodiscard]] std::string GetName() const;
|
||||
[[nodiscard]] std::vector<SkeletalVertexAttribute> GetSkeletalVertexAttributes() const;
|
||||
public:
|
||||
void AppendKeyFrame(const KeyFrame& new_key);
|
||||
void SetDuration(float duration);
|
||||
void SetID(int identifier);
|
||||
void SetName(const std::string& name_id);
|
||||
public:
|
||||
~Animation() = default;
|
||||
Animation(int id, float duration, const std::vector<KeyFrame>& key_frames, const std::vector<SkeletalVertexAttribute>& skeletal_vertex_attributes,
|
||||
const std::string& name = "");
|
||||
};
|
||||
|
||||
class JGL::AnimationState {
|
||||
private:
|
||||
int animation_id = -1;
|
||||
float animation_time = 0;
|
||||
public:
|
||||
|
||||
};
|
||||
|
62
include/JGL/types/Texture.h
Normal file
62
include/JGL/types/Texture.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include<vector>
|
||||
#include <filesystem>
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
#include <Color3.hpp>
|
||||
#include <Color4.hpp>
|
||||
#include <JGL/types/Enums.h>
|
||||
|
||||
namespace JGL {
|
||||
using J3ML::LinearAlgebra::Vector2i;
|
||||
class Texture;
|
||||
}
|
||||
|
||||
/// Represents texture data loaded on the GPU. Contains a handle that can be passed to OpenGL draw calls.
|
||||
class JGL::Texture {
|
||||
protected:
|
||||
unsigned int texture_handle = 0;
|
||||
bool invert_y = false;
|
||||
Vector2i size = {0, 0};
|
||||
ColorFormat format = ColorFormat::RGBA;
|
||||
FilteringMode filtering_mode;
|
||||
WrappingMode wrapping_mode;
|
||||
void load(const unsigned char* pixels);
|
||||
std::vector<unsigned char> png(const std::filesystem::path& file);
|
||||
std::vector<unsigned char> bmp(const std::filesystem::path& file);
|
||||
[[nodiscard]] bool SizeExceedsMaximum(const Vector2i& size);
|
||||
public:
|
||||
/// @returns A handle used to identify this texture.
|
||||
[[nodiscard]] unsigned int GetHandle() const;
|
||||
/// @returns The size of this texture.
|
||||
[[nodiscard]] Vector2i GetDimensions() const;
|
||||
/// @returns The filtering mode this texture is using.
|
||||
[[nodiscard]] FilteringMode GetFilteringMode() const;
|
||||
/// @returns The way this texture behaves when used on geometry of different sizes.
|
||||
[[nodiscard]] WrappingMode GetWrappingMode() const;
|
||||
/// @returns The orientation of this texture in v-ram.
|
||||
/// @note true is right-side-up because OpenGL defaults to upside-down.
|
||||
[[nodiscard]] bool Inverted() const;
|
||||
[[nodiscard]] ColorFormat GetFormat() const;
|
||||
/// @returns The raw pixels this texture is made up of.
|
||||
/// @note This will read-back from the GPU. Slow.
|
||||
[[nodiscard]] std::vector<Color4> GetPixelData() const;
|
||||
/// @returns The biggest size for a texture on this system.
|
||||
/// @note on modern systems this is *usually* ridiculous.
|
||||
[[nodiscard]] static Vector2i MaximumSize();
|
||||
public:
|
||||
/// Load a texture from a file,
|
||||
explicit Texture(const std::filesystem::path& file, FilteringMode filtering_mode = FilteringMode::BILINEAR, WrappingMode wrapping_mode = WrappingMode::CLAMP_TO_EDGE, bool invert_y = true);
|
||||
/// Load a texture from raw pixels.
|
||||
Texture(const Color4* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode);
|
||||
/// Load a texture from raw pixels.
|
||||
Texture(const Color3* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode);
|
||||
/// Construct a Texture Atlas from many different textures.
|
||||
/// @note THIS IS UNFINISHED.
|
||||
Texture(const Texture* textures, const size_t& texture_count);
|
||||
/// Initialize a texture filled with trash data.
|
||||
/// @see RenderTarget
|
||||
explicit Texture(const Vector2i& size, FilteringMode filtering_mode = FilteringMode::NEAREST);
|
||||
|
||||
Texture(const Texture& rhs);
|
||||
~Texture();
|
||||
};
|
68
include/JGL/types/VRamList.h
Normal file
68
include/JGL/types/VRamList.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
|
||||
namespace JGL {
|
||||
class VRamList;
|
||||
}
|
||||
|
||||
/// A wrapped for "Vertex Buffer Object" In OpenGL, Store things in VRam.
|
||||
class JGL::VRamList {
|
||||
private:
|
||||
GLuint list_handle = 0;
|
||||
long num_elements = 0;
|
||||
bool element_array_buffer = false;
|
||||
/// "Spin Locking" fix for multi-threading.
|
||||
bool spin_lock = false;
|
||||
void load(const GLfloat* data, const long& size);
|
||||
void load(const GLuint* data, const long& size);
|
||||
void SetData(void* data, const long& count);
|
||||
void UpdateData(void* data, const long& offset, const long& count);
|
||||
void Erase();
|
||||
public:
|
||||
VRamList(const GLuint* data, const long& count);
|
||||
VRamList(const GLfloat* data, const long& count);
|
||||
VRamList(const Vector2* data, const long& count);
|
||||
VRamList(const Vector3* data, const long& count);
|
||||
VRamList(const Vector4* data, const long& count);
|
||||
|
||||
~VRamList();
|
||||
/** Copying around the VBO data to a new VBO like this is slow.
|
||||
* Pass to function by const reference or pointer always. */
|
||||
VRamList(const VRamList& rhs);
|
||||
VRamList() : list_handle(0), num_elements(0), element_array_buffer(false), spin_lock(false) {}
|
||||
public:
|
||||
[[nodiscard]] GLuint GetHandle() const;
|
||||
/// Returns the number of elements in the list.
|
||||
[[nodiscard]] long GetLength() const;
|
||||
/// Returns the size of the data in bytes.
|
||||
[[nodiscard]] size_t GetDataSize() const;
|
||||
/** Get VBO data back from the GPU. This is *bad* because the CPU is going to wait
|
||||
* for the transfer to finish. Has limited use other than testing. */
|
||||
[[nodiscard]] std::vector<GLfloat> GetDataF() const;
|
||||
[[nodiscard]] std::vector<GLuint> GetDataUI() const;
|
||||
[[nodiscard]] bool IsFloatArray() const;
|
||||
/** Replace the data of an existing VBO in it's entirety. Must be same type. */
|
||||
void SetData(const GLfloat* data, const long& count);
|
||||
void SetData(const Vector2* data, const long& count);
|
||||
void SetData(const Vector3* data, const long& count);
|
||||
void SetData(const Vector4* data, const long& count);
|
||||
|
||||
void SetData(const GLuint* data, const long& count);
|
||||
void SetData(const Vector2i* data, const long& count);
|
||||
|
||||
/** Update only a portion of the data in a VBO. Must be same type.
|
||||
* "offset" refers the number of Typename T into the buffer the data you want to change is.
|
||||
* For ex, offset 0 and length of 1 overwrites the first value. Offset 1 the second etc */
|
||||
void UpdateData(const GLfloat* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector2* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector3* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector4* data, const long& offset, const long& count);
|
||||
|
||||
void UpdateData(const GLuint* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector2i* data, const long& offset, const long& count);
|
||||
};
|
103
include/JGL/types/VertexArray.h
Normal file
103
include/JGL/types/VertexArray.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <JGL/types/VRamList.h>
|
||||
#include <JGL/types/Skeleton.h>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/Geometry/Sphere.hpp>
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <J3ML/Geometry/OBB.hpp>
|
||||
|
||||
namespace JGL {
|
||||
/// A point that is part of an object in 3D space.
|
||||
typedef Vector3 Vertex;
|
||||
/// A direction vector which describes which way a triangle is facing.
|
||||
typedef Vector3 Normal;
|
||||
/// 2D positions that describe how a texture is to be wrapped around a 3D object.
|
||||
typedef Vector2 TextureCoordinate;
|
||||
/// Container for storing 3D models in v-ram, system memory, or both.
|
||||
class VertexArray;
|
||||
}
|
||||
|
||||
class JGL::VertexArray {
|
||||
private:
|
||||
Sphere me_sphere;
|
||||
OBB me_obb;
|
||||
protected:
|
||||
virtual void CreateMESphere();
|
||||
virtual void CreateMEOBB();
|
||||
protected:
|
||||
std::vector<Animation> animations{};
|
||||
protected:
|
||||
VRamList* vertices;
|
||||
VRamList* indices;
|
||||
VRamList* normals;
|
||||
VRamList* texture_coordinates;
|
||||
protected:
|
||||
/** For models which are not animated, This is intended for a low quality version in
|
||||
* system memory for calculations to be done on the CPU. For models that are, the default pose of the model is here.
|
||||
*/
|
||||
std::vector<Vertex> local_vertices{};
|
||||
std::vector<unsigned int> local_indices{};
|
||||
std::vector<TextureCoordinate> local_texture_coordinates{};
|
||||
std::vector<Normal> local_normals{};
|
||||
public:
|
||||
/** Don't use these for anything other than drawing because the GPU is gonna spin during read-back */
|
||||
[[nodiscard]] const VRamList* GetVertices() const;
|
||||
[[nodiscard]] const VRamList* GetIndices() const;
|
||||
[[nodiscard]] const VRamList* GetNormals() const;
|
||||
[[nodiscard]] const VRamList* GetTextureCoordinates() const;
|
||||
|
||||
/** These are for cpu side calculations */
|
||||
[[nodiscard]] std::vector<Vertex> GetLocalVertices() const;
|
||||
[[nodiscard]] std::vector<unsigned int> GetLocalIndices() const;
|
||||
[[nodiscard]] std::vector<TextureCoordinate> GetLocalTextureCoordinates() const;
|
||||
[[nodiscard]] std::vector<Normal> GetLocalNormals() const;
|
||||
public:
|
||||
/// Returns true if the VertexArray does not have any animations.
|
||||
bool Static();
|
||||
public:
|
||||
/// Provides the minimally enclosing bounding sphere of the vertex array given information from the instance.
|
||||
/// @param scale The scale of the instance.
|
||||
/// @param translate_part The center of the sphere would be shifted in 3D space by this. Primarily for world space.
|
||||
[[nodiscard]] Sphere GetMESphere(const Vector3& scale = Vector3::One, const Vector3& translate_part = Vector3::Zero) const;
|
||||
/// Provides the minimally enclosing bounding sphere of the vertex array given information from the instance.
|
||||
/// @param instance_matrix A Matrix4x4 which contains scale, rotation, and translation.
|
||||
/// @param translate Whether or not to translate to world space by the translate part of the Matrix.
|
||||
[[nodiscard]] Sphere GetMESphere(const Matrix4x4& instance_matrix, bool translate = false) const;
|
||||
|
||||
/// Provides the minimally enclosing oriented bounding box of the vertex array given information from the instance.
|
||||
/// @param rotation_matrix A Matrix3x3 representing rotation in 3D space.
|
||||
/// @param scale The scale of the instance.
|
||||
/// @param translate_part The center of the box would be shifted in 3D space by this. Primarily for world space.
|
||||
[[nodiscard]] OBB GetMEOBB(const Matrix3x3& rotation_matrix, const Vector3& scale = Vector3::One, const Vector3& translate_part = Vector3::Zero) const;
|
||||
/// Provides the minimally enclosing oriented bounding box of the vertex array given information from the instance.
|
||||
/// @param instance_matrix A Matrix4x4 which contains scale, rotation, and translation.
|
||||
/// @param translate Whether or not to translate to world space by the translate part of the Matrix.
|
||||
[[nodiscard]] OBB GetMEOBB(const Matrix4x4& instance_matrix, bool translate = false) const;
|
||||
|
||||
/// Provides the minimally enclosing axis-aligned bounding box of the vertex array given information from the instance.
|
||||
/// @param rotation_matrix A Matrix3x3 representing rotation in 3D space.
|
||||
/// @param scale The scale of the instance.
|
||||
/// @param translate_part The center of the box would be shifted in 3D space by this. Primarily for world space.
|
||||
[[nodiscard]] AABB GetMEAABB(const Matrix3x3& rotation_matrix, const Vector3& scale = Vector3::One, const Vector3& translate_part = Vector3::Zero) const;
|
||||
[[nodiscard]] AABB GetMEAABB(const Matrix4x4& instance_matrix, bool translate = false) const;
|
||||
public:
|
||||
VertexArray() = default;
|
||||
/// Vertices are required, Everything else is optional.
|
||||
VertexArray(const Vertex* vertex_positions, const long& vp_length, const unsigned int* vertex_indices = nullptr, const long& vi_length = 0,
|
||||
const Normal* vertex_normals = nullptr, const long& vn_length = 0, const TextureCoordinate* texture_coordinates = nullptr, const long& vt_length = 0);
|
||||
|
||||
/// Vertices are required, Everything else is optional.
|
||||
explicit VertexArray(const std::vector<Vertex>& vertex_positions, const std::vector<unsigned int>& vertex_indices = {},
|
||||
const std::vector<Normal>& vertex_normals = {}, const std::vector<TextureCoordinate>& texture_coordinates = {});
|
||||
|
||||
static VertexArray LoadWavefrontOBJ(const std::string& file_text);
|
||||
static VertexArray LoadAMO(const std::string& file_text);
|
||||
};
|
||||
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
static VertexArray Animate(int animation_id, float animation_time);
|
||||
static VertexArray Animate(const AnimationState& anim_state);
|
353
main.cpp
353
main.cpp
@@ -1,26 +1,98 @@
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/JGL.h>
|
||||
#include <rewindow/types/window.h>
|
||||
#include <JGL/Colors.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||
#include <ReWindow/types/Window.h>
|
||||
#include <Colors.hpp>
|
||||
#include <chrono>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <ReWindow/Logger.h>
|
||||
#include <JGL/types/VertexArray.h>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using namespace JGL::Fonts;
|
||||
using namespace JGL;
|
||||
using JGL::Font;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
float fps = 0.0f;
|
||||
|
||||
struct Character
|
||||
/// A draggable 2D point that highlights when moused over and when clicked.
|
||||
class Gizmo
|
||||
{
|
||||
unsigned int TextureID; // ID handle of the glyph texture
|
||||
Vector2 Size; // Size of glyph
|
||||
Vector2 Bearing; // Offset from baseline to left/top of glyph
|
||||
unsigned int Advance; // Offset to advance to next glyph
|
||||
public:
|
||||
Gizmo() {}
|
||||
Gizmo(const Vector2& pos) : position(pos) {}
|
||||
bool dragging = false;
|
||||
bool hovered = false;
|
||||
Vector2 position;
|
||||
float range = 6.f;
|
||||
float base_radius = 3.f;
|
||||
float hover_radius = 6.f;
|
||||
float drag_radius = 4.f;
|
||||
Color4 base_color = Colors::Reds::Salmon;
|
||||
Color4 hover_color = Colors::Reds::Firebrick;
|
||||
Color4 drag_color = Colors::White;
|
||||
float lerp_rate = 0.25f;
|
||||
float text_scale = 1.f;
|
||||
int text_size = 12;
|
||||
|
||||
void Grab() {
|
||||
if (hovered)
|
||||
dragging = true;
|
||||
}
|
||||
void Release() {
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
void Update(const Vector2& mouse) {
|
||||
if (dragging)
|
||||
position = position.Lerp(mouse, lerp_rate);
|
||||
|
||||
hovered = mouse.Distance(position) < range;
|
||||
}
|
||||
|
||||
void Draw() {
|
||||
if (dragging)
|
||||
J2D::DrawPoint(drag_color, position, drag_radius);
|
||||
else if (hovered)
|
||||
J2D::DrawPoint(hover_color, position, hover_radius);
|
||||
else
|
||||
J2D::DrawPoint(base_color, position, base_radius);
|
||||
|
||||
J2D::DrawString(Colors::White, std::format("{:.1f},{:.1f}", position.x, position.y), position.x, position.y, text_scale, text_size);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
std::map<char, Character> Characters;
|
||||
GLuint VAO, VBO;
|
||||
/// A 3D Camera Controller.
|
||||
class Camera {
|
||||
public:
|
||||
Vector3 position = {0,0,0};
|
||||
Vector3 angle = {0,0,0};
|
||||
|
||||
std::vector<GLfloat> lookAt(const Vector3& eye, const Vector3& center, const Vector3& up) {
|
||||
Vector3 f = Vector3::Normalized((center - eye));
|
||||
Vector3 upN = Vector3::Normalized(up);
|
||||
Vector3 s = Vector3::Normalized(f.Cross(upN));
|
||||
Vector3 u = Vector3::Normalized(s.Cross(f));
|
||||
|
||||
std::vector<GLfloat> result = {
|
||||
s.x, u.x, -f.x, 0.0f,
|
||||
s.y, u.y, -f.y, 0.0f,
|
||||
s.z, u.z, -f.z, 0.0f,
|
||||
-s.Dot(eye), -u.Dot(eye), f.Dot(eye), 1.0f
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
void render() {
|
||||
glRotatef(angle.x,1.0f, 0.0f, 0.0f);
|
||||
glRotatef(angle.y,0.0f, 1.0f, 0.0f);
|
||||
glRotatef(angle.z,0.0f, 0.0f, 1.0f);
|
||||
glMultMatrixf(lookAt({position.x, position.y, position.z}, {position.x, position.y, 100.f + position.z}, {0,1,0}).data());
|
||||
}
|
||||
};
|
||||
|
||||
Camera* camera;
|
||||
using J3ML::LinearAlgebra::Matrix4x4;
|
||||
|
||||
struct point {
|
||||
@@ -30,91 +102,228 @@ struct point {
|
||||
GLfloat t;
|
||||
};
|
||||
|
||||
class JGLDemoWindow : public ReWindow::RWindow
|
||||
Gizmo a({250, 150});
|
||||
Gizmo b({200, 250});
|
||||
Gizmo c({350, 300});
|
||||
Gizmo d({450, 250});
|
||||
|
||||
JGL::Font FreeSans;
|
||||
Texture* image;
|
||||
Texture* image_mask;
|
||||
RenderTarget* j2d_render_target;
|
||||
|
||||
class JGLDemoWindow : public ReWindow::OpenGLWindow
|
||||
{
|
||||
public:
|
||||
void initGL() {
|
||||
camera = new Camera;
|
||||
|
||||
JGLDemoWindow() : ReWindow::RWindow() {}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) :
|
||||
ReWindow::RWindow(title, width, height)
|
||||
{
|
||||
if (!JGL::Init({ GetSize().x, GetSize().y}, 75, 100))
|
||||
Logger::Fatal("Initialization failed.");
|
||||
|
||||
// Load a custom font.
|
||||
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(GL_TRUE);
|
||||
image = new Texture("assets/sprites/Re3D.png", FilteringMode::BILINEAR);
|
||||
image_mask = new Texture("assets/sprites/alpha_mask_2.png");
|
||||
j2d_render_target = new RenderTarget({540, 500}, {0,0,0,0}, false,
|
||||
MSAA_SAMPLE_RATE::MSAA_8X, FilteringMode::MIPMAP_TRILINEAR);
|
||||
|
||||
//Texture::MultiplyByAlphaMask(*image, *image_mask);
|
||||
}
|
||||
|
||||
void initGL()
|
||||
{
|
||||
gladLoadGL();
|
||||
EulerAngleXYZ textAngle = {0,0,0};
|
||||
float fov = 90;
|
||||
u8 pulse = 0;
|
||||
float sprite_radians = 0;
|
||||
bool fov_increasing = true;
|
||||
int blit_pos = 0;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, getSize().x, getSize().y, 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
void display() {
|
||||
pulse++;
|
||||
float dt = GetDeltaTime();
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
JGL::Update({ GetSize().x, GetSize().y });
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
if (fov_increasing)
|
||||
fov += 0.025;
|
||||
else
|
||||
fov -= 0.050;
|
||||
|
||||
JGL::InitTextEngine();
|
||||
}
|
||||
if (fov >= 120)
|
||||
fov_increasing = false;
|
||||
else if (fov <= 75)
|
||||
fov_increasing = true;
|
||||
//J3D::ChangeFOV(fov);
|
||||
|
||||
|
||||
void display()
|
||||
{
|
||||
sprite_radians += 0.005;
|
||||
textAngle.yaw += 1;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, getSize().x, getSize().y, 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
JGL::J2D::FillRect2D(JGL::Colors::Blue, {32, 32}, {100.5, 100.5});
|
||||
JGL::J2D::FillRect2D(JGL::Colors::Blue, {32, 32}, {100.5, 100.5});
|
||||
camera->render();
|
||||
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
|
||||
/* if rendering to screen space directly. */
|
||||
auto test_light = PointLight({2,1,2}, {pulse,pulse,pulse, 255}, {pulse, pulse, pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
|
||||
// If a 3D object has transparency. The things you'd like to see through it must be drawn before.
|
||||
|
||||
JGL::Triangle2D tri
|
||||
{
|
||||
{140, 200},
|
||||
{135, 100},
|
||||
{105, 100}
|
||||
};
|
||||
JGL::J2D::FillTriangle2D(JGL::Colors::Yellow, tri);
|
||||
J3D::Begin();
|
||||
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
|
||||
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
|
||||
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
|
||||
//J3D::WireframeSphere(Colors::Green, {0,0,0.5f}, 0.25f, 1, 128, 128);
|
||||
Sphere sphere = {{0,0, 0.5f}, 0.2125};
|
||||
J3D::BatchWireframeRevoSphere(Colors::Green, &sphere, 1, 1, 8, 8, true);
|
||||
J3D::RequiredLight(&test_light);
|
||||
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
|
||||
J3D::WireframeAABB(Colors::Gray, {0,0,0.5f}, {0.11f, 0.06f, 0.11f});
|
||||
|
||||
AABB boxes[1] = {{Vector3(-0.2125, -0.2125,0.28750), Vector3(0.2125,0.2125,0.7125)}};
|
||||
J3D::BatchWireframeAABB(Colors::Yellow, boxes, 1, 1);
|
||||
J3D::End();
|
||||
|
||||
JGL::J3D::DrawString3D(JGL::Colors::Red, "JGL Sample Text", {1, -120, 0.5f}, 2.f);
|
||||
JGL::J2D::DrawString2D(JGL::Colors::Green, "William J. Tomasine II ", 0.f, -120.f, 1.f);
|
||||
J2D::Begin(j2d_render_target, true);
|
||||
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
|
||||
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawPartialSprite(image, Vector2(225, 300), Vector2(image->GetDimensions()) * 0.25, Vector2(image->GetDimensions()) * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
|
||||
J2D::FillGradientRect(Colors::Red, Colors::Blue, Direction::Diagonal_SWNE, {100,52}, {100,100});
|
||||
J2D::FillRoundedRect(Colors::Red, {200, 52}, {100, 100}, 8, 8);
|
||||
J2D::FillRoundedRect(Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
|
||||
J2D::FillCircle(Colors::White, {52, 204}, 50, 24);
|
||||
J2D::OutlineCircle(Colors::White, {153, 204}, 50, 24);
|
||||
|
||||
JGL::J2D::DrawLine2D(JGL::Colors::Greens::DarkGreen, {10, 10}, {200, 300});
|
||||
JGL::J3D::DrawLine3D(JGL::Colors::Red, {0,0,0}, {1,0,0});
|
||||
JGL::J3D::DrawLine3D(JGL::Colors::Red, {0,0,0}, {1,0,0});
|
||||
J2D::FillChamferRect(Colors::Reds::LightSalmon, {150, 400}, {64, 64}, 5);
|
||||
J2D::OutlineRoundedRect(Colors::Reds::LightCoral, {250, 350}, {128, 128}, 10, 2);
|
||||
std::vector<Vector2> points = {{1,1}, {4,4}, {8,8}, {16,16}, {32,32}};
|
||||
J2D::FillGradientTriangle(Color4(Colors::Red), Color4(Colors::Green), Color4(Colors::Blue), {{0, 275}, {0, 375}, {100, 375}});
|
||||
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
|
||||
J2D::DrawGradientLine(Colors::Red, Colors::Blue, {105, 375}, {200, 275}, 2);
|
||||
auto result = Jupiteroid.MeasureString("Jupiteroid Font", 16);
|
||||
|
||||
J2D::DrawString(Colors::Green, "Jupteroid Font", 0.f, 0, 1.f, 16, Jupiteroid);
|
||||
J2D::DrawString(Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 16, 1,16, Jupiteroid);
|
||||
J2D::DrawString(Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 33, 1,16, Jupiteroid);
|
||||
J2D::DrawString(Colors::White, "Framerate: " + std::to_string((int) fps), 0, 48, 1, 16, Jupiteroid);
|
||||
std::array<Vector2, 5> polygon = {Vector2(200, 400), {220, 420}, {220, 430}, {230, 410}, {200, 400}};
|
||||
J2D::OutlinePolygon(Colors::White, polygon.data(), polygon.size());
|
||||
J2D::DrawCubicBezierCurve(Colors::Blues::CornflowerBlue,
|
||||
a.position,
|
||||
b.position,
|
||||
c.position,
|
||||
d.position
|
||||
, 20, 1.5f);
|
||||
|
||||
a.Draw();
|
||||
b.Draw();
|
||||
c.Draw();
|
||||
d.Draw();
|
||||
J2D::End();
|
||||
|
||||
J2D::Begin();
|
||||
J2D::DrawRenderTarget(j2d_render_target, {0, 0});
|
||||
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
|
||||
J2D::End();
|
||||
|
||||
//glFlush();
|
||||
}
|
||||
|
||||
void OnRefresh(float elapsed) override
|
||||
{
|
||||
void OnRefresh(float elapsed) override {
|
||||
|
||||
fps = GetRefreshRate();
|
||||
|
||||
if (IsKeyDown(Keys::RightArrow))
|
||||
camera->angle.y += 45.f * elapsed;
|
||||
if (IsKeyDown(Keys::LeftArrow))
|
||||
camera->angle.y -= 45.f * elapsed;
|
||||
if (IsKeyDown(Keys::UpArrow))
|
||||
camera->angle.x -= 45.f * elapsed;
|
||||
if (IsKeyDown(Keys::DownArrow))
|
||||
camera->angle.x += 45.f * elapsed;
|
||||
if (IsKeyDown(Keys::Space))
|
||||
camera->position.y += 1.f * elapsed;
|
||||
if (IsKeyDown(Keys::LeftShift))
|
||||
camera->position.y -= 1.f * elapsed;
|
||||
|
||||
//This is wrong of course. Just for testing purposes.
|
||||
if (IsKeyDown(Keys::W))
|
||||
camera->position.z += 1.f * elapsed;
|
||||
if (IsKeyDown(Keys::S))
|
||||
camera->position.z -= 1.f * elapsed;
|
||||
if (IsKeyDown(Keys::A))
|
||||
camera->position.x += 1.f * elapsed;
|
||||
if (IsKeyDown(Keys::D))
|
||||
camera->position.x -= 1.f * elapsed;
|
||||
|
||||
|
||||
auto mouse = GetMouseCoordinates();
|
||||
a.Update({(float) mouse.x, (float) mouse.y});
|
||||
b.Update({(float) mouse.x, (float) mouse.y});
|
||||
c.Update({(float) mouse.x, (float) mouse.y});
|
||||
d.Update({(float) mouse.x, (float) mouse.y});
|
||||
display();
|
||||
this->glSwapBuffers();
|
||||
int glError = glGetError();
|
||||
if (glError != GL_NO_ERROR)
|
||||
std::cout << glError << std::endl;
|
||||
SwapBuffers();
|
||||
}
|
||||
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override
|
||||
|
||||
|
||||
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent & ev) override
|
||||
{
|
||||
return true;
|
||||
RWindow::OnMouseButtonDown(ev);
|
||||
a.Grab();
|
||||
b.Grab();
|
||||
c.Grab();
|
||||
d.Grab();
|
||||
}
|
||||
|
||||
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent & ev) override
|
||||
{
|
||||
RWindow::OnMouseButtonUp(ev);
|
||||
a.Release();
|
||||
b.Release();
|
||||
c.Release();
|
||||
d.Release();
|
||||
}
|
||||
|
||||
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override {return true;}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::OpenGLWindow(title, width, height, 2, 1) {}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
auto* window = new JGLDemoWindow("JGL Demo Window", 1280, 720);
|
||||
window->setRenderer(RenderingAPI::OPENGL);
|
||||
window->Open();
|
||||
window->initGL();
|
||||
window->setResizable(true);
|
||||
while (window->isAlive())
|
||||
{
|
||||
window->pollEvents();
|
||||
window->refresh();
|
||||
}
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
auto* window = new JGLDemoWindow("JGL Demo Window", 1280, 720);
|
||||
if (!window->Open())
|
||||
exit(-1);
|
||||
window->initGL();
|
||||
window->SetResizable(true);
|
||||
window->SetVsyncEnabled(false);
|
||||
|
||||
std::ifstream file("assets/models/cube.amo");
|
||||
if (!file.is_open())
|
||||
return -1;
|
||||
|
||||
/*
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
std::string file_text = buffer.str();
|
||||
file.close();
|
||||
std::cout << file_text << std::endl;
|
||||
|
||||
auto result = VertexArray::LoadAMO(file_text);
|
||||
*/
|
||||
|
||||
//ReWindow::Logger::Error.EnableConsole(false);
|
||||
//ReWindow::Logger::Warning.EnableConsole(false);
|
||||
//ReWindow::Logger::Debug.EnableConsole(false);
|
||||
|
||||
while (window->IsAlive())
|
||||
window->ManagedRefresh();
|
||||
return 0;
|
||||
}
|
1
reci/scripts/builddeps.reci
Normal file
1
reci/scripts/builddeps.reci
Normal file
@@ -0,0 +1 @@
|
||||
Main:new("Install build dependencies", "apt-get install -yq libgl1-mesa-dev libfreetype-dev")
|
7
reci/scripts/install_build_dependencies.sh
Normal file
7
reci/scripts/install_build_dependencies.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
source $RECI/shlib/info.sh
|
||||
|
||||
INFO "Installing build dependencies for JGL"
|
||||
GROUP="Install build dependencies" RUN '
|
||||
apt-get install -yq libgl1-mesa-dev libfreetype-dev
|
||||
'
|
||||
|
8671
src/Fonts.cpp
Normal file
8671
src/Fonts.cpp
Normal file
File diff suppressed because it is too large
Load Diff
48
src/JGL.cpp
Normal file
48
src/JGL.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Created by dawsh on 1/17/24.
|
||||
//
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/JGL.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include "renderer/OpenGL/internals/internals.h"
|
||||
|
||||
namespace JGL {
|
||||
using namespace J3ML;
|
||||
|
||||
bool Init(const Vector2i& ws, float fovY, float far_plane) {
|
||||
gladLoadGL();
|
||||
if (!MeetsRequirements()) {
|
||||
Logger::Fatal("The graphics driver does not meet the minimum requirements to run this program.");
|
||||
return false;
|
||||
}
|
||||
|
||||
InitTextEngine();
|
||||
Fonts::Init();
|
||||
ShapeCache::Init();
|
||||
JGL::window_size = ws;
|
||||
J3D::fov = fovY;
|
||||
J3D::far_plane = far_plane;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Update(const Vector2i& ws) {
|
||||
if (state_stack.Size())
|
||||
Logger::Error("You shouldn't be running JGL::Update while inside a J2D or J3D context.");
|
||||
|
||||
JGL::window_size = ws;
|
||||
glViewport(0, 0, window_size.x, window_size.y);
|
||||
}
|
||||
|
||||
bool MeetsRequirements() {
|
||||
if (!GLAD_GL_VERSION_2_1)
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_framebuffer_object)
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_depth_texture)
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_shadow)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
298
src/JGL/JGL.cpp
298
src/JGL/JGL.cpp
@@ -1,298 +0,0 @@
|
||||
//
|
||||
// Created by dawsh on 1/17/24.
|
||||
//
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/JGL.h>
|
||||
#include <freetype2/ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <JGL/Color3.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
GLuint program;
|
||||
|
||||
namespace JGL
|
||||
{
|
||||
FT_Face face;
|
||||
FT_Library ft;
|
||||
|
||||
using namespace J3ML;
|
||||
|
||||
bool InitTextEngine() {
|
||||
constexpr u32 default_font_size = 16;
|
||||
if (FT_Init_FreeType(&ft))
|
||||
{
|
||||
std::cout << "Error::FREETYPE: " << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FT_New_Face(ft, "assets/fonts/FreeSans.ttf", 0, &face))
|
||||
{
|
||||
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace J2D
|
||||
{
|
||||
void FillRect2D(const Color3 &color, const Vector2 &pos, const Vector2 &size) {
|
||||
auto vp_pos = pos;
|
||||
auto vp_size = size;
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glVertex2f(vp_pos.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void OutlineRect2D(const Color3 &color, const Vector2 &pos, const Vector2 &size, float thickness) {
|
||||
auto vp_pos = pos;
|
||||
auto vp_size = size;
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glVertex2f(vp_pos.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawLine2D(const Color3 &color, const Vector2 &A, const Vector2 &B, float thickness) {
|
||||
auto vp_a = A;
|
||||
auto vp_b = B;
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_a.x, vp_a.y);
|
||||
glVertex2f(vp_b.x, vp_b.y);
|
||||
glEnd();
|
||||
|
||||
}
|
||||
|
||||
void DrawLine2D(const Color3 &color, float x, float y, float w, float h, float thickness) {
|
||||
DrawLine2D(color, {x, y}, {w, h}, thickness);
|
||||
}
|
||||
|
||||
void DrawPixel2D(const Color3 &color, float x, float y) {
|
||||
DrawPixel2D(color, {x, y});
|
||||
}
|
||||
|
||||
void DrawPixel2D(const Color3 &color, const Vector2 &coordinates) {
|
||||
auto vp_pos = coordinates;
|
||||
glBegin(GL_POINT);
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void
|
||||
OutlineCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions, float thickness) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float)subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step)
|
||||
{
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
y += center.y;
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void FillCircle2D(const Color3 &color, const Vector2 ¢er, float radius, int subdivisions) {
|
||||
glBegin(GL_POLYGON);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float)subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step)
|
||||
{
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
y += center.y;
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void OutlineTriangle2D(const Color3& color, const Triangle2D& tri)
|
||||
{
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void FillTriangle2D(const Color3& color, const Triangle2D& tri)
|
||||
{
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawString2D(const Color3& color, std::string text, float x, float y, float scale, u32 size) {
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
|
||||
FT_Set_Pixel_Sizes(face, 0, size);
|
||||
|
||||
GLuint textures[text.size()];
|
||||
for (int i = 0; i < text.length(); i++)
|
||||
{
|
||||
if (FT_Load_Char(face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = face->glyph;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGenTextures(1, &textures[i]);
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
float x2 = x + g->bitmap_left * scale;
|
||||
float y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
|
||||
float w = g->bitmap.width * scale;
|
||||
float h = g->bitmap.rows * scale;
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(x2, y2);
|
||||
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex2f(x2, y2 + h);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(x2 + w, y2 + h);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(x2, y2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(x2 + w, y2 + h);
|
||||
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(x2 + w, y2);
|
||||
|
||||
glEnd();
|
||||
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
}
|
||||
for (auto& t : textures)
|
||||
glDeleteTextures(1, &t);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace J3D
|
||||
{
|
||||
void DrawLine3D(const Color3& color, const Vector3& A, const Vector3& B, float thickness)
|
||||
{
|
||||
glBegin(GL_LINES);
|
||||
glLineWidth(thickness);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glVertex3f(A.x, A.y, A.z);
|
||||
glVertex3f(B.x, B.y, B.z);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawString3D(const Color3& color, const std::string& text, const Vector3& pos, float scale, u32 size)
|
||||
{
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
float z = pos.z;
|
||||
GLfloat currentColor[4];
|
||||
GLuint textures[text.size()];
|
||||
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
glColor4f(color.r, color.g, color.b, 1.0f);
|
||||
|
||||
FT_Set_Pixel_Sizes(face, 0, size);
|
||||
|
||||
//for (c = text.c_str(); *c; c++)
|
||||
for (int i = 0; i < text.length(); i++)
|
||||
{
|
||||
if (FT_Load_Char(face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = face->glyph;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenTextures(1, &textures[i]);
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
float x2 = x + g->bitmap_left * scale;
|
||||
float y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
|
||||
float z2 = z;
|
||||
float w = g->bitmap.width * scale;
|
||||
float h = g->bitmap.rows * scale;
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3f(x2, y2, z2);
|
||||
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex3f(x2, y2 + h, z2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(x2 + w, y2 + h, z2);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3f(x2, y2, z2);
|
||||
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex3f(x2 + w, y2 + h, z2);
|
||||
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex3f(x2 + w, y2, z2);
|
||||
|
||||
glEnd();
|
||||
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
|
||||
}
|
||||
|
||||
for (auto& t : textures)
|
||||
glDeleteTextures(1, &t);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
glColor4f(currentColor[0], currentColor[1], currentColor[2], currentColor[3]); //Set draw color back to whatever it was before.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
57
src/ShapeCache.cpp
Normal file
57
src/ShapeCache.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <JGL/JGL.h>
|
||||
|
||||
void JGL::ShapeCache::Init() {
|
||||
std::array<Vector3, 8> vertices = {
|
||||
Vector3(1.0f, 1.0f, -1.0f),
|
||||
Vector3(1.0f, -1.0f, -1.0f),
|
||||
Vector3(1.0f, 1.0f, 1.0f),
|
||||
Vector3(1.0f, -1.0f, 1.0f),
|
||||
Vector3(-1.0f, 1.0f, -1.0f),
|
||||
Vector3(-1.0f, -1.0f, -1.0f),
|
||||
Vector3(-1.0f, 1.0f, 1.0f),
|
||||
Vector3(-1.0f, -1.0f, 1.0f)
|
||||
};
|
||||
std::array<unsigned int, 36> indices = {
|
||||
4, 2, 0,
|
||||
2, 7, 3,
|
||||
6, 5, 7,
|
||||
1, 7, 5,
|
||||
0, 3, 1,
|
||||
4, 1, 5,
|
||||
4, 6, 2,
|
||||
2, 6, 7,
|
||||
6, 4, 5,
|
||||
1, 3, 7,
|
||||
0, 2, 3,
|
||||
4, 0, 1
|
||||
};
|
||||
|
||||
std::array<Vector3, 8> vertex_normals = {
|
||||
Vector3( 0.816f, 0.408f, -0.408f),
|
||||
Vector3( 0.333f, -0.667f, -0.667f),
|
||||
Vector3( 0.333f, 0.667f, 0.667f),
|
||||
Vector3( 0.816f, -0.408f, 0.408f),
|
||||
Vector3(-0.333f, 0.667f, -0.667f),
|
||||
Vector3(-0.816f, -0.408f, -0.408f),
|
||||
Vector3(-0.816f, 0.408f, 0.408f),
|
||||
Vector3(-0.333f, -0.667f, 0.667f)
|
||||
};
|
||||
|
||||
if (!cube_vertex_data)
|
||||
cube_vertex_data = new VRamList(vertices.data(), vertices.size());
|
||||
|
||||
if (!cube_index_data)
|
||||
cube_index_data = new VRamList(indices.data(), indices.size());
|
||||
|
||||
if (!cube_normal_data)
|
||||
cube_normal_data = new VRamList(vertex_normals.data(), vertex_normals.size());
|
||||
|
||||
if (!square_origin_topleft_vertex_data) {
|
||||
std::array<Vector2, 4> square_vertices = { Vector2(0, 0), {1, 0}, {1, -1}, {0, -1} };
|
||||
square_origin_topleft_vertex_data = new VRamList(square_vertices.data(), square_vertices.size());
|
||||
}
|
||||
if (!j2d_default_normal_data) {
|
||||
std::array<GLfloat, 3> normal {0, 0, 1};
|
||||
j2d_default_normal_data = new VRamList(normal.data(), normal.size());
|
||||
}
|
||||
}
|
9
src/logger/logger.cpp
Normal file
9
src/logger/logger.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
namespace JGL::Logger {
|
||||
using namespace jlog;
|
||||
|
||||
GenericLogger Fatal {"JGL::fatal", GlobalLogFile, Colors::Reds::Crimson, Colors::Gray, Colors::Gray, Colors::Reds::Crimson, Colors::White};
|
||||
GenericLogger Debug {"JGL::debug", GlobalLogFile, Colors::Purples::Purple, Colors::Gray, Colors::Gray, Colors::Purples::Purple, Colors::White};
|
||||
GenericLogger Error {"JGL::error", GlobalLogFile, Colors::Red, Colors::Gray, Colors::Gray, Colors::Red, Colors::White};
|
||||
}
|
1077
src/renderer/OpenGL/J2D.cpp
Normal file
1077
src/renderer/OpenGL/J2D.cpp
Normal file
File diff suppressed because it is too large
Load Diff
583
src/renderer/OpenGL/J3D.cpp
Normal file
583
src/renderer/OpenGL/J3D.cpp
Normal file
@@ -0,0 +1,583 @@
|
||||
#include <JGL/JGL.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <J3ML/Geometry/OBB.hpp>
|
||||
#include <J3ML/Algorithm/Bezier.hpp>
|
||||
#include <JGL/types/Light.h>
|
||||
#include "internals/internals.h"
|
||||
|
||||
|
||||
std::array<GLfloat, 16> JGL::OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far) {
|
||||
std::array<GLfloat, 16> result{};
|
||||
GLfloat f = 1.0f / std::tan(fovY * 0.5f * Math::Pi / 180.0f);
|
||||
result[0] = f / aspect;
|
||||
result[5] = f;
|
||||
result[10] = (z_far + z_near) / (z_near - z_far);
|
||||
result[11] = -1.0f;
|
||||
result[14] = (2.0f * z_far * z_near) / (z_near - z_far);
|
||||
return result;
|
||||
}
|
||||
|
||||
void JGL::J3D::ChangeFOV(float fov) {
|
||||
JGL::J3D::fov = fov;
|
||||
}
|
||||
|
||||
void JGL::J3D::ChangeFarPlane(float far_plane) {
|
||||
JGL::J3D::far_plane = far_plane;
|
||||
}
|
||||
|
||||
void JGL::J3D::RequiredLight(const JGL::LightBase* light) {
|
||||
bool success = false;
|
||||
for (auto& i : current_state.required_lights)
|
||||
if (i == nullptr) {
|
||||
i = light;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
Logger::Error("You cannot specify more than 8 required lights.");
|
||||
}
|
||||
|
||||
void JGL::J3D::OptionalLights(const JGL::LightBase** lights, const size_t& light_count) {
|
||||
for (size_t i = 0; i < light_count; i++)
|
||||
current_state.optional_lights.push_back(lights[i]);
|
||||
}
|
||||
|
||||
void JGL::J3D::Begin(bool two_pass) {
|
||||
auto aspect = (float) window_size.x / (float) window_size.y;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMultMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
//Get what the draw color was before we did anything.
|
||||
glGetFloatv(GL_CURRENT_COLOR, current_state.draw_color);
|
||||
glColor4fv(current_state.draw_color);
|
||||
|
||||
if (!glIsEnabled(GL_DEPTH_TEST))
|
||||
current_state.depth_test = false,
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
current_state.depth_test = true;
|
||||
|
||||
current_state.vertex_array = false;
|
||||
if (!glIsEnabled(GL_VERTEX_ARRAY))
|
||||
current_state.vertex_array = false,
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_NORMAL_ARRAY))
|
||||
current_state.normal_array = true,
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
|
||||
current_state.texture_coordinate_array = true,
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_TEXTURE_2D))
|
||||
current_state.texture_2D = true,
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
current_state.cull_face = false;
|
||||
if (glIsEnabled(GL_CULL_FACE))
|
||||
current_state.cull_face = true,
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (!glIsEnabled(GL_BLEND))
|
||||
current_state.blend = false,
|
||||
glEnable(GL_BLEND),
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else
|
||||
current_state.blend = true;
|
||||
|
||||
// Reset the lights.
|
||||
current_state.required_lights = empty_light_array;
|
||||
current_state.optional_lights = {};
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
void JGL::J3D::End() {
|
||||
if (!current_state.depth_test)
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (!current_state.vertex_array)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (current_state.texture_2D)
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if (!current_state.blend)
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
if (current_state.cull_face)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
if (current_state.normal_array)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (current_state.texture_coordinate_array)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_LIGHTING)) {
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_LIGHT0);
|
||||
glDisable(GL_LIGHT1);
|
||||
glDisable(GL_LIGHT2);
|
||||
glDisable(GL_LIGHT3);
|
||||
glDisable(GL_LIGHT4);
|
||||
glDisable(GL_LIGHT5);
|
||||
glDisable(GL_LIGHT6);
|
||||
glDisable(GL_LIGHT7);
|
||||
}
|
||||
|
||||
current_state.required_lights = empty_light_array;
|
||||
current_state.optional_lights = {};
|
||||
|
||||
//Put the draw color back how it was before.
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness) {
|
||||
Vector3 vertices[] = {A, B};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
Sphere sphere = {position, radius};
|
||||
BatchWireframeSphere(color,& sphere, 1, thickness, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeSphere(const Color4& color, const Sphere& sphere, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
BatchWireframeSphere(color,& sphere, 1, thickness, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
// Create one sphere with a radius of 1 about 0, 0.
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i <= sectors; i++) {
|
||||
float lat = J3ML::Math::Pi * (-0.5 + (float) i / sectors);
|
||||
float z = J3ML::Math::Sin(lat);
|
||||
float zr = J3ML::Math::Cos(lat);
|
||||
|
||||
for (int j = 0; j <= stacks; j++) {
|
||||
float lng = 2 * J3ML::Math::Pi * (float) (j - 1) / stacks;
|
||||
float x = J3ML::Math::Cos(lng);
|
||||
float y = J3ML::Math::Sin(lng);
|
||||
|
||||
float pos_x = r * x * zr;
|
||||
float pos_y = r * y * zr;
|
||||
float pos_z = r * z;
|
||||
|
||||
vertices[index++] = Vector3(pos_x, pos_y, pos_z);
|
||||
}
|
||||
}
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
|
||||
// Render each sphere in the batch at their given position and radius.
|
||||
for(size_t i = 0; i < sphere_count; i++) {
|
||||
glPushMatrix();
|
||||
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeRevoSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
|
||||
Sphere sphere = {position, radius};
|
||||
BatchWireframeRevoSphere(color,& sphere, 1, thickness, sectors, revolutions, draw_stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeRevoSphere(const Color4& color, const Sphere& sphere, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
|
||||
BatchWireframeRevoSphere(color,& sphere, 1, thickness, sectors, revolutions, draw_stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices;
|
||||
vertices.reserve((sectors + 1) * (revolutions + 1));
|
||||
|
||||
std::vector<Vector3> cross_section(sectors + 1);
|
||||
for (int i = 0; i <= sectors; i++) {
|
||||
float lat = J3ML::Math::Pi * (-0.5 + (float)i / sectors);
|
||||
float z = J3ML::Math::Sin(lat);
|
||||
float zr = J3ML::Math::Cos(lat);
|
||||
cross_section[i] = Vector3(0, zr * r, z * r);
|
||||
}
|
||||
|
||||
// Revolve
|
||||
for (int j = 0; j <= revolutions; j++) {
|
||||
float lng = 2 * J3ML::Math::Pi * (float)j / revolutions;
|
||||
float cosLng = J3ML::Math::Cos(lng);
|
||||
float sinLng = J3ML::Math::Sin(lng);
|
||||
|
||||
for (const auto& point : cross_section) {
|
||||
float pos_x = point.y * cosLng;
|
||||
float pos_y = point.y * sinLng;
|
||||
float pos_z = point.z;
|
||||
|
||||
vertices.emplace_back(pos_x, pos_y, pos_z);
|
||||
}
|
||||
}
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
VRamList vertex_data(vertices.data(), vertices.size());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
// Render each sphere in the batch at their given position and radius.
|
||||
for(size_t i = 0; i < sphere_count; i++) {
|
||||
glPushMatrix();
|
||||
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
|
||||
if (draw_stacks)
|
||||
glRotatef(90, 0, 1, 0),
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeIcosphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int subdivisions) {
|
||||
|
||||
// NOTE2SELF: Code i'm borrowing this from uses float-packed-arrays rather than discrete Vectors
|
||||
// working on translating that correctly...
|
||||
|
||||
// TODO: Revise this once J3ML::Geometry::Icosahedron is implemented.
|
||||
const float h_angle = J3ML::Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
|
||||
const float v_angle = J3ML::Math::Atan(1.0f / 2.f); // elevation = 26.565;
|
||||
|
||||
std::vector<Vector3> vertices; // array of 12 vertices (x,y,z)
|
||||
unsigned int index = 0; // indices
|
||||
float z, xy; // coords
|
||||
float hAngle1 = -Math::Pi / 2.f - h_angle / 2.f; // start from -126 at 1st row
|
||||
float hAngle2 = -Math::Pi / 2.f; // start from -90 deg at 2nd row
|
||||
|
||||
// the first top vertex at (0,0,r)
|
||||
vertices[0] = position + Vector3{0,0,radius};
|
||||
|
||||
|
||||
|
||||
// compute 10 vertices at 1st and 2nd rows
|
||||
for (int i = 1; i <= 5; ++i)
|
||||
{
|
||||
|
||||
z = radius * Math::Sin(v_angle); // elevation
|
||||
xy = radius * Math::Cos(v_angle); // length on XY plane
|
||||
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle1), xy * Math::Sin(hAngle1), z} ;
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle2), xy * Math::Sin(hAngle2), -z};
|
||||
|
||||
// next horizontal angles
|
||||
hAngle1 += h_angle;
|
||||
hAngle2 += h_angle;
|
||||
}
|
||||
|
||||
// the last bottom vertex at (0, 0, -r)
|
||||
vertices[11] = position + Vector3{0,0, -radius};
|
||||
|
||||
//glLineWidth(thickness);
|
||||
//glColor4ubv(color.ptr());
|
||||
//glBindBuffer(GL_ARRAY_BUFFER, vertices.size());
|
||||
//glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
//glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
|
||||
//glColor4fv(baseColor);
|
||||
|
||||
std::vector<Vector3> tmpVertices;
|
||||
std::vector<Vector3> tmpIndices;
|
||||
std::vector<Vector2> newVs((subdivisions+1) * (subdivisions+2) / 2 * 3);
|
||||
const Vector3 v1, v2, v3;
|
||||
Vector3 newV1, newV2, newV3;
|
||||
|
||||
int i, j, k;
|
||||
index = 0; // unsigned int
|
||||
float a; // lerp alpha
|
||||
unsigned int i1, i2; // indices
|
||||
|
||||
// copy prev arrays
|
||||
tmpVertices = vertices;
|
||||
//tmpIndices = indices;
|
||||
|
||||
// iterate each triangle of icosahedron
|
||||
for (i = 0; i < tmpIndices.size(); i++)
|
||||
{
|
||||
//v1 = tmpVertices[tmpIndices[i]];
|
||||
//v2 = tmpVertices[tmpIndices[i+1]];
|
||||
//v3 = tmpVertices[tmpIndices[i+2]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeIcosahedron(const Color4& color, const Vector3& position, float radius, float thickness) {
|
||||
// TODO: Revise this once J3ML::Geometry::Icosahedron is implemented.
|
||||
const float h_angle = J3ML::Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
|
||||
const float v_angle = J3ML::Math::Atan(1.0f / 2.f); // elevation = 26.565;
|
||||
|
||||
std::array<Vector3, 12> vertices; // array of 12 vertices (x,y,z)
|
||||
int index = 0; // indices
|
||||
float z, xy; // coords
|
||||
float hAngle1 = -Math::Pi / 2.f - h_angle / 2.f; // start from -126 at 1st row
|
||||
float hAngle2 = -Math::Pi / 2.f; // start from -90 deg at 2nd row
|
||||
|
||||
// the first top vertex at (0,0,r)
|
||||
vertices[0] = position + Vector3{0,0,radius};
|
||||
|
||||
|
||||
|
||||
// compute 10 vertices at 1st and 2nd rows
|
||||
for (int i = 1; i <= 5; ++i)
|
||||
{
|
||||
|
||||
z = radius * Math::Sin(v_angle); // elevation
|
||||
xy = radius * Math::Cos(v_angle); // length on XY plane
|
||||
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle1), xy * Math::Sin(hAngle1), z} ;
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle2), xy * Math::Sin(hAngle2), -z};
|
||||
|
||||
// next horizontal angles
|
||||
hAngle1 += h_angle;
|
||||
hAngle2 += h_angle;
|
||||
}
|
||||
|
||||
// the last bottom vertex at (0, 0, -r)
|
||||
vertices[11] = position + Vector3{0,0, -radius};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
//glBindBuffer(GL_ARRAY_BUFFER, vertices.size());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const size_t& box_count, float thickness) {
|
||||
glColor4ubv(color.ptr());
|
||||
glLineWidth(thickness);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
|
||||
Vector3 center = boxes[i].Centroid();
|
||||
glPushMatrix();
|
||||
glTranslatef(center.x, center.y, center.z);
|
||||
glScalef(delta.x, delta.y, delta.z);
|
||||
glDrawArrays(GL_LINES, 0, ShapeCache::cube_vertex_data->GetLength());
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeAABB(const Color4& color, const Vector3& pos, const Vector3& radii, float thickness) {
|
||||
AABB aabb = {Vector3(pos.x - radii.x, pos.y - radii.y, pos.z - radii.z), Vector3(pos.x + radii.x, pos.y + radii.y, pos.z + radii.z)};
|
||||
BatchWireframeAABB(color, &aabb, 1, thickness);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_t& box_count) {
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->GetHandle());
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
bool using_lights = false;
|
||||
if (UsingLighting()) {
|
||||
using_lights = true;
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_normal_data->GetHandle());
|
||||
glNormalPointer(GL_FLOAT, sizeof(float), nullptr);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
|
||||
Vector3 center = boxes[i].Centroid();
|
||||
glPushMatrix();
|
||||
glTranslatef(center.x, center.y, center.z);
|
||||
glScalef(delta.x, delta.y, delta.z);
|
||||
if (using_lights)
|
||||
SelectLights(center);
|
||||
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
|
||||
if (using_lights)
|
||||
ResetLights();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(current_state.draw_color);
|
||||
if (using_lights)
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
void JGL::J3D::FillAABB(const Color4& color, const Vector3& pos, const Vector3& radii) {
|
||||
AABB box = {pos - radii, pos + radii};
|
||||
BatchFillAABB(color, &box, 1);
|
||||
}
|
||||
|
||||
void JGL::J3D::FillAABB(const Color4& color, const AABB& aabb) {
|
||||
BatchFillAABB(color, &aabb, 1);
|
||||
}
|
||||
|
||||
void JGL::J3D::FillSphere(const Color4& color, const Sphere& sphere, unsigned int sectors, unsigned int stacks) {
|
||||
BatchFillSphere(color, &sphere, 1, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, unsigned int sectors, unsigned int stacks) {
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
|
||||
std::vector<unsigned int> indices; indices.reserve(sectors * stacks * 6);
|
||||
|
||||
float two_pi = 2 * J3ML::Math::Pi;
|
||||
int index = 0;
|
||||
for (int i = 0; i <= sectors; i++) {
|
||||
float lat = J3ML::Math::Pi * (-0.5 + (float) i / sectors);
|
||||
float z = J3ML::Math::Sin(lat);
|
||||
float zr = J3ML::Math::Cos(lat);
|
||||
|
||||
for (int j = 0; j <= stacks; j++) {
|
||||
float lng = two_pi * (float) (j - 1) / stacks;
|
||||
float x = J3ML::Math::Cos(lng);
|
||||
float y = J3ML::Math::Sin(lng);
|
||||
|
||||
float pos_x = r * x * zr;
|
||||
float pos_y = r * y * zr;
|
||||
float pos_z = r * z;
|
||||
vertices[index++] = Vector3(pos_x, pos_y, pos_z);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < sectors; i++) {
|
||||
for (int j = 0; j < stacks; j++) {
|
||||
int first_index = i * (stacks + 1) + j;
|
||||
int second_index = first_index + stacks + 1;
|
||||
|
||||
indices.push_back(first_index);
|
||||
indices.push_back(second_index);
|
||||
indices.push_back(first_index + 1);
|
||||
|
||||
indices.push_back(second_index);
|
||||
indices.push_back(second_index + 1);
|
||||
indices.push_back(first_index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
VRamList vertex_data(vertices.data(), vertices.size());
|
||||
VRamList index_data(indices.data(), indices.size());
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_data.GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
for (size_t i = 0; i < sphere_count; i++) {
|
||||
const Vector3 position = spheres[i].Position;
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawElements(GL_TRIANGLES, index_data.GetLength(), GL_UNSIGNED_INT, nullptr);
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::FillSphere(const Color4& color, const Vector3& position, float radius, unsigned int sectors, unsigned int stacks) {
|
||||
Sphere sphere = {position, radius};
|
||||
BatchFillSphere(color, &sphere, 1, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeAABB(const Color4& color, const AABB& aabb, float thickness) {
|
||||
BatchWireframeAABB(color, &aabb, 1, thickness);
|
||||
}
|
||||
|
||||
// TODO Make it work the same as AABB batching. I couldn't get rotation to do anything more than twitch in place :(.
|
||||
void JGL::J3D::BatchWireframeOBB(const Color4& color, const OBB* boxes, const size_t& box_count, float thickness) {
|
||||
std::array<Vector3, 8> corner_points;
|
||||
std::array<GLuint, 24> indices =
|
||||
{
|
||||
0, 1, 1, 2, 2, 3, 3, 0,
|
||||
4, 5, 5, 6, 6, 7, 7, 4,
|
||||
0, 4, 1, 5, 2, 6, 3, 7
|
||||
};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), corner_points.data());
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
boxes[i].GetCornerPoints(corner_points.data());
|
||||
glPushMatrix();
|
||||
glTranslatef(boxes[i].pos.x, boxes[i].pos.y, boxes[i].pos.z);
|
||||
glDrawElements(GL_LINES, indices.size(), GL_UNSIGNED_INT, indices.data());
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeOBB(const Color4& color, const OBB& obb, float thickness) {
|
||||
BatchWireframeOBB(color, &obb, 1, thickness);
|
||||
}
|
||||
|
||||
/*
|
||||
void JGL::J3D::WireframeOBB(const Color4& color, const Vector3& position, const Vector3& radii, const Matrix3x3& orientation, float thickness) {
|
||||
WireframeOBB(color, OBB(position, radii, orientation. * Vector3::UnitX, rotation * Vector3::UnitY, rotation * Vector3::UnitZ), thickness);
|
||||
}
|
||||
*/
|
||||
|
||||
void JGL::J3D::DrawCubicBezierCurve(const Color4& color, const Vector3& controlA, const Vector3& pointA,
|
||||
const Vector3& pointB, const Vector3& controlB, int subdivisions, float thickness) {
|
||||
Vector3 last = controlA;
|
||||
const Vector3& first = controlB;
|
||||
for (int i = 0; i < subdivisions; ++i)
|
||||
{
|
||||
float alpha = (float) i / (float) subdivisions;
|
||||
Vector3 step = J3ML::Algorithm::Bezier(alpha, controlA, pointA, pointB, controlB);
|
||||
DrawLine(color, last, step, thickness);
|
||||
last = step;
|
||||
}
|
||||
|
||||
// Have to manually draw the last segment of the curve.
|
||||
DrawLine(color, last, first, thickness);
|
||||
}
|
||||
|
||||
void JGL::J3D::DrawVertexArray(const Color4& color, const VertexArray& vertex_array, const Vector3& position) {
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_array.GetVertices()->GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, 0, nullptr);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
//glScalef(1,1,1);
|
||||
glDrawArrays(GL_TRIANGLES, 0, vertex_array.GetVertices()->GetLength());
|
||||
glPopMatrix();
|
||||
|
||||
//glDrawElements(GL_LINES, vertex_array.GetIndices()->GetLength(), GL_UNSIGNED_INT, nullptr);
|
||||
//std::cout << vertex_array.GetVertices()->GetLength() << std::endl;
|
||||
glColor4fv(current_state.draw_color);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
}
|
252
src/renderer/OpenGL/TextRendering.cpp
Normal file
252
src/renderer/OpenGL/TextRendering.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
#include <JGL/JGL.h>
|
||||
#include "internals/internals.h"
|
||||
|
||||
|
||||
#if __linux__
|
||||
#include <freetype2/ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_OUTLINE_H
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_OUTLINE_H
|
||||
#endif
|
||||
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/FontCache.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
namespace JGL {
|
||||
CachedFont* CacheFont(const Font& font, u32 size) {
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
CachedFont* cachedFont;
|
||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||
Logger::Debug("Caching font data...");
|
||||
GLuint texture_id;
|
||||
glGenTextures(1, &texture_id);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
GLsizei width = 0;
|
||||
GLsizei max_height = 0;
|
||||
FT_ULong charcode;
|
||||
FT_UInt gindex;
|
||||
|
||||
//We have to loop over the available glyphs twice as we need the
|
||||
//final width and height of the texture_handle before we can construct it
|
||||
//and subsequently upload the glyph data.
|
||||
charcode = FT_Get_First_Char(font.face, &gindex);
|
||||
//Strings are char-based so we only handle charcodes within the extended ASCII range.
|
||||
while (gindex != 0 && charcode < 255) {
|
||||
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
|
||||
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
width += g->bitmap.width;
|
||||
max_height = std::max(max_height, (GLsizei) g->bitmap.rows);
|
||||
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
|
||||
}
|
||||
|
||||
fontCache.newFont(texture_id, width, max_height, size, font.index);
|
||||
cachedFont = fontCache.getFont(size, font.index);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, max_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
GLsizei xoffset = 0;
|
||||
|
||||
charcode = FT_Get_First_Char(font.face, &gindex);
|
||||
while (gindex != 0 && charcode < 255) {
|
||||
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
|
||||
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
GLfloat u0 = (GLfloat)xoffset / cachedFont->getTextureWidth();
|
||||
GLfloat u1 = u0 + (GLfloat)g->bitmap.width / cachedFont->getTextureWidth();
|
||||
|
||||
GLfloat v0 = 0.0f;
|
||||
GLfloat v1 = (GLfloat)g->bitmap.rows / cachedFont->getTextureHeight();
|
||||
|
||||
std::array<GLfloat, 12> texcoords
|
||||
{
|
||||
u0, v0,
|
||||
u0, v1,
|
||||
u1, v1,
|
||||
u0, v0,
|
||||
u1, v1,
|
||||
u1, v0
|
||||
};
|
||||
|
||||
cachedFont->appendGlyph(new CachedGlyph((char)charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
|
||||
|
||||
xoffset += g->bitmap.width;
|
||||
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
|
||||
}
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
return cachedFont;
|
||||
}
|
||||
|
||||
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
|
||||
// Offset by height to render at "correct" location.
|
||||
y += size;
|
||||
|
||||
bool round_text_coords_for_crisp_rendering = true;
|
||||
|
||||
// TODO: This currently does not account for non-integer scale factors.
|
||||
if (round_text_coords_for_crisp_rendering)
|
||||
{
|
||||
x = J3ML::Math::Floor(x);
|
||||
y = J3ML::Math::Floor(y);
|
||||
}
|
||||
|
||||
CachedFont* cachedFont = fontCache.getFont(size, font.index);
|
||||
|
||||
if (font.face == nullptr)
|
||||
Logger::Fatal("Drawing a string with an uninitialized font?");
|
||||
|
||||
//If the font doesn't exist in the cache yet.
|
||||
if (!cachedFont)
|
||||
cachedFont = CacheFont(font, size);
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
//Texture parameters are restored when the texture_handle is bound
|
||||
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTextureHandle());
|
||||
|
||||
std::vector<std::array<GLfloat, 12>> vertices(text.size());
|
||||
std::vector<std::array<GLfloat, 12>> texcoords(text.size());
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
float x2, y2, w, h;
|
||||
CachedGlyph* glyph = cachedFont->getGlyph(text.c_str()[i]);
|
||||
if (glyph == nullptr)
|
||||
continue;
|
||||
|
||||
x2 = x + glyph->x2offset * scale;
|
||||
y2 = y - glyph->y2offset * scale; // Adjust y-coordinate
|
||||
w = glyph->w * scale;
|
||||
h = glyph->h * scale;
|
||||
x += glyph->advanceX * scale;
|
||||
y += glyph->advanceY * scale;
|
||||
|
||||
std::array<GLfloat, 12> glyph_vertices
|
||||
{
|
||||
x2, y2,
|
||||
x2, y2 + h,
|
||||
x2 + w, y2 + h,
|
||||
x2, y2,
|
||||
x2 + w, y2 + h,
|
||||
x2 + w, y2
|
||||
};
|
||||
|
||||
auto glyph_texcoords = glyph->getTexCoords();
|
||||
vertices[i] = glyph_vertices;
|
||||
texcoords[i] = glyph_texcoords;
|
||||
}
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
|
||||
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4fv(default_state.draw_color);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void J3D::DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngleXYZ& angle, bool draw_back_face) {
|
||||
// TODO: Determine the proper scale factor mathematically
|
||||
// This number was arrived at holistically.
|
||||
scale = scale * 0.002f;
|
||||
scale = -scale;
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
float z = pos.z;
|
||||
|
||||
// TODO: this is broken because it causes the text to be shifted downwards.
|
||||
/*
|
||||
bool round_text_coords_for_crisp_rendering = true;
|
||||
|
||||
// TODO: This currently does not account for non-integer scale factors.
|
||||
if (round_text_coords_for_crisp_rendering)
|
||||
{
|
||||
x = J3ML::Math::Floor(x);
|
||||
y = J3ML::Math::Floor(y);
|
||||
z = J3ML::Math::Floor(z);
|
||||
}
|
||||
*/
|
||||
|
||||
CachedFont* cachedFont = fontCache.getFont(size, font.index);
|
||||
if (font.face == nullptr)
|
||||
jlog::Fatal("Drawing a string with an uninitialized font?");
|
||||
|
||||
if (!cachedFont)
|
||||
cachedFont = CacheFont(font, size);
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glColor4ubv(color.ptr());
|
||||
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTextureHandle());
|
||||
|
||||
std::vector<std::array<GLfloat, 18>> vertices(text.size());
|
||||
std::vector<std::array<GLfloat, 12>> texcoords(text.size());
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(x, y, z);
|
||||
glRotatef(angle.pitch, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef(angle.yaw, 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(angle.roll, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
x = y = z = 0;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
CachedGlyph* glyph = cachedFont->getGlyph(text[i]);
|
||||
|
||||
float x2 = x + glyph->x2offset * scale;
|
||||
float y2 = y - glyph->y2offset * scale;
|
||||
float w = glyph->w * scale;
|
||||
float h = glyph->h * scale;
|
||||
|
||||
std::array<GLfloat, 18> glyph_vertices
|
||||
{
|
||||
x2, y2, z,
|
||||
x2, y2 + h, z,
|
||||
x2 + w, y2 + h, z,
|
||||
x2, y2, z,
|
||||
x2 + w, y2 + h, z,
|
||||
x2 + w, y2, z
|
||||
};
|
||||
|
||||
vertices[i] = glyph_vertices;
|
||||
texcoords[i] = glyph->getTexCoords();
|
||||
x += glyph->advanceX * scale;
|
||||
y += glyph->advanceY * scale;
|
||||
}
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
|
||||
|
||||
if (!draw_back_face)
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
|
||||
|
||||
if (!draw_back_face)
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4fv(current_state.draw_color);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
210
src/renderer/OpenGL/internals/internals.cpp
Normal file
210
src/renderer/OpenGL/internals/internals.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "internals.h"
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <JGL/types/Light.h>
|
||||
|
||||
// TODO handle the case that a required light is in the list of optional lights.
|
||||
void JGL::J3D::SelectLights(const Vector3& position) {
|
||||
std::array<const LightBase*, 8> result = current_state.required_lights;
|
||||
|
||||
unsigned int required_light_count = 0;
|
||||
for (const auto& i : result)
|
||||
if (i) required_light_count++;
|
||||
|
||||
// If there is optional lights.
|
||||
if (!current_state.optional_lights.empty()) {
|
||||
// The number of lights we need to solve for
|
||||
unsigned int remaining_lights = 8 - required_light_count;
|
||||
|
||||
std::vector<std::pair<float, const LightBase*>> light_influence;
|
||||
for (const auto* light: current_state.optional_lights)
|
||||
light_influence.emplace_back(light->GetAttenuationAtPosition(position), light);
|
||||
|
||||
// Sort by biggest influence.
|
||||
std::sort(light_influence.begin(), light_influence.end(),
|
||||
[](const auto &a, const auto &b) { return a.first > b.first; });
|
||||
|
||||
// Add in optional lights.
|
||||
for (unsigned int i = 0; i < remaining_lights && i < light_influence.size(); i++)
|
||||
result[required_light_count++] = light_influence[i].second;
|
||||
}
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
for (unsigned int i = 0; i < result.size(); i++) {
|
||||
// Terminate early if we have less than 8 lights.
|
||||
if (!result[i])
|
||||
break;
|
||||
|
||||
Vector4 ambient = { result[i]->GetAmbient().RN(), result[i]->GetAmbient().GN(), result[i]->GetAmbient().BN(), result[i]->GetAmbient().AN() };
|
||||
Vector4 diffuse = { result[i]->GetDiffuse().RN(), result[i]->GetDiffuse().GN(), result[i]->GetDiffuse().BN(), result[i]->GetDiffuse().AN() };
|
||||
Vector4 specular = { result[i]->GetSpecular().RN(), result[i]->GetSpecular().GN(), result[i]->GetSpecular().BN(), result[i]->GetSpecular().AN() };
|
||||
GLenum current_light = GL_LIGHT0 + i;
|
||||
|
||||
glEnable(GL_LIGHT0 + i);
|
||||
glLightfv(current_light, GL_POSITION, result[i]->GetPosition().ptr());
|
||||
|
||||
// How the light will affect different materials.
|
||||
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
|
||||
glLightfv(current_light, GL_DIFFUSE, diffuse.ptr());
|
||||
glLightfv(current_light, GL_SPECULAR, specular.ptr());
|
||||
|
||||
// How far the light goes.
|
||||
glLightf(current_light, GL_CONSTANT_ATTENUATION, result[i]->GetConstantAttenuation());
|
||||
glLightf(current_light, GL_LINEAR_ATTENUATION, result[i]->GetLinearAttenuation());
|
||||
glLightf(current_light, GL_QUADRATIC_ATTENUATION, result[i]->GetQuadraticAttenuation());
|
||||
}
|
||||
}
|
||||
|
||||
void JGL::J3D::ResetLights() {
|
||||
Vector4 position = {0, 0, 1, 0};
|
||||
Vector4 ambient = {0, 0, 0, 1};
|
||||
Vector4 diffuse_light0 = {1,1,1,1};
|
||||
Vector4 diffuse = {0,0,0,1};
|
||||
Vector4 specular_light0 = {1,1,1,1};
|
||||
Vector4 specular = {0,0,0,1};
|
||||
Vector3 spot_direction = {0.0, 0.0, -1.0};
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
GLenum current_light = GL_LIGHT0 + i;
|
||||
|
||||
glLightfv(current_light, GL_POSITION, position.ptr());
|
||||
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
|
||||
glLightf(current_light, GL_CONSTANT_ATTENUATION, 1);
|
||||
glLightf(current_light, GL_LINEAR_ATTENUATION, 0);
|
||||
glLightf(current_light, GL_QUADRATIC_ATTENUATION, 0);
|
||||
glLightf(current_light, GL_SPOT_CUTOFF, 180.0);
|
||||
glLightfv(current_light, GL_SPOT_DIRECTION, spot_direction.ptr());
|
||||
glLightf(current_light, GL_SPOT_EXPONENT, 0.0);
|
||||
glLightfv(current_light, GL_DIFFUSE, (i == 0 ? diffuse_light0.ptr() : diffuse.ptr()));
|
||||
glLightfv(current_light, GL_SPECULAR, (i == 0 ? specular_light0.ptr() : specular.ptr()));
|
||||
glDisable(current_light);
|
||||
}
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
bool JGL::J3D::UsingLighting() {
|
||||
if (!current_state.optional_lights.empty())
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i < current_state.required_lights.size(); i++)
|
||||
if (current_state.required_lights[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Vector3> JGL::TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count) {
|
||||
std::vector<Vector3> normals(vertex_count, Vector3(0, 0, 0));
|
||||
|
||||
for (size_t i = 0; i < index_count; i += 3) {
|
||||
GLuint i1 = indices[i];
|
||||
GLuint i2 = indices[i + 1];
|
||||
GLuint i3 = indices[i + 2];
|
||||
|
||||
Vector3 v1 = vertices[i1];
|
||||
Vector3 v2 = vertices[i2];
|
||||
Vector3 v3 = vertices[i3];
|
||||
|
||||
Vector3 edge1 = v2 - v1;
|
||||
Vector3 edge2 = v3 - v1;
|
||||
|
||||
Vector3 faceNormal = Vector3::Cross(edge1, edge2);
|
||||
|
||||
normals[i1] += faceNormal;
|
||||
normals[i2] += faceNormal;
|
||||
normals[i3] += faceNormal;
|
||||
}
|
||||
for (auto& normal : normals)
|
||||
normal = normal.Normalized();
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
void JGL::StateStack::Push(const JGL::State& state) {
|
||||
states.push_back(state);
|
||||
}
|
||||
|
||||
void JGL::StateStack::Pop() {
|
||||
states.pop_back();
|
||||
}
|
||||
|
||||
JGL::State* JGL::StateStack::PreviousState() {
|
||||
if (states.empty())
|
||||
return nullptr;
|
||||
|
||||
return &states.back();
|
||||
}
|
||||
|
||||
JGL::State JGL::State::SaveState() {
|
||||
State result;
|
||||
|
||||
result.depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
result.vertex_array = glIsEnabled(GL_VERTEX_ARRAY);
|
||||
result.normal_array = glIsEnabled(GL_NORMAL_ARRAY);
|
||||
result.cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
result.blend = glIsEnabled(GL_BLEND);
|
||||
result.texture_2D = glIsEnabled(GL_TEXTURE_2D);
|
||||
result.texture_coordinate_array = glIsEnabled(GL_TEXTURE_COORD_ARRAY);
|
||||
result.color_array = glIsEnabled(GL_COLOR_ARRAY);
|
||||
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &result.selected_texture_unit);
|
||||
result.selected_texture_unit -= GL_TEXTURE0;
|
||||
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, result.clear_color);
|
||||
glGetFloatv(GL_CURRENT_COLOR, result.draw_color);
|
||||
glGetIntegerv(GL_VIEWPORT, result.viewport);
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&result.current_fbo);
|
||||
glGetIntegerv(GL_BLEND_SRC, &result.blend_func[0]);
|
||||
glGetIntegerv(GL_BLEND_DST, &result.blend_func[1]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void JGL::State::RestoreState(const State& state) {
|
||||
if (state.depth_test)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (state.vertex_array)
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (state.normal_array)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (state.cull_face)
|
||||
glEnable(GL_CULL_FACE);
|
||||
else
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (state.blend)
|
||||
glEnable(GL_BLEND);
|
||||
else
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
|
||||
glClientActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
|
||||
|
||||
if (state.texture_2D)
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
else
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
if (state.texture_coordinate_array)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (state.color_array)
|
||||
glEnable(GL_COLOR_ARRAY);
|
||||
else
|
||||
glDisable(GL_COLOR_ARRAY);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, state.current_fbo);
|
||||
glViewport(state.viewport[0], state.viewport[1], state.viewport[2], state.viewport[3]);
|
||||
glClearColor(state.clear_color[0], state.clear_color[1], state.clear_color[2], state.clear_color[3]);
|
||||
glColor4f(state.draw_color[0], state.draw_color[1], state.draw_color[2], state.draw_color[3]);
|
||||
glBlendFunc(state.blend_func[0], state.blend_func[1]);
|
||||
}
|
88
src/renderer/OpenGL/internals/internals.h
Normal file
88
src/renderer/OpenGL/internals/internals.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/types/Light.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
namespace JGL {
|
||||
class State;
|
||||
class StateStack;
|
||||
}
|
||||
|
||||
class JGL::State {
|
||||
public:
|
||||
GLfloat clear_color[4] = {0, 0, 0, 1};
|
||||
GLfloat draw_color[4] = {1, 1, 1, 1};
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
GLint blend_func[2];
|
||||
GLuint current_fbo = 0;
|
||||
RenderTarget* current_render_target = nullptr;
|
||||
|
||||
bool texture_2D = false;
|
||||
bool texture_coordinate_array = false;
|
||||
bool normal_array = false;
|
||||
bool depth_test = false;
|
||||
bool vertex_array = false;
|
||||
bool cull_face = false;
|
||||
bool blend = false;
|
||||
bool color_array = false;
|
||||
GLint selected_texture_unit = 0;
|
||||
// List of lights required for each object in the scene. up-to 8. For example, the sun. Or a flash-light.
|
||||
std::array<const LightBase*, 8> required_lights{};
|
||||
// List of all lights in the scene.
|
||||
std::vector<const LightBase*> optional_lights{};
|
||||
public:
|
||||
static State SaveState();
|
||||
static void RestoreState(const State& state);
|
||||
};
|
||||
|
||||
class JGL::StateStack {
|
||||
private:
|
||||
std::vector<State> states{};
|
||||
public:
|
||||
size_t Size() { return states.size(); }
|
||||
void Push(const State& state);
|
||||
void Pop();
|
||||
State* PreviousState();
|
||||
public:
|
||||
StateStack() = default;
|
||||
~StateStack() = default;
|
||||
};
|
||||
|
||||
namespace JGL {
|
||||
inline constexpr std::array<const LightBase*, 8> empty_light_array = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
|
||||
std::vector<Vector3> TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count);
|
||||
inline StateStack state_stack;
|
||||
inline Vector2i window_size;
|
||||
}
|
||||
|
||||
namespace JGL::J2D {
|
||||
inline State default_state
|
||||
{
|
||||
{0, 0, 0, 1},
|
||||
{1, 1, 1, 1},
|
||||
{0, 0, 0, 0},
|
||||
{GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
|
||||
0, nullptr, false, false,
|
||||
false, false, true, true,
|
||||
true, false, 0,
|
||||
{}, {}
|
||||
};
|
||||
|
||||
inline State current_state;
|
||||
}
|
||||
|
||||
namespace JGL::J3D {
|
||||
inline State current_state;
|
||||
inline float far_plane = 0;
|
||||
inline float fov = 0;
|
||||
// Enables lighting and selects the correct lights to use.
|
||||
void SelectLights(const Vector3& position);
|
||||
// Resets the GL lights to default and disables them. Then, disables lighting.
|
||||
void ResetLights();
|
||||
[[nodiscard]] bool UsingLighting();
|
||||
}
|
169
src/types/Font.cpp
Normal file
169
src/types/Font.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <JGL/JGL.h>
|
||||
|
||||
#if __linux__
|
||||
#include <freetype2/ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_OUTLINE_H
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_OUTLINE_H
|
||||
#endif
|
||||
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/FontCache.h>
|
||||
|
||||
namespace JGL::Detail
|
||||
{
|
||||
FT_Library ft;
|
||||
|
||||
std::vector<Font> fonts;
|
||||
|
||||
bool InitTextEngine() {
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // NOTE: This MUST be called for text rendering to work properly!!!
|
||||
// Keep note of this, might cause problems later?
|
||||
|
||||
if (ft != nullptr)
|
||||
Logger::Fatal("Error::FREETYPE: FT_Library was initialized but is already initialized.");
|
||||
|
||||
if (FT_Init_FreeType(&ft))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void UnloadFont(int font_index) {
|
||||
|
||||
auto iter = fonts.begin();
|
||||
while (iter != fonts.end())
|
||||
{
|
||||
if (iter->index == font_index){
|
||||
FT_Done_Face(iter->face);
|
||||
iter = fonts.erase(iter);
|
||||
} else ++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace JGL {
|
||||
|
||||
bool InitTextEngine() {
|
||||
return Detail::InitTextEngine();
|
||||
}
|
||||
|
||||
Font::Font(const unsigned char* data, const size_t& size) {
|
||||
if (Detail::ft == nullptr)
|
||||
throw std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
|
||||
|
||||
if (FT_New_Memory_Face(Detail::ft, data, size, 0, &face))
|
||||
throw std::runtime_error("Error::FREETYPE: Failed to load font!");
|
||||
|
||||
unsigned int new_index = 0;
|
||||
for (const auto& f : Detail::fonts)
|
||||
if (f.index >= new_index)
|
||||
new_index = f.index + 1;
|
||||
index = new_index;
|
||||
|
||||
Detail::fonts.push_back(*this);
|
||||
std::cout << "Loaded font from memory at " << static_cast<const void*>(data) << " with index " << new_index << std::endl;
|
||||
}
|
||||
|
||||
Font::Font(const std::filesystem::path& path) {
|
||||
if (Detail::ft == nullptr)
|
||||
throw std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
|
||||
|
||||
if (FT_New_Face(Detail::ft, path.string().c_str(), 0, &face))
|
||||
throw std::runtime_error("Error::FREETYPE: Failed to load font!");
|
||||
|
||||
unsigned int new_index = 0;
|
||||
for (const auto& f : Detail::fonts)
|
||||
if (f.index >= new_index)
|
||||
new_index = f.index + 1;
|
||||
|
||||
index = new_index;
|
||||
Detail::fonts.push_back(*this);
|
||||
std::cout << "Loaded font from " << path << " with index " << new_index << std::endl;
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
//Detail::UnloadFont(this->index);
|
||||
}
|
||||
|
||||
|
||||
std::vector<Font> Font::GetLoadedFonts() {
|
||||
return Detail::fonts;
|
||||
}
|
||||
|
||||
|
||||
Font Font::LoadTTF(const std::filesystem::path& path)
|
||||
{
|
||||
return Font(path);
|
||||
}
|
||||
|
||||
Vector2 Font::MeasureString(const std::string &text, unsigned int ptSize) {
|
||||
Vector2 extents = Vector2(0,0);
|
||||
bool font_of_size_in_cache = false;
|
||||
|
||||
for(const auto& f : fontCache.getFonts()) {
|
||||
if (f->getFontSize() == ptSize) {
|
||||
font_of_size_in_cache = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (font_of_size_in_cache) {
|
||||
CachedFont* font;
|
||||
|
||||
for (auto* f: fontCache.getFonts())
|
||||
if (f->getFontSize() == ptSize)
|
||||
font = f;
|
||||
|
||||
for (const char& c : text)
|
||||
extents.x += font->getGlyph(c)->advanceX;
|
||||
|
||||
extents.y = ptSize;
|
||||
return extents;
|
||||
}
|
||||
|
||||
jlog::Warning("Measuring a font size that is not cached, Defaulting to Jupiteroid.");
|
||||
FT_Set_Pixel_Sizes(Fonts::Jupiteroid.face, ptSize, ptSize);
|
||||
|
||||
for (const char& c : text) {
|
||||
// TODO: Fix segfault
|
||||
//FT_GlyphSlot slot = Fonts::Jupiteroid.face->glyph;
|
||||
//auto glyph_index = FT_Get_Char_Index(Fonts::Jupiteroid.face, c);
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
auto glyph_index = FT_Get_Char_Index(this->face, c);
|
||||
|
||||
//auto error = FT_Load_Glyph(Fonts::Jupiteroid.face, glyph_index, FT_LOAD_DEFAULT);
|
||||
auto error = FT_Load_Glyph(this->face, glyph_index, FT_LOAD_DEFAULT);
|
||||
|
||||
if (error)
|
||||
continue;
|
||||
|
||||
|
||||
Vector2 advance = {static_cast<float>(slot->advance.x >> 6),
|
||||
static_cast<float>(slot->advance.y >> 6)};
|
||||
|
||||
|
||||
extents += advance;
|
||||
|
||||
// Gives smaller results than we'd want.
|
||||
if (extents.y < slot->metrics.height / 64)
|
||||
extents.y = slot->metrics.height / 64;
|
||||
|
||||
// Just fucking hardcode it, we know the glyph height is roughly always the ptSize anyway.
|
||||
if (extents.y < ptSize)
|
||||
extents.y = ptSize;
|
||||
}
|
||||
return extents;
|
||||
}
|
||||
}
|
112
src/types/FontCache.cpp
Normal file
112
src/types/FontCache.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include <JGL/types/FontCache.h>
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
char CachedGlyph::getCharacter() const {
|
||||
return character;
|
||||
}
|
||||
|
||||
std::array<GLfloat, 12> CachedGlyph::getTexCoords() const {
|
||||
return texcoords;
|
||||
}
|
||||
|
||||
CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
|
||||
character = c;
|
||||
this->x2offset = x2offset;
|
||||
this->y2offset = y2offset;
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
this->advanceX = advanceX;
|
||||
this->advanceY = advanceY;
|
||||
this->texcoords = texcoords;
|
||||
}
|
||||
|
||||
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
|
||||
glyphs.emplace(glyph->getCharacter(), glyph);
|
||||
}
|
||||
|
||||
unsigned int JGL::CachedFont::getFontSize() const {
|
||||
return font_size;
|
||||
}
|
||||
|
||||
unsigned int JGL::CachedFont::getFontIndex() const {
|
||||
return font_index;
|
||||
}
|
||||
|
||||
CachedGlyph* JGL::CachedFont::getGlyph(char c) {
|
||||
auto it = glyphs.find(c);
|
||||
if (it != glyphs.end())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CachedFont::CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index) {
|
||||
this->texture = texture_id;
|
||||
this->texture_width = texture_width;
|
||||
this->texture_height = texture_height;
|
||||
this->font_size = font_size;
|
||||
this->font_index = font_index;
|
||||
}
|
||||
|
||||
std::unordered_map<char, CachedGlyph*> CachedFont::getGlyphs() {
|
||||
return glyphs;
|
||||
}
|
||||
|
||||
const GLuint* CachedFont::getTextureHandle() {
|
||||
return &texture;
|
||||
}
|
||||
|
||||
GLsizei CachedFont::getTextureWidth() const {
|
||||
return texture_width;
|
||||
}
|
||||
|
||||
GLsizei CachedFont::getTextureHeight() const {
|
||||
return texture_height;
|
||||
}
|
||||
|
||||
void CachedFont::Erase() {
|
||||
if (texture != 0)
|
||||
glDeleteTextures(1, &texture);
|
||||
}
|
||||
|
||||
CachedFont::~CachedFont() {
|
||||
Erase();
|
||||
}
|
||||
|
||||
void FontCache::appendFont(CachedFont* font) {
|
||||
cachedFonts.push_back(font);
|
||||
}
|
||||
|
||||
void FontCache::newFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index) {
|
||||
auto* font = new CachedFont(texture_id, texture_width, texture_height, font_size, font_index);
|
||||
cachedFonts.push_back(font);
|
||||
}
|
||||
|
||||
void FontCache::eraseFont(CachedFont* font) {
|
||||
for (int i = 0; i < cachedFonts.size(); i++) {
|
||||
if (cachedFonts[i] == font) {
|
||||
delete cachedFonts[i];
|
||||
cachedFonts.erase(cachedFonts.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FontCache::purgeCache() {
|
||||
//Remove every font from the cache.
|
||||
for (const auto& font : cachedFonts)
|
||||
eraseFont(font);
|
||||
}
|
||||
|
||||
std::vector<CachedFont*> FontCache::getFonts() {
|
||||
return cachedFonts;
|
||||
}
|
||||
|
||||
CachedFont* FontCache::getFont(unsigned int font_size, unsigned int font_index) {
|
||||
if (cachedFonts.empty())
|
||||
return nullptr;
|
||||
|
||||
for (auto* f : cachedFonts)
|
||||
if (f->getFontIndex() == font_index && f->getFontSize() == font_size)
|
||||
return f;
|
||||
return nullptr;
|
||||
}
|
64
src/types/Light.cpp
Normal file
64
src/types/Light.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <JGL/types/Light.h>
|
||||
|
||||
JGL::PointLight::PointLight(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation, float linear_attenuation, float quadratic_attenuation) {
|
||||
this->position = Vector4(position, 1.0f);
|
||||
this->ambient = ambient;
|
||||
this->diffuse = diffuse;
|
||||
this->specular = specular;
|
||||
this->constant_attenuation = constant_attenuation;
|
||||
this->linear_attenuation = linear_attenuation;
|
||||
this->quadratic_attenuation = quadratic_attenuation;
|
||||
}
|
||||
|
||||
float JGL::PointLight::GetAttenuationAtPosition(const Vector3& pos) const {
|
||||
Vector3 light_pos = {position.x, position.y, position.z};
|
||||
Vector3 vector_to_position = pos - light_pos;
|
||||
float distance = vector_to_position.Length();
|
||||
|
||||
return 1.0f / (GetConstantAttenuation() + GetLinearAttenuation() * distance + GetQuadraticAttenuation() * distance * distance);
|
||||
}
|
||||
|
||||
JGL::SpotLight::SpotLight(const Vector3& position, const Matrix3x3& ro_mat, float cone_size_degrees, float exponent, const Color4& ambient, const Color4& diffuse, const Color4& specular,
|
||||
float constant_attenuation, float linear_attenuation, float quadratic_attenuation) {
|
||||
this->position = Vector4(position, 1);
|
||||
//TODO RotationMatrix to "Normalized direction vector."
|
||||
orientation = ro_mat;
|
||||
this->cut = cone_size_degrees;
|
||||
this->exponent = exponent;
|
||||
this->ambient = ambient;
|
||||
this->diffuse = diffuse;
|
||||
this->specular = specular;
|
||||
this->constant_attenuation = constant_attenuation;
|
||||
this->linear_attenuation = linear_attenuation;
|
||||
this->quadratic_attenuation = quadratic_attenuation;
|
||||
}
|
||||
|
||||
Vector4 JGL::LightBase::GetPosition() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
Color4 JGL::LightBase::GetAmbient() const {
|
||||
return ambient;
|
||||
}
|
||||
|
||||
Color4 JGL::LightBase::GetDiffuse() const {
|
||||
return diffuse;
|
||||
}
|
||||
|
||||
Color4 JGL::LightBase::GetSpecular() const {
|
||||
return specular;
|
||||
}
|
||||
|
||||
float JGL::LightBase::GetConstantAttenuation() const {
|
||||
return constant_attenuation;
|
||||
}
|
||||
|
||||
float JGL::LightBase::GetLinearAttenuation() const {
|
||||
return linear_attenuation;
|
||||
}
|
||||
|
||||
float JGL::LightBase::GetQuadraticAttenuation() const {
|
||||
return quadratic_attenuation;
|
||||
}
|
||||
|
||||
|
31
src/types/Material.cpp
Normal file
31
src/types/Material.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <JGL/types/Material.h>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
|
||||
JGL::Material::Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine) {
|
||||
ambient_ref = ambient_reflection;
|
||||
diffuse_ref = diffuse_reflection;
|
||||
specular_ref = specular_reflection;
|
||||
emission = light_emission;
|
||||
shininess = shine;
|
||||
}
|
||||
|
||||
void JGL::Material::SetActiveMaterial(const Material& material) {
|
||||
Vector4 ambient = { material.ambient_ref.RN(), material.ambient_ref.BN(), material.ambient_ref.GN(), material.ambient_ref.AN() };
|
||||
Vector4 diffuse = { material.diffuse_ref.RN(), material.diffuse_ref.BN(), material.diffuse_ref.GN(), material.diffuse_ref.AN() };
|
||||
Vector4 specular = { material.specular_ref.RN(), material.specular_ref.BN(), material.specular_ref.GN(), material.specular_ref.AN() };
|
||||
Vector4 emission = { material.emission.RN(), material.emission.BN(), material.emission.GN(), material.emission.AN() };
|
||||
|
||||
// Determine which faces we're going to apply this material to.
|
||||
GLenum face = GL_FRONT;
|
||||
if (glIsEnabled(GL_CULL_FACE)) {
|
||||
GLint current; glGetIntegerv(GL_CULL_FACE_MODE, ¤t);
|
||||
if (current == GL_FRONT)
|
||||
face = GL_BACK;
|
||||
}
|
||||
|
||||
glMaterialfv(face, GL_AMBIENT, ambient.ptr());
|
||||
glMaterialfv(face, GL_DIFFUSE, diffuse.ptr());
|
||||
glMaterialfv(face, GL_SPECULAR, specular.ptr());
|
||||
glMaterialfv(face, GL_EMISSION, emission.ptr());
|
||||
glMaterialf(face, GL_SHININESS, material.shininess);
|
||||
}
|
368
src/types/RenderTarget.cpp
Normal file
368
src/types/RenderTarget.cpp
Normal file
@@ -0,0 +1,368 @@
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <stdexcept>
|
||||
|
||||
const JGL::Texture* JGL::RenderTarget::GetTexture() const {
|
||||
return texture;
|
||||
}
|
||||
|
||||
GLuint JGL::RenderTarget::GetTextureHandle() const {
|
||||
return texture->GetHandle();
|
||||
}
|
||||
|
||||
GLuint JGL::RenderTarget::GetGLFramebufferObjectHandle() const {
|
||||
return framebuffer_object;
|
||||
}
|
||||
|
||||
GLuint JGL::RenderTarget::GetGLDepthBufferHandle() const {
|
||||
return depth_buffer;
|
||||
}
|
||||
|
||||
GLuint JGL::RenderTarget::GetActiveGLFramebufferHandle() {
|
||||
GLuint fbo;
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &fbo);
|
||||
return fbo;
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::SetActiveGLRenderTarget(const RenderTarget& render_target) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, render_target.MSAAEnabled() ? render_target.msaa_framebuffer_object : render_target.GetGLFramebufferObjectHandle());
|
||||
glViewport(0,0, render_target.GetDimensions().x, render_target.GetDimensions().y);
|
||||
}
|
||||
|
||||
Vector2i JGL::RenderTarget::GetDimensions() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Erase() {
|
||||
if (GetActiveGLFramebufferHandle() == framebuffer_object)
|
||||
Logger::Warning("Deleting the framebuffer that's currently in use?");
|
||||
|
||||
if (using_depth)
|
||||
glDeleteRenderbuffers(1, &depth_buffer);
|
||||
|
||||
glDeleteFramebuffers(1, &framebuffer_object);
|
||||
|
||||
if (MSAAEnabled())
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
}
|
||||
|
||||
Color4 JGL::RenderTarget::GetClearColor() const {
|
||||
return clear_color;
|
||||
}
|
||||
|
||||
/// Idk why you'd ever want to clear it out if you're rendering onto a texture you passed in :shrug:.
|
||||
JGL::RenderTarget::RenderTarget(const JGL::Texture* texture, const Color4& clear_color) {
|
||||
if (texture->GetDimensions().x < 1 || texture->GetDimensions().y < 1)
|
||||
Logger::Fatal("Creating a render target where the color attachment is empty?");
|
||||
|
||||
this->size = { static_cast<int>(texture->GetDimensions().x), static_cast<int>(texture->GetDimensions().y) };
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
glGenFramebuffers(1, &framebuffer_object);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
glViewport(0,0, size.x, size.y);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetHandle(), 0);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
throw std::runtime_error("A new framebuffer could not be allocated.");
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
this->clear_color = clear_color;
|
||||
this->texture = texture;
|
||||
texture_created_by_us = false;
|
||||
}
|
||||
|
||||
JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate, FilteringMode filtering_mode) {
|
||||
if (size.x < 1 || size.y < 1)
|
||||
Logger::Fatal("Creating a render target where the color attachment is empty?");
|
||||
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
//Textures behave strangely if they're not square aaaaaaaaaaaaa.
|
||||
|
||||
texture = new Texture(size, filtering_mode);
|
||||
glGenFramebuffers(1, &framebuffer_object);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
glViewport(0,0, size.x, size.y);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetHandle(), 0);
|
||||
|
||||
if (use_depth) {
|
||||
GLuint depthBuffer;
|
||||
glGenRenderbuffers(1, &depthBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
using_depth = true;
|
||||
}
|
||||
|
||||
GLfloat old_clear_color[4];
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
|
||||
glClearColor(clear_color.RedChannelNormalized(), clear_color.GreenChannelNormalized(), clear_color.BlueChannelNormalized(), clear_color.AlphaChannelNormalized());
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
throw std::runtime_error("A new framebuffer could not be allocated.");
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
this->clear_color = clear_color;
|
||||
this->size = size;
|
||||
texture_created_by_us = true;
|
||||
|
||||
if (sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
SetMSAAEnabled(sample_rate);
|
||||
}
|
||||
|
||||
std::vector<GLfloat> JGL::RenderTarget::GetPixels() const {
|
||||
std::vector<GLfloat> data(GetDimensions().x * GetDimensions().y * 4);
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
glReadPixels(0, 0, GetDimensions().x, GetDimensions().y, GL_RGBA, GL_FLOAT, data.data());
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
return data;
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Resize(const Vector2i& new_size) {
|
||||
if (!texture_created_by_us)
|
||||
Logger::Error("Resizing a Render Target that does not own it's texture?");
|
||||
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLfloat old_clear_color[4];
|
||||
GLint old_viewport[4] = {0, 0, 0, 0};
|
||||
glGetIntegerv(GL_VIEWPORT, old_viewport);
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
|
||||
|
||||
//If we have to remake the texture.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
|
||||
// Erase it.
|
||||
delete texture;
|
||||
|
||||
auto cc = GetClearColor();
|
||||
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
|
||||
glViewport(0,0, size.x, size.y);
|
||||
|
||||
texture = new Texture(new_size);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetHandle(), 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
|
||||
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
|
||||
size = new_size;
|
||||
|
||||
//Disable & Re-enable MSAA so the msaa buffer is remade with the correct dimensions.
|
||||
if (MSAAEnabled()) {
|
||||
MSAA_SAMPLE_RATE current_sample_rate = msaa_sample_rate;
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
SetMSAAEnabled(current_sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
JGL::RenderTarget::~RenderTarget() {
|
||||
Erase();
|
||||
if (texture_created_by_us)
|
||||
delete texture;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::OwnsTexture() const {
|
||||
return texture_created_by_us;
|
||||
}
|
||||
|
||||
JGL::MSAA_SAMPLE_RATE JGL::RenderTarget::GetMSAASampleRate() const {
|
||||
return msaa_sample_rate;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::MSAAEnabled() const {
|
||||
return msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
// If we'd be setting the same sample_rate we already have.
|
||||
if (sample_rate == msaa_sample_rate)
|
||||
return false;
|
||||
|
||||
// If we'd be rendering onto a texture and not a plain render target we don't want this.
|
||||
if (!OwnsTexture())
|
||||
return false;
|
||||
|
||||
// Remove it if they request no msaa or if what they requested is different than what they already have.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE || msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE) {
|
||||
if(using_depth)
|
||||
glDeleteRenderbuffers(1, &msaa_depth_buffer);
|
||||
|
||||
glDeleteRenderbuffers(1, &msaa_render_buffer);
|
||||
glDeleteFramebuffers(1, &msaa_framebuffer_object);
|
||||
|
||||
msaa_framebuffer_object = 0;
|
||||
msaa_depth_buffer = 0;
|
||||
msaa_render_buffer = 0;
|
||||
msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
|
||||
// Only return here if they specifically requested no MSAA. else continue to change mode.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
glGenFramebuffers(1, &msaa_framebuffer_object);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, msaa_framebuffer_object);
|
||||
|
||||
GLint current_renderbuffer = 0;
|
||||
glGetIntegerv(GL_RENDERBUFFER_BINDING, ¤t_renderbuffer);
|
||||
glGenRenderbuffers(1, &msaa_render_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa_render_buffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, to_int(sample_rate), GL_RGBA, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa_render_buffer);
|
||||
|
||||
if (using_depth) {
|
||||
glGenRenderbuffers(1, &msaa_depth_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa_depth_buffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, to_int(sample_rate), GL_DEPTH_COMPONENT, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaa_depth_buffer);
|
||||
}
|
||||
|
||||
bool failure = false;
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
failure = true, Logger::Fatal("A new " + to_string(sample_rate) + " framebuffer couldn't be allocated.");
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, current_renderbuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
msaa_sample_rate = sample_rate;
|
||||
|
||||
if (failure)
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
return failure;
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::MSAABlit() const {
|
||||
if (MSAAEnabled() && OwnsTexture()) {
|
||||
// Save the GL state.
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint current_draw_fbo = 0;
|
||||
GLint current_read_fbo = 0;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, ¤t_read_fbo);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_draw_fbo);
|
||||
|
||||
// Draw the contents of one into the other.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaa_framebuffer_object);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer_object);
|
||||
glBlitFramebuffer(0, 0, size.x, size.y, 0, 0, size.x, size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
// Put the GL state back.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, current_read_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget* destination, const Vector2i& position) {
|
||||
if (source.GetDimensions().x > destination->GetDimensions().x || source.GetDimensions().y > destination->GetDimensions().y)
|
||||
Logger::Warning("Blitting a Render Target onto another Render Target but the destination Render Target is too small?");
|
||||
|
||||
// Save the GL state.
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint current_draw_fbo = 0;
|
||||
GLint current_read_fbo = 0;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, ¤t_read_fbo);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_draw_fbo);
|
||||
|
||||
// Draw the contents of one into the other.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.framebuffer_object);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination->framebuffer_object);
|
||||
glBlitFramebuffer(0, 0, source.size.x, source.size.y, position.x, position.y, position.x + source.size.x, position.y + source.size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
// Put the GL state back.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, current_read_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit(const Texture* source, RenderTarget* destination, const Vector2i& position) {
|
||||
auto temp = new RenderTarget(source);
|
||||
Blit(*temp, destination);
|
||||
delete temp;
|
||||
}
|
||||
|
||||
// To avoid repeatedly allocating and deallocating.
|
||||
JGL::RenderTarget* pixel = nullptr;
|
||||
void JGL::RenderTarget::Blit(const Color4& color, const Vector2i& position, JGL::RenderTarget* destination) {
|
||||
if (position.x > destination->size.x || position.y > destination->size.y)
|
||||
Logger::Warning("Blitting outside of the renderable area of the destination.");
|
||||
|
||||
if (pixel == nullptr)
|
||||
pixel = new RenderTarget({1,1});
|
||||
|
||||
GLint current_draw_fbo = 0;
|
||||
GLint current_read_fbo = 0;
|
||||
GLint viewport[4];
|
||||
GLfloat clear_color[4];
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, clear_color);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, ¤t_read_fbo);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_draw_fbo);
|
||||
|
||||
SetActiveGLRenderTarget(*pixel);
|
||||
glClearColor(color.RedChannelNormalized(), color.GreenChannelNormalized(), color.BlueChannelNormalized(), color.AlphaChannelNormalized());
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Invert so it's relative to the top left corner.
|
||||
int target_y = destination->size.y - position.y - 1;
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, pixel->framebuffer_object);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination->framebuffer_object);
|
||||
glBlitFramebuffer(0, 0, 1, 1, position.x, target_y, position.x + 1, target_y + 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, current_read_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
|
||||
}
|
||||
|
||||
JGL::RenderTarget::RenderTarget(const JGL::RenderTarget& rhs) {
|
||||
auto* this_render_target = new RenderTarget(rhs.size, rhs.clear_color, rhs.using_depth, rhs.msaa_sample_rate);
|
||||
RenderTarget::Blit(rhs, this_render_target);
|
||||
|
||||
this->clear_color = this_render_target->clear_color;
|
||||
this->size = this_render_target->size;
|
||||
this->using_depth = this_render_target->using_depth;
|
||||
this->texture_created_by_us = true;
|
||||
this->texture = this_render_target->texture;
|
||||
this->framebuffer_object = this_render_target->framebuffer_object;
|
||||
this->depth_buffer = this_render_target->depth_buffer;
|
||||
this->msaa_sample_rate = this_render_target->msaa_sample_rate;
|
||||
this->msaa_framebuffer_object = this_render_target->msaa_framebuffer_object;
|
||||
this->msaa_depth_buffer = this_render_target->msaa_depth_buffer;
|
||||
this->msaa_render_buffer = this_render_target->msaa_render_buffer;
|
||||
|
||||
operator delete(this_render_target);
|
||||
}
|
||||
|
||||
Vector2i JGL::RenderTarget::MaximumSize() {
|
||||
return Texture::MaximumSize();
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::RegenerateMipMaps() {
|
||||
// Fixes using render targets on a texture that has mipmaps.
|
||||
if (GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_NEAREST
|
||||
|| GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_BILINEAR ||
|
||||
GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_TRILINEAR) {
|
||||
GLint current_texture = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, GetTexture()->GetHandle());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, current_texture);
|
||||
}
|
||||
}
|
186
src/types/Skeleton.cpp
Normal file
186
src/types/Skeleton.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include <JGL/types/Skeleton.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
std::array<int, 4> JGL::SkeletalVertexAttribute::GetAffectingBoneIDs() const {
|
||||
return bone_ids;
|
||||
}
|
||||
|
||||
std::array<float, 4> JGL::SkeletalVertexAttribute::GetAffectingBoneWeights() const {
|
||||
return bone_weights;
|
||||
}
|
||||
|
||||
JGL::SkeletalVertexAttribute::SkeletalVertexAttribute(const std::vector<int>& ids, const std::vector<float>& weights) {
|
||||
|
||||
if (bone_ids.size() > 4 || bone_weights.size() > 4)
|
||||
Logger::Fatal("Initialization of a skeletal vertex that is effected by more than 4 bones.");
|
||||
|
||||
memcpy(this->bone_ids.data(), bone_ids.data(), sizeof(int) * 4);
|
||||
memcpy(this->bone_weights.data(), bone_weights.data(), sizeof(float) * 4);
|
||||
}
|
||||
|
||||
bool JGL::Bone::IsRootBone() const {
|
||||
if (parent_id == -1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int JGL::Bone::GetID() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string JGL::Bone::GetName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
Matrix4x4 JGL::Bone::GetInverseBindMatrix() const {
|
||||
return inverse_bind_matrix;
|
||||
}
|
||||
|
||||
Matrix4x4 JGL::Bone::GetOffsetMatrix() const {
|
||||
return offset_matrix;
|
||||
}
|
||||
|
||||
Matrix4x4 JGL::Bone::GetFinalTransform() const {
|
||||
return final_transform;
|
||||
}
|
||||
|
||||
std::vector<int> JGL::Bone::GetChildren() const {
|
||||
return children;
|
||||
}
|
||||
|
||||
void Bone::SetParent(int parent_identifier) {
|
||||
parent_id = parent_identifier;
|
||||
}
|
||||
|
||||
void Bone::AppendChild(int new_child) {
|
||||
children.push_back(new_child);
|
||||
}
|
||||
|
||||
void Bone::SetID(int numeric_id) {
|
||||
id = numeric_id;
|
||||
}
|
||||
|
||||
void Bone::SetName(const std::string& string_id) {
|
||||
name = string_id;
|
||||
}
|
||||
|
||||
void Bone::SetInverseBindMatrix(const Matrix4x4& inverse_bind) {
|
||||
inverse_bind_matrix = inverse_bind;
|
||||
}
|
||||
|
||||
void Bone::SetOffsetMatrix(const Matrix4x4& offset) {
|
||||
offset_matrix = offset;
|
||||
}
|
||||
|
||||
void Bone::SetFinalTransformMatrix(const Matrix4x4& final) {
|
||||
final_transform = final;
|
||||
}
|
||||
|
||||
int Bone::GetParentID() const {
|
||||
return parent_id;
|
||||
}
|
||||
|
||||
Bone::Bone(int numeric_id, const std::string& string_id, int parent_bone, const std::vector<int>& children_ids, const Matrix4x4& inverse_bind, const Matrix4x4& offset, const Matrix4x4& final) {
|
||||
id = numeric_id;
|
||||
name = string_id;
|
||||
parent_id = parent_bone;
|
||||
inverse_bind_matrix = inverse_bind;
|
||||
offset_matrix = offset;
|
||||
final_transform = final;
|
||||
children = children_ids;
|
||||
}
|
||||
|
||||
Bone* Skeleton::GetRootBone() {
|
||||
return &root;
|
||||
}
|
||||
|
||||
Bone* Skeleton::FindBone(int id) {
|
||||
if (root.GetID() == id)
|
||||
return &root;
|
||||
|
||||
for (auto& bone : bones)
|
||||
if (bone.GetID() == id)
|
||||
return &bone;
|
||||
// If we couldn't find it.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Bone* Skeleton::FindBone(const std::string& string_id) {
|
||||
if (root.GetName() == string_id)
|
||||
return &root;
|
||||
|
||||
for (auto& bone : bones)
|
||||
if (bone.GetName() == string_id)
|
||||
return &bone;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Skeleton::AppendBone(const Bone& new_bone) {
|
||||
bones.push_back(new_bone);
|
||||
}
|
||||
|
||||
Skeleton::Skeleton(const Bone& root_bone, const std::vector<Bone>& children) {
|
||||
root = root_bone;
|
||||
bones = children;
|
||||
}
|
||||
|
||||
float KeyFrame::GetTimeStamp() const {
|
||||
return time_stamp;
|
||||
}
|
||||
|
||||
Skeleton KeyFrame::GetSkeleton() const {
|
||||
return pose;
|
||||
}
|
||||
|
||||
KeyFrame::KeyFrame(const Skeleton& pose, float time_stamp) {
|
||||
this->pose = pose;
|
||||
this->time_stamp = time_stamp;
|
||||
}
|
||||
|
||||
Animation::Animation(int id, float duration, const std::vector<KeyFrame>& key_frames, const std::vector<SkeletalVertexAttribute>& skeletal_vertex_attributes,
|
||||
const std::string& name) {
|
||||
length = duration;
|
||||
this->key_frames = key_frames;
|
||||
this->id = id;
|
||||
this->name = name;
|
||||
this->vertex_attributes = skeletal_vertex_attributes;
|
||||
}
|
||||
|
||||
float Animation::GetDuratrion() const {
|
||||
return length;
|
||||
}
|
||||
|
||||
std::vector<KeyFrame> Animation::GetKeyFrames() const {
|
||||
return key_frames;
|
||||
}
|
||||
|
||||
void Animation::AppendKeyFrame(const KeyFrame& new_key) {
|
||||
key_frames.push_back(new_key);
|
||||
}
|
||||
|
||||
void Animation::SetDuration(float duration) {
|
||||
length = duration;
|
||||
}
|
||||
|
||||
int Animation::GetID() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string Animation::GetName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
void Animation::SetID(int identifier) {
|
||||
id = identifier;
|
||||
}
|
||||
|
||||
void Animation::SetName(const std::string& name_id) {
|
||||
name = name_id;
|
||||
}
|
||||
|
||||
std::vector<SkeletalVertexAttribute> Animation::GetSkeletalVertexAttributes() const {
|
||||
return vertex_attributes;
|
||||
}
|
312
src/types/Texture.cpp
Normal file
312
src/types/Texture.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <glad/glad.h>
|
||||
#include <fstream>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "internals/stb_image.h"
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
Texture::Texture(const std::filesystem::path& file, FilteringMode filtering_mode, WrappingMode wrapping_mode, bool invert_y) :
|
||||
invert_y(invert_y), filtering_mode(filtering_mode), wrapping_mode(wrapping_mode) {
|
||||
std::vector<unsigned char> pixels{};
|
||||
|
||||
std::ifstream ifStream(file, std::ios::in | std::ios::binary);
|
||||
if (!ifStream.is_open())
|
||||
Logger::Fatal("Trying to load a texture from: " + file.string() + "but we couldn't read the file.");
|
||||
|
||||
unsigned char bmpFileHeader[14];
|
||||
|
||||
ifStream.read(reinterpret_cast<char*>(bmpFileHeader), 14);
|
||||
if (bmpFileHeader[0] == 'B' && bmpFileHeader[1] == 'M')
|
||||
pixels = bmp(file);
|
||||
|
||||
//TODO determine if it's a PNG using the file header instead.
|
||||
else if (file.string().ends_with(".png"))
|
||||
pixels = png(file);
|
||||
ifStream.close();
|
||||
|
||||
|
||||
if (invert_y) {
|
||||
unsigned int row_size = size.x * 4;;
|
||||
if (format == ColorFormat::RGB)
|
||||
row_size = size.x * 3;
|
||||
|
||||
std::vector<unsigned char> temp(row_size);
|
||||
for (unsigned int y = 0; y < size.y / 2; ++y) {
|
||||
unsigned char *topRow = &pixels[y * row_size];
|
||||
unsigned char *bottomRow = &pixels[(size.y - y - 1) * row_size];
|
||||
std::copy(bottomRow, bottomRow + row_size, temp.begin());
|
||||
std::copy(topRow, topRow + row_size, bottomRow);
|
||||
std::copy(temp.begin(), temp.end(), topRow);
|
||||
}
|
||||
}
|
||||
|
||||
load(pixels.data());
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Texture::png(const std::filesystem::path& file) {
|
||||
std::vector<unsigned char> result{};
|
||||
int channels;
|
||||
|
||||
unsigned char* image_data = stbi_load(file.c_str(), &size.x, &size.y, &channels, 0);
|
||||
if (!image_data)
|
||||
Logger::Fatal("Trying to load a texture from: " + file.string() + "but we couldn't read the file.");
|
||||
|
||||
if (channels == 4)
|
||||
format = ColorFormat::RGBA;
|
||||
else if (channels == 3)
|
||||
format = ColorFormat::RGB;
|
||||
|
||||
if (image_data)
|
||||
result.assign(image_data, image_data + size.x * size.y * channels);
|
||||
|
||||
stbi_image_free(image_data);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Texture::bmp(const std::filesystem::path& file) {
|
||||
std::vector<unsigned char> result{};
|
||||
std::ifstream bmp_file(file, std::ios::in | std::ios::binary);
|
||||
|
||||
unsigned char bmpFileHeader[14];
|
||||
unsigned char bmpInfoHeader[40];
|
||||
|
||||
bmp_file.read(reinterpret_cast<char *>(bmpFileHeader), 14);
|
||||
bmp_file.read(reinterpret_cast<char *>(bmpInfoHeader), 40);
|
||||
|
||||
size.x = bmpInfoHeader[4] + (bmpInfoHeader[5] << 8) + (bmpInfoHeader[6] << 16) + (bmpInfoHeader[7] << 24);
|
||||
size.y = bmpInfoHeader[8] + (bmpInfoHeader[9] << 8) + (bmpInfoHeader[10] << 16) + (bmpInfoHeader[11] << 24);
|
||||
|
||||
int row_padded = (size.x * 3 + 3) & (~3);
|
||||
result.resize(size.x * size.y * 3);
|
||||
|
||||
std::vector<unsigned char> rowData(row_padded);
|
||||
for (int y = size.y - 1; y >= 0; --y) {
|
||||
bmp_file.read(reinterpret_cast<char *>(rowData.data()), row_padded);
|
||||
for (int x = 0; x < size.x; ++x) {
|
||||
result[(y * size.x + x) * 3 + 2] = rowData[x * 3 + 0];
|
||||
result[(y * size.x + x) * 3 + 1] = rowData[x * 3 + 1];
|
||||
result[(y * size.x + x) * 3 + 0] = rowData[x * 3 + 2];
|
||||
}
|
||||
}
|
||||
|
||||
bmp_file.close();
|
||||
format = ColorFormat::RGB;
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture::Texture(const Vector2i& size, FilteringMode filtering_mode) : invert_y(true), format(ColorFormat::RGBA), size(size), filtering_mode(filtering_mode), wrapping_mode(WrappingMode::CLAMP_TO_EDGE) {
|
||||
if (SizeExceedsMaximum(size))
|
||||
Logger::Error("Creating a texture where the size is bigger than the maximum for this system.");
|
||||
GLuint previous_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
|
||||
|
||||
glGenTextures(1, &texture_handle);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_handle);
|
||||
//NEAREST
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
if (filtering_mode == FilteringMode::NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if (filtering_mode == FilteringMode::MIPMAP_NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_TRILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
//Clamp
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glBindTexture(GL_TEXTURE_2D, previous_texture);
|
||||
}
|
||||
void Texture::load(const unsigned char* pixels) {
|
||||
if (SizeExceedsMaximum(size))
|
||||
Logger::Error("Creating a texture where the size is bigger than the maximum for this system.");
|
||||
|
||||
GLuint previous_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
|
||||
|
||||
glGenTextures(1, &texture_handle);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_handle);
|
||||
|
||||
if (format == ColorFormat::RGBA)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
else if (format == ColorFormat::RGB)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.x, size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
if (wrapping_mode == WrappingMode::CLAMP_TO_EDGE)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
else if (wrapping_mode == WrappingMode::REPEAT)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
else if (wrapping_mode == WrappingMode::MIRRORED_REPEAT)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
||||
|
||||
else if (wrapping_mode == WrappingMode::CLAMP_TO_BORDER)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
|
||||
if (filtering_mode == FilteringMode::NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_NEAREST ||
|
||||
filtering_mode == FilteringMode::MIPMAP_BILINEAR ||
|
||||
filtering_mode == FilteringMode::MIPMAP_TRILINEAR) {
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
|
||||
if (filtering_mode == FilteringMode::MIPMAP_NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_TRILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, previous_texture);
|
||||
}
|
||||
|
||||
std::vector<Color4> JGL::Texture::GetPixelData() const {
|
||||
GLint current_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
std::vector<Color4> result((size_t) (size.x * size.y));
|
||||
glBindTexture(GL_TEXTURE_2D, texture_handle);
|
||||
|
||||
if (format == ColorFormat::RGBA) {
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, result.data());
|
||||
glBindTexture(GL_TEXTURE_2D, current_texture);
|
||||
return result;
|
||||
}
|
||||
|
||||
//if RGB
|
||||
std::vector<Color3> color3((size_t) (size.x * size.y));
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, color3.data());
|
||||
for (const auto &c: color3)
|
||||
result.emplace_back(c);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, current_texture);
|
||||
return result;
|
||||
}
|
||||
|
||||
GLuint Texture::GetHandle() const {
|
||||
return texture_handle;
|
||||
}
|
||||
|
||||
Vector2i Texture::GetDimensions() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
bool Texture::Inverted() const {
|
||||
return invert_y;
|
||||
}
|
||||
|
||||
ColorFormat Texture::GetFormat() const {
|
||||
return format;
|
||||
}
|
||||
|
||||
FilteringMode Texture::GetFilteringMode() const {
|
||||
return filtering_mode;
|
||||
}
|
||||
|
||||
WrappingMode Texture::GetWrappingMode() const {
|
||||
return wrapping_mode;
|
||||
}
|
||||
|
||||
Texture::Texture(const Color4* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode) :
|
||||
size(size), format(format), filtering_mode(filtering_mode), wrapping_mode(wrapping_mode) {
|
||||
load((unsigned char*) pixels);
|
||||
}
|
||||
|
||||
Texture::Texture(const Color3* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode) :
|
||||
size(size), format(format), filtering_mode(filtering_mode), wrapping_mode(wrapping_mode) {
|
||||
load((unsigned char*) pixels);
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
if (texture_handle != 0)
|
||||
glDeleteTextures(1, &texture_handle);
|
||||
texture_handle = 0;
|
||||
}
|
||||
|
||||
Texture::Texture(const Texture& rhs) {
|
||||
auto* this_texture = new Texture(rhs.GetDimensions());
|
||||
auto this_render_target = RenderTarget(this_texture);
|
||||
auto rhs_render_target = RenderTarget(&rhs);
|
||||
|
||||
RenderTarget::Blit(rhs_render_target, &this_render_target);
|
||||
|
||||
this->texture_handle = this_texture->texture_handle;
|
||||
this->size = this_texture->size;
|
||||
this->invert_y = this_texture->invert_y;
|
||||
this->format = this_texture->format;
|
||||
this->filtering_mode = this_texture->filtering_mode;
|
||||
this->wrapping_mode = this_texture->wrapping_mode;
|
||||
operator delete(this_texture);
|
||||
}
|
||||
|
||||
Texture::Texture(const Texture* textures, const size_t& texture_count) {
|
||||
int length = 0;
|
||||
int biggest_y = 0;
|
||||
|
||||
for (int i = 0; i < texture_count; i++) {
|
||||
if (biggest_y < textures[i].size.y)
|
||||
biggest_y = textures[i].size.y;
|
||||
length += textures[i].size.x;
|
||||
}
|
||||
|
||||
auto* result = new Texture(Vector2i(length, biggest_y));
|
||||
auto render_target = RenderTarget(result);
|
||||
|
||||
int next_x = 0;
|
||||
for (int i = 0; i < texture_count; i++) {
|
||||
RenderTarget::Blit(&textures[i], &render_target, Vector2i(next_x, 0));
|
||||
next_x += textures[i].GetDimensions().x;
|
||||
}
|
||||
}
|
||||
|
||||
bool Texture::SizeExceedsMaximum(const Vector2i& s) {
|
||||
|
||||
auto max_size = Texture::MaximumSize();
|
||||
return s.x > max_size.x || s.y > max_size.y;
|
||||
}
|
||||
|
||||
Vector2i Texture::MaximumSize() {
|
||||
GLint max_size;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
|
||||
|
||||
return { max_size, max_size };
|
||||
}
|
302
src/types/VRamList.cpp
Normal file
302
src/types/VRamList.cpp
Normal file
@@ -0,0 +1,302 @@
|
||||
#include <JGL/types/VRamList.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <cstring>
|
||||
|
||||
void JGL::VRamList::load(const GLfloat* data, const long& size) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
GLint current_array_buffer = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_array_buffer);
|
||||
glGenBuffers(1, &list_handle);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, current_array_buffer);
|
||||
element_array_buffer = false;
|
||||
num_elements = size / sizeof(GLfloat);
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
void JGL::VRamList::load(const GLuint* data, const long& size) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
GLint current_element_array_buffer = 0;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤t_element_array_buffer);
|
||||
glGenBuffers(1, &list_handle);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_element_array_buffer);
|
||||
element_array_buffer = true;
|
||||
num_elements = size / sizeof(GLuint);
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
void JGL::VRamList::Erase() {
|
||||
if (list_handle == 0)
|
||||
return;
|
||||
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
GLint current_element_array_buffer = 0;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤t_element_array_buffer);
|
||||
GLint current_array_buffer = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_array_buffer);
|
||||
|
||||
if (element_array_buffer && current_element_array_buffer == list_handle)
|
||||
JGL::Logger::Warning("Erasing an element array buffer while it's in use?");
|
||||
|
||||
else if (!element_array_buffer && current_array_buffer == list_handle)
|
||||
JGL::Logger::Warning("Erasing an array buffer while it's in use?");
|
||||
|
||||
glDeleteBuffers(1, &list_handle);
|
||||
list_handle = 0;
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
GLuint JGL::VRamList::GetHandle() const {
|
||||
return list_handle;
|
||||
}
|
||||
|
||||
bool JGL::VRamList::IsFloatArray() const {
|
||||
return !element_array_buffer;
|
||||
}
|
||||
|
||||
long JGL::VRamList::GetLength() const {
|
||||
return num_elements;
|
||||
}
|
||||
|
||||
size_t JGL::VRamList::GetDataSize() const {
|
||||
if (element_array_buffer)
|
||||
return sizeof(GLuint) * num_elements;
|
||||
return sizeof(GLfloat) * num_elements;
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(void* data, const long& length) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
bool should_resize = (this->num_elements != length);
|
||||
if (should_resize) {
|
||||
glDeleteBuffers(1, &list_handle);
|
||||
list_handle = 0;
|
||||
spin_lock = false;
|
||||
element_array_buffer ? load((GLuint*) data, sizeof(GLuint) * length) : load((GLfloat*) data, sizeof(GLfloat) * length);
|
||||
return;
|
||||
}
|
||||
|
||||
// if (!should resize)
|
||||
GLint current_buffer = 0;
|
||||
GLenum buffer_type = GL_ARRAY_BUFFER;
|
||||
GLenum buffer_binding = GL_ARRAY_BUFFER_BINDING;
|
||||
if (element_array_buffer)
|
||||
buffer_type = GL_ELEMENT_ARRAY_BUFFER,
|
||||
buffer_binding = GL_ELEMENT_ARRAY_BUFFER_BINDING;
|
||||
|
||||
glGetIntegerv(buffer_binding, ¤t_buffer);
|
||||
glBindBuffer(buffer_type, list_handle);
|
||||
|
||||
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
|
||||
if (!vram)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
memcpy(vram, data, (element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat)) * length);
|
||||
|
||||
if (!glUnmapBuffer(buffer_type))
|
||||
JGL::Logger::Fatal("We couldn't unmap the buffer?");
|
||||
|
||||
glBindBuffer(buffer_type, current_buffer);
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(void* data, const long& offset, const long& length) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
if (offset + length > num_elements) {
|
||||
JGL::Logger::Warning("Using UpdateData to out-of-bounds write the VRamList? I'll resize it for you, But this is slow.");
|
||||
unsigned long oob_delta = (offset + length) - num_elements;
|
||||
|
||||
if (element_array_buffer) {
|
||||
auto list_data = GetDataUI();
|
||||
list_data.resize(list_data.size() + oob_delta);
|
||||
memcpy(list_data.data() + (offset * sizeof(GLuint)), data, length * sizeof(GLuint));
|
||||
spin_lock = false; // This is going unlock and relock really fast, But this code fixes something considered wrong anyway - Redacted.
|
||||
return SetData(list_data.data(), list_data.size());
|
||||
}
|
||||
|
||||
// if (!element_array_buffer)
|
||||
auto list_data = GetDataF();
|
||||
list_data.resize(list_data.size() + oob_delta);
|
||||
memcpy(list_data.data() + (offset * sizeof(GLfloat)), data, length * sizeof(GLfloat));
|
||||
spin_lock = false;
|
||||
return SetData(list_data.data(), list_data.size());
|
||||
}
|
||||
|
||||
GLint current_buffer = 0;
|
||||
GLenum buffer_type = GL_ARRAY_BUFFER;
|
||||
GLenum buffer_binding = GL_ARRAY_BUFFER_BINDING;
|
||||
|
||||
if (element_array_buffer)
|
||||
buffer_type = GL_ELEMENT_ARRAY_BUFFER,
|
||||
buffer_binding = GL_ELEMENT_ARRAY_BUFFER_BINDING;
|
||||
|
||||
glGetIntegerv(buffer_binding, ¤t_buffer);
|
||||
glBindBuffer(buffer_type, list_handle);
|
||||
|
||||
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
|
||||
if (!vram)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
|
||||
memcpy(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(vram) + (offset * element_size)), data, length * element_size);
|
||||
|
||||
if (!glUnmapBuffer(buffer_type))
|
||||
JGL::Logger::Fatal("We couldn't unmap the buffer?");
|
||||
|
||||
glBindBuffer(buffer_type, current_buffer);
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
std::vector<GLfloat> JGL::VRamList::GetDataF() const {
|
||||
while (spin_lock) {}
|
||||
|
||||
if (element_array_buffer)
|
||||
JGL::Logger::Warning("Getting data as GLfloat but the buffer data is GLuint?");
|
||||
|
||||
bool vertex_array_enabled = glIsEnabled(GL_VERTEX_ARRAY);
|
||||
if (!vertex_array_enabled)
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
GLint current_buffer = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
|
||||
|
||||
std::vector<GLfloat> data(num_elements);
|
||||
void* vram = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
|
||||
if (vram == nullptr)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
memcpy(data.data(), vram, num_elements * sizeof(GLfloat));
|
||||
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, current_buffer);
|
||||
|
||||
if (!vertex_array_enabled)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<GLuint> JGL::VRamList::GetDataUI() const {
|
||||
while (spin_lock) {}
|
||||
|
||||
if (!element_array_buffer)
|
||||
JGL::Logger::Warning("Getting data as GLuint but the buffer data is GLfloat?");
|
||||
|
||||
GLint current_buffer = 0;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤t_buffer);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
|
||||
std::vector<GLuint> data(num_elements);
|
||||
|
||||
void* vram = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
|
||||
if (vram == nullptr)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
memcpy(data.data(), vram, num_elements * sizeof(GLuint));
|
||||
|
||||
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_buffer);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const GLfloat* data, const long& length) {
|
||||
load(data, (long) sizeof(GLfloat) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const GLuint* data, const long& length) {
|
||||
load(data, (long) sizeof(GLuint) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const Vector2* data, const long& length) {
|
||||
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector2) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const Vector3* data, const long& length) {
|
||||
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector3) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const Vector4* data, const long& length) {
|
||||
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector4) * length);
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(const GLfloat* data, const long& length) {
|
||||
SetData((void*) data, length);
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(const Vector2* data, const long& length) {
|
||||
SetData((void*) data, length * 2);
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(const Vector3* data, const long& length) {
|
||||
SetData((void*) data, length * 3);
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(const Vector4* data, const long& length) {
|
||||
SetData((void*) data, length * 4);
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(const GLuint* data, const long& length) {
|
||||
SetData((void*) data, length);
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(const Vector2i* data, const long& length) {
|
||||
SetData((void*) data, length * 2);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const GLfloat* data, const long& offset, const long& length) {
|
||||
UpdateData((void*) data, offset, length);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const Vector2* data, const long& offset, const long& length) {
|
||||
UpdateData((void*) data, offset, length * 2);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const Vector3* data, const long& offset, const long& length) {
|
||||
UpdateData((void*) data, offset, length * 3);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const Vector4* data, const long& offset, const long& length) {
|
||||
UpdateData((void*) data, offset, length * 4);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const GLuint* data, const long& offset, const long& length) {
|
||||
UpdateData((void*) data, offset, length);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const Vector2i* data, const long& offset, const long& length) {
|
||||
UpdateData((void*) data, offset, length * 2);
|
||||
}
|
||||
|
||||
JGL::VRamList::~VRamList() {
|
||||
Erase();
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
|
||||
while (rhs.spin_lock) {}
|
||||
|
||||
if (rhs.element_array_buffer) {
|
||||
auto data_array = rhs.GetDataUI();
|
||||
this->load(data_array.data(), data_array.size());
|
||||
}
|
||||
|
||||
auto data_array = rhs.GetDataF();
|
||||
this->load(data_array.data(), data_array.size());
|
||||
}
|
179
src/types/VertexArray.cpp
Normal file
179
src/types/VertexArray.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
#include <JGL/types/VertexArray.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
const VRamList* VertexArray::GetVertices() const {
|
||||
return vertices;
|
||||
}
|
||||
|
||||
const VRamList* VertexArray::GetIndices() const {
|
||||
return indices;
|
||||
}
|
||||
|
||||
const VRamList* VertexArray::GetNormals() const {
|
||||
return normals;
|
||||
}
|
||||
|
||||
const VRamList* VertexArray::GetTextureCoordinates() const {
|
||||
return texture_coordinates;
|
||||
}
|
||||
|
||||
std::vector<Vertex> VertexArray::GetLocalVertices() const {
|
||||
return local_vertices;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> VertexArray::GetLocalIndices() const {
|
||||
return local_indices;
|
||||
}
|
||||
|
||||
std::vector<TextureCoordinate> VertexArray::GetLocalTextureCoordinates() const {
|
||||
return local_texture_coordinates;
|
||||
}
|
||||
|
||||
std::vector<Normal> VertexArray::GetLocalNormals() const {
|
||||
return local_normals;
|
||||
}
|
||||
|
||||
Sphere VertexArray::GetMESphere(const Vector3& scale, const Vector3& translate_part) const {
|
||||
if (scale == Vector3::One)
|
||||
return { me_sphere.Position + translate_part, me_sphere.Radius };
|
||||
|
||||
float scale_factor = 0;
|
||||
if (scale.x > scale_factor)
|
||||
scale_factor = scale.x;
|
||||
if (scale.y > scale_factor)
|
||||
scale_factor = scale.y;
|
||||
if (scale.z > scale_factor)
|
||||
scale_factor = scale.z;
|
||||
|
||||
return { me_sphere.Position + translate_part, me_sphere.Radius * scale_factor };
|
||||
}
|
||||
|
||||
Sphere VertexArray::GetMESphere(const Matrix4x4& instance_matrix, bool translate) const {
|
||||
Vector3 scale = instance_matrix.GetScale();
|
||||
Vector3 origin = Vector3::Zero;
|
||||
if (translate)
|
||||
origin = instance_matrix.GetTranslatePart();
|
||||
|
||||
return GetMESphere(scale, origin);
|
||||
}
|
||||
|
||||
void VertexArray::CreateMESphere() {
|
||||
Sphere result = {Vector3::Zero, 0};
|
||||
Vector3 minimum = {std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
|
||||
Vector3 maximum = { std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest()};
|
||||
|
||||
for (const auto& vertex : local_vertices) {
|
||||
if (vertex.x < minimum.x)
|
||||
minimum.x = vertex.x;
|
||||
if (vertex.x > maximum.x)
|
||||
maximum.x = vertex.x;
|
||||
|
||||
if (vertex.y < minimum.y)
|
||||
minimum.y = vertex.y;
|
||||
if (vertex.y > maximum.y)
|
||||
maximum.y = vertex.y;
|
||||
|
||||
if (vertex.z < minimum.z)
|
||||
minimum.z = vertex.z;
|
||||
if (vertex.z > maximum.z)
|
||||
maximum.z = vertex.z;
|
||||
}
|
||||
result.Position = (minimum + maximum) * 0.5f;
|
||||
for (const auto& vertex : local_vertices) {
|
||||
float distance_squared = Vector3::DistanceSquared(result.Position, vertex);
|
||||
if (distance_squared > result.Radius)
|
||||
result.Radius = distance_squared;
|
||||
}
|
||||
result.Radius = std::sqrt(result.Radius);
|
||||
me_sphere = result;
|
||||
}
|
||||
|
||||
void VertexArray::CreateMEOBB() {
|
||||
Vector3 minimum(std::numeric_limits<float>::max());
|
||||
Vector3 maximum (std::numeric_limits<float>::min());
|
||||
|
||||
for (const auto& vertex : local_vertices) {
|
||||
if (vertex.x < minimum.x)
|
||||
minimum.x = vertex.x;
|
||||
if (vertex.x > maximum.x)
|
||||
maximum.x = vertex.x;
|
||||
|
||||
if (vertex.y < minimum.y)
|
||||
minimum.y = vertex.y;
|
||||
if (vertex.y > maximum.y)
|
||||
maximum.y = vertex.y;
|
||||
|
||||
if (vertex.z < minimum.z)
|
||||
minimum.z = vertex.z;
|
||||
if (vertex.z > maximum.z)
|
||||
maximum.z = vertex.z;
|
||||
}
|
||||
|
||||
Vector3 position = (minimum + maximum) * 0.5f;
|
||||
Vector3 half_extents = (maximum - minimum) * 0.5f;
|
||||
|
||||
me_obb = { position, half_extents, Vector3::UnitX, Vector3::UnitY, Vector3::UnitZ };
|
||||
}
|
||||
|
||||
OBB VertexArray::GetMEOBB(const Matrix3x3& rotation_matrix, const Vector3& scale, const Vector3& translate_part) const {
|
||||
Vector3 half_extents = me_obb.r.Mul(scale);
|
||||
Vector3 axis0 = rotation_matrix * me_obb.axis[0];
|
||||
Vector3 axis1 = rotation_matrix * me_obb.axis[1];
|
||||
Vector3 axis2 = rotation_matrix * me_obb.axis[2];
|
||||
Vector3 position = me_obb.pos + translate_part;
|
||||
|
||||
return { position, half_extents, axis0, axis1, axis2 };
|
||||
}
|
||||
|
||||
OBB VertexArray::GetMEOBB(const Matrix4x4& instance_matrix, bool translate) const {
|
||||
return GetMEOBB(instance_matrix.GetRotatePart(), instance_matrix.GetScale(), translate ? instance_matrix.GetTranslatePart() : Vector3::Zero);
|
||||
}
|
||||
|
||||
AABB VertexArray::GetMEAABB(const Matrix3x3& rotation_matrix, const Vector3& scale, const Vector3& translate_part) const {
|
||||
/* kind-of a cheat. It's faster to calculate the oriented bounding box and then put the axis-aligned one around that
|
||||
* than to loop over the whole model like an idiot. You gain back all the speed with the simplicity of the physics anyways. - Redacted */
|
||||
return GetMEOBB(rotation_matrix, scale, translate_part).MinimalEnclosingAABB();
|
||||
}
|
||||
|
||||
AABB VertexArray::GetMEAABB(const Matrix4x4& instance_matrix, bool translate) const {
|
||||
return GetMEAABB(instance_matrix.GetRotatePart(), instance_matrix.GetScale(), translate ? instance_matrix.GetTranslatePart() : Vector3::Zero);
|
||||
}
|
||||
|
||||
VertexArray::VertexArray(const Vector3* vertex_positions, const long& vp_length, const unsigned int* vertex_indices, const long& vi_length,
|
||||
const Normal* vertex_normals, const long& vn_length, const TextureCoordinate* texture_coordinates, const long& vt_length) {
|
||||
|
||||
// TODO decimator. This is a total waste of memory as it sits.
|
||||
this->vertices = new VRamList(vertex_positions, vp_length);
|
||||
|
||||
local_vertices.resize(vp_length);
|
||||
memcpy(local_vertices.data(), vertex_positions, sizeof(Vector3) * vp_length);
|
||||
|
||||
if (vertex_indices && vi_length) {
|
||||
indices = new VRamList(vertex_indices, vi_length);
|
||||
local_indices.resize(vi_length);
|
||||
memcpy(local_indices.data(), vertex_indices, sizeof(unsigned int) * vi_length);
|
||||
}
|
||||
|
||||
if (vertex_normals && vn_length) {
|
||||
normals = new VRamList(vertex_normals, vn_length);
|
||||
local_normals.resize(vn_length);
|
||||
memcpy(local_normals.data(), vertex_indices, sizeof(Normal) * vn_length);
|
||||
}
|
||||
|
||||
if (texture_coordinates && vt_length) {
|
||||
this->texture_coordinates = new VRamList(texture_coordinates, vt_length);
|
||||
local_texture_coordinates.resize(vt_length);
|
||||
memcpy(local_texture_coordinates.data(), texture_coordinates, sizeof(TextureCoordinate) * vt_length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VertexArray::VertexArray(const std::vector<Vertex>& vertex_positions, const std::vector<unsigned int>& vertex_indices, const std::vector<Normal>& vertex_normals, const std::vector<TextureCoordinate>& texture_coordinates) {
|
||||
*this = VertexArray(vertex_positions.data(), vertex_positions.size(), vertex_indices.data(), vertex_indices.size(), vertex_normals.data(), vertex_normals.size(), texture_coordinates.data(), texture_coordinates.size());
|
||||
}
|
||||
|
||||
bool VertexArray::Static() {
|
||||
return animations.empty();
|
||||
}
|
7988
src/types/internals/stb_image.h
Normal file
7988
src/types/internals/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
334
src/types/model/WavefrontOBJ.cpp
Normal file
334
src/types/model/WavefrontOBJ.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
#include <JGL/types/VertexArray.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
std::pair<float, unsigned long> ParseNumber(const std::string& file_text, const unsigned long& offset) {
|
||||
std::string number;
|
||||
unsigned long new_offset = offset;
|
||||
bool decimal_used = false;
|
||||
|
||||
if (offset >= file_text.size())
|
||||
return {0.0f, offset};
|
||||
|
||||
for (; new_offset < file_text.size(); new_offset++) {
|
||||
if (file_text[new_offset] == '-') {
|
||||
if (number.empty()) {
|
||||
number.push_back(file_text[new_offset]);
|
||||
continue;
|
||||
}
|
||||
Logger::Error("Error while parsing number, Index: " + std::to_string(new_offset) + " Extra negative sign.");
|
||||
return {0.0f, offset};
|
||||
}
|
||||
|
||||
else if (file_text[new_offset] == '.') {
|
||||
if (!decimal_used) {
|
||||
number.push_back(file_text[new_offset]);
|
||||
decimal_used = true;
|
||||
continue;
|
||||
}
|
||||
Logger::Error("Error parsing number at: " + std::to_string(new_offset) + " Extra decimal point.");
|
||||
return {0.0f, offset};
|
||||
}
|
||||
|
||||
else if (isdigit(file_text[new_offset]))
|
||||
number.push_back(file_text[new_offset]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return {std::stof(number), new_offset};
|
||||
}
|
||||
|
||||
std::pair<Vector2, unsigned long> ParseVector2(const std::string& file_text, const unsigned long& offset) {
|
||||
auto x_result = ParseNumber(file_text, offset);
|
||||
auto y_result = ParseNumber(file_text, x_result.second + 1);
|
||||
|
||||
// If the new offset is the same as the offset we passed in then we know it didn't work.
|
||||
if (x_result.second == offset || y_result.second == x_result.second)
|
||||
return {Vector2(0, 0), offset};
|
||||
|
||||
return {Vector2(x_result.first, y_result.first), y_result.second + 1};
|
||||
}
|
||||
|
||||
std::pair<Vector3, unsigned long> ParseVector3(const std::string& file_text, const unsigned long& offset) {
|
||||
auto x_result = ParseNumber(file_text, offset);
|
||||
auto y_result = ParseNumber(file_text, x_result.second + 1);
|
||||
auto z_result = ParseNumber(file_text, y_result.second + 1);
|
||||
|
||||
// If the new offset is the same as the offset we passed in then we know it didn't work.
|
||||
if (x_result.second == offset || y_result.second == x_result.second || z_result.second == y_result.second)
|
||||
return {Vector3(0,0,0), offset};
|
||||
|
||||
return {Vector3(x_result.first, y_result.first, z_result.first), z_result.second + 1};
|
||||
}
|
||||
|
||||
std::pair<Vector4, unsigned long> ParseVector4(const std::string& file_text, const unsigned long& offset) {
|
||||
auto x_result = ParseNumber(file_text, offset);
|
||||
auto y_result = ParseNumber(file_text, x_result.second + 1);
|
||||
auto z_result = ParseNumber(file_text, y_result.second + 1);
|
||||
auto w_result = ParseNumber(file_text, z_result.second + 1);
|
||||
|
||||
if (x_result.second == offset || y_result.second == x_result.second || z_result.second == y_result.second || w_result.second == z_result.second)
|
||||
return {Vector4(0, 0, 0, 0), offset};
|
||||
|
||||
return {Vector4(x_result.first, y_result.first, z_result.first, w_result.first), w_result.second + 1};
|
||||
}
|
||||
|
||||
std::pair<std::array<Vector3, 3>, unsigned long> ParseWavefrontFaceData(const std::string& file_text, const unsigned long& offset) {
|
||||
unsigned long new_offset = offset;
|
||||
std::array<Vector3, 3> face_data;
|
||||
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
Vector3 vertex = {-1, -1, -1};
|
||||
|
||||
// Vertex
|
||||
if (std::isdigit(file_text[new_offset])) {
|
||||
auto v_result = ParseNumber(file_text, new_offset);
|
||||
vertex.x = v_result.first;
|
||||
new_offset = v_result.second;
|
||||
}
|
||||
|
||||
// UV
|
||||
if (new_offset < file_text.size() && file_text[new_offset] == '/') {
|
||||
new_offset++;
|
||||
|
||||
if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
|
||||
auto vt_result = ParseNumber(file_text, new_offset);
|
||||
vertex.y = vt_result.first;
|
||||
new_offset = vt_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Normal
|
||||
if (new_offset < file_text.size() && file_text[new_offset] == '/') {
|
||||
new_offset++;
|
||||
|
||||
if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
|
||||
auto vn_result = ParseNumber(file_text, new_offset);
|
||||
vertex.z = vn_result.first;
|
||||
new_offset = vn_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
face_data[i] = vertex;
|
||||
new_offset++;
|
||||
}
|
||||
return {face_data, new_offset};
|
||||
}
|
||||
|
||||
VertexArray VertexArray::LoadWavefrontOBJ(const std::string &file_text) {
|
||||
std::vector<std::array<Vector3, 3>> faceline_data;
|
||||
|
||||
std::vector<TextureCoordinate> temp_uvs;
|
||||
std::vector<Normal> temp_normals;
|
||||
std::vector<Vertex> temp_vertices;
|
||||
|
||||
unsigned long offset = 0;
|
||||
while (offset < file_text.size()) {
|
||||
char c = file_text[offset];
|
||||
|
||||
// TODO the entire line a comment is on should be skipped.
|
||||
// Skip forward to the character after the next newline.
|
||||
if (c == '#' || c == '\n' || c == '\r') {
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Vertices
|
||||
if (c == 'v' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
|
||||
offset += 2;
|
||||
|
||||
auto vertex_result = ParseVector3(file_text, offset);
|
||||
if (vertex_result.second != offset) {
|
||||
temp_vertices.push_back(vertex_result.first);
|
||||
offset = vertex_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Normals.
|
||||
else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 'n' &&
|
||||
file_text[offset + 2] == ' ') {
|
||||
offset += 3;
|
||||
|
||||
auto normal_result = ParseVector3(file_text, offset);
|
||||
if (normal_result.second != offset) {
|
||||
temp_normals.push_back(normal_result.first);
|
||||
offset = normal_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Texture Coordinates
|
||||
else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 't' &&
|
||||
file_text[offset + 2] == ' ') {
|
||||
offset += 3;
|
||||
|
||||
auto uv_result = ParseVector2(file_text, offset);
|
||||
if (uv_result.second != offset) {
|
||||
temp_uvs.push_back(uv_result.first);
|
||||
offset = uv_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Face lines.
|
||||
else if (c == 'f' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
|
||||
offset += 2;
|
||||
|
||||
auto faceline_result = ParseWavefrontFaceData(file_text, offset);
|
||||
if (faceline_result.second != offset) {
|
||||
faceline_data.push_back(faceline_result.first);
|
||||
offset = faceline_result.second;
|
||||
}
|
||||
} else
|
||||
offset++;
|
||||
}
|
||||
|
||||
// Pick everything out of the face lines and set up how OpenGL expects.
|
||||
std::vector<Vertex> final_vertices;
|
||||
std::vector<TextureCoordinate> final_uvs;
|
||||
std::vector<Normal> final_normals;
|
||||
std::vector<unsigned int> final_indices;
|
||||
for (const auto &face: faceline_data) {
|
||||
for (const auto &vp: face) {
|
||||
Vertex vertex;
|
||||
TextureCoordinate uv;
|
||||
Normal normal;
|
||||
|
||||
if (vp.x != -1)
|
||||
vertex = temp_vertices[vp.x - 1];
|
||||
if (vp.y != -1)
|
||||
uv = temp_uvs[vp.y - 1];
|
||||
if (vp.z != -1)
|
||||
normal = temp_normals[vp.z - 1];
|
||||
|
||||
final_vertices.push_back(vertex);
|
||||
final_uvs.push_back(uv);
|
||||
final_normals.push_back(normal);
|
||||
final_indices.push_back((unsigned int) final_vertices.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return VertexArray(
|
||||
final_vertices.data(), final_vertices.size(),
|
||||
final_indices.data(), final_indices.size(),
|
||||
final_normals.data(), final_normals.size(),
|
||||
final_uvs.data(), final_uvs.size());
|
||||
}
|
||||
|
||||
/*
|
||||
VertexArray JGL::LoadAMO(const std::string& file_text) {
|
||||
std::vector<Vector3> temp_vertices;
|
||||
std::vector<Vector3> temp_normals;
|
||||
std::vector<Vector2> temp_uvs;
|
||||
std::vector<std::array<Vector3, 3>> faceline_data;
|
||||
std::string name;
|
||||
|
||||
unsigned long offset = 0;
|
||||
while (offset < file_text.size()) {
|
||||
char c = file_text[offset];
|
||||
|
||||
// If we've dropped on a newline character somehow then just skip passed it.
|
||||
if (c == '\n' || c == '\r') {
|
||||
offset++; continue;
|
||||
}
|
||||
|
||||
// File name.
|
||||
else if (offset + 2 < file_text.size() && c == 'a' && file_text[offset + 1] == 'o' && file_text[offset + 2] == ' ') {
|
||||
offset += 3;
|
||||
while (offset < file_text.size()) {
|
||||
if (file_text[offset] != '\n' && file_text[offset] != '\r')
|
||||
name.push_back(file_text[offset]), offset++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertices
|
||||
else if (offset + 1 < file_text.size() && c == 'v' && file_text[offset + 1] == ' ') {
|
||||
offset += 2; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Vertex count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long vertex_count = parsed_number.first;
|
||||
offset = parsed_number.second;
|
||||
|
||||
for (unsigned long i = 0; i < vertex_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
auto parsed_vector3 = ParseVector3(file_text, offset);
|
||||
if (parsed_vector3.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Vertex at: " + std::to_string(offset));
|
||||
|
||||
temp_vertices.push_back(parsed_vector3.first);
|
||||
offset = parsed_vector3.second;
|
||||
}
|
||||
}
|
||||
|
||||
// UVs
|
||||
else if (offset + 2 < file_text.size() && c == 'v' && file_text[offset + 1] == 't' && file_text[offset + 2] == ' ') {
|
||||
offset += 3; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the UV count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long uv_count = parsed_number.first;
|
||||
offset = parsed_number.second;
|
||||
|
||||
for (unsigned long i = 0; i < uv_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
auto parsed_vector2 = ParseVector2(file_text, offset);
|
||||
if (parsed_vector2.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the UV at: " + std::to_string(offset));
|
||||
|
||||
temp_uvs.push_back(parsed_vector2.first);
|
||||
offset = parsed_vector2.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Normals
|
||||
else if (offset + 2 < file_text.size() && c == 'v' && file_text[offset + 1] == 'n' && file_text[offset + 2] == ' ') {
|
||||
offset += 3; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Normal count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long uv_count = parsed_number.first;
|
||||
offset = parsed_number.second;
|
||||
|
||||
for (unsigned long i = 0; i < uv_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
auto parsed_vector3 = ParseVector3(file_text, offset);
|
||||
if (parsed_vector3.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Normal at: " + std::to_string(offset));
|
||||
|
||||
temp_normals.push_back(parsed_vector3.first);
|
||||
offset = parsed_vector3.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Face Lines
|
||||
else if (offset + 1 < file_text.size() && c == 'f' && file_text[offset + 1] == ' ') {
|
||||
offset += 2; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Face Line count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long faceline_count = parsed_number.first;
|
||||
for (unsigned long i = 0; i < faceline_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
Reference in New Issue
Block a user