Compare commits
131 Commits
Prerelease
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
41916a4089 | |||
222dd346fb | |||
e6e567725b | |||
93612bb816 | |||
9ac22a8a87 | |||
1eaa9c6574 | |||
|
f5f590164a | ||
c45485cabd | |||
143703dea3 | |||
|
48493cb2fc | ||
5b7829b1f8 | |||
868f52464e |
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 && 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 }}."
|
110
CMakeLists.txt
110
CMakeLists.txt
@@ -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,59 +9,103 @@ 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-4.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME J3ML
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/Prerelease-18.zip
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/Release-3.2.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ReWindow
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/vA0.2.16.zip
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-21.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_fboV2.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME jlog
|
||||
URL https://git.redacted.cc/josh/jlog/Prerelease-16.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ReImage
|
||||
URL https://git.redacted.cc/Redacted/ReImage/archive/Release-2.0.zip
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
#CPMAddPackage(
|
||||
#NAME harfbuzz
|
||||
#URL https://github.com/harfbuzz/harfbuzz/archive/refs/tags/9.0.0.zip
|
||||
#)
|
||||
|
||||
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" )
|
||||
file(GLOB_RECURSE ASSETS "content/*")
|
||||
|
||||
add_library(JGL SHARED ${SOURCES}
|
||||
include/JGL/JGL.h
|
||||
src/JGL/JGL.cpp
|
||||
include/LearnOpenGL/Shader.h
|
||||
include/LearnOpenGL/Texture2D.h
|
||||
include/JGL/Color3.h
|
||||
include/JGL/Colors.h
|
||||
include/JGL/Color4.h
|
||||
)
|
||||
set_target_properties(JGL PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
|
||||
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)
|
||||
|
||||
#Don't expose these ones.
|
||||
include_directories(
|
||||
${ReWindow_SOURCE_DIR}/include
|
||||
${Event_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_include_directories(JGL PUBLIC
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${OPENGL_INCLUDE_DIRS}
|
||||
${ReImage_SOURCE_DIR}/include
|
||||
${mcolor_SOURCE_DIR}/include
|
||||
${J3ML_SOURCE_DIR}/include
|
||||
${glad_SOURCE_DIR}/include
|
||||
${jlog_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(${GLUT_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_link_libraries(JGL PRIVATE ${FREETYPE_LIBRARIES})
|
||||
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS})
|
||||
target_link_libraries(JGL_Demo PUBLIC JGL ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} J3ML ReWindowLibrary GLEW 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 ${OPENGL_LIBRARIES} mcolor J3ML glad jlog ReImage)
|
||||
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 ReImage)
|
||||
endif()
|
||||
|
||||
target_link_libraries(JGL_Demo PUBLIC JGL ReWindowLibrary Event)
|
||||
|
64
README.md
64
README.md
@@ -1,11 +1,59 @@
|
||||
# Josh 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
|
||||

|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* Modern C++ (20)
|
||||
* Provides single-function-calls to render various graphics primitives in 2D and 3D.
|
||||
* Integrates directly with our other toolkits (ReWindow, J3ML)
|
||||
* Quick Rendering of Debug Text, Geometric Widgets, Textures, and so forth.
|
||||
* Little-to-no overhead.
|
||||
* Integrates right into an existing OpenGL rendering system.
|
||||
* High-performance text rendering.
|
||||
|
||||
## API Overview
|
||||
|
||||
### J2D
|
||||
* DrawPoint
|
||||
* DrawLine / DrawGradientLine
|
||||
* DrawSprite
|
||||
* OutlineRect / FillRect / FillGradientRect / FillRoundedRect
|
||||
* OutlineCircle / FillCircle
|
||||
* OutlineTriangle / FillTriangle
|
||||
* DrawString
|
||||
### J3D
|
||||
* DrawLine
|
||||
* DrawString
|
||||
* DrawMatrixGizmo (WIP)
|
||||
* DrawAxisAngleGizmo (WIP)
|
||||
* DrawQuaternionGizmo (WIP)
|
||||
|
||||
### Types
|
||||
* Font
|
||||
* Sprite
|
||||
* Color4/Color3
|
||||
* Gradient
|
||||
|
||||
## Usage
|
||||
|
||||
Install instructions and code samples coming soon :tm: !
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation is (sic: will be) automatically generated from latest commit and is hosted at https://doc.redacted.cc/jgl .
|
||||
|
||||
## 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!
|
||||
|
||||
## License
|
||||
|
||||
JGL is licensed under the Public Domain. See the LICENSE file for details.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
JGL is developed and maintained by Josh O'Leary @ Co from Redacted Software and contributors. Special thanks to Redacted.
|
BIN
assets/fonts/Jupiteroid.ttf
Normal file
BIN
assets/fonts/Jupiteroid.ttf
Normal file
Binary file not shown.
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 |
@@ -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,97 +1,192 @@
|
||||
//
|
||||
// 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-07-16
|
||||
|
||||
|
||||
#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>
|
||||
|
||||
// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
|
||||
/// 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;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct Triangle2D
|
||||
{
|
||||
Vector2 A;
|
||||
Vector2 B;
|
||||
Vector2 C;
|
||||
};
|
||||
|
||||
struct Triangle3D
|
||||
{
|
||||
Vector3 A;
|
||||
Vector3 B;
|
||||
Vector3 C;
|
||||
};
|
||||
|
||||
bool InitTextEngine();
|
||||
|
||||
// TODO: implement correct coloring
|
||||
using J3ML::u32;
|
||||
|
||||
void Update(const Vector2& window_size);
|
||||
inline void PurgeFontCache() { fontCache.purgeCache(); }
|
||||
std::array<GLfloat, 16> OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far);
|
||||
/// Returns true if the graphics driver meets the requirements (GL Version & Extensions).
|
||||
bool MeetsRequirements();
|
||||
/// Drawing functions for primitive 2D Shapes.
|
||||
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);
|
||||
/// 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.
|
||||
void Begin(RenderTarget* render_target = nullptr, bool clear_buffers = false);
|
||||
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
|
||||
/// @see Begin().
|
||||
void End();
|
||||
/// 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 LightArray(Light*, size_t size);
|
||||
void LightArray(std::vector<Light> lights);
|
||||
|
||||
/// 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.
|
||||
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 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);
|
||||
|
||||
///Draws a line with a gradient that transitions across it.
|
||||
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 x, float y, float w, float h, float thickness = 1);
|
||||
|
||||
/// Draws an outline of a rectangle on the screen.
|
||||
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||
|
||||
/// Draws a filled rectangle on the screen.
|
||||
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
|
||||
|
||||
/// Draws a filled rectangle where the color transitions across it.
|
||||
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.
|
||||
void FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
|
||||
|
||||
/// Draws a render target to the screen.
|
||||
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 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
|
||||
/// @param position
|
||||
/// @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 32-bit RGBA value represented as four unsigned 8-bit integers.
|
||||
/// @param inversion inverts the texture only.
|
||||
/// @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,
|
||||
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
|
||||
/// @param position
|
||||
/// @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
|
||||
/// @param scale
|
||||
/// @param color
|
||||
/// @param inversion
|
||||
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);
|
||||
|
||||
/// 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
|
||||
/// @param position
|
||||
/// @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
|
||||
/// @param color
|
||||
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.
|
||||
void OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
|
||||
|
||||
/// Draws a filled circle on the screen.
|
||||
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
|
||||
/// @param tri
|
||||
/// @param thickness
|
||||
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.
|
||||
void FillTriangle(const Color4& color, const Triangle2D& tri);
|
||||
void FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC);
|
||||
|
||||
/// Draws a triangle where each corner is defined by a given color, Smoothly transitioning between them.
|
||||
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri);
|
||||
|
||||
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.
|
||||
void OutlinePolygon(const Color4& color, const std::vector<Vector2>& points, float thickness = 1);
|
||||
|
||||
/// Draws a text string on the screen with a given point-size and font.
|
||||
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font);
|
||||
|
||||
/// TODO Implement the following. These ones are going to be extremely annoying.
|
||||
void FillPolygon(const Color4& color, const std::vector<Vector2>& points);
|
||||
void FillTexturedPolygon();
|
||||
void OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, float thickness = 1);
|
||||
void FillTexturedTriangle();
|
||||
}
|
||||
|
||||
/// Drawing functions for primitive 3D Shapes.
|
||||
namespace J3D {
|
||||
void Init(const Vector2& window_size, float fov, float far_plane);
|
||||
void ChangeFOV(float fov);
|
||||
void ChangeFarPlane(float far_plane);
|
||||
void Begin();
|
||||
void End();
|
||||
void SetMatrix(const std::vector<GLfloat>& matrix, const Vector2& window_size);
|
||||
void DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness = 1);
|
||||
void FillSphere(const Color3& color, const Sphere& sphere);
|
||||
void WireframeSphere(const Color3& color, const Sphere& sphere, float thickness = 1);
|
||||
void FillOBB(const Color3& color, const OBB& obb);
|
||||
void WireframeOBB(const Color3& color, const OBB& obb, float thickness = 1);
|
||||
void FillCapsule(const Color3& color, const Capsule& capsule);
|
||||
void WireframeCapsule(const Color3& color, const Capsule& cap, float thickness = 1);
|
||||
void FillTriangleMesh(const Color3& color, const TriangleMesh& mesh);
|
||||
void WireframeTriangleMesh(const Color3& color, const TriangleMesh& mesh, float thickness = 1);
|
||||
void DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngle& angle = {0, 0, 0}, bool draw_back_face = false);
|
||||
void DrawSprite();
|
||||
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
|
||||
void DrawMatrixGizmo (const Matrix4x4&);
|
||||
void DrawAxisAngleGizmo (const AxisAngle&, 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;
|
||||
|
||||
}
|
72
include/JGL/types/Enums.h
Normal file
72
include/JGL/types/Enums.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
40
include/JGL/types/Font.h
Normal file
40
include/JGL/types/Font.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#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
|
||||
{
|
||||
|
||||
/// Initializes FreeType engine. Remember to call this during program initialization.
|
||||
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;
|
||||
Font(const std::filesystem::path& path);
|
||||
/// 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;
|
||||
};
|
||||
}
|
67
include/JGL/types/FontCache.h
Normal file
67
include/JGL/types/FontCache.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#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();
|
||||
[[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;
|
||||
public:
|
||||
void appendGlyph(CachedGlyph* glyph);
|
||||
unsigned int getFontSize();
|
||||
unsigned int getFontIndex();
|
||||
CachedGlyph* getGlyph(char c);
|
||||
std::unordered_map<char, CachedGlyph*> getGlyphs();
|
||||
const GLuint* getTexture();
|
||||
[[nodiscard]] GLsizei getTextureWidth() const;
|
||||
[[nodiscard]] GLsizei getTextureHeight() const;
|
||||
CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
30
include/JGL/types/Light.h
Normal file
30
include/JGL/types/Light.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <Color4.hpp>
|
||||
|
||||
namespace JGL {
|
||||
class Light;
|
||||
class OmnidirectionalLight2D;
|
||||
class PointLight2D;
|
||||
}
|
||||
|
||||
class JGL::Light {
|
||||
private:
|
||||
/// W in position seems to determine whether or not the light is omni-directional. 1 = omni 0 = point.
|
||||
/// Position is un-normalized screen space. For ex 500, 500, 1 for a light coming from where you're sitting.
|
||||
Vector4 position = {0, 0, 0, 1};
|
||||
Color4 ambient = {0, 0, 0, 0};
|
||||
Color4 diffuse = {0, 0, 0, 0};
|
||||
Color4 specular = {0, 0, 0, 0};
|
||||
public:
|
||||
Light(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular);
|
||||
Vector3 GetNormalizedSceenSpaceCoordinates() const;
|
||||
};
|
||||
|
||||
class JGL::OmnidirectionalLight2D {
|
||||
private:
|
||||
public:
|
||||
OmnidirectionalLight2D(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular);
|
||||
|
||||
};
|
4
include/JGL/types/Material.h
Normal file
4
include/JGL/types/Material.h
Normal file
@@ -0,0 +1,4 @@
|
||||
/// A simple wrapper for OpenGL materials. Lets you set things such as the "shininess" of your elements.
|
||||
class Material {
|
||||
|
||||
};
|
63
include/JGL/types/RenderTarget.h
Normal file
63
include/JGL/types/RenderTarget.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <Color4.hpp>
|
||||
#include <Colors.hpp>
|
||||
#include <JGL/types/Enums.h>
|
||||
|
||||
namespace JGL {
|
||||
class RenderTarget;
|
||||
}
|
||||
|
||||
//TODO copy constructor for this. Copying this as it is and then that copy going out of scope will crash the program as it sits.
|
||||
//If you do copy it you're doing it wrong. But still.
|
||||
|
||||
class JGL::RenderTarget {
|
||||
private:
|
||||
Color4 clear_color{0,0,0,0};
|
||||
/// "Size" in this sense is the "Renderable Area" because OpenGL textures behave strangely if they're not square.
|
||||
Vector2 size{0, 0};
|
||||
bool using_depth = false;
|
||||
bool texture_created_by_us = false;
|
||||
GLuint framebuffer_object = 0;
|
||||
GLuint depth_buffer = 0;
|
||||
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:
|
||||
static GLuint GetActiveGLFramebufferHandle();
|
||||
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
|
||||
|
||||
/** Change the size of the renderable area of the Render Target. **/
|
||||
/// @param new_size new size in px.
|
||||
void Resize(const Vector2& new_size);
|
||||
void SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
|
||||
/// If you're using raw OpenGL commands to draw to this outside of J2D or J3D don't forget to do this.
|
||||
/// Blits the MSAA FBO onto the regular FBO if MSAA is enabled and or If you're rendering to a texture which uses mipmaps,
|
||||
/// It regenerates them so what you drew doesn't disappear at a distance. Otherwise it does nothing.
|
||||
void Blit() const;
|
||||
[[nodiscard]] bool TextureCreatedByRenderTarget() const;
|
||||
public:
|
||||
[[nodiscard]] Vector2 GetDimensions() const;
|
||||
[[nodiscard]] MSAA_SAMPLE_RATE GetMSAASampleRate() const;
|
||||
/// Returns whether or not MSAA is enabled, If it is and you're not using J2D || J3D Begin / End,
|
||||
/// You need to run "Blit()" after rendering to your FBO before you show it.
|
||||
/// @note Also, If the texture wasn't made by the RenderTarget you don't want this. It would destroy the texture.
|
||||
[[nodiscard]] bool MSAAEnabled() const;
|
||||
[[nodiscard]] Texture* GetJGLTexture() const;
|
||||
[[nodiscard]] GLuint GetGLTextureHandle() const;
|
||||
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
|
||||
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
|
||||
[[nodiscard]] Color4 GetClearColor() const;
|
||||
/// Get the data back from the FBO. This is *not* async friendly.
|
||||
[[nodiscard]] std::vector<GLfloat> GetData() const;
|
||||
public:
|
||||
/// Create a render target for a texture that already exists. For adding to an existing texture.
|
||||
explicit RenderTarget(Texture* texture, const Color4& clear_color = Colors::Black);
|
||||
/// Create a Render Target with a brand new texture. Want to render JGL elements onto a texture and display it as a sprite?
|
||||
explicit RenderTarget(const Vector2& size, const Color4& clear_color = Colors::Black, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
~RenderTarget();
|
||||
};
|
59
include/JGL/types/Texture.h
Normal file
59
include/JGL/types/Texture.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include <ReImage/Image.h>
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <Color3.hpp>
|
||||
#include <Color4.hpp>
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace JGL {
|
||||
using namespace ReImage;
|
||||
enum class TextureFilteringMode : 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 TextureWrappingMode : u8 {
|
||||
REPEAT = 0,
|
||||
MIRRORED_REPEAT = 1,
|
||||
CLAMP_TO_EDGE = 2,
|
||||
CLAMP_TO_BORDER = 3 //Effectively the same as clamp_to_edge
|
||||
};
|
||||
|
||||
/// Represents texture data loaded on the GPU. Contains a handle that can be passed to OpenGL draw calls.
|
||||
class Texture {
|
||||
private:
|
||||
void Erase();
|
||||
protected:
|
||||
GLuint texture_handle = 0;
|
||||
Vector2 texture_size = {0, 0};
|
||||
ReImage::TextureFlag texture_flags;
|
||||
ReImage::TextureFormat texture_format;
|
||||
TextureFilteringMode texture_filtering_mode;
|
||||
TextureWrappingMode texture_wrapping_mode;
|
||||
void load(Image* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
|
||||
public:
|
||||
/// Load a texture from a file,
|
||||
explicit Texture(const std::string& file, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE, const TextureFlag& flags = TextureFlag::INVERT_Y);
|
||||
Texture(Image* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
|
||||
/* Initialize a texture filled with trash data
|
||||
this is primarily for the RenderTarget */
|
||||
explicit Texture(const Vector2& size);
|
||||
Texture(const Texture& rhs);
|
||||
~Texture();
|
||||
public:
|
||||
[[nodiscard]] GLuint GetGLTextureHandle() const;
|
||||
[[nodiscard]] Vector2 GetDimensions() const;
|
||||
[[nodiscard]] TextureFilteringMode GetFilteringMode() const;
|
||||
[[nodiscard]] TextureWrappingMode GetWrappingMode() const;
|
||||
[[nodiscard]] TextureFlag GetFlags() const;
|
||||
[[nodiscard]] TextureFormat GetFormat() const;
|
||||
[[nodiscard]] std::vector<Color4> GetPixelData() const;
|
||||
void SetTextureHandle(GLuint handle);
|
||||
void SetFlags(const TextureFlag& flags);
|
||||
};
|
||||
|
||||
}
|
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;
|
||||
void load(const GLfloat* data, const long& size);
|
||||
void load(const GLuint* data, const long& size);
|
||||
void SetData(void* data, const long& length);
|
||||
void UpdateData(void* data, const long& offset, const long& length);
|
||||
void Erase();
|
||||
public:
|
||||
VRamList(const GLuint* data, const long& length);
|
||||
VRamList(const GLfloat* data, const long& length);
|
||||
VRamList(Vector2* data, const long& length);
|
||||
VRamList(Vector3* data, const long& length);
|
||||
VRamList(Vector4* data, const long& length);
|
||||
|
||||
~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);
|
||||
|
||||
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 GetSize() 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.
|
||||
* "length" refers to the number of elements in data. Not the number of bytes. */
|
||||
void SetData(const GLfloat* data, const long& length);
|
||||
void SetData(const Vector2* data, const long& length);
|
||||
void SetData(const Vector3* data, const long& length);
|
||||
void SetData(const Vector4* data, const long& length);
|
||||
|
||||
void SetData(const GLuint* data, const long& length);
|
||||
void SetData(const Vector2i* data, const long& length);
|
||||
|
||||
/** Update only a portion of the data in a VBO. Must be same type.
|
||||
* "length" refers to the number of elements in data. Not the number of bytes.
|
||||
* "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& length);
|
||||
void UpdateData(const Vector2* data, const long& offset, const long& length);
|
||||
void UpdateData(const Vector3* data, const long& offset, const long& length);
|
||||
void UpdateData(const Vector4* data, const long& offset, const long& length);
|
||||
|
||||
void UpdateData(const GLuint* data, const long& offset, const long& length);
|
||||
void UpdateData(const Vector2i* data, const long& offset, const long& length);
|
||||
};
|
@@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// LearnOpenGL::Shader
|
||||
// OpenGL Shader Class Wrapper
|
||||
// Updated by dawsh
|
||||
// https://learnopengl.com/code_viewer_gh.php?code=includes/learnopengl/shader.h
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <glad/glad.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||
#include <J3ML/LinearAlgebra/Vector3.h>
|
||||
#include <J3ML/LinearAlgebra/Vector4.h>
|
||||
#include <J3ML/LinearAlgebra/Matrix2x2.h>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.h>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.h>
|
||||
|
||||
namespace LearnOpenGL {
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using J3ML::LinearAlgebra::Vector3;
|
||||
using J3ML::LinearAlgebra::Vector4;
|
||||
using J3ML::LinearAlgebra::Matrix2x2;
|
||||
using J3ML::LinearAlgebra::Matrix3x3;
|
||||
using J3ML::LinearAlgebra::Matrix4x4;
|
||||
|
||||
class Shader
|
||||
{
|
||||
public:
|
||||
unsigned int ID{};
|
||||
|
||||
Shader();
|
||||
Shader(std::filesystem::path vertexProgramPath, std::filesystem::path fragmentProgramPath);
|
||||
Shader(std::string vertexProgramSrc, std::string fragmentProgramSrc);
|
||||
|
||||
void use();
|
||||
// Utility uniform functions
|
||||
void setBool(const std::string& name, bool value) const;
|
||||
void setInt(const std::string& name, int value) const;
|
||||
void setFloat(const std::string& name, float value) const;
|
||||
void setVec2(const std::string& name, const Vector2& value) const;
|
||||
void setVec2(const std::string& name, float x, float y) const;
|
||||
void setVec3(const std::string& name, const Vector3& value) const;
|
||||
void setVec3(const std::string& name, float x, float y, float z) const;
|
||||
void setVec4(const std::string& name, const Vector4& value) const;
|
||||
void setVec4(const std::string& name, float x, float y, float z, float w) const;
|
||||
void setMat2(const std::string& name, const Matrix2x2 &mat) const;
|
||||
void setMat3(const std::string& name, const Matrix3x3 &mat) const;
|
||||
void setMat4(const std::string& name, const Matrix4x4 &mat) const;
|
||||
|
||||
GLint getAttribute(const std::string& name) const;
|
||||
GLint getUniform(const std::string& name) const;
|
||||
|
||||
private:
|
||||
void checkCompileErrors(GLuint shader, std::string type);
|
||||
};
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace {
|
||||
// Texture2D is able to store and configure a texture in OpenGL
|
||||
// It also hosts utility functions for easy management.
|
||||
class Texture2D {
|
||||
public:
|
||||
unsigned int ID; // ID of the texture object
|
||||
unsigned int Width, Height;
|
||||
unsigned int InternalFormat;
|
||||
unsigned int ImageFormat;
|
||||
unsigned int WrapS;
|
||||
unsigned int WrapT;
|
||||
unsigned int Filter_Min;
|
||||
unsigned int Filter_Max;
|
||||
|
||||
Texture2D();
|
||||
|
||||
void Generate(unsigned int width, unsigned int height, unsigned char *data);
|
||||
|
||||
void Bind() const;
|
||||
};
|
||||
}
|
301
main.cpp
301
main.cpp
@@ -1,44 +1,84 @@
|
||||
//#include <GL/glew.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <JGL/JGL.h>
|
||||
#include <rewindow/types/window.h>
|
||||
#include <iostream>
|
||||
#include <LearnOpenGL/Shader.h>
|
||||
#include <JGL/Colors.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||
#include <Colors.hpp>
|
||||
#include <chrono>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using namespace JGL;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
JGL::Font FreeSans;
|
||||
JGL::Font Jupiteroid;
|
||||
float fps = 0.0f;
|
||||
|
||||
struct Character
|
||||
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;
|
||||
|
||||
void Grab() {
|
||||
if (hovered)
|
||||
dragging = true;
|
||||
}
|
||||
void Release() {
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
void Update(const Vector2& mouse) {
|
||||
if (dragging)
|
||||
position = position.Lerp(mouse, 0.25f);
|
||||
|
||||
hovered = mouse.Distance(position) < range;
|
||||
}
|
||||
|
||||
void Draw() {
|
||||
if (dragging)
|
||||
J2D::DrawPoint(Colors::White, position, 4.f);
|
||||
else if (hovered)
|
||||
J2D::DrawPoint(Colors::Reds::Crimson, position, 6.f);
|
||||
else
|
||||
J2D::DrawPoint(Colors::Reds::Salmon, position, 3.f);
|
||||
|
||||
J2D::DrawString(Colors::White, std::format("{:.1f},{:.1f}", position.x, position.y), position.x, position.y, 1.f, 10, FreeSans);
|
||||
}
|
||||
};
|
||||
|
||||
std::map<char, Character> Characters;
|
||||
GLuint VAO, VBO;
|
||||
const std::string vertexShader = "attribute vec4 coord;\n"
|
||||
"varying vec2 texpos;\n"
|
||||
"\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(coord.xy, 0, 1);\n"
|
||||
" texpos = coord.zw;\n"
|
||||
"}\n"
|
||||
"";
|
||||
const std::string fragmentShader = "varying vec2 texpos;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"uniform vec4 color;\n"
|
||||
"\n"
|
||||
"void main(void) {\n"
|
||||
" gl_FragColor = vec4(1, 1, 1, texture2D(tex, texpos).a) * color;\n"
|
||||
"}";
|
||||
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 {
|
||||
@@ -48,90 +88,179 @@ struct point {
|
||||
GLfloat t;
|
||||
};
|
||||
|
||||
Gizmo a({250, 150});
|
||||
Gizmo b({200, 250});
|
||||
Gizmo c({350, 300});
|
||||
Gizmo d({450, 250});
|
||||
|
||||
Texture* image;
|
||||
Texture* image2;
|
||||
RenderTarget* j2d_render_target;
|
||||
RenderTarget* image2_render_target;
|
||||
|
||||
class JGLDemoWindow : public ReWindow::RWindow
|
||||
{
|
||||
public:
|
||||
LearnOpenGL::Shader shader;
|
||||
|
||||
JGLDemoWindow() : ReWindow::RWindow()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void initGL()
|
||||
{
|
||||
void initGL() {
|
||||
camera = new Camera;
|
||||
gladLoadGL();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, getSize().x, getSize().y, 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
if (!JGL::MeetsRequirements())
|
||||
Logger::Warning("The graphics driver does not meet the minimum requirements to run this program.");
|
||||
|
||||
JGL::InitTextEngine();
|
||||
JGL::Update(getSize());
|
||||
J3D::Init(getSize(), 90, 100);
|
||||
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
|
||||
Jupiteroid = JGL::Font("assets/fonts/Jupiteroid.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", TextureFilteringMode::BILINEAR);
|
||||
j2d_render_target = new RenderTarget({540, 540}, {0,0,0,0}, false, MSAA_SAMPLE_RATE::MSAA_8X);
|
||||
image2 = new Texture("assets/sprites/Re3D.png",TextureFilteringMode::BILINEAR);
|
||||
image2_render_target = new RenderTarget(image2);
|
||||
|
||||
J2D::Begin(image2_render_target);
|
||||
J2D::FillRect(Colors::Red, {0,0}, {4,4});
|
||||
J2D::DrawString(Colors::Red, "TEST", 0, 16, 1, 16, FreeSans);
|
||||
J2D::End();
|
||||
}
|
||||
|
||||
Vector3 textAngle = {0,0,0};
|
||||
float fov = 90;
|
||||
float sprite_radians = 0;
|
||||
bool fov_increasing = true;
|
||||
|
||||
void display()
|
||||
{
|
||||
void display() {
|
||||
JGL::Update(getSize());
|
||||
if (fov_increasing)
|
||||
fov += 0.25;
|
||||
else
|
||||
fov -= 0.50;
|
||||
|
||||
if (fov >= 120)
|
||||
fov_increasing = false;
|
||||
else if (fov <= 75)
|
||||
fov_increasing = true;
|
||||
J3D::ChangeFOV(fov);
|
||||
|
||||
sprite_radians += 0.05;
|
||||
textAngle.y += 2.0f;
|
||||
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. */
|
||||
|
||||
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::End();
|
||||
|
||||
|
||||
JGL::J3D::DrawString3D(JGL::Colors::White, "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(*image2, {300, 300}, 0, {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, {225, 300}, image->GetDimensions() * 0.25, 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::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::FillRect(Colors::Gray, {0, 0}, result);
|
||||
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);
|
||||
J2D::OutlinePolygon(Colors::White, {{200, 400}, {220, 420}, {220, 430}, {230, 410}, {200, 400}});
|
||||
//J2D::FillPolygon(Colors::White, {{200, 400}, {220, 420}, {220, 430}, {230, 410}, {200, 400}});
|
||||
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();
|
||||
|
||||
//Draw the Render Target that we just drew all that stuff onto.
|
||||
|
||||
J2D::Begin();
|
||||
J2D::DrawSprite(*j2d_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::DrawSprite(*image2_render_target, {300, 500}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::End();
|
||||
|
||||
//glFlush();
|
||||
}
|
||||
|
||||
void OnRefresh(float elapsed) override
|
||||
{
|
||||
void OnRefresh(float elapsed) override {
|
||||
auto mouse = GetMouseCoordinates();
|
||||
a.Update(mouse);
|
||||
b.Update(mouse);
|
||||
c.Update(mouse);
|
||||
d.Update(mouse);
|
||||
display();
|
||||
this->glSwapBuffers();
|
||||
int glError = glGetError();
|
||||
if (glError != GL_NO_ERROR)
|
||||
std::cout << glError << std::endl;
|
||||
glSwapBuffers();
|
||||
}
|
||||
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override
|
||||
|
||||
|
||||
void OnMouseButtonDown(const ReWindow::WindowEvents::MouseButtonDownEvent & ev) override
|
||||
{
|
||||
return true;
|
||||
RWindow::OnMouseButtonDown(ev);
|
||||
a.Grab();
|
||||
b.Grab();
|
||||
c.Grab();
|
||||
d.Grab();
|
||||
}
|
||||
|
||||
void OnMouseButtonUp(const ReWindow::WindowEvents::MouseButtonUpEvent & ev) override
|
||||
{
|
||||
RWindow::OnMouseButtonUp(ev);
|
||||
a.Release();
|
||||
b.Release();
|
||||
c.Release();
|
||||
d.Release();
|
||||
}
|
||||
|
||||
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override {return true;}
|
||||
JGLDemoWindow() : ReWindow::RWindow() {}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height){}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
auto* window = new JGLDemoWindow();
|
||||
|
||||
window->init(RenderingAPI::OPENGL, "Window", 1280, 720, false);
|
||||
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->setVsyncEnabled(false);
|
||||
|
||||
while (window->isAlive()) {
|
||||
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
|
||||
window->pollEvents();
|
||||
window->refresh();
|
||||
std::chrono::high_resolution_clock::time_point stop = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<float> frame_time = stop - start;
|
||||
fps = 1.0f / frame_time.count();
|
||||
}
|
||||
|
||||
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
|
||||
'
|
||||
|
814
src/JGL.cpp
Normal file
814
src/JGL.cpp
Normal file
@@ -0,0 +1,814 @@
|
||||
//
|
||||
// Created by dawsh on 1/17/24.
|
||||
//
|
||||
|
||||
#include <JGL/JGL.h>
|
||||
#include <glad/glad.h>
|
||||
#include <J3ML/Algorithm/Bezier.hpp>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
JGL::RenderTarget* render_target = nullptr;
|
||||
GLfloat oldColor[4] = {0, 0, 0, 1};
|
||||
GLfloat baseColor[4] = {1, 1, 1, 1};
|
||||
|
||||
GLuint current_fbo = 0;
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
|
||||
bool inJ2D = false;
|
||||
bool inJ3D = false;
|
||||
bool wasTexture2DEnabled = false;
|
||||
bool wasTextureCoordArrayEnabled = false;
|
||||
bool wasDepthTestEnabled = false;
|
||||
bool wasVertexArraysEnabled = false;
|
||||
bool wasCullFaceEnabled = false;
|
||||
bool wasBlendEnabled = false;
|
||||
bool wasColorArrayEnabled = false;
|
||||
GLint activeTextureUnit = 0;
|
||||
|
||||
namespace JGL {
|
||||
using namespace J3ML;
|
||||
Vector2 wS;
|
||||
|
||||
void Update(const Vector2& window_size) {
|
||||
wS = window_size;
|
||||
glViewport(0, 0, (int) wS.x, (int) wS.y);
|
||||
}
|
||||
|
||||
bool MeetsRequirements() {
|
||||
if (!GLAD_GL_VERSION_2_1)
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_framebuffer_object)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma region J2D
|
||||
void J2D::Begin(RenderTarget* rt, bool clear_buffers) {
|
||||
GLfloat old_clear_color[4];
|
||||
if (rt != nullptr) {
|
||||
render_target = rt;
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
current_fbo = JGL::RenderTarget::GetActiveGLFramebufferHandle();
|
||||
JGL::RenderTarget::SetActiveGLRenderTarget(*rt);
|
||||
|
||||
if (!(rt->GetJGLTexture()->GetFlags() & INVERT_Y))
|
||||
Logger::Warning("You're rendering onto a texture that is upside-down. Your draw commands won't work how you'd expect.");
|
||||
}
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
if (rt == nullptr)
|
||||
glViewport(0, 0, (int) wS.x, (int) wS.y),
|
||||
glOrtho(0, wS.x, wS.y, 0, -1, 1);
|
||||
else
|
||||
glOrtho(0, rt->GetDimensions().x, rt->GetDimensions().y, 0, -1, 1);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
//Get what the draw color was before we did anything.
|
||||
glGetFloatv(GL_CURRENT_COLOR, oldColor);
|
||||
glColor4fv(baseColor);
|
||||
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTextureUnit);
|
||||
activeTextureUnit = activeTextureUnit - GL_TEXTURE0;
|
||||
|
||||
if (activeTextureUnit != 0)
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
if (glIsEnabled(GL_DEPTH_TEST))
|
||||
wasDepthTestEnabled = true,
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
else
|
||||
wasDepthTestEnabled = false;
|
||||
|
||||
if (!glIsEnabled(GL_VERTEX_ARRAY))
|
||||
wasVertexArraysEnabled = false,
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
else
|
||||
wasVertexArraysEnabled = true;
|
||||
|
||||
if (!glIsEnabled(GL_CULL_FACE))
|
||||
wasCullFaceEnabled = false,
|
||||
glEnable(GL_CULL_FACE),
|
||||
glCullFace(GL_BACK);
|
||||
else
|
||||
wasCullFaceEnabled = true;
|
||||
|
||||
if (!glIsEnabled(GL_BLEND))
|
||||
wasBlendEnabled = false,
|
||||
glEnable(GL_BLEND),
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else
|
||||
wasBlendEnabled = true;
|
||||
|
||||
if (!glIsEnabled(GL_TEXTURE_2D))
|
||||
wasTexture2DEnabled = false,
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
else
|
||||
wasTexture2DEnabled = true;
|
||||
|
||||
if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY))
|
||||
wasTextureCoordArrayEnabled = false,
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
wasTextureCoordArrayEnabled = true;
|
||||
|
||||
if (glIsEnabled(GL_COLOR_ARRAY))
|
||||
wasColorArrayEnabled = true,
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
else
|
||||
wasColorArrayEnabled = false;
|
||||
|
||||
if (!inJ3D)
|
||||
inJ2D = true;
|
||||
else { Logger::Error("Beginning J2D context inside of J3D context?"); }
|
||||
|
||||
if (rt != nullptr && clear_buffers) {
|
||||
glClearColor(rt->GetClearColor().R(), rt->GetClearColor().G(), rt->GetClearColor().B(), rt->GetClearColor().A());
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void J2D::End() {
|
||||
//Change back to the previous projection (The 3D one in Re3D's case.)
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
if (wasDepthTestEnabled)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
if (!wasVertexArraysEnabled)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (!wasCullFaceEnabled)
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (!wasBlendEnabled)
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
if (!wasTexture2DEnabled)
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
if (!wasTextureCoordArrayEnabled)
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (wasColorArrayEnabled)
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
//Select whatever texture_handle unit was selected before.
|
||||
glActiveTexture(GL_TEXTURE0 + activeTextureUnit);
|
||||
|
||||
//Put the draw color back how it was before.
|
||||
glColor4fv(oldColor);
|
||||
|
||||
if (render_target != nullptr) {
|
||||
render_target->Blit();
|
||||
render_target = nullptr;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
}
|
||||
inJ2D = false;
|
||||
}
|
||||
|
||||
void J2D::DrawPoint(const Color4& color, const Vector2& coordinates, float radius) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
glPointSize(radius);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), coordinates.ptr());
|
||||
glDrawArrays(GL_POINTS, 0, 1);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::DrawPoint(const Color4& color, float x, float y, float radius) {
|
||||
DrawPoint(color, {x, y}, radius);
|
||||
}
|
||||
|
||||
void J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
Vector2 vertices[] = {A, B};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::DrawLine(const Color4& color, float x, float y, float w, float h, float thickness) {
|
||||
J2D::DrawLine(color, {x, y}, {w, h}, thickness);
|
||||
}
|
||||
|
||||
void J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
Vector2 vertices[] = {A, B};
|
||||
GLfloat colors[8] = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),
|
||||
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized() };
|
||||
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glLineWidth(thickness);
|
||||
glColorPointer(4,GL_FLOAT,sizeof(Color4), colors);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void DrawGradientLine(const Color4& color1, const Color4& color2, float x, float y, float w, float h, float thickness) {
|
||||
J2D::DrawGradientLine(color1, color2, {x, y}, {w, h}, thickness);
|
||||
}
|
||||
|
||||
void J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
|
||||
std::vector<GLfloat> colors{};
|
||||
|
||||
if (gradient == Direction::Horizontal)
|
||||
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),
|
||||
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(), color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized()};
|
||||
|
||||
else if (gradient == Direction::Vertical)
|
||||
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(),
|
||||
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(), color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized()};
|
||||
|
||||
else if (gradient == Direction::Diagonal_SWNE)
|
||||
colors = {(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f, (color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f,
|
||||
color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), (color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f,
|
||||
(color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f, color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized()};
|
||||
|
||||
else if (gradient == Direction::Diagonal_NWSE)
|
||||
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f,
|
||||
(color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f, color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(),
|
||||
(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f, (color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f,(color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f};
|
||||
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glColorPointer(4, GL_FLOAT, 0, colors.data());
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, unsigned int subdivisions) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
J2D::FillRect(color, {pos.x + radius, pos.y}, {size.x - 2 * radius, size.y});
|
||||
J2D::FillRect(color, {pos.x, pos.y + radius}, {size.x, size.y - 2 * radius});
|
||||
|
||||
J2D::FillCircle(color, {pos.x + radius, pos.y + radius}, radius, subdivisions);
|
||||
J2D::FillCircle(color, {pos.x + size.x - radius, pos.y + radius}, radius, subdivisions);
|
||||
J2D::FillCircle(color, {pos.x + radius, pos.y + size.y - radius}, radius, subdivisions);
|
||||
J2D::FillCircle(color, {pos.x + size.x - radius, pos.y + size.y - radius}, radius, subdivisions);
|
||||
}
|
||||
|
||||
void J2D::DrawSprite(const JGL::RenderTarget& rt, const Vector2& position, float rad_rotation, const Vector2& origin,
|
||||
const Vector2& scale, const Color4& color, Direction inversion) {
|
||||
|
||||
//Correct for the render-target being upside-down.
|
||||
Direction d{};
|
||||
if (inversion == Direction::None && !(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
|
||||
d = Direction::Vertical;
|
||||
else if (inversion == Direction::Horizontal) {
|
||||
d = Direction::Horizontal;
|
||||
if (!(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
|
||||
d = Direction::Horizontal | Direction::Vertical;
|
||||
}
|
||||
else if (inversion& Direction::Horizontal && inversion& Direction::Vertical) {
|
||||
d = Direction::Horizontal;
|
||||
if (!(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
|
||||
d = Direction::Horizontal | Direction::Vertical;
|
||||
}
|
||||
|
||||
//Change the blending mode such that the alpha doesn't get multiplied again.
|
||||
if (rt.TextureCreatedByRenderTarget())
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
J2D::DrawPartialSprite(*rt.GetJGLTexture(), position, {0, 0}, rt.GetDimensions(), rad_rotation, origin, scale, color, d);
|
||||
|
||||
if (rt.TextureCreatedByRenderTarget())
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
void J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_rotation, const Vector2& origin,
|
||||
const Vector2& scale, const Color4& color, Direction inversion) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
|
||||
const Vector2 size = texture.GetDimensions();
|
||||
|
||||
std::array<Vector2, 4> textureCoordinates{};
|
||||
if (texture.GetFlags() & INVERT_Y)
|
||||
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
|
||||
else
|
||||
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
|
||||
|
||||
// TODO: Kind of a mess, refactor to be more sensible later.
|
||||
// Factors in scaling and origin correctly.
|
||||
// i.e. to render at 2x size, from the center, at coords XY, use {2, 2} scale, and {0.5, 0.5} offset.
|
||||
const Vector2 offset = origin * size;
|
||||
Vector2 pos2 = pos;
|
||||
Vector2 scaled_size = scale * size;
|
||||
Vector2 size2 = scaled_size;
|
||||
float cos_theta = std::cos(rad_rotation);
|
||||
float sin_theta = std::sin(rad_rotation);
|
||||
|
||||
std::array<Vector2, 4> vertices =
|
||||
{
|
||||
pos2, // Top-left vertex
|
||||
{pos2.x, pos2.y + size2.y}, // Bottom-left
|
||||
{pos2.x + size2.x, pos2.y + size2.y}, // Bottom-right
|
||||
{pos2.x + size2.x, pos2.y} // Top-right
|
||||
};
|
||||
|
||||
//Rotate the vertices about the origin by float rad_rotation.
|
||||
if (rad_rotation != 0)
|
||||
for (auto& v: vertices)
|
||||
v = {(v.x - pos2.x - offset.x * scale.x) * cos_theta - (v.y - pos2.y - offset.y * scale.y) * sin_theta +
|
||||
pos2.x + offset.x * scale.x,
|
||||
(v.x - pos2.x - offset.x * scale.x) * sin_theta + (v.y - pos2.y - offset.y * scale.y) * cos_theta +
|
||||
pos2.y + offset.y * scale.y
|
||||
};
|
||||
|
||||
if (inversion == Direction::Vertical)
|
||||
std::swap(textureCoordinates[0], textureCoordinates[1]),
|
||||
std::swap(textureCoordinates[3], textureCoordinates[2]);
|
||||
if (inversion == Direction::Horizontal)
|
||||
std::swap(textureCoordinates[0], textureCoordinates[3]),
|
||||
std::swap(textureCoordinates[1], textureCoordinates[2]);
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
|
||||
void J2D::DrawSprite(const Texture& texture, float positionX, float positionY, float rad_rotation, float originX,
|
||||
float originY, float scaleX, float scaleY, const Color4& color, Direction inversion) {
|
||||
DrawSprite(texture,
|
||||
{positionX, positionY},
|
||||
rad_rotation,
|
||||
{originX, originY},
|
||||
{scaleX, scaleY},
|
||||
color, inversion);
|
||||
}
|
||||
|
||||
void J2D::DrawPartialSprite(const Texture& texture, const Vector2 &position, const Vector2& sub_texture_position,
|
||||
const Vector2& sub_texture_size, float rad_rotation, const Vector2& origin,
|
||||
const Vector2& scale, const Color4& color, Direction inversion) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
const Vector2 textureSize = texture.GetDimensions();
|
||||
std::array<GLfloat, 8> textureCoordinates{};
|
||||
// Calculate texture coordinates (relative to the whole texture)
|
||||
if (!(texture.GetFlags() & INVERT_Y))
|
||||
textureCoordinates = {
|
||||
sub_texture_position.x / textureSize.x,
|
||||
sub_texture_position.y / textureSize.y,
|
||||
sub_texture_position.x / textureSize.x,
|
||||
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
|
||||
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
|
||||
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
|
||||
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
|
||||
sub_texture_position.y / textureSize.y
|
||||
};
|
||||
|
||||
else {
|
||||
textureCoordinates = {
|
||||
sub_texture_position.x / textureSize.x,
|
||||
(textureSize.y - sub_texture_position.y) / textureSize.y,
|
||||
sub_texture_position.x / textureSize.x,
|
||||
(textureSize.y - (sub_texture_position.y + sub_texture_size.y)) / textureSize.y,
|
||||
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
|
||||
(textureSize.y - (sub_texture_position.y + sub_texture_size.y)) / textureSize.y,
|
||||
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
|
||||
(textureSize.y - sub_texture_position.y) / textureSize.y
|
||||
};
|
||||
}
|
||||
|
||||
if (inversion& Direction::Vertical)
|
||||
std::swap(textureCoordinates[1], textureCoordinates[3]),
|
||||
std::swap(textureCoordinates[5], textureCoordinates[7]);
|
||||
|
||||
if (inversion& Direction::Horizontal)
|
||||
std::swap(textureCoordinates[0], textureCoordinates[6]),
|
||||
std::swap(textureCoordinates[2], textureCoordinates[4]);
|
||||
|
||||
const Vector2 offset = origin * sub_texture_size;
|
||||
Vector2 pos2 = position;
|
||||
Vector2 scaled_size = scale * sub_texture_size;
|
||||
Vector2 size2 = scaled_size;
|
||||
float cos_theta = std::cos(rad_rotation);
|
||||
float sin_theta = std::sin(rad_rotation);
|
||||
|
||||
std::array<Vector2, 4> vertices =
|
||||
{
|
||||
pos2, // Top-left
|
||||
{pos2.x, pos2.y + size2.y}, // Bottom-left
|
||||
{pos2.x + size2.x, pos2.y + size2.y},// Bottom-right
|
||||
{pos2.x + size2.x, pos2.y} // Top-right
|
||||
};
|
||||
|
||||
//Rotate the vertices about the origin by float rad_rotation.
|
||||
if (rad_rotation != 0)
|
||||
for (auto& v: vertices)
|
||||
v = {(v.x - pos2.x - offset.x * scale.x) * cos_theta - (v.y - pos2.y - offset.y * scale.y) * sin_theta +
|
||||
pos2.x + offset.x * scale.x,
|
||||
(v.x - pos2.x - offset.x * scale.x) * sin_theta + (v.y - pos2.y - offset.y * scale.y) * cos_theta +
|
||||
pos2.y + offset.y * scale.y};
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordinates.data());
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void
|
||||
J2D::DrawPartialSprite(const JGL::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 originX, float originY, float rad_rotation,
|
||||
float scaleX, float scaleY, const Color4& color, JGL::Direction inversion) {
|
||||
|
||||
J2D::DrawPartialSprite(texture, {positionX, positionY}, {sub_texture_positionX, sub_texture_positionY},
|
||||
{(float) sub_texture_sizeX, (float) sub_texture_sizeY}, rad_rotation, {originX, originY},
|
||||
{scaleX, scaleY}, color, inversion);
|
||||
}
|
||||
|
||||
void J2D::DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis, float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
if (mirror_axis == Direction::None)
|
||||
Logger::Warning("Drawing non-mirrored sprite with J2D::DrawMirrorSprite?");
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
|
||||
Vector2 size = texture.GetDimensions();
|
||||
|
||||
std::array<Vector2, 4> textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
|
||||
if (mirror_axis == Direction::Horizontal) {
|
||||
size.x *= 2;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
|
||||
if (texture.GetFlags() & INVERT_Y)
|
||||
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(2, 0), Vector2(2, 1)};
|
||||
else
|
||||
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(2, 1), Vector2(2, 0)};
|
||||
}
|
||||
|
||||
else if (mirror_axis == Direction::Vertical) {
|
||||
size.y *= 2;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
||||
if (texture.GetFlags() & INVERT_Y)
|
||||
textureCoordinates = {Vector2(0, 2), Vector2(0, 0), Vector2(1, 0), Vector2(1, 2)};
|
||||
else
|
||||
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(1, 2), Vector2(1, 0)};
|
||||
}
|
||||
|
||||
else if ((mirror_axis& Direction::Horizontal) && (mirror_axis& Direction::Vertical)) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
||||
size *= 2;
|
||||
if (texture.GetFlags() & INVERT_Y)
|
||||
textureCoordinates = {Vector2(0, 2), Vector2(0, 0), Vector2(2, 0), Vector2(2, 2)};
|
||||
else
|
||||
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(2, 2), Vector2(2, 0)};
|
||||
}
|
||||
|
||||
const Vector2 offset = origin * size;
|
||||
Vector2 pos2 = position;
|
||||
Vector2 size2 = scale * size;
|
||||
float cos_theta = std::cos(rad_rotation);
|
||||
float sin_theta = std::sin(rad_rotation);
|
||||
|
||||
std::array<Vector2, 4> vertices =
|
||||
{
|
||||
pos2,
|
||||
{pos2.x, pos2.y + size2.y},
|
||||
{pos2.x + size2.x, pos2.y + size2.y},
|
||||
{pos2.x + size2.x, pos2.y}
|
||||
};
|
||||
|
||||
if (rad_rotation != 0)
|
||||
for (auto& v : vertices)
|
||||
v = {
|
||||
(v.x - pos2.x - offset.x * scale.x) * cos_theta - (v.y - pos2.y - offset.y * scale.y) * sin_theta + pos2.x + offset.x * scale.x,
|
||||
(v.x - pos2.x - offset.x * scale.x) * sin_theta + (v.y - pos2.y - offset.y * scale.y) * cos_theta + pos2.y + offset.y * scale.y
|
||||
};
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
|
||||
//Reset the wrapping mode.
|
||||
if (texture.GetWrappingMode() == TextureWrappingMode::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 (texture.GetWrappingMode() == TextureWrappingMode::REPEAT)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
else if (texture.GetWrappingMode() == TextureWrappingMode::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);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions, float thickness) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
float step = (2.f * Math::Pi) / (float) subdivisions;
|
||||
std::vector<Vector2> vertices(subdivisions);
|
||||
GLfloat angle, x, y;
|
||||
|
||||
int i = 0;
|
||||
for (angle = 0.0f; angle < (2.f * Math::Pi); angle += step) {
|
||||
x = radius * std::sin(angle) + center.x;
|
||||
y = radius * std::cos(angle) + center.y;
|
||||
if (i < subdivisions)
|
||||
vertices[i] = {x, y};
|
||||
else
|
||||
vertices.emplace_back(x, y);
|
||||
i++;
|
||||
}
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glDrawArrays(GL_LINE_LOOP, 0, (int) vertices.size());
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
GLfloat angle, x, y;
|
||||
float step = (2.f * Math::Pi) / (float) subdivisions;
|
||||
std::vector<Vector2> vertices(subdivisions);
|
||||
|
||||
/* Most of the time the vector "vertices" is either the same size or size + 1 of the number of subdivisions.
|
||||
* Because a float is a decimal, It'd take too long to get rid of the emplace-back making us
|
||||
* wait around for the container to resize. This gets rid of it for what we can guarantee. */
|
||||
int i = 0;
|
||||
for (angle = 0.0f; angle < (2.f * Math::Pi); angle += step) {
|
||||
x = radius * std::sin(angle) + center.x;
|
||||
y = radius * std::cos(angle) + center.y;
|
||||
if (i < subdivisions)
|
||||
vertices[i] = {x, y};
|
||||
else
|
||||
vertices.emplace_back(x, y);
|
||||
i++;
|
||||
}
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, (int) vertices.size());
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
Vector2 vertices[] = {{tri.A.x, tri.A.y}, {tri.B.x, tri.B.y}, {tri.C.x, tri.C.y}};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 3);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::FillTriangle(const Color4& color, const Triangle2D& tri) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
Vector2 vertices[] = {{tri.A.x, tri.A.y}, {tri.B.x, tri.B.y}, {tri.C.x, tri.C.y}};
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
Vector2 vertices[] = {{tri.A.x, tri.A.y}, {tri.B.x, tri.B.y}, {tri.C.x, tri.C.y}};
|
||||
GLfloat colors[] = {a_color.RedChannelNormalized(), a_color.GreenChannelNormalized(), a_color.BlueChannelNormalized(), a_color.AlphaChannelNormalized(),
|
||||
b_color.RedChannelNormalized(),b_color.GreenChannelNormalized(), b_color.BlueChannelNormalized(), b_color.AlphaChannelNormalized(),
|
||||
c_color.RedChannelNormalized(), c_color.GreenChannelNormalized(), c_color.BlueChannelNormalized(),c_color.AlphaChannelNormalized()};
|
||||
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4, GL_FLOAT, sizeof(Color4), colors);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
//TODO render all in once pass with GL_LINE_LOOP instead of separate lines.
|
||||
void J2D::DrawCubicBezierCurve(const Color4 &color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
|
||||
int subdivisions, float thickness) {
|
||||
|
||||
|
||||
Vector2 last = controlA;
|
||||
const Vector2& first = controlB;
|
||||
for (int i = 0; i < subdivisions; ++i)
|
||||
{
|
||||
float alpha = (float) i / (float) subdivisions;
|
||||
Vector2 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 J2D::OutlinePolygon(const Color4 &color, const std::vector<Vector2>& points, float thickness) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
if (points.front() != points.back())
|
||||
throw std::runtime_error("J2D::OutlinePolygon: The first point and the last point must connect.");
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), points.data());
|
||||
glDrawArrays(GL_LINE_LOOP, 0, (int) points.size());
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region J3D
|
||||
std::array<GLfloat, 16> 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;
|
||||
}
|
||||
|
||||
bool j3d_initialized = false;
|
||||
float j3d_far_plane = 0;
|
||||
float j3d_fov = 0;
|
||||
|
||||
void J3D::Init(const J3ML::LinearAlgebra::Vector2& window_size, float fov, float far_plane) {
|
||||
wS = window_size;
|
||||
j3d_far_plane = far_plane;
|
||||
j3d_fov = fov;
|
||||
j3d_initialized = true;
|
||||
}
|
||||
|
||||
void J3D::ChangeFOV(float fov) {
|
||||
j3d_fov = fov;
|
||||
}
|
||||
|
||||
void J3D::ChangeFarPlane(float far_plane) {
|
||||
j3d_far_plane = far_plane;
|
||||
}
|
||||
|
||||
void J3D::Begin() {
|
||||
if (!j3d_initialized)
|
||||
throw std::runtime_error("You have to run J3D::Init before rendering 3D elements.");
|
||||
|
||||
auto aspect = (float) wS.x / (float) wS.y;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMultMatrixf(OpenGLPerspectiveProjectionRH(j3d_fov, aspect, 0.001, j3d_far_plane).data());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
//Get what the draw color was before we did anything.
|
||||
glGetFloatv(GL_CURRENT_COLOR, oldColor);
|
||||
glColor4fv(baseColor);
|
||||
|
||||
wasDepthTestEnabled = false;
|
||||
if (glIsEnabled(GL_DEPTH_TEST))
|
||||
wasDepthTestEnabled = true,
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
wasVertexArraysEnabled = false;
|
||||
if (!glIsEnabled(GL_VERTEX_ARRAY))
|
||||
wasVertexArraysEnabled = false,
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY))
|
||||
wasTextureCoordArrayEnabled = false,
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
wasTextureCoordArrayEnabled = true;
|
||||
|
||||
|
||||
wasTexture2DEnabled = true;
|
||||
if (!glIsEnabled(GL_TEXTURE_2D))
|
||||
wasTexture2DEnabled = false,
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
wasCullFaceEnabled = false;
|
||||
if (glIsEnabled(GL_CULL_FACE))
|
||||
wasCullFaceEnabled = true,
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (!glIsEnabled(GL_BLEND))
|
||||
wasBlendEnabled = false,
|
||||
glEnable(GL_BLEND),
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else
|
||||
wasBlendEnabled = true;
|
||||
|
||||
if (!inJ2D)
|
||||
inJ3D = true;
|
||||
else
|
||||
Logger::Error("Beginning J3D context inside of J2D context?");
|
||||
}
|
||||
|
||||
void J3D::End() {
|
||||
if (wasDepthTestEnabled)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
if (!wasVertexArraysEnabled)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (wasTexture2DEnabled)
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
if (!wasBlendEnabled)
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
if (wasCullFaceEnabled)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
if (!wasTextureCoordArrayEnabled)
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
//Put the draw color back how it was before.
|
||||
glColor4fv(oldColor);
|
||||
inJ3D = false;
|
||||
}
|
||||
|
||||
void J3D::DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
Vector3 vertices[] = {A, B};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
#pragma endregion
|
||||
}
|
291
src/JGL/JGL.cpp
291
src/JGL/JGL.cpp
@@ -1,291 +0,0 @@
|
||||
//
|
||||
// Created by dawsh on 1/17/24.
|
||||
//
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/JGL.h>
|
||||
#include <GL/glut.h>
|
||||
#include <J3ML/LinearAlgebra/Transform2D.h>
|
||||
#include <rewindow/types/window.h>
|
||||
#include <freetype2/ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <JGL/Color3.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
GLuint program;
|
||||
GLuint texture;
|
||||
|
||||
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, "content/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);
|
||||
|
||||
const char* c;
|
||||
for (c = text.c_str(); *c; c++)
|
||||
{
|
||||
if (FT_Load_Char(face, *c, FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = face->glyph;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
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;
|
||||
|
||||
}
|
||||
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;
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
FT_Set_Pixel_Sizes(face, 0, size);
|
||||
|
||||
const char* c;
|
||||
for (c = text.c_str(); *c; c++)
|
||||
{
|
||||
if (FT_Load_Char(face, *c, FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = face->glyph;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
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;
|
||||
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,209 +0,0 @@
|
||||
#include <LearnOpenGL/Shader.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace LearnOpenGL
|
||||
{
|
||||
|
||||
Shader::Shader(std::filesystem::path vertexProgramPath, std::filesystem::path fragmentProgramPath) {
|
||||
std::string vertexCode;
|
||||
std::string fragmentCode;
|
||||
std::string geometryCode;
|
||||
std::ifstream vShaderFile;
|
||||
std::ifstream fShaderFile;
|
||||
std::ifstream gShaderFile;
|
||||
|
||||
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
|
||||
try { // Open Files
|
||||
vShaderFile.open(vertexProgramPath);
|
||||
fShaderFile.open(fragmentProgramPath);
|
||||
std::stringstream vShaderStream, fShaderStream;
|
||||
// read file's buffer contents into streams
|
||||
vShaderStream << vShaderFile.rdbuf();
|
||||
fShaderStream << fShaderFile.rdbuf();
|
||||
// close file handlers
|
||||
vShaderFile.close();
|
||||
fShaderFile.close();
|
||||
// convert stream into string
|
||||
vertexCode = vShaderStream.str();
|
||||
fragmentCode = fShaderStream.str();
|
||||
if (false)
|
||||
{
|
||||
gShaderFile.open("");
|
||||
std::stringstream gShaderStream;
|
||||
gShaderStream << gShaderFile.rdbuf();
|
||||
gShaderFile.close();
|
||||
geometryCode = gShaderStream.str();
|
||||
}
|
||||
} catch (std::ifstream::failure& e) {
|
||||
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
|
||||
}
|
||||
const char* vShaderCode = vertexCode.c_str();
|
||||
const char* fShaderCode = fragmentCode.c_str();
|
||||
// 2. Compile shaders
|
||||
unsigned int vertex, fragment;
|
||||
// vertex shader
|
||||
vertex = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertex, 1, &vShaderCode, NULL);
|
||||
glCompileShader(vertex);
|
||||
checkCompileErrors(vertex, "VERTEX");
|
||||
// fragment shader
|
||||
fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragment, 1, &fShaderCode, NULL);
|
||||
glCompileShader(fragment);
|
||||
checkCompileErrors(fragment, "FRAGMENT");
|
||||
// if geometry shader is given, compile geometry shader
|
||||
unsigned int geometry;
|
||||
if (false)
|
||||
{
|
||||
//const char * gShaderCode = geometryCode.c_str();
|
||||
//geometry = glCreateShader(GL_GEOMETRY_SHADER);
|
||||
//glShaderSource(geometry, 1, &gShaderCode, NULL);
|
||||
//glCompileShader(geometry);
|
||||
//checkCompileErrors(geometry, "GEOMETRY");
|
||||
}
|
||||
// shader Program
|
||||
ID = glCreateProgram();
|
||||
glAttachShader(ID, vertex);
|
||||
glAttachShader(ID, fragment);
|
||||
if (false) // geometryPath != nullptr)
|
||||
glAttachShader(ID, geometry);
|
||||
glLinkProgram(ID);
|
||||
checkCompileErrors(ID, "PROGRAM");
|
||||
// delete the shaders as they're linked into our program now and are no longer necessary
|
||||
glDeleteShader(vertex);
|
||||
glDeleteShader(fragment);
|
||||
if (false) //geometryPath != nullptr)
|
||||
glDeleteShader(geometry);
|
||||
}
|
||||
|
||||
Shader::Shader(std::string vertexProgramSrc, std::string fragmentProgramSrc) {
|
||||
|
||||
std::string geometryCode;
|
||||
|
||||
const char* vShaderCode = vertexProgramSrc.c_str();
|
||||
const char* fShaderCode = fragmentProgramSrc.c_str();
|
||||
// 2. Compile shaders
|
||||
unsigned int vertex, fragment;
|
||||
// vertex shader
|
||||
vertex = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertex, 1, &vShaderCode, NULL);
|
||||
glCompileShader(vertex);
|
||||
checkCompileErrors(vertex, "VERTEX");
|
||||
// fragment shader
|
||||
fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragment, 1, &fShaderCode, NULL);
|
||||
glCompileShader(fragment);
|
||||
checkCompileErrors(fragment, "FRAGMENT");
|
||||
// if geometry shader is given, compile geometry shader
|
||||
unsigned int geometry;
|
||||
if (false)
|
||||
{
|
||||
//const char * gShaderCode = geometryCode.c_str();
|
||||
//geometry = glCreateShader(GL_GEOMETRY_SHADER);
|
||||
//glShaderSource(geometry, 1, &gShaderCode, NULL);
|
||||
//glCompileShader(geometry);
|
||||
//checkCompileErrors(geometry, "GEOMETRY");
|
||||
}
|
||||
// shader Program
|
||||
ID = glCreateProgram();
|
||||
glAttachShader(ID, vertex);
|
||||
glAttachShader(ID, fragment);
|
||||
if (false) // geometryPath != nullptr)
|
||||
glAttachShader(ID, geometry);
|
||||
glLinkProgram(ID);
|
||||
checkCompileErrors(ID, "PROGRAM");
|
||||
// delete the shaders as they're linked into our program now and are no longer necessary
|
||||
glDeleteShader(vertex);
|
||||
glDeleteShader(fragment);
|
||||
if (false) //geometryPath != nullptr)
|
||||
glDeleteShader(geometry);
|
||||
}
|
||||
|
||||
void Shader::use() {
|
||||
glUseProgram(ID);
|
||||
}
|
||||
|
||||
GLint Shader::getAttribute(const std::string& name) const
|
||||
{
|
||||
return glGetAttribLocation(ID, name.c_str());
|
||||
}
|
||||
|
||||
GLint Shader::getUniform(const std::string &name) const {
|
||||
return glGetUniformLocation(ID, name.c_str());
|
||||
}
|
||||
|
||||
void Shader::setBool(const std::string &name, bool value) const {
|
||||
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
|
||||
}
|
||||
|
||||
void Shader::setInt(const std::string &name, int value) const {
|
||||
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::setFloat(const std::string &name, float value) const {
|
||||
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::setVec2(const std::string &name, const Vector2 &value) const {
|
||||
glUniform2f(glGetUniformLocation(ID, name.c_str()), value.x, value.y);
|
||||
}
|
||||
|
||||
void Shader::setVec2(const std::string &name, float x, float y) const {
|
||||
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
|
||||
}
|
||||
|
||||
void Shader::setVec3(const std::string &name, const Vector3 &value) const {
|
||||
glUniform3f(glGetUniformLocation(ID, name.c_str()), value.x, value.y, value.z);
|
||||
}
|
||||
|
||||
void Shader::setVec3(const std::string &name, float x, float y, float z) const {
|
||||
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
|
||||
}
|
||||
|
||||
void Shader::setVec4(const std::string &name, const Vector4 &value) const {
|
||||
glUniform4f(glGetUniformLocation(ID, name.c_str()), value.x, value.y, value.z, value.w);
|
||||
}
|
||||
|
||||
void Shader::setVec4(const std::string &name, float x, float y, float z, float w) const {
|
||||
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
|
||||
}
|
||||
|
||||
void Shader::setMat2(const std::string &name, const Matrix2x2 &mat) const {
|
||||
//glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat.At(0, 0));
|
||||
}
|
||||
|
||||
void Shader::setMat3(const std::string &name, const Matrix3x3 &mat) const {
|
||||
//glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat.At(0, 0));
|
||||
}
|
||||
|
||||
void Shader::setMat4(const std::string &name, const Matrix4x4 &mat) const {
|
||||
//glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat.At(0, 0));
|
||||
}
|
||||
|
||||
void Shader::checkCompileErrors(GLuint shader, std::string type) {
|
||||
GLint success;
|
||||
GLchar infoLog[1024];
|
||||
if (type != "PROGRAM") {
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
|
||||
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << std::endl;
|
||||
}
|
||||
} else {
|
||||
glGetProgramiv(shader, GL_LINK_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
|
||||
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Shader::Shader() {}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
#include <LearnOpenGL/Texture2D.h>
|
||||
#include <glad/glad.h>
|
||||
#include <GL/glut.h>
|
||||
|
||||
Texture2D::Texture2D()
|
||||
: Width(0), Height(0), InternalFormat(GL_RGB), ImageFormat(GL_RGB), WrapS(GL_REPEAT), WrapT(GL_REPEAT),
|
||||
Filter_Min(GL_LINEAR), Filter_Max(GL_LINEAR) {
|
||||
glGenTextures(1, &this->ID);
|
||||
}
|
||||
|
||||
void Texture2D::Generate(unsigned int width, unsigned int height, unsigned char *data) {
|
||||
this->Width = width;
|
||||
this->Height = height;
|
||||
glBindTexture(GL_TEXTURE_2D, this->ID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, this->InternalFormat, width, height, 0, this->ImageFormat, GL_UNSIGNED_BYTE,
|
||||
data);
|
||||
// set Texture wrap and filter modes
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, this->WrapS);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, this->WrapT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, this->Filter_Min);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, this->Filter_Max);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void Texture2D::Bind() const
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, this->ID);
|
||||
}
|
216
src/TextRendering.cpp
Normal file
216
src/TextRendering.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#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>
|
||||
#include "JGL/logger/logger.h"
|
||||
|
||||
namespace JGL {
|
||||
CachedFont* CacheFont(const Font& font, u32 size) {
|
||||
CachedFont* cachedFont;
|
||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||
jlog::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);
|
||||
}
|
||||
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;
|
||||
|
||||
CachedFont* cachedFont = fontCache.getFont(size, font.index);
|
||||
|
||||
if (font.face == nullptr)
|
||||
jlog::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());
|
||||
//Texture parameters are restored when the texture_handle is bound
|
||||
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTexture());
|
||||
|
||||
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);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
void J3D::DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngle& angle, bool draw_back_face) {
|
||||
// TODO: Determine the proper scale factor mathematically
|
||||
scale = scale * 0.002f;
|
||||
scale = -scale;
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
float z = pos.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);
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTexture());
|
||||
|
||||
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);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
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};
|
||||
}
|
158
src/types/Font.cpp
Normal file
158
src/types/Font.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <glad/glad.h>
|
||||
#include <jlog/Logger.hpp>
|
||||
|
||||
#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)
|
||||
throw std::runtime_error("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 std::filesystem::path& path)
|
||||
{
|
||||
if (Detail::ft == nullptr)
|
||||
throw new std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
|
||||
|
||||
Font font;
|
||||
if (FT_New_Face(Detail::ft, path.string().c_str(), 0, &face)) {
|
||||
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
|
||||
throw new std::runtime_error("Error::FREETYPE: Failed to load font!");
|
||||
//return -1;
|
||||
}
|
||||
unsigned int newIndex = 0;
|
||||
for (const auto& f : Detail::fonts)
|
||||
if (f.index >= newIndex)
|
||||
newIndex = f.index + 1;
|
||||
|
||||
index = newIndex;
|
||||
Detail::fonts.push_back(font);
|
||||
std::cout << "Loaded font from " << path << " with index " << newIndex << std::endl;
|
||||
//return newIndex;
|
||||
}
|
||||
|
||||
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, This is *super* slow.");
|
||||
FT_Set_Pixel_Sizes(this->face, ptSize, ptSize);
|
||||
|
||||
for (const char& c : text) {
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
auto glyph_index = FT_Get_Char_Index(this->face, c);
|
||||
|
||||
auto error = FT_Load_Glyph(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;
|
||||
}
|
||||
|
||||
|
||||
}
|
103
src/types/FontCache.cpp
Normal file
103
src/types/FontCache.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include <JGL/types/FontCache.h>
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
char CachedGlyph::getCharacter() {
|
||||
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() {
|
||||
return font_size;
|
||||
}
|
||||
|
||||
unsigned int JGL::CachedFont::getFontIndex() {
|
||||
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::getTexture() {
|
||||
return &texture;
|
||||
}
|
||||
|
||||
GLsizei CachedFont::getTextureWidth() const {
|
||||
return texture_width;
|
||||
}
|
||||
|
||||
GLsizei CachedFont::getTextureHeight() const {
|
||||
return texture_height;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
19
src/types/Light.cpp
Normal file
19
src/types/Light.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <JGL/types/Light.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
JGL::Light::Light(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular) {
|
||||
this->position = Vector4(position, 1.0f);
|
||||
this->ambient = ambient;
|
||||
this->diffuse = diffuse;
|
||||
this->specular = specular;
|
||||
}
|
||||
|
||||
Vector3 JGL::Light::GetNormalizedSceenSpaceCoordinates() const {
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
float normalized_x = 2.0f * (position.x - viewport[0]) / viewport[2] - 1.0f;
|
||||
float normalized_y = 2.0f * (position.y - viewport[1]) / viewport[3] - 1.0f;
|
||||
|
||||
return {normalized_x, normalized_y, position.z};
|
||||
}
|
0
src/types/Material.cpp
Normal file
0
src/types/Material.cpp
Normal file
303
src/types/RenderTarget.cpp
Normal file
303
src/types/RenderTarget.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <stdexcept>
|
||||
|
||||
JGL::Texture* JGL::RenderTarget::GetJGLTexture() const {
|
||||
return texture;
|
||||
}
|
||||
|
||||
GLuint JGL::RenderTarget::GetGLTextureHandle() const {
|
||||
return texture->GetGLTextureHandle();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Vector2 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(JGL::Texture* texture, const Color4& clear_color) {
|
||||
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->GetGLTextureHandle(), 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->size = texture->GetDimensions();
|
||||
this->texture = texture;
|
||||
texture_created_by_us = false;
|
||||
}
|
||||
|
||||
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
//Textures behave strangely if they're not square aaaaaaaaaaaaa.
|
||||
unsigned int biggest;
|
||||
if (size.x >= size.y)
|
||||
biggest = size.x;
|
||||
else biggest = size.y;
|
||||
|
||||
texture = new Texture(Vector2(biggest, biggest));
|
||||
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->GetGLTextureHandle(), 0);
|
||||
|
||||
if (use_depth) {
|
||||
GLuint depthBuffer;
|
||||
glGenRenderbuffers(1, &depthBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, biggest, biggest);
|
||||
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;
|
||||
this->texture->SetFlags(INVERT_Y);
|
||||
|
||||
if (sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
SetMSAAEnabled(sample_rate);
|
||||
}
|
||||
|
||||
std::vector<GLfloat> JGL::RenderTarget::GetData() 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 Vector2& new_size) {
|
||||
if (!texture_created_by_us)
|
||||
Logger::Fatal("Resizing a texture that already existed?");
|
||||
|
||||
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 what was previously not part of the renderable area is big enough to
|
||||
* just set the new size without reading data back */
|
||||
if (new_size.x <= texture->GetDimensions().x && new_size.y <= texture->GetDimensions().y) {
|
||||
size = new_size;
|
||||
|
||||
// Clear.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
auto cc = GetClearColor();
|
||||
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
|
||||
glViewport(0,0, size.x, size.y);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (using_depth)
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
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]);
|
||||
return;
|
||||
}
|
||||
|
||||
//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;
|
||||
|
||||
unsigned int biggest;
|
||||
if (new_size.x >= new_size.y)
|
||||
biggest = new_size.x;
|
||||
else
|
||||
biggest = new_size.y;
|
||||
|
||||
auto cc = GetClearColor();
|
||||
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
|
||||
glViewport(0,0, size.x, size.y);
|
||||
|
||||
texture = new Texture(Vector2((float) biggest, (float) biggest));
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 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::TextureCreatedByRenderTarget() 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;
|
||||
}
|
||||
|
||||
void 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;
|
||||
|
||||
// If we'd be rendering onto a texture and not a plain render target we don't want this.
|
||||
if (!TextureCreatedByRenderTarget())
|
||||
return;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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, JGL::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, JGL::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 MSAA " + std::to_string(to_int(sample_rate)) + "x 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);
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit() const {
|
||||
if (MSAAEnabled() && TextureCreatedByRenderTarget()) {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Fixes using render targets on a texture that has mipmaps.
|
||||
if (GetJGLTexture()->GetFilteringMode() == TextureFilteringMode::MIPMAP_NEAREST
|
||||
|| GetJGLTexture()->GetFilteringMode() == TextureFilteringMode::MIPMAP_BILINEAR ||
|
||||
GetJGLTexture()->GetFilteringMode() == TextureFilteringMode::MIPMAP_TRILINEAR) {
|
||||
GLint current_texture = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, GetJGLTexture()->GetGLTextureHandle());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, current_texture);
|
||||
}
|
||||
}
|
185
src/types/Texture.cpp
Normal file
185
src/types/Texture.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace ReImage;
|
||||
|
||||
namespace JGL
|
||||
{
|
||||
Texture::Texture(const std::string& file, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode, const TextureFlag& flags)
|
||||
{
|
||||
auto* t = new ReImage::Image(file, flags);
|
||||
GLuint previous_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
|
||||
|
||||
load(t, {(float) t->getWidth(), (float) t->getHeight()}, t->getTextureFormat(), filtering_mode, wrapping_mode);
|
||||
texture_flags = flags;
|
||||
|
||||
delete t;
|
||||
}
|
||||
|
||||
Texture::Texture(const Vector2& size) {
|
||||
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);
|
||||
//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, (int) size.x, (int) size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
texture_format = TextureFormat::RGBA;
|
||||
texture_size = size;
|
||||
texture_filtering_mode = TextureFilteringMode::NEAREST;
|
||||
texture_wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE;
|
||||
texture_flags = TextureFlag::NONE;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, previous_texture);
|
||||
}
|
||||
|
||||
void Texture::load(Image* software_texture, const Vector2& size, const TextureFormat& format,
|
||||
TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
|
||||
|
||||
GLuint previous_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
|
||||
|
||||
glGenTextures(1, &texture_handle);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_handle);
|
||||
|
||||
if (format == TextureFormat::RGBA)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int) size.x, (int) size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
software_texture->pixel_data.data());
|
||||
|
||||
else if (format == TextureFormat::RGB)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (int) size.x, (int) size.y, 0, GL_RGB, GL_UNSIGNED_BYTE,
|
||||
software_texture->pixel_data.data());
|
||||
|
||||
if (wrapping_mode == TextureWrappingMode::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 == TextureWrappingMode::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 == TextureWrappingMode::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 == TextureWrappingMode::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 == TextureFilteringMode::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 == TextureFilteringMode::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 == TextureFilteringMode::MIPMAP_NEAREST ||
|
||||
filtering_mode == TextureFilteringMode::MIPMAP_BILINEAR ||
|
||||
filtering_mode == TextureFilteringMode::MIPMAP_TRILINEAR) {
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
|
||||
if (filtering_mode == TextureFilteringMode::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 == TextureFilteringMode::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 == TextureFilteringMode::MIPMAP_TRILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
texture_size = size;
|
||||
texture_format = format;
|
||||
texture_filtering_mode = filtering_mode;
|
||||
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) (texture_size.x * texture_size.y));
|
||||
glBindTexture(GL_TEXTURE_2D, texture_handle);
|
||||
|
||||
if (texture_format == TextureFormat::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) (texture_size.x * texture_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;
|
||||
}
|
||||
|
||||
void Texture::Erase() {
|
||||
if (texture_handle != 0)
|
||||
glDeleteTextures(1, &texture_handle);
|
||||
texture_handle = 0;
|
||||
}
|
||||
|
||||
GLuint Texture::GetGLTextureHandle() const {
|
||||
return texture_handle;
|
||||
}
|
||||
|
||||
Vector2 Texture::GetDimensions() const {
|
||||
return texture_size;
|
||||
}
|
||||
|
||||
TextureFlag Texture::GetFlags() const {
|
||||
return texture_flags;
|
||||
}
|
||||
|
||||
TextureFormat Texture::GetFormat() const {
|
||||
return texture_format;
|
||||
}
|
||||
|
||||
TextureFilteringMode Texture::GetFilteringMode() const {
|
||||
return texture_filtering_mode;
|
||||
}
|
||||
|
||||
void Texture::SetTextureHandle(GLuint handle) {
|
||||
texture_handle = handle;
|
||||
}
|
||||
|
||||
TextureWrappingMode Texture::GetWrappingMode() const {
|
||||
return texture_wrapping_mode;
|
||||
}
|
||||
|
||||
Texture::Texture(Image* software_texture, const Vector2& size, const TextureFormat& format,
|
||||
TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
|
||||
load(software_texture, size, format, filtering_mode, wrapping_mode);
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
Erase();
|
||||
}
|
||||
|
||||
Texture::Texture(const Texture& rhs) {
|
||||
auto pixels = rhs.GetPixelData();
|
||||
auto image = Image(pixels.data(), pixels.size(), rhs.GetDimensions().x, rhs.GetDimensions().y);
|
||||
this->load(&image, rhs.GetDimensions(), rhs.texture_format, rhs.texture_filtering_mode, rhs.texture_wrapping_mode);
|
||||
this->texture_flags = rhs.texture_flags;
|
||||
}
|
||||
|
||||
void Texture::SetFlags(const TextureFlag &flags) {
|
||||
this->texture_flags = flags;
|
||||
}
|
||||
}
|
270
src/types/VRamList.cpp
Normal file
270
src/types/VRamList.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
#include <JGL/types/VRamList.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <cstring>
|
||||
|
||||
void JGL::VRamList::load(const GLfloat* data, const long& size) {
|
||||
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);
|
||||
}
|
||||
|
||||
void JGL::VRamList::load(const GLuint* data, const long& size) {
|
||||
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);
|
||||
}
|
||||
|
||||
void JGL::VRamList::Erase() {
|
||||
if (list_handle == 0) {
|
||||
JGL::Logger::Warning("Erasing an uninitialized VRamList?");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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::GetSize() const {
|
||||
if (element_array_buffer)
|
||||
return sizeof(GLuint) * num_elements;
|
||||
return sizeof(GLfloat) * num_elements;
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(void* data, const long& length) {
|
||||
bool should_resize = (this->num_elements != length);
|
||||
|
||||
if (should_resize) {
|
||||
glDeleteBuffers(1, &list_handle);
|
||||
list_handle = 0;
|
||||
|
||||
if (!element_array_buffer)
|
||||
load((GLfloat*) data, sizeof(GLfloat) * length);
|
||||
else
|
||||
load((GLuint*) data, sizeof(GLuint) * length);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(void* data, const long& offset, const long& length) {
|
||||
|
||||
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));
|
||||
SetData(list_data.data(), list_data.size());
|
||||
}
|
||||
else {
|
||||
auto list_data = GetDataF();
|
||||
list_data.resize(list_data.size() + oob_delta);
|
||||
memcpy(list_data.data() + (offset * sizeof(GLfloat)), data, length * sizeof(GLfloat));
|
||||
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);
|
||||
}
|
||||
|
||||
std::vector<GLfloat> JGL::VRamList::GetDataF() const {
|
||||
if (element_array_buffer)
|
||||
JGL::Logger::Warning("Getting data as GLfloat but the buffer data is GLuint?");
|
||||
|
||||
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);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<GLuint> JGL::VRamList::GetDataUI() const {
|
||||
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(Vector2* data, const long& length) {
|
||||
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector2) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(Vector3* data, const long& length) {
|
||||
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector3) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(Vector4* data, const long& length) {
|
||||
load(reinterpret_cast<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) {
|
||||
if (rhs.element_array_buffer) {
|
||||
auto data_array = rhs.GetDataUI();
|
||||
this->load(data_array.data(), data_array.size());
|
||||
return;
|
||||
}
|
||||
|
||||
auto data_array = rhs.GetDataF();
|
||||
this->load(data_array.data(), data_array.size());
|
||||
}
|
Reference in New Issue
Block a user