Compare commits

...

165 Commits

Author SHA1 Message Date
1597662e2e Just pushing what I have.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 47s
2024-12-22 00:38:16 -05:00
0823730e82 Better Wavefront OBJ loader.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m35s
2024-12-20 10:12:11 -05:00
6cbd369d51 Fixed one side of the cube looking weird
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m9s
How I understand it, When lighting a cube specifically. It will always look weird because it's just not enough information 🤷
2024-12-18 11:11:26 -05:00
926ae06834 Merge branch 'master' of https://git.redacted.cc/Josh/JGL
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m59s
2024-12-17 21:40:06 -05:00
d5fd68eba8 Light test 1 2024-12-17 21:39:58 -05:00
08b2dfbecc Update internals.h
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m20s
msvc
2024-12-17 13:58:07 -05:00
e33a51b7d4 Materials.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m18s
2024-12-16 22:25:36 -05:00
7f5ee5cf0c Pushing what I have.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m57s
2024-12-16 16:33:16 -05:00
401e2c0883 Minor edits.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m37s
2024-12-09 18:46:24 -05:00
e5bdc441d1 Merge branch 'master' of https://git.redacted.cc/Josh/JGL
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m45s
2024-12-09 14:21:44 -05:00
392375e56c small refactor 2024-12-09 14:21:34 -05:00
b007c78cfe Roll back to code from prelease-41. Fix segfault later
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m0s
2024-12-09 13:15:46 -05:00
512dc3cb1a Separate J2D and J3D.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m10s
2024-12-08 10:30:03 -05:00
a22a83d2f8 Fix out-of-date ReWindow API usage.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m0s
2024-12-06 12:05:29 -05:00
76cd48c9b7 Update Font.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m31s
Fixed several cases where the font index would be incorrect.
2024-12-06 11:34:38 -05:00
38bb1b22ce Include Jupiteroid as a default font
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m41s
2024-12-04 16:22:14 -05:00
122644a013 Update repositories
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m3s
2024-12-04 14:25:48 -05:00
Redacted
641f2de8d0 Update CMakeLists.txt
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m22s
2024-12-04 11:16:20 -05:00
6618aa5e6b just pushing what I have
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m20s
2024-12-01 11:00:48 -05:00
3970aa2718 Update GLAD
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m22s
2024-11-25 16:53:20 -05:00
fb5ca55fda Alpha masked sprite.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m44s
2024-11-22 07:46:48 -05:00
bcca6285af J2D DottedLine & DashedLine
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m41s
2024-11-20 18:04:21 -05:00
f8395726cd Improve performance of single-pixel blit.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m5s
2024-11-20 09:23:09 -05:00
ca7abb3044 DrawPartialRenderTarget
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m57s
2024-11-19 19:55:08 -05:00
14c45ab0f1 Merge branch 'master' of https://git.redacted.cc/Josh/JGL
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m34s
2024-11-14 18:19:42 -05:00
1ca5e5a694 Fix for Windows. 2024-11-14 18:22:28 -05:00
25fc3f8698 Fix for Windows.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2024-11-14 18:20:57 -05:00
a836fc7b32 More batching & performance optimization.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m56s
2024-11-14 16:14:18 -05:00
e6dcc9d61e Reformatting
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m56s
2024-11-14 10:57:00 -05:00
6dff2f97c1 BatchWireframeAABB
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m54s
2024-11-13 21:07:21 -05:00
dbcc3e11e1 Update CMakeLists.txt
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m23s
2024-11-13 15:16:29 -05:00
b2bc1170df Blit single pixel onto target RenderTarget (cave-game)
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m25s
2024-11-13 11:51:20 -05:00
5d7fe84bd0 BatchWireframeRevoSphere
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m11s
2024-11-13 10:04:32 -05:00
627a047a9b Batching for WireframeSphere.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m48s
2024-11-12 22:50:18 -05:00
f0e2cd151f cleanup
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m43s
2024-11-12 21:41:42 -05:00
bf60c14d5e Improve thread safety.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m42s
2024-11-12 14:31:43 -05:00
83a9baea34 Cleanup
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m9s
2024-11-12 11:31:18 -05:00
Redacted
95de887499 Update README.md
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m48s
2024-11-01 15:13:02 -04:00
81ebc175e2 Structures for skeletons
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m57s
2024-11-01 13:09:32 -04:00
82669b43bc Wireframe OBB + VertexArray
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m47s
2024-10-31 12:50:56 -04:00
779f212a29 Implemented J3D::DrawCubicBezierCurve
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m42s
2024-10-25 13:17:07 -04:00
0cc18cfdad J3D Framework Progress
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m19s
2024-10-25 11:35:31 -04:00
da35075735 Work-in-progress documentation for J3D x2
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m21s
2024-10-24 13:33:32 -04:00
d29ea018c3 Work-in-progress documentation for J3D
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 3m55s
2024-10-24 13:22:51 -04:00
72c256f907 FillSphere is completely fucked.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m46s
2024-10-24 12:42:38 -04:00
7687c0d873 fix winding order
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m51s
2024-10-24 12:23:55 -04:00
ad34e9ffc0 Implement FillAABB
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m1s
2024-10-24 12:09:59 -04:00
5a9716af02 Implementation of WireframeAABB (Still validating?)
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m1s
2024-10-24 11:24:25 -04:00
ce5c4d4eb1 Sending up work
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m44s
2024-10-23 14:16:33 -04:00
0302c43f5d Merge branch 'master' of https://git.redacted.cc/Josh/JGL
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m41s
2024-10-22 22:32:27 -04:00
9a5554e447 Update README.md 2024-10-22 22:32:21 -04:00
7dada0e51f This Dick
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m47s
2024-10-22 20:32:32 -04:00
807eef59bc a word
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m47s
2024-10-22 19:04:49 -04:00
4d97c6dead Make it go faster
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2024-10-22 19:02:01 -04:00
686a4be0c9 Visible Wireframe Sphere, need some camera rotation to see it properly though.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m44s
2024-10-22 13:46:59 -04:00
68ba438433 Fix Prior issue with circle render.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m17s
2024-10-22 13:30:52 -04:00
e4a4f01b28 Un-commenting Line 166 stops all rendering, also, it appears circles are gone?
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2024-10-22 13:26:04 -04:00
aa4a29961c Implement FillEllipse and OutlineEllipse
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m30s
2024-10-22 12:26:40 -04:00
55b67ab850 Update RenderTarget.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m38s
crash related to making a render target with a color attachment 0x0
2024-10-22 10:49:56 -04:00
68e98e6c43 Implement documentation + A special case check on DrawArc.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m50s
2024-10-21 13:03:44 -04:00
4e9645436e Implement documentation + A special case check on DrawArc.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2024-10-21 12:57:20 -04:00
ea99a96e64 Doxyfile
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m47s
2024-10-18 15:00:51 -04:00
6866ba828b Outline of Documentation work
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m45s
2024-10-18 14:50:20 -04:00
4893233301 Outline of Documentation work
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m51s
2024-10-18 13:25:48 -04:00
7b5ef6045b CachedFont destructor.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m59s
2024-10-18 10:01:21 -04:00
5998bec833 Cleanup.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m1s
Preparing for Release-1, J2D lighting is all that's left and then I can work on J3D.

Added helper functions to get rid of the constant need to dereference things.

Wrote a few functions that were defined but never implemented.
2024-10-17 12:48:28 -04:00
0f4ada563e Fix for Nvidia driver being exceedingly picky.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m24s
2024-10-17 00:40:55 -04:00
b9bae43cf3 Documentation work
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m51s
2024-10-16 14:30:42 -04:00
7f1794e48f Naiive & Slow (But correct) implementation of OutlineRoundedRect. Needs to be performance-improved to a contiguous line loop.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m7s
2024-10-16 13:19:42 -04:00
cc504c65ec copy construct RenderTarget.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m36s
2024-10-13 16:37:51 -04:00
bb4a80e36d Copy texture without readbacks.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m5s
2024-10-13 09:45:24 -04:00
5d981e64fc Merge remote-tracking branch 'origin/master'
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m6s
2024-10-11 13:29:59 -04:00
5b19d26b79 Implement rounding on DrawString input coordinates (Crisp text rendering even when users pass in non-integer values, however, still need to account for non-integer scaling). 2024-10-11 13:29:53 -04:00
8e834f9c5a glad update
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m51s
Only use the GL_ARB extension because it'll be more widely supported than EXT.
2024-10-10 22:09:21 -04:00
dbdb4f7ec1 I'll try this I guess idk.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m40s
2024-10-10 19:34:34 -04:00
39c7c7ac0d Fix using RenderTargets on a texture that has mipmaps.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m40s
Also better mipmap generation.
2024-10-10 13:12:18 -04:00
e155d272bb Update to latest everything
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m37s
2024-10-10 12:28:45 -04:00
2ee5015d61 Update RenderTarget.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m47s
Whoopsies
2024-10-09 23:08:17 -04:00
4484fd482f Update JGL.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m47s
Fix memory error
2024-10-09 22:54:41 -04:00
97573e28a9 Multi-Sample-Anti-Alias.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m4s
2024-10-09 22:22:24 -04:00
0417c37460 Render Targets Update.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m54s
Allow rendering onto a texture that's been loaded already.

Make DrawSprite commands work regardless of if the texture was loaded in inverted or not.

You however cannot draw onto a texture which is upside-down in vram because your draw commands would be positioned incorrectly.
2024-10-08 18:25:31 -04:00
0a757407d8 Update CMakeLists.txt
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m5s
Don't link libJGL.so to event.
2024-10-08 12:13:42 -04:00
308b0dc854 Improve memory safety.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m44s
Also fixed a case where we didn't reset the GL state correctly 🤷
2024-10-06 23:03:50 -04:00
5f367efc28 Ability to resize render targets.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m48s
2024-10-06 00:01:06 -04:00
b4c29315f4 Improve memory safety of VRamList
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m5s
Copying it around is slow and you wouldn't do it. But incase some idiot actually does so it doesn't break everything.
2024-10-05 20:14:46 -04:00
Redacted
a568faa701 Update .gitea/workflows/buildtest.yml
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m35s
2024-10-04 23:30:47 -04:00
9d89abb2b8 UpdateData in VRamList & QOL changes.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m45s
2024-10-04 22:50:57 -04:00
6e8185e2cd Fixed a memory error & unfinished lighting wrapper.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m50s
2024-10-02 22:38:29 -04:00
8fcfbddd44 Small performance optimizations.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m36s
2024-09-21 13:31:42 -04:00
4d761e874e Update main.cpp
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m39s
2024-09-19 19:49:29 -04:00
131ce4c78e Check for graphics driver support.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m44s
2024-09-19 19:39:07 -04:00
e712a5aaa3 RenderTarget GetData
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m11s
Async GetData is todo
2024-09-19 19:15:04 -04:00
b86377a092 Get VBO data back from the GPU.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 7m17s
2024-09-19 10:55:13 -04:00
5fc4914180 fix logger
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m45s
2024-09-17 23:19:55 -04:00
58e432b9c3 Make logging fit to standard
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m7s
2024-09-17 23:17:19 -04:00
41fa634da1 "VRam List" wrapped for VBO (useful later)
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 6m25s
2024-09-17 14:36:32 -04:00
9d6d256e80 fix for windoze
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m34s
2024-09-14 22:27:20 -04:00
0e22bc721a Positioning & Rotation bugfixes.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m51s
Make it such that a sprites "origin" doesn't effect the position. It is only the point at which transformations are done about.
2024-09-14 21:28:32 -04:00
881d031f3c Render Target for J2D
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m10s
2024-09-13 13:24:20 -04:00
9e3e0c949f Bugfix + Begin work on RenderTarget
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m0s
Fixed an issue that'd sometimes cause declaring a new texture to change to that texture.
2024-09-12 19:20:29 -04:00
1526a101c3 J3D::DrawString is now fast.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m33s
2024-09-11 20:36:46 -04:00
f6e8875eb9 ~ 5% speedup for font-rendering overall
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m55s
This is probably the last speedup for this.
2024-09-11 18:33:29 -04:00
9903fc19c9 Mirror Sprite and Cleanup
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 7m5s
2024-09-11 09:50:52 -04:00
e809b1b665 Rotate sprite & sub-sprite about origin
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 5m24s
2024-09-08 21:52:49 -04:00
d15b3f660d J3D draw string draw_back_face
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 7m30s
2024-09-05 11:50:12 -04:00
ff2a8ab787 Refactor & undo shader commits AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 6m18s
2024-09-05 11:20:57 -04:00
55160044b6 Fix cmake_minimum_required using rebitch
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m40s
2024-08-26 19:46:51 -04:00
04a4cbd54d Add Attributes to Shader.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m40s
2024-08-24 23:27:10 -04:00
f96a3851a1 Update engine components
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m32s
2024-08-24 10:58:37 -04:00
4996288163 More work on shader support.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m24s
2024-08-23 19:50:41 -04:00
f3c2fd5e93 Initial shader class & restructure
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m38s
2024-08-23 12:25:46 -04:00
6650af4fc4 Framerate test (Press 1)
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m42s
2024-08-22 19:27:31 -04:00
1d8823b046 Outline Polygon
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m8s
2024-08-22 11:55:56 -04:00
c0b65818c8 DrawPartialSprite
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m11s
2024-08-22 10:58:20 -04:00
32de87229e Update Texture.h
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 18m9s
2024-08-21 20:59:25 -04:00
3759affa5d Fix texture
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m10s
2024-08-21 20:36:31 -04:00
8ce9a08951 Resize fix
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m54s
2024-08-21 13:20:42 -04:00
ec964dbee1 Wondows :(
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m25s
2024-08-08 00:14:24 -04:00
91baa826fa Allow changing the fov and render distance
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m30s
2024-08-06 12:31:44 -04:00
c2446763ad Merge remote-tracking branch 'origin/master'
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m24s
2024-08-05 20:11:18 -04:00
6286b62998 Pull out debug iteration steps from DrawCubicBezierCurve 2024-08-05 20:11:12 -04:00
4de44ba1e2 Put this code back because it got removed again. Make sure you have the latest commit before doing anything :/
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m26s
2024-08-05 19:49:30 -04:00
166db43f2e Migrate to latest J3ML and ReWindow
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m36s
2024-08-05 18:31:13 -04:00
2a1085df2d Revert "Merge remote-tracking branch 'origin/master'"
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m20s
This reverts commit 240fa7ddbc, reversing
changes made to d89f79e70e.
2024-08-05 15:04:22 -04:00
240fa7ddbc Merge remote-tracking branch 'origin/master'
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m20s
# Conflicts:
#	main.cpp
2024-08-05 14:39:36 -04:00
d89f79e70e Cool BezierCurve demo (You can drag the endpoints around) 2024-08-05 14:38:42 -04:00
7bf30f6f39 Idk like make the viewport work maybe?
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m29s
2024-08-05 13:41:12 -04:00
2a70981bf0 Get software texture back.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m44s
2024-08-05 11:30:40 -04:00
0147245325 Refactored DrawSprite
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m16s
2024-08-05 00:52:08 -04:00
15dcb79479 Upd8
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m29s
2024-08-04 20:28:08 -04:00
50895153f5 Texture filtering
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m46s
2024-08-03 22:17:21 -04:00
9688854533 Texture class
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m25s
2024-08-02 20:03:32 -04:00
0005c036b4 Texture2D header
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m32s
2024-08-02 13:05:34 -04:00
af42d8fd25 Merge remote-tracking branch 'origin/master'
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m26s
2024-08-02 10:49:05 -04:00
ff4d014739 Implement Color3::FromHex() 2024-08-02 10:49:00 -04:00
9dda4bebc5 Make measure string go brrrrrrr
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 4m9s
2024-07-31 12:01:57 -04:00
a5bfb4972a Fill quad
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m32s
2024-07-30 23:37:47 -04:00
4348f2708a Gradient triangle
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m32s
2024-07-30 15:49:13 -04:00
32dd2b54ca incorporate builddeps.reci
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m40s
2024-07-29 19:30:23 -04:00
e8b601aa25 install build deps reci script
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 45s
2024-07-29 19:29:11 -04:00
d5fd3e1a49 reci lua edition
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 48s
2024-07-29 19:24:55 -04:00
f593a0beac Cleanup & Update ReTexture.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m29s
2024-07-19 17:16:38 -04:00
0b7af6fd31 Cleanup
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m46s
2024-07-19 01:34:43 -04:00
eca4309e85 DrawSprite
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m21s
2024-07-18 22:24:19 -04:00
4be97f52d9 Minor documentation additions.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m19s
2024-07-18 14:51:19 -04:00
613a13618c Merge branch 'master' of https://git.redacted.cc/Josh/JGL
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2024-07-18 14:49:19 -04:00
4150c93c85 Make it like, go faster. 2024-07-18 14:49:15 -04:00
9dee59fd45 Merge remote-tracking branch 'origin/master'
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m32s
2024-07-18 14:04:16 -04:00
b6b2ca1bfe Remove old LoadFont function. 2024-07-18 14:04:11 -04:00
4eca3311c8 Fix text being shifted up by it's own height.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2024-07-18 14:01:58 -04:00
54711355c4 Merge branch 'master' of https://git.redacted.cc/Josh/JGL
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m29s
2024-07-18 14:01:14 -04:00
8bddf3e0a7 Update JGL.cpp
Fix glBlend always being enabled because I'm an idiot
2024-07-18 14:00:57 -04:00
26d17dae38 Move glPixelStore call inside of InitTextEngine so users don't need to call it. Also adjusted Color3 and Color4, more work coming soon.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m18s
2024-07-18 13:45:11 -04:00
4ff8d8ff07 Update Font.cpp
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m33s
fix memleak
2024-07-17 16:52:31 -04:00
162732e4b7 Fix Dereference
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m24s
2024-07-17 16:11:36 -04:00
289157ab8a Fiddle with README some
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m37s
2024-07-17 15:54:39 -04:00
3a658b1096 Testing MeasureString with underlaid box. But it appears to be offset by half-height?
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 4m39s
2024-07-17 15:19:38 -04:00
480502f89e Implement Font::MeasureString (TODO: double check!!)
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m53s
2024-07-17 14:59:34 -04:00
d28f680cd0 Half-baked Font class implementation
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m29s
2024-07-16 14:54:47 -04:00
2d1e42c23b Half-ass Font class implementation
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m30s
2024-07-16 14:39:44 -04:00
abd691b648 uhhhhhhhhhh yeeeeeeea
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m28s
2024-07-16 14:19:39 -04:00
e261b610c2 Update TextRendering.cpp
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 5m24s
Reset the Texture after drawing text.
2024-07-15 11:50:27 -04:00
8625c52ee9 Implement optimizations for 2D text rendering (#23)
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m51s
The following patches are included:

## J2D: Rewrite text rendering

This patch rewrites text rendering for `J2D::DrawString` to now construct
a texture atlas for all ASCII-range glyphs in the FT font face, instead
of constructing a texture for every glyph.

This improves text rendering performance for several reasons:

1. Binding textures is relatively expensive as the GPU is required to do
   a context switch for internal data like texture parameters, and also
   cannot optimize for accesses to the same texture across draw calls.
   This patch removes the need to call `glBindTexture` more than once per
   call to `J2D::DrawString`.
2. As a consequence of the above, all glyphs for a given string can now
   be rendered in a single call to `glDrawArrays`. This is done by storing
   the cached texture coordinates on `CachedGlyph` and constructing a full
   array of vertices and texture coordinates for the entire string at
   once, resulting in only /one/ set of client-to-device attribute
   uploads and only one draw call, instead of being required to upload
   attribute data for each glyph separately.

## FontCache: Use map for efficient glyph lookup

This patch updates `CachedFont` to now use an `std::map` for cached glyphs,
instead of an `std::vector`. `std::map` allows O(log n) lookup, whereas
`std::vector` only allows O(n) lookup.

Note: `std::unordered_map` technically has better lookup complexity here,
with amortized O(1) lookup. However, hashmaps have a higher inherent
overhead than red-black trees so this would only be viable when going
above around 1000 entries, which should never happen here for ASCII
glyphs.

Co-authored-by: Ori Sky Farrell <ori.sky.farrell+git@gmail.com>
Reviewed-on: #23
Co-authored-by: ori_sky <redacted@ori.mx>
Co-committed-by: ori_sky <redacted@ori.mx>
2024-07-15 11:38:20 -04:00
74a4705e44 Fix windows being picky.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m28s
2024-07-12 13:14:24 -04:00
ae327b96a5 Cleanup
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m23s
2024-07-12 01:47:49 -04:00
55 changed files with 17480 additions and 1275 deletions

View File

@@ -17,8 +17,6 @@ jobs:
- 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 git && git clone $RECI_GIT $RECI
- run: bash $RECI/scripts/setup_build_tools.sh
- run: bash reci/scripts/install_build_dependencies.sh
- run: bash $RECI/scripts/run_buildtest.sh ${{ gitea.repository }}
- 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 }}."

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
/cmake-build-debug
/.idea
/assets/test_files

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.18)
cmake_minimum_required(VERSION 3.18..3.27)
project(JGL
VERSION 1.0
LANGUAGES CXX
@@ -14,30 +14,37 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Enable Package Managers
include(cmake/CPM.cmake)
CPMAddPackage(
NAME mcolor
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-5.zip
)
CPMAddPackage(
NAME J3ML
URL https://git.redacted.cc/josh/j3ml/archive/Release-2.2.zip
URL https://git.redacted.cc/josh/j3ml/archive/3.4.3.zip
)
CPMAddPackage(
NAME ReWindow
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-3.zip
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-26.zip
)
CPMAddPackage(
NAME GLAD
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_mt.zip
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo_depthtexture_shadow.zip
)
CPMAddPackage(
NAME jlog
URL https://git.redacted.cc/josh/jlog/Prerelease-12.zip
URL https://git.redacted.cc/josh/jlog/Prerelease-16.zip
)
CPMAddPackage(
NAME Event
URL https://git.redacted.cc/josh/Event/archive/Release-6.zip
NAME ReImage
URL https://git.redacted.cc/Redacted/ReImage/archive/Release-2.0.zip
)
if (WIN32)
#CPMAddPackage(
#NAME harfbuzz
@@ -50,10 +57,12 @@ if (WIN32)
)
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 HEADERS "include/*.h" "include/*.hpp" )
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp" "src/internals/*.h")
find_package(OpenGL REQUIRED)
@@ -68,29 +77,35 @@ 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
${Event_SOURCE_DIR}/include
${ReWindow_SOURCE_DIR}/include
${glad_SOURCE_DIR}/include
${jlog_SOURCE_DIR}/include
${glad_SOURCE_DIR}/include
)
add_executable(JGL_Demo main.cpp)
#set_target_properties(JGL_Demo PROPERTIES LINK_FLAGS "-Wl,-rpath,./lib")
if (UNIX AND NOT APPLE)
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS} )
target_link_libraries(JGL PRIVATE ${FREETYPE_LIBRARIES})
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} J3ML ReWindowLibrary glad jlog Event)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML jlog ReImage glad)
endif()
if (WIN32)
target_include_directories(JGL PRIVATE ${freetype_SOURCE_DIR}/include)
target_link_libraries(JGL PRIVATE freetype)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} J3ML ReWindowLibrary glad jlog Event)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog ReImage glad)
endif()
target_link_libraries(JGL_Demo PUBLIC JGL)
target_link_libraries(JGL_Demo PUBLIC JGL ReWindowLibrary Event glad)

2743
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,43 +1,77 @@
# Josh Graphics Library
# Josh's Graphics Library
Yet Another C++ Rendering Toolkit
![Static Badge](https://img.shields.io/badge/Lit-Based-%20)
[![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue.svg)](http://unlicense.org/) ![Static Badge](https://img.shields.io/badge/Lit-Based-%20)
## 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.
## Non-Goals
* Full Rendering Engine
* OpenGL/Vulkan Wrapper
* Asset Loading & Management
## Features
* Modern C++ (20)
* Little-to-no overhead
* No hand-holding
* No-frills, straight up just renders shapes and text.
* Modern C++ (20).
* Cross Platform (Linux & Windows 10 1909 or newer).
* Provides single-function-calls to render various graphics in 2D and 3D.
* Integrates right into an existing OpenGL rendering system.
* Quick Rendering of Text, Shapes, Sprites / Textures, etc.
* High-performance text rendering.
* Little-to-no overhead.
## API Overview
### J2D
* DrawPoint
* DrawLine / DrawGradientLine
* DrawSprite / DrawPartialSprite
* OutlineRect / FillRect / FillGradientRect / FillRoundedRect
* OutlineCircle / FillCircle
* OutlineTriangle / FillTriangle
* DrawString
### J3D
* DrawLine
* DrawString
* DrawMatrixGizmo (WIP)
* DrawAxisAngleGizmo (WIP)
* DrawQuaternionGizmo (WIP)
### Types
* RenderTarget
* VRamList
* Texture
* Font
## Usage
```cpp
// Makes sure the glViewport will be the correct size.
// Typically done once per frame.
JGL::Update(window_size);
Install instructions and code samples coming soon :tm: !
JGL::J2D::Begin();
JGL::J2D::FillRect(Colors::Blue, {0,0}, {16,16});
JGL::J2D::End();
// See the example program in main.cpp for more in-depth usage.
```
## Requirements
An OpenGL 2.1 or newer accelerator with at-least two texture mappers that supports the `GL_ARB_framebuffer_object` extension or
an implementation that can provide those features through alternative means (common on ArmSoC and Risc-V).
## Compatability
* AMD ✓
* NVIDIA ✓
* Intel ✓
* Zink (OpenGL-on-Vulkan) ✓
* GL4ES ✓
## Documentation
Documentation is (sic: will be) automatically generated from latest commit and is hosted at https://doc.redacted.cc/jgl .
Documentation is available [here](https://doc.redacted.cc/JGL/d3/dcc/md__r_e_a_d_m_e.html).
## Contributing
Contributions to JGL are welcome! If you find a bug, have a feature request, or would like to contribute code, please submit an issue or pull request to our repository!
## 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.

Binary file not shown.

164
assets/models/cone.obj Normal file
View File

@@ -0,0 +1,164 @@
# Blender v3.6.4 OBJ File: ''
# www.blender.org
o Cone
v 0.000000 -1.000000 -1.000000
v 0.195090 -1.000000 -0.980785
v 0.382683 -1.000000 -0.923880
v 0.555570 -1.000000 -0.831470
v 0.707107 -1.000000 -0.707107
v 0.831470 -1.000000 -0.555570
v 0.923880 -1.000000 -0.382683
v 0.980785 -1.000000 -0.195090
v 1.000000 -1.000000 0.000000
v 0.980785 -1.000000 0.195090
v 0.923880 -1.000000 0.382683
v 0.831470 -1.000000 0.555570
v 0.707107 -1.000000 0.707107
v 0.555570 -1.000000 0.831470
v 0.382683 -1.000000 0.923880
v 0.195090 -1.000000 0.980785
v 0.000000 -1.000000 1.000000
v -0.195090 -1.000000 0.980785
v -0.382683 -1.000000 0.923880
v -0.555570 -1.000000 0.831470
v -0.707107 -1.000000 0.707107
v -0.831470 -1.000000 0.555570
v -0.923880 -1.000000 0.382683
v -0.980785 -1.000000 0.195090
v -1.000000 -1.000000 0.000000
v -0.980785 -1.000000 -0.195090
v -0.923880 -1.000000 -0.382683
v -0.831470 -1.000000 -0.555570
v -0.707107 -1.000000 -0.707107
v -0.555570 -1.000000 -0.831470
v -0.382683 -1.000000 -0.923880
v -0.195090 -1.000000 -0.980785
v 0.000000 1.000000 0.000000
vt 0.250000 0.490000
vt 0.250000 0.250000
vt 0.296822 0.485388
vt 0.341844 0.471731
vt 0.383337 0.449553
vt 0.419706 0.419706
vt 0.449553 0.383337
vt 0.471731 0.341844
vt 0.485388 0.296822
vt 0.490000 0.250000
vt 0.485388 0.203178
vt 0.471731 0.158156
vt 0.449553 0.116663
vt 0.419706 0.080294
vt 0.383337 0.050447
vt 0.341844 0.028269
vt 0.296822 0.014612
vt 0.250000 0.010000
vt 0.203178 0.014612
vt 0.158156 0.028269
vt 0.116663 0.050447
vt 0.080294 0.080294
vt 0.050447 0.116663
vt 0.028269 0.158156
vt 0.014612 0.203178
vt 0.010000 0.250000
vt 0.014612 0.296822
vt 0.028269 0.341844
vt 0.050447 0.383337
vt 0.080294 0.419706
vt 0.116663 0.449553
vt 0.158156 0.471731
vt 0.796822 0.014612
vt 0.514612 0.203178
vt 0.703178 0.485388
vt 0.203178 0.485388
vt 0.750000 0.490000
vt 0.796822 0.485388
vt 0.841844 0.471731
vt 0.883337 0.449553
vt 0.919706 0.419706
vt 0.949553 0.383337
vt 0.971731 0.341844
vt 0.985388 0.296822
vt 0.990000 0.250000
vt 0.985388 0.203178
vt 0.971731 0.158156
vt 0.949553 0.116663
vt 0.919706 0.080294
vt 0.883337 0.050447
vt 0.841844 0.028269
vt 0.750000 0.010000
vt 0.703178 0.014612
vt 0.658156 0.028269
vt 0.616663 0.050447
vt 0.580294 0.080294
vt 0.550447 0.116663
vt 0.528269 0.158156
vt 0.510000 0.250000
vt 0.514612 0.296822
vt 0.528269 0.341844
vt 0.550447 0.383337
vt 0.580294 0.419706
vt 0.616663 0.449553
vt 0.658156 0.471731
s off
f 1/1 33/2 2/3
f 2/3 33/2 3/4
f 3/4 33/2 4/5
f 4/5 33/2 5/6
f 5/6 33/2 6/7
f 6/7 33/2 7/8
f 7/8 33/2 8/9
f 8/9 33/2 9/10
f 9/10 33/2 10/11
f 10/11 33/2 11/12
f 11/12 33/2 12/13
f 12/13 33/2 13/14
f 13/14 33/2 14/15
f 14/15 33/2 15/16
f 15/16 33/2 16/17
f 16/17 33/2 17/18
f 17/18 33/2 18/19
f 18/19 33/2 19/20
f 19/20 33/2 20/21
f 20/21 33/2 21/22
f 21/22 33/2 22/23
f 22/23 33/2 23/24
f 23/24 33/2 24/25
f 24/25 33/2 25/26
f 25/26 33/2 26/27
f 26/27 33/2 27/28
f 27/28 33/2 28/29
f 28/29 33/2 29/30
f 29/30 33/2 30/31
f 30/31 33/2 31/32
f 16/33 24/34 32/35
f 31/32 33/2 32/36
f 32/36 33/2 1/1
f 32/35 1/37 2/38
f 2/38 3/39 4/40
f 4/40 5/41 6/42
f 6/42 7/43 8/44
f 8/44 9/45 10/46
f 10/46 11/47 12/48
f 12/48 13/49 14/50
f 14/50 15/51 16/33
f 16/33 17/52 18/53
f 18/53 19/54 20/55
f 20/55 21/56 22/57
f 22/57 23/58 24/34
f 24/34 25/59 26/60
f 26/60 27/61 28/62
f 28/62 29/63 30/64
f 30/64 31/65 32/35
f 32/35 2/38 8/44
f 2/38 4/40 8/44
f 4/40 6/42 8/44
f 8/44 10/46 16/33
f 10/46 12/48 16/33
f 12/48 14/50 16/33
f 16/33 18/53 24/34
f 18/53 20/55 24/34
f 20/55 22/57 24/34
f 24/34 26/60 32/35
f 26/60 28/62 32/35
f 28/62 30/64 32/35
f 32/35 8/44 16/33

38
assets/models/cube.obj Normal file
View File

@@ -0,0 +1,38 @@
# Blender v3.6.4 OBJ File: ''
# www.blender.org
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vt 0.875000 0.500000
vt 0.625000 0.750000
vt 0.625000 0.500000
vt 0.375000 1.000000
vt 0.375000 0.750000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.375000 0.500000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.625000 0.250000
vt 0.875000 0.750000
vt 0.625000 1.000000
s off
f 5/1 3/2 1/3
f 3/2 8/4 4/5
f 7/6 6/7 8/8
f 2/9 8/10 6/11
f 1/3 4/5 2/9
f 5/12 2/9 6/7
f 5/1 7/13 3/2
f 3/2 7/14 8/4
f 7/6 5/12 6/7
f 2/9 4/5 8/10
f 1/3 3/2 4/5
f 5/12 1/3 2/9

View File

@@ -0,0 +1,5 @@
#version 120
void main() {
gl_FragColor = vec4(1, 1, 1, 1);
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,24 +0,0 @@
#pragma once
#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;
Color3(u8 R, u8 G, u8 B) : r(R), g(G), b(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;}
};
}

View File

@@ -1,17 +0,0 @@
#pragma once
#include <JGL/Color3.h>
namespace JGL
{
class Color4 {
public:
explicit Color4(const Color3& color3, unsigned int alpha) {r = color3.r; g = color3.g; b = color3.b; a = alpha;}
Color4(int red, int green, int blue, int alpha = 127) : r(red), g(green), b(blue), a(alpha) {}
static Color4 FromColor3(const Color3& color3, unsigned int alpha = 127) {return Color4(color3, alpha);}
int r;
int g;
int b;
int a;
};
}

View File

@@ -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};
}
}
}

View File

@@ -1,53 +0,0 @@
#pragma once
#include <vector>
#include <glad/glad.h>
namespace JGL {
class CachedGlyph;
class CachedFont;
class FontCache;
}
class JGL::CachedGlyph {
private:
GLuint texture = 0;
char character;
public:
int x2offset = 0, y2offset = 0, w = 0, h = 0;
float advanceX = 0, advanceY = 0;
//CachedGlyph(GLuint texture_id, char c);
CachedGlyph(GLuint texture_id, char c, float x2o, float y2o, float w, float h, float advX, float advY);
char getCharacter();
const GLuint* getTexture();
};
class JGL::CachedFont {
private:
std::vector<CachedGlyph*> glyphs{};
unsigned int font_size = 0;
unsigned int font_index = 0;
public:
void appendGlyph(CachedGlyph* glyph);
void eraseGlyph(CachedGlyph* glyph);
void eraseGlyph(char c);
void eraseGlyph(GLuint texture_id);
unsigned int getFontSize();
unsigned int getFontIndex();
CachedGlyph* getGlyph(char c);
std::vector<CachedGlyph*>* getGlyphs();
CachedFont(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(unsigned int font_size, unsigned int font_index);
void eraseFont(CachedFont* font);
void purgeCache();
};

View File

@@ -1,12 +0,0 @@
#pragma once
#include <J3ML/J3ML.h>
namespace JGL {
enum class Gradient : u8 {
Vertical = 0,
Horizontal = 1,
DiagonalTopLeft = 2,
DiagonalBottomLeft = 3
};
}

View File

@@ -1,167 +1,686 @@
//
// Created by dawsh on 1/17/24.
//
/// Josh's Graphics Library
/// A C++20 Library for rendering 2D and 3D primitives in an OpenGL context.
/// Developed and Maintained by Josh O'Leary @ Redacted Software.
/// Special Thanks to William Tomasine II and Maxine Hayes.
/// (c) 2024 Redacted Software
/// This work is dedicated to the public domain.
/// @file JGL.h
/// @desc All JGL usable functions are defined here. This is the public API.
/// @edit 2024-10-24
#pragma once
#include <string>
#include <iostream>
#include <JGL/Color4.h>
#include <JGL/Gradient.h>
#include <JGL/FontCache.h>
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Vector2.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/Geometry/Sphere.h>
#include <J3ML/Geometry/Capsule.h>
#include <J3ML/Geometry/TriangleMesh.h>
#include <Color4.hpp>
#include <JGL/types/Texture.h>
#include <JGL/types/Enums.h>
#include <JGL/types/FontCache.h>
#include <JGL/types/Font.h>
#include <JGL/types/RenderTarget.h>
#include <JGL/types/Light.h>
#include <J3ML/LinearAlgebra.hpp>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/Geometry/Sphere.hpp>
#include <J3ML/Geometry/Capsule.hpp>
#include <J3ML/Geometry/Triangle2D.hpp>
#include <JGL/types/Font.h>
#include <JGL/types/VRamList.h>
#include <JGL/types/VertexArray.h>
// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
// Fonts that are included by default.
namespace JGL::Fonts {
void Init();
// Built in fonts.
inline Font Jupiteroid;
}
// Simple shapes that are pre-computed and used in some draw functions.
namespace JGL::ShapeCache {
inline VRamList* cube_vertex_data = nullptr;
inline VRamList* cube_index_data = nullptr;
inline VRamList* cube_normal_data = nullptr;
// Facing straight out.
inline VRamList* j2d_default_normal_data = nullptr;
void Init();
}
/// OpenGL Wrapper for rendering 2D & 3D graphics in both a 2D and 3D context.
namespace JGL {
using namespace J3ML::LinearAlgebra;
using namespace J3ML::Geometry;
using J3ML::LinearAlgebra::Vector2;
using J3ML::LinearAlgebra::Vector3;
using J3ML::LinearAlgebra::Matrix3x3;
using J3ML::LinearAlgebra::Matrix4x4;
using J3ML::LinearAlgebra::AxisAngle;
using J3ML::LinearAlgebra::Quaternion;
[[nodiscard]] bool Init(const Vector2& window_size, float fovY, float far_plane);
void Update(const Vector2& window_size);
inline void PurgeFontCache() { JGL::fontCache.purgeCache(); }
using J3ML::Geometry::Sphere;
using J3ML::Geometry::OBB;
using J3ML::Geometry::Capsule;
using J3ML::Geometry::TriangleMesh;
using J3ML::Geometry::Plane;
struct HSV {
float hue;
float saturation;
float value;
};
std::array<GLfloat, 16> OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far);
struct Triangle2D
{
Vector2 A;
Vector2 B;
Vector2 C;
};
/// @returns true if the graphics driver meets the requirements (GL Version & Extensions).
bool MeetsRequirements();
}
struct Triangle3D
{
Vector3 A;
Vector3 B;
Vector3 C;
};
/// Drawing functions for 2D objects.
namespace JGL::J2D {
/// Open a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @note This call may not strictly be necessary on some setups, but is provided to keep the API constant.
/// It is recommended to always open a JGL 2D context to render your content, then close when completed.
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 3D content in between our calls.
/// @param render_target
/// @param clear_buffers
void Begin(RenderTarget* render_target = nullptr, bool clear_buffers = false);
bool Update(const Vector2& window_size);
bool InitTextEngine();
int LoadFont(const std::string& font_path);
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @see Begin().
void End();
void UnloadFont(int font_index);
// TODO: implement correct coloring
/// Provide a list of lights to be used in 2D space. Typically directly after J2D::Begin();
/// 8 lights maximum for now. Some kind of light sorting will eventually be needed per j2d element.
void OptionalLights(const LightBase** lights, const size_t& light_count);
/// Drawing functions for primitive 2D Shapes.
/// Each function is overloaded with Color3 and Color4 for optional transparency.
namespace J2D {
/// Specifies a light which is required for every object in the scene.
void RequiredLight(const LightBase* light);
/// 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();
/// Closes a 2-D rendering context with the underlying graphics system (In this case & by default OpenGL).
/// @see Begin().
void End();
/// Plots a single pixel on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param coordinates The pixel-point on-screen at which to plot the pixel.
/// @param radius The size of the point to plot. By default, a single pixel.
void DrawPoint(const Color4& color, const Vector2& coordinates, float radius = 1.f);
void DrawPoint(const Color4& color, float x, float y, float radius = 1.f);
/// Plots a single pixel on the screen.
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4
/// @param coordinates The pixel-point on-screen at which to plot the pixel.
void DrawPixel(const Color3& color, const Vector2& coordinates);
void DrawPixel(const Color3& color, float x, float y);
void DrawPixel(const Color4& color, const Vector2& coordinates);
void DrawPixel(const Color4& color, float x, float y);
/// Plots a series of pixel-points on the screen, in a batch.
/// @note This is more performant for multiple points than plotting them individually.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param points A set of x,y points to render.
/// @param radius The size of the point to plot. By default, a single pixel.
void DrawPoints(const Color4& color, const Vector2* points, int point_count, float radius = 1.f);
/// Plots a line (segment) on the screen.
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
/// @param A The starting point of the line segment.
/// @param B The end point of the line segment.
/// @param thickness The width at which to render the line.
void DrawLine(const Color3& color, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawLine(const Color3 &color, float x, float y, float w, float h, float thickness = 1);
void DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawLine(const Color4& color, float x1, float y1, float x2, float y2, float thickness = 1);
/// Plots 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& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawGradientLine(const Color3& color1, const Color3& color2, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawGradientLine(const Color4& color1, const Color4& color2, float x, float y, float w, float h, float thickness = 1);
void DrawGradientLine(const Color3& color1, const Color3& color2, float x, float y, float w, float h, float thickness = 1);
/// Plots a line segment using a series of points separated by a given distance.
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
/// @param A The starting point of the line segment.
/// @param B The end point of the line segment.
/// @param spacing The distance between each point (px)
/// @param thickness The width at which to render the line.
/// @note With diagonal lines, the distance between points can differ by one px.
void DrawDottedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing = 1.f, float thickness = 1.f);
void DrawDottedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing = 1.f, float thickness = 1.f);
/// Draws an outline of a rectangle on the screen.
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
void OutlineRect(const Color3& color, const Vector2& pos, const Vector2& size, float thickness = 1);
/// Plots a line segment using a series of points separated by a given distance.
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
/// @param A The starting point of the line segment.
/// @param B The end point of the line segment.
/// @param spacing The distance between each point (px)
/// @param dash_length The length of each dash making up the line.
/// @param thickness The width at which to render the line.
/// @note With diagonal lines, the distance between dashes can differ by one px.
void DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing = 4.f, float dash_length = 6.f, float thickness = 1.f);
void DrawDashedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing = 4.f, float dash_length = 6.f, float thickness = 1.f);
/// Draws a filled rectangle on the screen.
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
void FillRect(const Color3& color, const Vector2& pos, const Vector2& size);
/// Draws a line with a color gradient that transitions across it.
/// @param color_a A 3-or-4 channel color value. @see class Color3, class Color4
/// @param color_b A 3-or-4 channel color value. @see class Color3, class Color4
/// @param A The starting point of the line segment.
/// @param B The end point of the line segment.
/// @param thickness The width at which to render the line.
void DrawGradientLine(const Color4& color_a, const Color4& color_b, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawGradientLine(const Color4& color_a, const Color4& color_b, float x1, float y1, float x2, float y2, float thickness = 1);
/// Draws a filled rectangle where the color transitions across it.
void FillGradientRect(const Color4& color1, const Color4& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size);
void FillGradientRect(const Color3& color1, const Color3& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size);
/// Draws an outline of a rectangle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @param thickness The width at which to render the lines.
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
/// Draws 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);
void FillRoundedRect(const Color3& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
/// Draws an outline of a rectangle with rounded corners onto the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @param radius The corner-rounding radius (in radians).
/// @param thickness The width at which to render the lines.
void OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, float thickness = 1);
/// Draws an outline of a circle on the screen.
void OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
void OutlineCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
/// Draws an outline of a rectangle with chamfered corners onto the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @param radius The corner-rounding radius (in radians).
/// @param thickness The width at which to render the lines.
void OutlineChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, float thickness = 1);
/// Draws a filled circle on the screen.
void FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 8);
void FillCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions = 8);
/// Draws a filled rectangle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @see FillRoundedRect, FillGradientRect, FillChamferRect.
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
/// Draws an outline of a triangle on the screen.
void OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness = 1);
void OutlineTriangle(const Color3& color, const Triangle2D& tri, float thickness = 1);
// TODO: Implement an overload that simply takes 3 Vector3's
/// Draws a filled rectangle where the color transitions across it.
/// @param color1 A 3-or-4 channel color value. @see class Color3, class Color4
/// @param color2 A 3-or-4 channel color value. @see class Color3, class Color4
/// @param gradient See enum Direction
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
void FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size);
/// Draws a filled triangle on the screen.
void FillTriangle(const Color4& color, const Triangle2D &tri);
void FillTriangle(const Color3& color, const Triangle2D& tri);
// TODO: Implement an overload that simply takes 3 Vector3's
/// Draws a filled rectangle with rounded corners on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @param radius The corner-rounding radius (in radians).
/// @param subdivisions The amount of sub-divisions (and calculations) to be performed per-arc rounding corner.
void FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
/// Draws a text string on the screen with a given point-size and font.
void DrawString(const Color3& color, std::string text, float x, float y, float scale, u32 size, unsigned int font_index);
/// Draws a filled rectangle with chamfered (beveled) corners on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @param radius The corner-rounding radius (in radians).
void FillChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5);
// TODO: Implement the following:
void FillTexturedTriangle();
void FillTexturedPolygon();
void DrawSprite();
void DrawPartialSprite();
void DrawCubicBezierCurve();
void OutlinePolygon (const Color4& color, std::vector<Vector2> points);
void FillPolygon (const Color4& color, std::vector<Vector2> points, float thickness = 1);
void OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, float thickness = 1);
}
/// Draws a render-target (runtime-modifiable texture) to the screen.
/// @param render_target A RenderTarget instance to be displayed.
/// @param position The position at which to render this object from it's center-point, defined by the origin parameter.
/// @param rad_rotation The amount of radians to rotate this render-target about it's center-point.
/// @param origin The center-point in the image to use for rendering, rotation, and scaling. Top-left is {0,0} and bottom right is {1, 1}.
/// @param scale The amount (in both x, and y axis) to scale the image, with {1,1} being default scaling.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
void DrawRenderTarget(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawRenderTarget(const RenderTarget* render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
namespace J3D {
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 DrawLine(const Color3& 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 Color3& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, unsigned int font_index);
void DrawPartialRenderTarget(const RenderTarget&, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialRenderTarget(const RenderTarget*, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
void DrawMatrixGizmo (const Matrix4x4&);
void DrawAxisAngleGizmo (const AxisAngle&, const Vector3&);
void DrawQuaternionGizmo (const Quaternion&, const Vector3&);
}
/// Draws a sprite (technically, actually a render target) to the screen.
/// @note This similar overload exists because we expect someone will be an idiot and turn all of their sprites into RenderTargets. ~william
/// @param render_target A RenderTarget instance to be displayed.
/// @param position The position at which to render this object from it's center-point, defined by the origin parameter.
/// @param rad_rotation The amount of radians to rotate this render-target about it's center-point.
/// @param origin The center-point in the image to use for rendering, rotation, and scaling. Top-left is {0,0} and bottom right is {1, 1}.
/// @param scale The amount (in both x, and y axis) to scale the image, with {1,1} being default scaling.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
/// @see DrawSprite
void DrawSprite(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const RenderTarget* render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
/// @param texture A texture instance to be displayed.
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param origin The center point around which the image should have all transformations applied to it.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
/// @see class Texture
void DrawSprite(const Texture& texture, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture& texture, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, float positionX, float positionY, float rad_rotation = 0,
float originX = 0, float originY = 0,float scaleX = 1, float scaleY = 1,
const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
/// @param texture A texture instance to be displayed.
/// @param alpha_mask A texture which determines how much of the sprite you can see. Grayscale image exported as "8bpc RGBA".
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param origin The center point around which the image should have all transformations applied to it.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
/// @see class Texture
void DrawSprite(const Texture& texture, const Texture& alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, const Texture* alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture& texture, const Texture& alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, const Texture* alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a piece of a sprite to the screen, similar to DrawSprite.
/// @param texture A texture instance to be displayed.
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param sub_texture_position The top left corner of the sub-texture to be drawn.
/// @param sub_texture_size The size of the sub-texture in px.
/// @param origin The center point around which the image should have all transformations applied to it.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
void DrawPartialSprite(const Texture& texture, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialSprite(const Texture* texture, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialSprite(const Texture& texture, float positionX, float positionY, float sub_texture_positionX, float sub_texture_positionY, unsigned int sub_texture_sizeX, unsigned int sub_texture_sizeY,
float rad_rotation = 0, float originX = 0, float originY = 0, float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialSprite(const Texture* texture, float positionX, float positionY, float sub_texture_positionX, float sub_texture_positionY, unsigned int sub_texture_sizeX, unsigned int sub_texture_sizeY,
float rad_rotation = 0, float originX = 0, float originY = 0, float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
/// To save v-ram, Use if a sprite would be identical if mirrored horizontally, vertically, or both. For example, a circle.
/// Assumes the input texture is the top left quadrant. You can use "SoftwareTexture" to invert it correctly so that's the case.
/// @param texture A texture instance to be displayed.
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param mirror_axis The axes to mirror across, Vertical and Horizontal or both only.
/// @param rad_rotation The rotation of the final result.
/// @param origin The point at which transformations are done about.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
void DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis = Direction::Horizontal | Direction::Vertical, float rad_rotation = 0, const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White);
void DrawMirrorSprite(const Texture* texture, const Vector2& position, Direction mirror_axis = Direction::Horizontal | Direction::Vertical, float rad_rotation = 0, const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White);
/// Draws an outline of a circle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param center The point in cartesian space at which to draw the circle. This will by-definition be the centroid of this circle.
/// @param radius The radius of the circle to be drawn. AKA Half the diameter.
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
/// @param thickness The line-width of the circle to be rendered at.
void OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
/// Draws a filled circle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param center The point in cartesian space at which to draw the circle. This will by-definition be the centroid of this circle.
/// @param radius The radius of the circle to be drawn. AKA Half the diameter.
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
void FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 8);
/// Draws an outline of a triangle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param tri The triangle defined by its vertices (A, B, and C).
/// @param thickness The line-width of the triangle to be rendered at.
void OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness = 1);
void OutlineTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC, float thickness = 1);
/// Draws a filled triangle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param tri The triangle defined by its vertices (A, B, and C).
void FillTriangle(const Color4& color, const Triangle2D& tri);
void FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC);
/// Fills a triangle defined by the provided vertices with a gradient that transitions smoothly between the three specified colors at each corner.
/// @param a_color The color at vertex A of the triangle.
/// @param b_color The color at vertex B of the triangle.
/// @param c_color The color at vertex C of the triangle.
/// @param tri The triangle defined by its vertices (A, B, and C).
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri);
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Vector2& tri_a, const Vector2& tri_b, const Vector2& tri_c);
/// Draws a smooth, curved line segment between two control points, with the curve controlled by the two inner points.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param controlA The first control point, which can be considered the start of the line.
/// @param pointA The first inner point, which controls the contour of the curve.
/// @param pointB The second inner point, which controls the contour of the curve.
/// @param controlB The second control point, which can be considered the end of the line.
/// @param subdivisions The accuracy of the approximation of the curve, measured in iteration steps taken.
/// @param thickness The line-width to draw the curve with.
/// @see J3ML::Algorithm::Bezier
void DrawCubicBezierCurve(const Color4& color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
int subdivisions = 10, float thickness = 1);
/// Draws a series of points where the last point always connects to the first point.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param points The array of vector2's to draw as a polygon.
/// @param point_count The number of points
/// @param thickness The line-width of the polygon
void OutlinePolygon(const Color4& color, const Vector2* points, int point_count, float thickness = 1);
/// Draws a text string on the screen with a given point-size and font.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param text The text to be rendered.
/// @param x The position on the screen at which to draw the text, from the top-left.
/// @param y The position on the screen at which to draw the text, from the top-left.
/// @param scale The value (in both axes) to scale the text by. Defaults to {1,1}.
/// @param size The point-size at which to render the font out. Re-using the same point-size allows efficient glyph caching.
/// @param font The font to use for rendering. @see Font.
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font = Fonts::Jupiteroid);
/// Draws an Arc (section of a circle) to the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param center The point in cartesian space at which to draw the arc. This will by-definition be the centroid of this partial circle.
/// @param radius The radius of the partial circle to be drawn. AKA Half the diameter.
/// @param arc_begin The point (0 - 2pi) around a unit-circle of which to start the arc.
/// @param arc_end The point (0 - 2pi) around a unit-circle of which to start the arc.
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
/// @param thickness The line-width to draw the arc with.
void DrawArc(const Color4& color, const Vector2& center, float radius, float arc_begin, float arc_end,
unsigned int subdivisions, float thickness);
/// TODO Implement the following. These ones are going to be extremely annoying.
void FillPolygon(const Color4& color, const std::vector<Vector2>& points);
void OutlineEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, float thickness = 1, int subdivisions = 8);
void FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions = 8);
}
/// Drawing functions for 3D objects.
namespace JGL::J3D {
/// A light for this 3D render that should never be culled out. up-to 8.
/// The more you put here, The less we will solve for if you're also using LightArray.
/// @note More than 8 lights will cause an error to be printed.
void RequiredLight(const LightBase* light);
/// When each 3D object is drawn, We'll do our best to determine which lights would effect it the most and use those ones.
void OptionalLights(const LightBase** lights, const size_t& light_count);
/// Helper function to conveniently change the Field-Of-View.
void ChangeFOV(float fov);
/// Helper function to change the far-plane, which is the cutoff distance for rendering.
void ChangeFarPlane(float far_plane);
/// Open a 3-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// It is recommended to always open a JGL 3D context to render your content, then close when completed.
/// @param two_pass Whether or not we'll use two-pass rendering for occlusion.
void Begin(bool two_pass = false);
/// Closes a 3-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @see Begin().
void End();
void SetMatrix(const std::vector<GLfloat>& matrix, const Vector2& window_size);
/// Draws a line in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param A The start-point of the line segment.
/// @param B The end-point of the line segment.
/// @param thickness The line-width to draw the line segment with.
void DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness = 1.f);
/// Draws a smooth, curved line segment between two control points, with the curve controlled by the two inner points.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param controlA The first control point, which can be considered the start of the line.
/// @param pointA The first inner point, which controls the contour of the curve.
/// @param pointB The second inner point, which controls the contour of the curve.
/// @param controlB The second control point, which can be considered the end of the line.
/// @param subdivisions The accuracy of the approximation of the curve, measured in iteration steps taken.
/// @param thickness The line-width to draw the curve with.
/// @see J3ML::Algorithm::Bezier
void DrawCubicBezierCurve(const Color4& color, const Vector3& controlA, const Vector3& pointA, const Vector3& pointB, const Vector3& controlB,
int subdivisions = 10, float thickness = 1);
/// Draws the outline of an Icosahedron in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Icosahedron.
/// @param radius The size to draw the Icosahedron at.
/// @param thickness The line-width to draw the Icosahedron outline with.
void WireframeIcosahedron(const Color4& color, const Vector3& position, float radius, float thickness = 1.f);
/// Draws a solid Icosahedron in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Icosahedron.
/// @param radius The size to draw the Icosahedron at.
void FillIcosahedron(const Color4& color, const Vector3& position, float radius);
/// Draws the outline of a Sphere in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Sphere.
/// @param radius The size to draw the Sphere at.
/// @param thickness The line-width to draw the Icosahedron outline with.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
void WireframeSphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int sectors = 10, unsigned int stacks = 10);
/// Draws the outline of a Sphere in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param sphere The mathematically-defined sphere object to be rendered.
/// @param thickness The line-width to draw the Icosahedron outline with.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
void WireframeSphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int sectors = 10, unsigned int stacks = 10);
/// Draws outlines of multiple spheres in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param spheres The mathematically-defined sphere objects to be rendered.
/// @param sphere_count The number of spheres.
/// @param thickness The line-width to draw the Icosahedron outline with.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
/// @note The "Position" of the spheres is expected to be in world space.
void BatchWireframeSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness = 1.f, unsigned int sectors = 10, unsigned int stacks = 10);
/// Draws outlines of a sphere in 3D space. Calculates a cross section and revolves it around the center.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Sphere.
/// @param radius The size to draw the Sphere at.
/// @param thickness The line-width to draw the Icosahedron outline with.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param revolutions The number of times to revolve the cross section about the center.
/// @param draw_stacks Whether or not to draw the stacks of the sphere.
void WireframeRevoSphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int sectors = 10, unsigned int revolutions = 10, bool draw_stacks = false);
/// Draws the outline of a Sphere in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param sphere The mathematically-defined sphere object to be rendered.
/// @param thickness The line-width to draw the Icosahedron outline with.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param revolutions The number of times to revolve the cross section about the center.
/// @param draw_stacks Whether or not to draw the stacks of the sphere.
void WireframeRevoSphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int sectors = 10, unsigned int revolutions = 10, bool draw_stacks = false);
/// Draws outlines of multiple spheres in 3D space. Calculates a cross section and revolves it around the center.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param spheres The mathematically-defined sphere objects to be rendered.
/// @param sphere_count The number of spheres.
/// @param thickness The line-width to draw the Icosahedron outline with.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param revolutions The number of times to revolve the cross section about the center.
/// @param draw_stacks Whether or not to draw the stacks of the sphere.
/// @note The "Position" of the spheres is expected to be in world space.
/// @note This method of drawing a sphere is *probably* the fastest out of all of them.
void BatchWireframeRevoSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness = 1.f, unsigned int sectors = 10, unsigned int revolutions = 10, bool draw_stacks = false);
/// Draws the outline of an Icosphere in 3D space.
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Sphere.
/// @param radius The size to draw the Sphere at.
/// @param thickness The line-width to draw the Icosahedron outline with.
/// @param subdivisions The accuracy of the approximation of the Icosphere, measured in iteration steps taken.
void WireframeIcosphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int subdivisions = 10);
/// Draws the outline of an Icosphere in 3D space.
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param sphere The mathematically-defined sphere object to be rendered.
/// @param thickness The line-width to draw the Icosphere outline with.
/// @param subdivisions The accuracy of the approximation of the Icosphere, measured in iteration steps taken.
void WireframeIcosphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int subdivisions = 10);
/// Draws the outline of a Cubesphere in 3D space.
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Sphere.
/// @param radius The size to draw the Sphere at.
/// @param thickness The line-width to draw the Cubesphere outline with.
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
void WireframeCubesphere(const Color4& color, const Vector3& position, float radius, float thickness = 1.f, unsigned int subdivisions = 10);
/// Draws the outline of a Cubesphere in 3D space.
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param sphere The mathematically-defined sphere object to be rendered.
/// @param thickness The line-width to draw the Cubesphere outline with.
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
void WireframeCubesphere(const Color4& color, const Sphere& sphere, float thickness = 1.f, unsigned int subdivisions = 10);
/// Draws a solid Sphere in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Sphere.
/// @param radius The size to draw the Sphere at.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
void FillSphere(const Color4& color, const Vector3& position, float radius, unsigned int sectors = 10, unsigned int stacks = 10);
/// Draws a solid Sphere in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param sphere The mathematically-defined sphere object to be rendered.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
void FillSphere(const Color4& color, const Sphere& sphere, unsigned int sectors = 10, unsigned int stacks = 10);
/// Draws multiple solid Spheres in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param spheres The mathematically-defined sphere objects to be rendered.
/// @param sphere_count The number of spheres to be rendered.
/// @param sectors The amount of latitudinal subdivisions to perform when computing the sphere.
/// @param stacks The amount of longitudinal subdivisions to perform when computing the sphere.
void BatchFillSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, unsigned int sectors = 10, unsigned int stacks = 10);
/// Draws a solid Icosphere in 3D space.
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Sphere.
/// @param radius The size to draw the Sphere at.
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
void FillIcosphere(const Color4& color, const Vector3& position, float radius, unsigned int subdivisions = 10);
/// Draws a solid Icosphere in 3D space.
/// @note An Icosphere is an approximation of a sphere that is generated by recursively subdividing an Icosahedron.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param sphere The mathematically-defined sphere object to be rendered.
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
void FillIcosphere(const Color4& color, const Sphere& sphere, unsigned int subdivisions = 10);
/// Draws a solid Cubesphere in 3D space.
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space at which to draw the Sphere.
/// @param radius The size to draw the Sphere at.
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
void FillCubesphere(const Color4& color, const Vector3& position, float radius, unsigned int subdivisions = 10);
/// Draws a solid Cubesphere in 3D space.
/// @note A Cubesphere is an approximation of a sphere that is generated by recursively subdividing a Cube.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param sphere The mathematically-defined sphere object to be rendered.
/// @param subdivisions The accuracy of the approximation of the Cubesphere, measured in iteration steps taken.
void FillCubesphere(const Color4& color, const Sphere& sphere, unsigned int subdivisions = 10);
/// Draws an outline of an axis-aligned bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The point in 3D space that is the center of the AABB.
/// @param radii The radii along x,y,z axes to size the bounding box.
/// @param thickness The line-width to draw the Icosphere outline with.
void WireframeAABB(const Color4& color, const Vector3& pos, const Vector3& radii, float thickness = 1.f);
/// Draws an outline of an axis-aligned bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param aabb The AABB object to render.
/// @param thickness The line-width to draw the Icosphere outline with.
void WireframeAABB(const Color4& color, const AABB& aabb, float thickness = 1.f);
/// Draws outlines of multiple axis-aligned bounding-boxes in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param boxes The boxes to be drawn.
/// @param box_count The number of boxes to be drawn.
/// @param thickness The line-width to draw the Icosahedron outline with.
void BatchWireframeAABB(const Color4& color, const AABB* boxes, const size_t& box_count, float thickness = 1.f);
/// Draws a solid axis-aligned bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The point in 3D space that is the center of the AABB.
/// @param radii The radii along x,y,z axes to size the bounding box.
void FillAABB(const Color4& color, const Vector3& pos, const Vector3& radii);
/// Draws a solid axis-aligned bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param aabb The AABB object to visualize.
void FillAABB(const Color4& color, const AABB& aabb);
/// Draws solid axis-aligned bounding boxes in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param aabb The AABB objects to visualize.
/// @param box_count The number of AABBs to draw.
void BatchFillAABB(const Color4& color, const AABB* boxes, const size_t& box_count);
/// Draws an outline of an oriented bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The point in 3D space that is the center of the AABB.
/// @param radii The radii along x,y,z axes to size the bounding box.
/// @param orientation The rotation in 3D space of the OBB.
/// @param thickness The line-width to draw the OBB outline with.
void WireframeOBB(const Color4& color, const Vector3& position, const Vector3& radii, const Matrix3x3& orientation, float thickness = 1.f);
/// Draws an outline of an oriented bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param obb The OBB object to visualize.
/// @param thickness The line-width to draw the OBB outline with.
void WireframeOBB(const Color4& color, const OBB& obb, float thickness = 1.f);
void BatchWireframeOBB(const Color4& color, const OBB* boxes, const size_t& box_count, float thickness = 1.f);
/// Draws a solid oriented bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param position The center-position of the oriented bounding box.
/// @param radii The radii along x,y,z axes to size the bounding box.
/// @param orientation The rotation in 3D space of the OBB.
void FillOBB(const Color4& color, const Vector3& position, const Vector3& radii, const EulerAngleXYZ& orientation);
/// Draws a solid oriented bounding box in 3D space.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param obb The oriented-bounding-box object to visualize.
void FillOBB(const Color4& color, const OBB& obb);
void WireframeCylinder();
void FillCylinder();
void WireframePrism();
void FillPrism();
void WireframePipe();
void FillPipe();
void WireframeCone();
void FillCone();
void WireframeTorus();
void FillTorus();
void FillCapsule(const Color3& color, const Capsule& capsule);
void WireframeCapsule(const Color3& color, const Capsule& cap, float thickness = 1.f);
void FillTriangleMesh(const Color3& color, const TriangleMesh& mesh);
void WireframeTriangleMesh(const Color3& color, const TriangleMesh& mesh, float thickness = 1.f);
/// Draws a string of text in 3D space, with an arbitrary rotation.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param text The content to display on the screen.
/// @param pos The position in 3D space to display the text.
/// @param scale The scaling factor to render the text with, 1 being default. TODO: Vector2 scaling?
/// @param size The pixel size to rasterize the font with.
/// @param font The font object to use when drawing.
/// @param angle The orientation in 3D space.
/// @param draw_back_face
void DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font = Fonts::Jupiteroid, const EulerAngleXYZ& angle = {0, 0, 0}, bool draw_back_face = false);
void DrawVertexArray(const Color4& color, const VertexArray& vertex_array, const Vector3& position);
/// Draws a string of text in 3D space that is always facing the exact direction of the camera projection.
void DrawBillboardString();
/// Draws a texture sprite in 3D space that is always facing the exact direction of the camera projection.
void DrawBillboardSprite();
void DrawSprite();
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
void DrawMatrixGizmo (const Matrix4x4&);
void DrawAxisAngleGizmo (const AxisAngle&, const Vector3&);
void DrawQuaternionGizmo (const Quaternion&, const Vector3&);
}

View 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
View 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;
}
}
}

39
include/JGL/types/Font.h Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#include <vector>
#include <filesystem>
#include <J3ML/LinearAlgebra.hpp>
#include <filesystem>
#include <iostream>
/// Defines external C references to FreeType Data Structures
extern "C" typedef struct FT_FaceRec_* FT_Face;
extern "C" typedef struct FT_LibraryRec_* FT_Library;
namespace JGL
{
bool InitTextEngine();
/// A Font class implementation.
/// Wraps the font's FreeType asset handle and provides helper functions.
class Font {
public:
/// Default constructor does not initialize any members
Font() = default;
explicit Font(const std::filesystem::path& path);
Font(const unsigned char* data, const size_t& size);
/// Destructor handles freeing of the underlying asset handle.
~Font();
static Font LoadTTF(const std::filesystem::path& filepath);
static std::vector<Font> GetLoadedFonts();
/// Returns the bounding-box the given string would occupy at the given point-size, assuming normal (1) scaling.
/// @param text The string to measure.
/// @param ptSize The font size at which to measure.
/// @return The size-in-pixels that would contain the entire text.
Vector2 MeasureString(const std::string& text, unsigned int ptSize);
public:
int index = 0;
FT_Face face = nullptr;
};
}

View File

@@ -0,0 +1,70 @@
#pragma once
#include <glad/glad.h>
#include <vector>
#include <array>
#include <unordered_map>
/// TODO: FontCache mechanism works amazing, but makes no fucking sense
/// Let's document and reorganize it to be a little nicer on the mental :)
namespace JGL {
class CachedGlyph;
class CachedFont;
class FontCache;
}
/// Represents a single font-character "glyph", that has been cached in-memory for fast retrieval.
class JGL::CachedGlyph {
private:
char character;
std::array<GLfloat, 12> texcoords;
public:
int x2offset = 0, y2offset = 0, w = 0, h = 0;
float advanceX = 0, advanceY = 0;
//CachedGlyph(GLuint texture_id, char c);
CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2o, float y2o, float w, float h, float advX, float advY);
char getCharacter() const;
[[nodiscard]] std::array<GLfloat, 12> getTexCoords() const;
};
/// Represents a Font object as it exists in the font-cache.
class JGL::CachedFont {
private:
std::unordered_map<char, CachedGlyph*> glyphs;
GLuint texture = 0;
GLsizei texture_width = 0, texture_height = 0;
unsigned int font_size = 0;
unsigned int font_index = 0;
void Erase();
public:
void appendGlyph(CachedGlyph* glyph);
unsigned int getFontSize() const;
unsigned int getFontIndex() const;
CachedGlyph* getGlyph(char c);
std::unordered_map<char, CachedGlyph*> getGlyphs();
const GLuint* getTextureHandle();
[[nodiscard]] GLsizei getTextureWidth() const;
[[nodiscard]] GLsizei getTextureHeight() const;
public:
CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
~CachedFont();
};
class JGL::FontCache {
private:
std::vector<CachedFont*> cachedFonts{};
public:
std::vector<CachedFont*> getFonts();
CachedFont* getFont(unsigned int font_size, unsigned int font_index);
void appendFont(CachedFont* font);
void newFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
void eraseFont(CachedFont* font);
void purgeCache();
};
namespace JGL {
inline FontCache fontCache;
}

70
include/JGL/types/Light.h Normal file
View File

@@ -0,0 +1,70 @@
#pragma once
#include <J3ML/LinearAlgebra/Vector4.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/LinearAlgebra/DirectionVector.hpp>
#include <J3ML/Geometry/Frustum.hpp>
#include <Color4.hpp>
namespace JGL {
class LightBase;
class PointLight;
class SpotLight;
}
// TODO this can be consolidated.
class JGL::LightBase {
protected:
/* The 4th number represents whether the light is a positional light.
* In OpenGL, You can have positional lights, Like Point Lights or Spot Lights,
* Or global lights, Like the sun. */
Vector4 position = {0, 0, 0, 1};
Color4 ambient = {0, 0, 0, 0};
Color4 diffuse = {0, 0, 0, 0};
Color4 specular = {0, 0, 0, 0};
float constant_attenuation = 1;
float linear_attenuation = 0;
float quadratic_attenuation = 0;
public:
[[nodiscard]] Vector4 GetPosition() const;
[[nodiscard]] Color4 GetAmbient() const;
[[nodiscard]] Color4 GetDiffuse() const;
[[nodiscard]] Color4 GetSpecular() const;
[[nodiscard]] float GetConstantAttenuation() const;
[[nodiscard]] float GetLinearAttenuation() const;
[[nodiscard]] float GetQuadraticAttenuation() const;
public:
/// Runs a calculation to determine the lights influence on a given point in 3D space.
/// @note 0 would be no impact, 1 would be the light is at the same position.
[[nodiscard]] virtual float GetAttenuationAtPosition(const Vector3& pos) const { return 0; }
public:
virtual ~LightBase() = default;
};
/// Omni-directional lights.
class JGL::PointLight : public LightBase {
public:
[[nodiscard]] float GetAttenuationAtPosition(const Vector3& pos) const final;
public:
PointLight(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation = 1, float linear_attenuation = 0, float quadratic_attenuation = 0);
};
/// Lights which only effect things in a given cone.
// TODO get attenuation at position for this.
class JGL::SpotLight : public LightBase {
protected:
Matrix3x3 orientation;
float exponent;
float cut;
public:
/// Create a spotlight in 3D space.
/// @param position The position of the light in 3D space.
/// @param ro_mat Orientation of the light in 3D space.
/// @param cone_size_degrees The size of the cone.
/// @param exponent How focused the beam should be, Higher is more focused, Lower is less.
/// @param ambient How much this light should effect the ambient light of the scene.
/// @param diffuse
/// @param specular How much this light should effect specular highlights of objects being influenced by it.
SpotLight(const Vector3& position, const Matrix3x3& ro_mat, float cone_size_degrees, float exponent, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation = 1, float linear_attenuation = 0, float quadratic_attenuation = 0);
};

View File

@@ -0,0 +1,19 @@
/// A simple wrapper for OpenGL materials. Lets you set things such as the "shininess" of your elements.
#include <Color4.hpp>
#include <glad/glad.h>
namespace JGL {
class Material;
}
class JGL::Material {
public:
Color4 ambient_ref;
Color4 diffuse_ref;
Color4 specular_ref;
Color4 emission;
float shininess;
public:
Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine);
/// @param material Material to use.
static void SetActiveMaterial(const Material& material);
};

View File

@@ -0,0 +1,116 @@
#pragma once
#include <vector>
#include <glad/glad.h>
#include <Color4.hpp>
#include <Colors.hpp>
#include <JGL/types/Enums.h>
#include <J3ML/LinearAlgebra/Vector2i.hpp>
namespace JGL {
class RenderTarget;
class Texture;
}
using J3ML::LinearAlgebra::Vector2i;
class JGL::RenderTarget {
private:
Color4 clear_color{0,0,0,0};
Vector2i size{0, 0};
bool using_depth = false;
bool texture_created_by_us = false;
GLuint framebuffer_object = 0;
GLuint depth_buffer = 0;
const Texture* texture = nullptr;
MSAA_SAMPLE_RATE msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
GLuint msaa_framebuffer_object = 0;
GLuint msaa_depth_buffer = 0;
GLuint msaa_render_buffer = 0;
void Erase();
public:
/// @returns The Render Target currently in use by OpenGL.
/// @note Zero is the screen.
static GLuint GetActiveGLFramebufferHandle();
/// Changes the Render Target that OpenGL will draw on.
/// @param render_target The new Render Target for OpenGL to draw on.
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
/// Changes the size of the renderable area of this Render Target.
/// @param new_size new width & height in pixels.
/// @note The data stored in this Render Target will be lost.
void Resize(const Vector2i& new_size);
/// Sets the MSAA mode for this Render Target.
/// @returns false if the mode isn't available, true for success.
[[nodiscard]] bool SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
/// If you're using MSAA and not using J2D || J3D Begin & End you must do this.
void MSAABlit() const;
/// Copy one Render Target onto another. Will break if they're not the same size.
// TODO support different sizes. If the destination is too small fix it for them but log a warning.
static void Blit(const RenderTarget& source, RenderTarget* destination);
/// Plots a single pixel onto a Render Target.
/// @param color The color to render.
/// @param position The position in the destination to draw the pixel.
/// @param destination The destination RenderTarget.
static void Blit(const Color4& color, const Vector2i& position, RenderTarget* destination);
/// @returns Whether or not this Render Target created it's Texture.
[[nodiscard]] bool OwnsTexture() const;
public:
/// @returns the size of the renderable area.
[[nodiscard]] Vector2i GetDimensions() const;
/// @returns The currently selected MSAA Sample Rate.
[[nodiscard]] MSAA_SAMPLE_RATE GetMSAASampleRate() const;
/// @returns Whether or not this Render Target is using MSAA.
[[nodiscard]] bool MSAAEnabled() const;
/// @returns The JGL texture this Render Target draws on.
[[nodiscard]] const Texture* GetJGLTexture() const;
/// @returns The OpenGL handle for the texture this Render Target draws on.
[[nodiscard]] GLuint GetGLTextureHandle() const;
/// @returns The OpenGL handle for this Render Target.
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
/// @returns The handle to the OpenGL buffer containing depth information
/// @note Only valid if this Render Target is being used for 3D.
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
/// @returns The color that should be used to clear this Render Target.
[[nodiscard]] Color4 GetClearColor() const;
/// @returns The color information for this Render Target.
/// @note Both the CPU & GPU cannot do anything while this takes place. It's very slow.
[[nodiscard]] std::vector<GLfloat> GetPixels() const;
public:
/// Create a Render Target from a Render Target that already exists.
/** @note Render Targets that are copies of another will copy the Texture.
* This is so that deleting the copy doesn't delete the Texture of the original.
*/
RenderTarget(const RenderTarget& rhs);
/// Create a Render Target for a texture that already exists.
/// @param texture The Texture that using this Render Target would draw on.
/// @param clear_color The color to be used if you want to clear the Render Target.
/// @note For Render Targets created this way, The destructor will not delete the texture.
explicit RenderTarget(const Texture* texture, const Color4& clear_color = Colors::Transparent);
/// Create a Render Target with a new texture.
/// @param size The width & height the Render Target should have.
/// @param clear_color The color to be used if you want to clear the Render Target.
/// @param use_depth Whether or not this Render Target will have depth information.
/// @param sample_rate The MSAA sample rate this Render Target will use.
explicit RenderTarget(const Vector2i& size, const Color4& clear_color = Colors::Transparent, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
/// Deletes this Render Target.
/** @note If this Render Target was made with a Texture that already existed
* the Texture will not be deleted. */
~RenderTarget();
};

View File

@@ -0,0 +1,18 @@
#pragma once
#include <JGL/types/RenderTarget.h>
#include <JGL/types/Light.h>
namespace JGL {
class ShadowMap;
}
/// You render your scene with all the static objects from the perspective of each static light to a ShadowMap.
/// Then, for shadow casters which move. Or lights that move. You only redraw that object from the perspective of each light.
/// Some of the approaches I saw for this were disgusting - Redacted.
class JGL::ShadowMap {
private:
RenderTarget shadow_map;
private:
void Create(const LightBase* Light);
};

View File

@@ -0,0 +1,124 @@
#pragma once
#include <vector>
#include <array>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
#include <unordered_map>
namespace JGL {
class Bone;
class SkeletalVertexAttribute;
class Skeleton;
class KeyFrame;
class Animation;
class AnimationState;
}
class JGL::SkeletalVertexAttribute {
private:
std::array<int, 4> bone_ids = { 0, 0, 0, 0 };
std::array<float, 4> bone_weights = { 0, 0, 0, 0 };
public:
[[nodiscard]] std::array<int, 4> GetAffectingBoneIDs() const;
[[nodiscard]] std::array<float, 4> GetAffectingBoneWeights() const;
public:
SkeletalVertexAttribute() = default;
/// These cannpt be longer than 4.
SkeletalVertexAttribute(const std::vector<int>& ids, const std::vector<float>& weights);
};
class JGL::Bone {
private:
int id = 0;
// Not every gltf2 model includes names, but I'll still include it.
std::string name;
Matrix4x4 inverse_bind_matrix = Matrix4x4::Identity;
Matrix4x4 offset_matrix = Matrix4x4::Identity;
Matrix4x4 final_transform = Matrix4x4::Identity;
int parent_id = -1;
std::vector<int> children{};
public:
[[nodiscard]] int GetID() const;
[[nodiscard]] std::string GetName() const;
[[nodiscard]] Matrix4x4 GetInverseBindMatrix() const;
[[nodiscard]] Matrix4x4 GetOffsetMatrix() const;
[[nodiscard]] Matrix4x4 GetFinalTransform() const;
[[nodiscard]] bool IsRootBone() const;
public:
[[nodiscard]] int GetParentID() const;
[[nodiscard]] std::vector<int> GetChildren() const;
public:
void SetParent(int parent_id);
void AppendChild(int new_child);
void SetID(int numeric_id);
void SetName(const std::string& string_id);
void SetInverseBindMatrix(const Matrix4x4& inverse_bind);
void SetOffsetMatrix(const Matrix4x4& offset);
void SetFinalTransformMatrix(const Matrix4x4& final);
public:
~Bone() = default;
Bone() = default;
explicit Bone(int numeric_id, const std::string& string_id = "", int parent_id = -1, const std::vector<int>& children_ids = {},
const Matrix4x4& inverse_bind = Matrix4x4::Identity, const Matrix4x4& offset = Matrix4x4::Identity, const Matrix4x4& final = Matrix4x4::Identity);
};
class JGL::Skeleton {
private:
Bone root;
std::vector<Bone> bones;
public:
[[nodiscard]] Bone* GetRootBone();
[[nodiscard]] Bone* FindBone(int id);
[[nodiscard]] Bone* FindBone(const std::string& string_id);
public:
void AppendBone(const Bone& bone);
public:
explicit Skeleton(const Bone& root_bone, const std::vector<Bone>& children = {});
~Skeleton() = default;
Skeleton() = default;
};
class JGL::KeyFrame {
private:
float time_stamp = 0;
Skeleton pose;
public:
[[nodiscard]] float GetTimeStamp() const;
[[nodiscard]] Skeleton GetSkeleton() const;
public:
KeyFrame(const Skeleton& pose, float time_stamp);
};
class JGL::Animation {
private:
int id = -1;
// Not all animations have names.
std::string name;
float length = 0;
std::vector<KeyFrame> key_frames;
std::vector<SkeletalVertexAttribute> vertex_attributes{};
public:
[[nodiscard]] float GetDuratrion() const;
[[nodiscard]] std::vector<KeyFrame> GetKeyFrames() const;
[[nodiscard]] int GetID() const;
[[nodiscard]] std::string GetName() const;
[[nodiscard]] std::vector<SkeletalVertexAttribute> GetSkeletalVertexAttributes() const;
public:
void AppendKeyFrame(const KeyFrame& new_key);
void SetDuration(float duration);
void SetID(int identifier);
void SetName(const std::string& name_id);
public:
~Animation() = default;
Animation(int id, float duration, const std::vector<KeyFrame>& key_frames, const std::vector<SkeletalVertexAttribute>& skeletal_vertex_attributes,
const std::string& name = "");
};
class JGL::AnimationState {
private:
int animation_id = -1;
float animation_time = 0;
public:
};

View File

@@ -0,0 +1,57 @@
#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;
};
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <vector>
#include <glad/glad.h>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <J3ML/LinearAlgebra/Vector2i.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/LinearAlgebra/Vector4.hpp>
namespace JGL {
class VRamList;
}
/// A wrapped for "Vertex Buffer Object" In OpenGL, Store things in VRam.
class JGL::VRamList {
private:
GLuint list_handle = 0;
long num_elements = 0;
bool element_array_buffer = false;
/// "Spin Locking" fix for multi-threading.
bool spin_lock = false;
void load(const GLfloat* data, const long& size);
void load(const GLuint* data, const long& size);
void SetData(void* data, const long& count);
void UpdateData(void* data, const long& offset, const long& count);
void Erase();
public:
VRamList(const GLuint* data, const long& count);
VRamList(const GLfloat* data, const long& count);
VRamList(const Vector2* data, const long& count);
VRamList(const Vector3* data, const long& count);
VRamList(const Vector4* data, const long& count);
~VRamList();
/** Copying around the VBO data to a new VBO like this is slow.
* Pass to function by const reference or pointer always. */
VRamList(const VRamList& rhs);
VRamList() : list_handle(0), num_elements(0), element_array_buffer(false), spin_lock(false) {}
public:
[[nodiscard]] GLuint GetHandle() const;
/// Returns the number of elements in the list.
[[nodiscard]] long GetLength() const;
/// Returns the size of the data in bytes.
[[nodiscard]] size_t GetDataSize() const;
/** Get VBO data back from the GPU. This is *bad* because the CPU is going to wait
* for the transfer to finish. Has limited use other than testing. */
[[nodiscard]] std::vector<GLfloat> GetDataF() const;
[[nodiscard]] std::vector<GLuint> GetDataUI() const;
[[nodiscard]] bool IsFloatArray() const;
/** Replace the data of an existing VBO in it's entirety. Must be same type. */
void SetData(const GLfloat* data, const long& count);
void SetData(const Vector2* data, const long& count);
void SetData(const Vector3* data, const long& count);
void SetData(const Vector4* data, const long& count);
void SetData(const GLuint* data, const long& count);
void SetData(const Vector2i* data, const long& count);
/** Update only a portion of the data in a VBO. Must be same type.
* "offset" refers the number of Typename T into the buffer the data you want to change is.
* For ex, offset 0 and length of 1 overwrites the first value. Offset 1 the second etc */
void UpdateData(const GLfloat* data, const long& offset, const long& count);
void UpdateData(const Vector2* data, const long& offset, const long& count);
void UpdateData(const Vector3* data, const long& offset, const long& count);
void UpdateData(const Vector4* data, const long& offset, const long& count);
void UpdateData(const GLuint* data, const long& offset, const long& count);
void UpdateData(const Vector2i* data, const long& offset, const long& count);
};

View File

@@ -0,0 +1,102 @@
#pragma once
#include <vector>
#include <JGL/types/VRamList.h>
#include <JGL/types/Skeleton.h>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/Geometry/Sphere.hpp>
#include <J3ML/Geometry/AABB.hpp>
#include <J3ML/Geometry/OBB.hpp>
namespace JGL {
/// A point that is part of an object in 3D space.
typedef Vector3 Vertex;
/// A direction vector which describes which way a triangle is facing.
typedef Vector3 Normal;
/// 2D positions that describe how a texture is to be wrapped around a 3D object.
typedef Vector2 TextureCoordinate;
/// Container for storing 3D models in v-ram, system memory, or both.
class VertexArray;
}
class JGL::VertexArray {
private:
Sphere me_sphere;
OBB me_obb;
protected:
virtual void CreateMESphere();
virtual void CreateMEOBB();
protected:
std::vector<Animation> animations{};
protected:
VRamList* vertices;
VRamList* indices;
VRamList* normals;
VRamList* texture_coordinates;
protected:
/** For models which are not animated, This is intended for a low quality version in
* system memory for calculations to be done on the CPU. For models that are, the default pose of the model is here.
*/
std::vector<Vertex> local_vertices{};
std::vector<unsigned int> local_indices{};
std::vector<TextureCoordinate> local_texture_coordinates{};
std::vector<Normal> local_normals{};
public:
/** Don't use these for anything other than drawing because the GPU is gonna spin during read-back */
[[nodiscard]] const VRamList* GetVertices() const;
[[nodiscard]] const VRamList* GetIndices() const;
[[nodiscard]] const VRamList* GetNormals() const;
[[nodiscard]] const VRamList* GetTextureCoordinates() const;
/** These are for cpu side calculations */
[[nodiscard]] std::vector<Vertex> GetLocalVertices() const;
[[nodiscard]] std::vector<unsigned int> GetLocalIndices() const;
[[nodiscard]] std::vector<TextureCoordinate> GetLocalTextureCoordinates() const;
[[nodiscard]] std::vector<Normal> GetLocalNormals() const;
public:
/// Returns true if the VertexArray does not have any animations.
bool Static();
public:
/// Provides the minimally enclosing bounding sphere of the vertex array given information from the instance.
/// @param scale The scale of the instance.
/// @param translate_part The center of the sphere would be shifted in 3D space by this. Primarily for world space.
[[nodiscard]] Sphere GetMESphere(const Vector3& scale = Vector3::One, const Vector3& translate_part = Vector3::Zero) const;
/// Provides the minimally enclosing bounding sphere of the vertex array given information from the instance.
/// @param instance_matrix A Matrix4x4 which contains scale, rotation, and translation.
/// @param translate Whether or not to translate to world space by the translate part of the Matrix.
[[nodiscard]] Sphere GetMESphere(const Matrix4x4& instance_matrix, bool translate = false) const;
/// Provides the minimally enclosing oriented bounding box of the vertex array given information from the instance.
/// @param rotation_matrix A Matrix3x3 representing rotation in 3D space.
/// @param scale The scale of the instance.
/// @param translate_part The center of the box would be shifted in 3D space by this. Primarily for world space.
[[nodiscard]] OBB GetMEOBB(const Matrix3x3& rotation_matrix, const Vector3& scale = Vector3::One, const Vector3& translate_part = Vector3::Zero) const;
/// Provides the minimally enclosing oriented bounding box of the vertex array given information from the instance.
/// @param instance_matrix A Matrix4x4 which contains scale, rotation, and translation.
/// @param translate Whether or not to translate to world space by the translate part of the Matrix.
[[nodiscard]] OBB GetMEOBB(const Matrix4x4& instance_matrix, bool translate = false) const;
/// Provides the minimally enclosing axis-aligned bounding box of the vertex array given information from the instance.
/// @param rotation_matrix A Matrix3x3 representing rotation in 3D space.
/// @param scale The scale of the instance.
/// @param translate_part The center of the box would be shifted in 3D space by this. Primarily for world space.
[[nodiscard]] AABB GetMEAABB(const Matrix3x3& rotation_matrix, const Vector3& scale = Vector3::One, const Vector3& translate_part = Vector3::Zero) const;
[[nodiscard]] AABB GetMEAABB(const Matrix4x4& instance_matrix, bool translate = false) const;
public:
VertexArray() = default;
/// Vertices are required, Everything else is optional.
VertexArray(const Vertex* vertex_positions, const long& vp_length, const unsigned int* vertex_indices = nullptr, const long& vi_length = 0,
const Normal* vertex_normals = nullptr, const long& vn_length = 0, const TextureCoordinate* texture_coordinates = nullptr, const long& vt_length = 0);
/// Vertices are required, Everything else is optional.
explicit VertexArray(const std::vector<Vertex>& vertex_positions, const std::vector<unsigned int>& vertex_indices = {},
const std::vector<Normal>& vertex_normals = {}, const std::vector<TextureCoordinate>& texture_coordinates = {});
static VertexArray LoadWavefrontOBJ(const std::string& file_text);
};
using namespace JGL;
static VertexArray Animate(int animation_id, float animation_time);
static VertexArray Animate(const AnimationState& anim_state);

315
main.cpp
View File

@@ -1,36 +1,80 @@
#include <glad/glad.h>
#include <JGL/JGL.h>
#include <rewindow/types/window.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>
#include <J3ML/Geometry/AABB.hpp>
#include <rewindow/logger/logger.h>
#include <JGL/types/VertexArray.h>
using J3ML::LinearAlgebra::Vector2;
using namespace JGL::Fonts;
using namespace JGL;
//The Re3D style base projection.
std::vector<GLfloat> perspective(float fov, float aspect, float nearPlane, float farPlane) {
std::vector<float> result(16);
float f = 1.0f / tan(fov * 0.5f * M_PI / 180.0f);
result[0] = f / aspect;
result[5] = f;
result[10] = (farPlane + nearPlane) / (nearPlane - farPlane);
result[11] = -1.0f;
result[14] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
return result;
}
float fps = 0.0f;
/// A draggable 2D point that highlights when moused over and when clicked.
class Gizmo
{
public:
Gizmo() {}
Gizmo(const Vector2& pos) : position(pos) {}
bool dragging = false;
bool hovered = false;
Vector2 position;
float range = 6.f;
float base_radius = 3.f;
float hover_radius = 6.f;
float drag_radius = 4.f;
Color4 base_color = Colors::Reds::Salmon;
Color4 hover_color = Colors::Reds::Firebrick;
Color4 drag_color = Colors::White;
float lerp_rate = 0.25f;
float text_scale = 1.f;
int text_size = 12;
void Grab() {
if (hovered)
dragging = true;
}
void Release() {
dragging = false;
}
void Update(const Vector2& mouse) {
if (dragging)
position = position.Lerp(mouse, lerp_rate);
hovered = mouse.Distance(position) < range;
}
void Draw() {
if (dragging)
J2D::DrawPoint(drag_color, position, drag_radius);
else if (hovered)
J2D::DrawPoint(hover_color, position, hover_radius);
else
J2D::DrawPoint(base_color, position, base_radius);
J2D::DrawString(Colors::White, std::format("{:.1f},{:.1f}", position.x, position.y), position.x, position.y, text_scale, text_size);
}
};
/// A 3D Camera Controller.
class Camera {
public:
Vector3 position = {0,0,0};
Vector3 angle = {0,0,0};
std::array<GLfloat, 16> lookAt(const Vector3& eye, const Vector3& center, const Vector3& up) {
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::array<GLfloat, 16> result = {
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,
@@ -57,93 +101,242 @@ struct point {
GLfloat t;
};
int FreeSans;
int Jupiteroid;
Gizmo a({250, 150});
Gizmo b({200, 250});
Gizmo c({350, 300});
Gizmo d({450, 250});
JGL::Font FreeSans;
Texture* image;
Texture* image_mask;
RenderTarget* j2d_render_target;
class JGLDemoWindow : public ReWindow::RWindow
{
public:
void initGL() {
camera = new Camera;
auto window_size = getSize();
auto aspect = (float) window_size[0] / (float) window_size[1];
gladLoadGL();
JGL::Update(getSize());
FreeSans = JGL::LoadFont("assets/fonts/FreeSans.ttf");
Jupiteroid = JGL::LoadFont("assets/fonts/Jupiteroid.ttf");
if (!JGL::Init(GetSize(), 75, 100))
Logger::Fatal("Initialization failed.");
// Load a custom font.
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(perspective(75, aspect, 0.001, 100).data());
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.f, 0.f, 0.f, 0.f);
glViewport(0,0,window_size.x,window_size.y);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR);
image_mask = new Texture("assets/sprites/alpha_mask_2.png");
j2d_render_target = new RenderTarget({540, 540}, {0,0,0,0}, false, MSAA_SAMPLE_RATE::MSAA_NONE);
//Texture::MultiplyByAlphaMask(*image, *image_mask);
}
Vector3 textAngle = {0,0,0};
EulerAngleXYZ textAngle = {0,0,0};
float fov = 90;
u8 pulse = 0;
float sprite_radians = 0;
bool fov_increasing = true;
int blit_pos = 0;
void display() {
textAngle.y += 2.0f;
pulse++;
float dt = GetDeltaTime();
JGL::Update(GetSize());
if (fov_increasing)
fov += 0.025;
else
fov -= 0.050;
if (fov >= 120)
fov_increasing = false;
else if (fov <= 75)
fov_increasing = true;
//J3D::ChangeFOV(fov);
sprite_radians += 0.005;
textAngle.yaw += 1;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camera->render();
///All 3D elements of the scene and JGL elements *must* be rendered before the 2d stuff.
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
/* if rendering to screen space directly. */
auto test_light = PointLight({2,1,2}, {pulse,pulse,pulse, 255}, {pulse, pulse, pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
// If a 3D object has transparency. The things you'd like to see through it must be drawn before.
J3D::Begin();
J3D::DrawLine(JGL::Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
J3D::DrawLine(JGL::Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
J3D::DrawString(JGL::Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f},textAngle, 1.f, 32, FreeSans);
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
//J3D::WireframeSphere(Colors::Green, {0,0,0.5f}, 0.25f, 1, 128, 128);
Sphere sphere = {{0,0, 0.5f}, 0.2125};
J3D::BatchWireframeRevoSphere(Colors::Green, &sphere, 1, 1, 8, 8, true);
J3D::RequiredLight(&test_light);
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
J3D::WireframeAABB(Colors::Gray, {0,0,0.5f}, {0.11f, 0.06f, 0.11f});
AABB boxes[1] = {{Vector3(-0.2125, -0.2125,0.28750), Vector3(0.2125,0.2125,0.7125)}};
J3D::BatchWireframeAABB(Colors::Yellow, boxes, 1, 1);
//J3D::WireframeOBB(Colors::Red, {0, 0, 1.5f}, {0.40f, 0.10f, 0.10f}, {0,textAngle.y, 0});
//J3D::FillSphere({0,255,0,120}, sphere);
//J3D::DrawCubicBezierCurve(Colors::Blue, {0,0,0.3}, {0,0,0.5}, {0.2,0,0.3}, {0.2, 0.3, 0.1}, 30);
//J3D::WireframeIcosahedron(Colors::Green, {0,0,0.5f}, 0.125f, 1.f);
J3D::End();
J2D::Begin();
J2D::Begin(j2d_render_target, true);
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::FillRect(Color4::FromColor3(Colors::Pinks::HotPink), {68, 120}, {32, 32});
J2D::FillGradientRect(Colors::Red, Colors::Blue, Gradient::DiagonalBottomLeft, {100,52}, {100,100});
J2D::FillRoundedRect(JGL::Colors::Red, {200, 52}, {100, 100}, 8, 8);
J2D::FillRoundedRect(JGL::Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
J2D::DrawPartialSprite(image, {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);
J2D::FillCircle(JGL::Colors::White, {52, 204}, 50, 24);
J2D::OutlineCircle(JGL::Colors::White, {153, 204}, 50, 24);
J2D::FillTriangle(Colors::Red, {{0, 275}, {0, 375}, {100, 375}});
J2D::FillChamferRect(Colors::Reds::LightSalmon, {150, 400}, {64, 64}, 5);
J2D::OutlineRoundedRect(Colors::Reds::LightCoral, {250, 350}, {128, 128}, 10, 2);
std::vector<Vector2> points = {{1,1}, {4,4}, {8,8}, {16,16}, {32,32}};
J2D::FillGradientTriangle(Color4(Colors::Red), Color4(Colors::Green), Color4(Colors::Blue), {{0, 275}, {0, 375}, {100, 375}});
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
J2D::DrawGradientLine(JGL::Colors::Red, JGL::Colors::Blue, {105, 375}, {200, 275}, 2);
J2D::DrawGradientLine(Colors::Red, Colors::Blue, {105, 375}, {200, 275}, 2);
auto result = Jupiteroid.MeasureString("Jupiteroid Font", 16);
J2D::DrawString(JGL::Colors::Green, "Jupteroid Font", 0.f, 16, 1.f, 16, Jupiteroid);
J2D::DrawString(JGL::Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 33, 1,16, Jupiteroid);
J2D::DrawString(JGL::Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 50, 1,16, Jupiteroid);
//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);
std::array<Vector2, 5> polygon = {Vector2(200, 400), {220, 420}, {220, 430}, {230, 410}, {200, 400}};
J2D::OutlinePolygon(Colors::White, polygon.data(), polygon.size());
//J2D::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();
RenderTarget::Blit(Colors::Red, {0, 0}, j2d_render_target);
//Draw the Render Target that we just drew all that stuff onto.
J2D::Begin();
J2D::DrawPartialRenderTarget(j2d_render_target, {0, 0}, {0,0}, {512, 512});
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
//J2D::DrawSprite(, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
//J2D::DrawSprite( {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
J2D::End();
}
void OnRefresh(float elapsed) override {
fps = GetRefreshRate();
if (IsKeyDown(Keys::RightArrow))
camera->angle.y += 45.f * elapsed;
if (IsKeyDown(Keys::LeftArrow))
camera->angle.y -= 45.f * elapsed;
if (IsKeyDown(Keys::UpArrow))
camera->angle.x -= 45.f * elapsed;
if (IsKeyDown(Keys::DownArrow))
camera->angle.x += 45.f * elapsed;
if (IsKeyDown(Keys::Space))
camera->position.y += 1.f * elapsed;
if (IsKeyDown(Keys::LeftShift))
camera->position.y -= 1.f * elapsed;
//This is wrong of course. Just for testing purposes.
if (IsKeyDown(Keys::W))
camera->position.z += 1.f * elapsed;
if (IsKeyDown(Keys::S))
camera->position.z -= 1.f * elapsed;
if (IsKeyDown(Keys::A))
camera->position.x += 1.f * elapsed;
if (IsKeyDown(Keys::D))
camera->position.x -= 1.f * elapsed;
auto mouse = GetMouseCoordinates();
a.Update(mouse);
b.Update(mouse);
c.Update(mouse);
d.Update(mouse);
display();
if (glGetError() != GL_NO_ERROR)
exit(1);
glSwapBuffers();
int glError = glGetError();
if (glError != GL_NO_ERROR)
std::cout << glError << std::endl;
GLSwapBuffers();
}
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent & ev) override
{
RWindow::OnMouseButtonDown(ev);
a.Grab();
b.Grab();
c.Grab();
d.Grab();
}
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent & ev) override
{
RWindow::OnMouseButtonUp(ev);
a.Release();
b.Release();
c.Release();
d.Release();
}
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override {return true;}
JGLDemoWindow() : ReWindow::RWindow() {}
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height){}
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height) {}
};
int main(int argc, char** argv) {
auto* window = new JGLDemoWindow("JGL Demo Window", 1280, 720);
window->setRenderer(RenderingAPI::OPENGL);
window->SetRenderer(RenderingAPI::OPENGL);
window->Open();
window->initGL();
window->setResizable(false);
window->SetResizable(true);
window->SetVsyncEnabled(true);
while (window->isAlive()) {
window->pollEvents();
window->refresh();
}
std::ifstream file("assets/models/cube.obj");
if (!file.is_open())
return -1;
std::stringstream buffer;
buffer << file.rdbuf();
std::string file_text = buffer.str();
file.close();
//std::cout << "File contents:\n" << file_text << std::endl;
auto result = VertexArray::LoadWavefrontOBJ(file_text);
ReWindow::Logger::Error.EnableConsole(false);
ReWindow::Logger::Warning.EnableConsole(false);
ReWindow::Logger::Debug.EnableConsole(false);
while (window->IsAlive())
window->ManagedRefresh();
return 0;
//for (const auto& v3 : result)
//std::cout << v3.x << " " << v3.y << " " << v3.z << std::endl;
}

View File

@@ -0,0 +1 @@
Main:new("Install build dependencies", "apt-get install -yq libgl1-mesa-dev libfreetype-dev")

View File

@@ -1,119 +0,0 @@
#include <JGL/FontCache.h>
using namespace JGL;
char CachedGlyph::getCharacter() {
return character;
}
const GLuint* CachedGlyph::getTexture() {
return &texture;
}
CachedGlyph::CachedGlyph(GLuint texture_id, char c, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
texture = texture_id;
character = c;
this->x2offset = x2offset;
this->y2offset = y2offset;
this->w = w;
this->h = h;
this->advanceX = advanceX;
this->advanceY = advanceY;
}
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
glyphs.push_back(glyph);
}
unsigned int JGL::CachedFont::getFontSize() {
return font_size;
}
unsigned int JGL::CachedFont::getFontIndex() {
return font_index;
}
CachedGlyph* JGL::CachedFont::getGlyph(char c) {
for (const auto& g : glyphs)
if (c == g->getCharacter())
return g;
return nullptr;
}
CachedFont::CachedFont(unsigned int font_size, unsigned int font_index) {
this->font_size = font_size;
this->font_index = font_index;
}
void CachedFont::eraseGlyph(CachedGlyph* glyph) {
if (glyph == nullptr)
return;
for (int i = 0; i < glyphs.size(); i++)
if (glyphs[i] == glyph)
glDeleteTextures(1, glyphs[i]->getTexture()),
delete glyphs[i],
glyphs.erase(glyphs.begin() + i);
}
void CachedFont::eraseGlyph(char c) {
for (int i = 0; i < glyphs.size(); i++)
if (glyphs[i]->getCharacter() == c)
glDeleteTextures(1, glyphs[i]->getTexture()),
delete glyphs[i],
glyphs.erase(glyphs.begin() + i);
}
void CachedFont::eraseGlyph(GLuint texture_id) {
for (int i = 0; i < glyphs.size(); i++)
if (glyphs[i]->getTexture() == &texture_id)
glDeleteTextures(1, glyphs[i]->getTexture()),
delete glyphs[i],
glyphs.erase(glyphs.begin() + i);
}
std::vector<CachedGlyph*>* CachedFont::getGlyphs() {
return &glyphs;
}
void FontCache::appendFont(CachedFont* font) {
cachedFonts.push_back(font);
}
void FontCache::newFont(unsigned int font_size, unsigned int font_index) {
auto* font = new CachedFont(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) {
for (auto& g: *cachedFonts[i]->getGlyphs())
cachedFonts[i]->eraseGlyph(g);
delete cachedFonts[i];
cachedFonts.erase(cachedFonts.begin() + i);
}
}
}
void FontCache::purgeCache() {
//Remove every font from the cache.
for (const auto& font : cachedFonts)
eraseFont(font);
cachedFonts = {};
}
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;
}

View File

@@ -2,426 +2,44 @@
// Created by dawsh on 1/17/24.
//
#include <JGL/JGL.h>
#include <glad/glad.h>
#include <JGL/Color3.h>
#include <jlog/jlog.hpp>
GLfloat oldColor[4] = {0, 0, 0, 255};
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;
#include <JGL/JGL.h>
#include <JGL/logger/logger.h>
#include "internals/include/internals.h"
namespace JGL {
using namespace J3ML;
Vector2 wS;
bool Update(const Vector2& window_size) {
wS = window_size;
return JGL::InitTextEngine();
}
void J2D::Begin() {
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, wS.x, wS.y, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
wasDepthTestEnabled = false;
if (glIsEnabled(GL_DEPTH_TEST))
wasDepthTestEnabled = true,
glDisable(GL_DEPTH_TEST);
wasVertexArraysEnabled = true;
if (!glIsEnabled(GL_VERTEX_ARRAY))
wasVertexArraysEnabled = false,
glEnable(GL_VERTEX_ARRAY);
wasCullFaceEnabled = true;
if (!glIsEnabled(GL_CULL_FACE))
wasCullFaceEnabled = false,
glEnable(GL_CULL_FACE),
glCullFace(GL_BACK);
wasBlendEnabled = true;
if (!glIsEnabled(GL_BLEND))
wasBlendEnabled = false,
glEnable(GL_BLEND),
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
wasTexture2DEnabled = true;
if (!glIsEnabled(GL_TEXTURE_2D))
wasTexture2DEnabled = false,
glEnable(GL_TEXTURE_2D);
wasTextureCoordArrayEnabled = true;
if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY))
wasTextureCoordArrayEnabled = false,
glEnable(GL_TEXTURE_COORD_ARRAY);
wasColorArrayEnabled = false;
if (glIsEnabled(GL_COLOR_ARRAY))
wasColorArrayEnabled = true,
glDisable(GL_COLOR_ARRAY);
if (!inJ3D)
inJ2D = true;
else { ERROR("Attempt to Begin J2D inside of J3D context.") }
}
void J2D::End() {
//Change back to the previous projection (The 3D one in Re3D's case.)
glDisable(GL_TEXTURE_2D);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
if (wasDepthTestEnabled)
glEnable(GL_DEPTH_TEST);
if (!wasVertexArraysEnabled)
glDisable(GL_VERTEX_ARRAY);
if (!wasCullFaceEnabled)
glDisable(GL_CULL_FACE);
if (!wasBlendEnabled)
glDisable(GL_BLEND);
if (!wasTexture2DEnabled)
glDisable(GL_TEXTURE_2D);
if (!wasTextureCoordArrayEnabled)
glDisable(GL_TEXTURE_COORD_ARRAY);
if (wasColorArrayEnabled)
glEnable(GL_COLOR_ARRAY);
//Put the draw color back how it was before.
glColor4f(oldColor[0], oldColor[1], oldColor[2], oldColor[3]);
inJ2D = false;
}
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
if (!inJ2D)
ERROR("Attempt to Render 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}};
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_QUADS, 0, 4);
}
void J2D::FillRect(const Color3& color, const Vector2& pos, const Vector2& size) {
J2D::FillRect({color.r, color.g, color.b, 255}, pos, size);
}
void J2D::FillGradientRect(const Color4& color1, const Color4& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size) {
if (!inJ2D)
ERROR("Attempt to Render 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 == Gradient::Horizontal)
colors = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f, color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,
color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f, color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f};
else if (gradient == Gradient::Vertical)
colors = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f, color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f,
color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f, color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f};
else if (gradient == Gradient::DiagonalBottomLeft)
colors = {(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f, (color1.b + color2.b) / 2.f / 255.f, (color1.a + color2.a) / 2.f / 255.f,
color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f,
(color1.b + color2.b) / 2.f / 255.f, (color1.a + color2.a) / 2.f / 255.f, color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f};
else if (gradient == Gradient::DiagonalTopLeft)
colors = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f,
(color1.b + color2.b) / 2.f / 255.f, (color1.a + color2.a) / 2.f / 255.f,color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f,
(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f, (color1.b + color2.b) / 2.f / 255.f,(color1.a + color2.a) / 2.f / 255.f};
glEnable(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glColorPointer(4, GL_FLOAT, 0, colors.data());
glDrawArrays(GL_QUADS, 0, 4);
glDisable(GL_COLOR_ARRAY);
}
void J2D::FillGradientRect(const Color3& color1, const Color3& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size) {
J2D::FillGradientRect({color1.r, color1.g, color1.b, 255}, {color2.r, color2.g, color2.b, 255}, gradient, pos, size);
}
void J2D::FillRoundedRect(const Color4 &color, const Vector2 &pos, const Vector2 &size, float radius, unsigned int subdivisions) {
if (!inJ2D)
ERROR("Attempt to Render 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::FillRoundedRect(const JGL::Color3& color, const J3ML::LinearAlgebra::Vector2& pos, const J3ML::LinearAlgebra::Vector2& size, float radius, unsigned int subdivisions) {
J2D::FillRoundedRect({color.r, color.g, color.b, 255}, pos, size, radius, subdivisions);
}
void J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render 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);
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINE_LOOP, 0, 4);
}
void J2D::OutlineRect(const Color3& color, const Vector2& pos, const Vector2& size, float thickness) {
J2D::OutlineRect({color.r, color.g, color.b, 255}, pos, size, thickness);
}
void J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.");
Vector2 vertices[] = {A, B};
glLineWidth(thickness);
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINES, 0, 2);
}
void J2D::DrawLine(const Color3& color, const Vector2& A, const Vector2& B, float thickness) {
J2D::DrawLine({color.r, color.g, color.b, 255}, A, B, thickness);
}
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::DrawLine(const Color3& color, float x, float y, float w, float h, float thickness) {
J2D::DrawLine({color.r, color.g, color.b, 255}, x, y, w, h, thickness);
}
void J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.");
Vector2 vertices[] = {A, B};
GLfloat colors[8] = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,
color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f};
glEnable(GL_COLOR_ARRAY);
glLineWidth(thickness);
glColorPointer(4,GL_FLOAT,sizeof(GL_FLOAT) * 4, colors);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINES, 0, 2);
glDisable(GL_COLOR_ARRAY);
}
void J2D::DrawGradientLine(const Color3& color1, const Color3& color2, const Vector2& A, const Vector2& B, float thickness) {
J2D::DrawGradientLine({color1.r, color1.g, color1.b, 255}, {color2.r, color2.g, color2.b, 255}, A, B, thickness);
}
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 DrawGradientLine(const Color3& color1, const Color3& color2, float x, float y, float w, float h, float thickness) {
J2D::DrawGradientLine({color1.r, color1.g, color1.b, 255}, {color2.r, color2.g, color2.b, 255}, {x, y}, {w, h}, thickness);
}
void J2D::DrawPixel(const Color4& color, const Vector2& coordinates) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.");
Vector2 vertices[] = {coordinates};
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINES, 0, 1);
}
void J2D::DrawPixel(const Color3& color, const Vector2& coordinates) {
J2D::DrawPixel({color.r, color.g, color.b, 255}, coordinates);
}
void J2D::DrawPixel(const Color4& color, float x, float y) {
DrawPixel(color, {x, y});
}
void J2D::DrawPixel(const Color3& color, float x, float y) {
DrawPixel({color.r, color.g, color.b, 255}, {x, y});
}
void J2D::OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
float step = (2.f * M_PI) / (float) subdivisions;
std::vector<Vector2> vertices{};
GLfloat angle, x, y;
for (angle = 0.0f; angle < (2.f * M_PI); angle += step) {
x = radius * std::sin(angle) + center.x;
y = radius * std::cos(angle) + center.y;
vertices.emplace_back(x,y);
bool Init(const Vector2& window_size, float fovY, float far_plane) {
gladLoadGL();
if (!MeetsRequirements()) {
Logger::Fatal("The graphics driver does not meet the minimum requirements to run this program.");
return false;
}
glLineWidth(thickness);
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
InitTextEngine();
Fonts::Init();
ShapeCache::Init();
OpenGLState::window_size = window_size;
J3D::fov = fovY;
J3D::far_plane = far_plane;
return true;
}
void J2D::OutlineCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions, float thickness) {
J2D::OutlineCircle({color.r, color.g, color.b, 255}, center, radius, subdivisions, thickness);
void Update(const Vector2& window_size) {
OpenGLState::window_size = window_size;
glViewport(0, 0, (int) window_size.x, (int) window_size.y);
}
void J2D::FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
float step = (2.f * M_PI) / (float) subdivisions;;
std::vector<Vector2> vertices{};
GLfloat angle, x, y;
for (angle = 0.0f; angle < (2.f * M_PI); angle += step)
x = radius * sin(angle) + center.x,
y = radius * cos(angle) + center.y,
vertices.push_back({x, y});
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size());
}
void J2D::FillCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions) {
J2D::FillCircle({color.r, color.g, color.b, 255}, center, radius, subdivisions);
}
void J2D::OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render 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);
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINE_LOOP, 0, 3);
}
void J2D::OutlineTriangle(const Color3& color, const Triangle2D& tri, float thickness) {
J2D::OutlineTriangle({color.r, color.g, color.b, 255}, tri, thickness);
}
void J2D::FillTriangle(const Color4& color, const Triangle2D &tri) {
if (!inJ2D)
ERROR("Attempt to Render 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}};
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void J2D::FillTriangle(const Color3& color, const Triangle2D &tri) {
J2D::FillTriangle({color.r, color.g, color.b, 255}, tri);
}
void J3D::Begin() {
//Get what the draw color was before we did anything.
glGetFloatv(GL_CURRENT_COLOR, oldColor);
wasDepthTestEnabled = false;
if (glIsEnabled(GL_DEPTH_TEST))
wasDepthTestEnabled = true,
glDisable(GL_DEPTH_TEST);
wasVertexArraysEnabled = false;
if (!glIsEnabled(GL_VERTEX_ARRAY))
wasVertexArraysEnabled = false,
glEnable(GL_VERTEX_ARRAY);
wasTexture2DEnabled = true;
if (!glIsEnabled(GL_TEXTURE_2D))
wasTexture2DEnabled = false,
glEnable(GL_TEXTURE_2D);
//TODO We won't always want this but for now we do.
wasCullFaceEnabled = false;
if (glIsEnabled(GL_CULL_FACE))
wasCullFaceEnabled = true,
glDisable(GL_CULL_FACE);
wasBlendEnabled = true;
if (!glIsEnabled(GL_BLEND))
wasBlendEnabled = false,
glEnable(GL_BLEND),
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (!inJ2D)
inJ3D = true;
else { ERROR("Attempt to Begin J3D inside of J2D context.") }
}
void J3D::End() {
glDisable(GL_TEXTURE_2D);
if (wasDepthTestEnabled)
glEnable(GL_DEPTH_TEST);
if (!wasVertexArraysEnabled)
glDisable(GL_VERTEX_ARRAY);
if (wasTexture2DEnabled)
glDisable(GL_TEXTURE_2D);
if (wasBlendEnabled)
glDisable(GL_BLEND);
if (wasCullFaceEnabled)
glEnable(GL_CULL_FACE);
//Put the draw color back how it was before.
glColor4f(oldColor[0], oldColor[1], oldColor[2], oldColor[3]);
inJ3D = false;
}
void J3D::DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness) {
if (!inJ3D)
ERROR("Attempt to Render J3D element before J3D begin.")
Vector3 vertices[] = {A, B};
glLineWidth(thickness);
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices);
glDrawArrays(GL_LINES, 0, 2);
}
void J3D::DrawLine(const Color3& color, const Vector3& A, const Vector3& B, float thickness) {
J3D::DrawLine({color.r, color.g, color.b, 255}, A, B, thickness);
bool MeetsRequirements() {
if (!GLAD_GL_VERSION_2_1)
return false;
if (!GLAD_GL_ARB_framebuffer_object)
return false;
if (!GLAD_GL_ARB_depth_texture)
return false;
if (!GLAD_GL_ARB_shadow)
return false;
return true;
}
}

View File

@@ -1,223 +0,0 @@
#include <JGL/JGL.h>
#if __linux__
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#endif
#if _WIN32
#include <ft2build.h>
#include FT_FREETYPE_H
#endif
namespace JGL {
FT_Library ft;
struct Font {
int index = 0;
FT_Face face;
};
std::vector<Font> faces;
int LoadFont(const std::string &font_path) {
if (ft == nullptr)
return -1;
Font font;
if (FT_New_Face(ft, font_path.c_str(), 0, &font.face)) {
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
return -1;
}
unsigned int newIndex = 0;
for (const auto& f : faces)
if (f.index >= newIndex)
newIndex = f.index + 1;
font.index = newIndex;
faces.push_back(font);
std::cout << "Loaded font from " << font_path << " with index " << newIndex << std::endl;
return newIndex;
}
bool InitTextEngine() {
if (FT_Init_FreeType(&ft))
return true;
return false;
}
void UnloadFont(int font_index) {
for (int i = 0; i < faces.size(); i++)
if (faces[i].index == font_index)
FT_Done_Face(faces[i].face),
faces.erase(faces.begin() + i);
}
FontCache fontCache;
void J2D::DrawString(const Color3& color, std::string text, float x, float y, float scale, u32 size, unsigned int font_index) {
glUseProgram(0); // Fixed-function pipeline.
Font font{};
CachedFont* cachedFont = fontCache.getFont(size, font_index);
//If the font doesn't exist in the cache yet.
if (!cachedFont) {
fontCache.newFont(size, font_index);
cachedFont = fontCache.getFont(size, font_index);
}
//Set up the regular font.
for (const auto& f : faces)
if (f.index == font_index)
font = f;
if (font.face == nullptr)
return;
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, 1.0f);
FT_Set_Pixel_Sizes(font.face, 0, size);
std::vector<GLuint> textures(text.length());
//For each character
for (int i = 0; i < text.length(); i++) {
float x2, y2, w, h;
//If the font is in the cache already.
if (cachedFont->getGlyph(text.c_str()[i])) {
CachedGlyph* glyph = cachedFont->getGlyph(text.c_str()[i]);
glBindTexture(GL_TEXTURE_2D, *glyph->getTexture());
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);
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;
} else {
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
continue;
FT_GlyphSlot g = font.face->glyph;
glGenTextures(1, &textures.at(i));
glBindTexture(GL_TEXTURE_2D, textures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
x2 = x + g->bitmap_left * scale;
y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
w = g->bitmap.width * scale;
h = g->bitmap.rows * scale;
x += (g->advance.x >> 6) * scale;
y += (g->advance.y >> 6) * scale;
cachedFont->appendGlyph(new CachedGlyph(textures.at(i), text.c_str()[i], g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
}
GLfloat vertices[12] = {x2, y2, x2, y2 + h, x2 + w, y2 + h,x2, y2, x2 + w, y2 + h, x2 + w, y2};
GLfloat textureCoordinates[12] = {0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
glTexCoordPointer(2, GL_FLOAT, sizeof(GL_FLOAT) * 2, &textureCoordinates);
glVertexPointer(2, GL_FLOAT, sizeof(GL_FLOAT) * 2, &vertices);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
}
void J3D::DrawString(const Color3& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, unsigned int font_index) {
//TODO figure out what the scale should actually be mathematically.
scale = scale * 0.002f;
scale = -scale;
float x = pos.x;
float y = pos.y;
float z = pos.z;
std::vector<GLuint> textures(text.length());;
glUseProgram(0); // Fixed-function pipeline.
glColor4f(color.r, color.g, color.b, 1.0f);
Font font;
for (auto& f : faces)
if (f.index == font_index)
font = f;
if (font.face == NULL) {
std::cout << "null font" << std::endl;
return;
}
FT_Set_Pixel_Sizes(font.face, 0, size);
glPushMatrix();
glTranslatef(x, y, z);
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);
x = 0;
y = 0;
z = 0;
for (int i = 0; i < text.length(); i++)
{
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
continue;
FT_GlyphSlot g = font.face->glyph;
glGenTextures(1, &textures.at(i));
glBindTexture(GL_TEXTURE_2D, textures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
float x2 = x + g->bitmap_left * scale;
float y2 = y - g->bitmap_top * scale; // Adjust y-coordinate
float z2 = z;
float w = g->bitmap.width * scale;
float h = g->bitmap.rows * scale;
glBegin(GL_TRIANGLES);
glTexCoord2f(0, 0);
glVertex3f(x2, y2, z2);
glTexCoord2f(0, 1);
glVertex3f(x2, y2 + h, z2);
glTexCoord2f(1, 1);
glVertex3f(x2 + w, y2 + h, z2);
glTexCoord2f(0, 0);
glVertex3f(x2, y2, z2);
glTexCoord2f(1, 1);
glVertex3f(x2 + w, y2 + h, z2);
glTexCoord2f(1, 0);
glVertex3f(x2 + w, y2, z2);
glEnd();
x += (g->advance.x >> 6) * scale;
y += (g->advance.y >> 6) * scale;
}
for (unsigned int& texture : textures)
glDeleteTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
glPopMatrix();
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include <string>
namespace JGL {
class VertexArray;
VertexArray LoadWavefrontOBJ(const std::string& file_text);
}

View File

@@ -0,0 +1,59 @@
/// Things used in J2D and J3D that should not be exposed to the user of the library.
#pragma once
#include "glad/glad.h"
#include <array>
#include <vector>
#include "J3ML/LinearAlgebra/Vector2.hpp"
#include "JGL/types/RenderTarget.h"
#include "JGL/types/Light.h"
#include "JGL/logger/logger.h"
namespace JGL {
inline constexpr std::array<const LightBase*, 8> empty_light_array = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
inline bool inJ2D = false;
inline bool inJ3D = false;
std::vector<Vector3> TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count);
}
namespace JGL::OpenGLState {
inline JGL::RenderTarget* render_target = nullptr;
inline Vector2 window_size;
inline GLfloat oldColor[4] = {0, 0, 0, 1};
inline GLfloat baseColor[4] = {1, 1, 1, 1};
inline GLuint current_fbo = 0;
inline GLint viewport[4] = {0, 0, 0, 0};
inline bool wasTexture2DEnabled = false;
inline bool wasTextureCoordArrayEnabled = false;
inline bool wasNormalArrayEnabled = false;
inline bool wasDepthTestEnabled = false;
inline bool wasVertexArraysEnabled = false;
inline bool wasCullFaceEnabled = false;
inline bool wasBlendEnabled = false;
inline bool wasColorArrayEnabled = false;
inline GLint activeTextureUnit = 0;
}
namespace JGL::J2D {
inline std::array<const LightBase*, 8> required_lights;
inline std::vector<const LightBase*> light_array;
}
namespace JGL::J3D {
// List of lights required for each objects in the scene. up-to 8. For example, the sun. Or a flash-light.
inline std::array<const LightBase*, 8> required_lights;
// List of all lights in the scene.
inline std::vector<const LightBase*> optional_lights;
inline float far_plane = 0;
inline float fov = 0;
// Enables lighting and selects the correct lights to use.
void SelectLights(const Vector3& position);
// Resets the GL lights to default and disables them. Then, disables lighting.
void ResetLights();
[[nodiscard]] bool UsingLighting();
}

8671
src/internals/src/Fonts.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
#include <JGL/JGL.h>
void JGL::ShapeCache::Init() {
std::array<Vector3, 8> vertices = {
Vector3(1.0f, 1.0f, -1.0f),
Vector3(1.0f, -1.0f, -1.0f),
Vector3(1.0f, 1.0f, 1.0f),
Vector3(1.0f, -1.0f, 1.0f),
Vector3(-1.0f, 1.0f, -1.0f),
Vector3(-1.0f, -1.0f, -1.0f),
Vector3(-1.0f, 1.0f, 1.0f),
Vector3(-1.0f, -1.0f, 1.0f)
};
std::array<unsigned int, 36> indices = {
4, 2, 0,
2, 7, 3,
6, 5, 7,
1, 7, 5,
0, 3, 1,
4, 1, 5,
4, 6, 2,
2, 6, 7,
6, 4, 5,
1, 3, 7,
0, 2, 3,
4, 0, 1
};
std::array<Vector3, 8> vertex_normals = {
Vector3( 0.816f, 0.408f, -0.408f),
Vector3( 0.333f, -0.667f, -0.667f),
Vector3( 0.333f, 0.667f, 0.667f),
Vector3( 0.816f, -0.408f, 0.408f),
Vector3(-0.333f, 0.667f, -0.667f),
Vector3(-0.816f, -0.408f, -0.408f),
Vector3(-0.816f, 0.408f, 0.408f),
Vector3(-0.333f, -0.667f, 0.667f)
};
if (!cube_vertex_data)
cube_vertex_data = new VRamList(vertices.data(), vertices.size());
if (!cube_index_data)
cube_index_data = new VRamList(indices.data(), indices.size());
if (!cube_normal_data) {
cube_normal_data = new VRamList(vertex_normals.data(), vertex_normals.size());
}
if (!j2d_default_normal_data) {
std::array<GLfloat, 3> normal {0, 0, 1};
j2d_default_normal_data = new VRamList(normal.data(), normal.size());
}
}

View File

@@ -0,0 +1,203 @@
#include "../include/WavefrontOBJ.h"
#include <JGL/types/VertexArray.h>
#include <JGL/logger/logger.h>
std::pair<float, unsigned long> ParseNumber(const std::string& file_text, const unsigned long& offset) {
std::string number;
unsigned long new_offset = offset;
bool decimal_used = false;
if (offset >= file_text.size())
return {0.0f, offset};
for (; new_offset < file_text.size(); new_offset++) {
if (file_text[new_offset] == '-') {
if (number.empty()) {
number.push_back(file_text[new_offset]);
continue;
}
Logger::Error("Error while parsing number, Index: " + std::to_string(new_offset) + " Extra negative sign.");
return {0.0f, offset};
}
else if (file_text[new_offset] == '.') {
if (!decimal_used) {
number.push_back(file_text[new_offset]);
decimal_used = true;
continue;
}
Logger::Error("Error parsing number at: " + std::to_string(new_offset) + " Extra decimal point.");
return {0.0f, offset};
}
else if (isdigit(file_text[new_offset]))
number.push_back(file_text[new_offset]);
else
break;
}
return {std::stof(number), new_offset};
}
std::pair<Vector2, unsigned long> ParseVector2(const std::string& file_text, const unsigned long& offset) {
auto x_result = ParseNumber(file_text, offset);
auto y_result = ParseNumber(file_text, x_result.second + 1);
// If the new offset is the same as the offset we passed in then we know it didn't work.
if (x_result.second == offset || y_result.second == x_result.second)
return {Vector2(0, 0), offset};
return {Vector2(x_result.first, y_result.first), y_result.second + 1};
}
std::pair<Vector3, unsigned long> ParseVector3(const std::string& file_text, const unsigned long& offset) {
auto x_result = ParseNumber(file_text, offset);
auto y_result = ParseNumber(file_text, x_result.second + 1);
auto z_result = ParseNumber(file_text, y_result.second + 1);
// If the new offset is the same as the offset we passed in then we know it didn't work.
if (x_result.second == offset || y_result.second == x_result.second || z_result.second == y_result.second)
return {Vector3(0,0,0), offset};
return {Vector3(x_result.first, y_result.first, z_result.first), z_result.second + 1};
}
std::pair<std::array<Vector3, 3>, unsigned long> ParseFaceData(const std::string& file_text, const unsigned long& offset) {
unsigned long new_offset = offset;
std::array<Vector3, 3> face_data;
for (unsigned int i = 0; i < 3; i++) {
Vector3 vertex = {-1, -1, -1};
// Vertex
if (std::isdigit(file_text[new_offset])) {
auto v_result = ParseNumber(file_text, new_offset);
vertex.x = v_result.first;
new_offset = v_result.second;
}
// UV
if (new_offset < file_text.size() && file_text[new_offset] == '/') {
new_offset++;
if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
auto vt_result = ParseNumber(file_text, new_offset);
vertex.y = vt_result.first;
new_offset = vt_result.second;
}
}
// Normal
if (new_offset < file_text.size() && file_text[new_offset] == '/') {
new_offset++;
if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
auto vn_result = ParseNumber(file_text, new_offset);
vertex.z = vn_result.first;
new_offset = vn_result.second;
}
}
face_data[i] = vertex;
new_offset++;
}
return {face_data, new_offset};
}
VertexArray JGL::LoadWavefrontOBJ(const std::string &file_text) {
std::vector<std::array<Vector3, 3>> faceline_data;
std::vector<TextureCoordinate> temp_uvs;
std::vector<Normal> temp_normals;
std::vector<Vertex> temp_vertices;
unsigned long offset = 0;
while (offset < file_text.size()) {
char c = file_text[offset];
// TODO the entire line a comment is on should be skipped.
// Skip forward to the character after the next newline.
if (c == '#' || c == '\n' || c == '\r') {
offset++;
continue;
}
// Vertices
if (c == 'v' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
offset += 2;
auto vertex_result = ParseVector3(file_text, offset);
if (vertex_result.second != offset) {
temp_vertices.push_back(vertex_result.first);
offset = vertex_result.second;
}
}
// Normals.
else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 'n' &&
file_text[offset + 2] == ' ') {
offset += 3;
auto normal_result = ParseVector3(file_text, offset);
if (normal_result.second != offset) {
temp_normals.push_back(normal_result.first);
offset = normal_result.second;
}
}
// Texture Coordinates
else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 't' &&
file_text[offset + 2] == ' ') {
offset += 3;
auto uv_result = ParseVector2(file_text, offset);
if (uv_result.second != offset) {
temp_uvs.push_back(uv_result.first);
offset = uv_result.second;
}
}
// Face lines.
else if (c == 'f' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
offset += 2;
auto faceline_result = ParseFaceData(file_text, offset);
if (faceline_result.second != offset) {
faceline_data.push_back(faceline_result.first);
offset = faceline_result.second;
}
} else
offset++;
}
// Pick everything out of the face lines and set up how OpenGL expects.
std::vector<Vertex> final_vertices;
std::vector<TextureCoordinate> final_uvs;
std::vector<Normal> final_normals;
std::vector<unsigned int> final_indices;
for (const auto &face: faceline_data) {
for (const auto &vp: face) {
Vertex vertex;
TextureCoordinate uv;
Normal normal;
if (vp.x != -1)
vertex = temp_vertices[vp.x - 1];
if (vp.y != -1)
uv = temp_uvs[vp.y - 1];
if (vp.z != -1)
normal = temp_normals[vp.z - 1];
final_vertices.push_back(vertex);
final_uvs.push_back(uv);
final_normals.push_back(normal);
final_indices.push_back((unsigned int) final_vertices.size() - 1);
}
}
return VertexArray(
final_vertices.data(), final_vertices.size(),
final_indices.data(), final_indices.size(),
final_normals.data(), final_normals.size(),
final_uvs.data(), final_uvs.size());
}

View File

@@ -0,0 +1,119 @@
#include "../include/internals.h"
#include "J3ML/LinearAlgebra/Vector4.hpp"
#include "JGL/types/Light.h"
// TODO handle the case that a required light is in the list of optional lights.
void JGL::J3D::SelectLights(const Vector3& position) {
std::array<const LightBase*, 8> result = required_lights;
unsigned int required_light_count = 0;
for (const auto& i : result)
if (i) required_light_count++;
// If there is optional lights.
if (!optional_lights.empty()) {
// The number of lights we need to solve for
unsigned int remaining_lights = 8 - required_light_count;
std::vector<std::pair<float, const LightBase*>> light_influence;
for (const auto* light: optional_lights)
light_influence.emplace_back(light->GetAttenuationAtPosition(position), light);
// Sort by biggest influence.
std::sort(light_influence.begin(), light_influence.end(),
[](const auto &a, const auto &b) { return a.first > b.first; });
// Add in optional lights.
for (unsigned int i = 0; i < remaining_lights && i < light_influence.size(); i++)
result[required_light_count++] = light_influence[i].second;
}
glEnable(GL_LIGHTING);
for (unsigned int i = 0; i < result.size(); i++) {
// Terminate early if we have less than 8 lights.
if (!result[i])
break;
Vector4 ambient = { result[i]->GetAmbient().RN(), result[i]->GetAmbient().GN(), result[i]->GetAmbient().BN(), result[i]->GetAmbient().AN() };
Vector4 diffuse = { result[i]->GetDiffuse().RN(), result[i]->GetDiffuse().GN(), result[i]->GetDiffuse().BN(), result[i]->GetDiffuse().AN() };
Vector4 specular = { result[i]->GetSpecular().RN(), result[i]->GetSpecular().GN(), result[i]->GetSpecular().BN(), result[i]->GetSpecular().AN() };
GLenum current_light = GL_LIGHT0 + i;
glEnable(GL_LIGHT0 + i);
glLightfv(current_light, GL_POSITION, result[i]->GetPosition().ptr());
// How the light will affect different materials.
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
glLightfv(current_light, GL_DIFFUSE, diffuse.ptr());
glLightfv(current_light, GL_SPECULAR, specular.ptr());
// How far the light goes.
glLightf(current_light, GL_CONSTANT_ATTENUATION, result[i]->GetConstantAttenuation());
glLightf(current_light, GL_LINEAR_ATTENUATION, result[i]->GetLinearAttenuation());
glLightf(current_light, GL_QUADRATIC_ATTENUATION, result[i]->GetQuadraticAttenuation());
}
}
void JGL::J3D::ResetLights() {
Vector4 position = {0, 0, 1, 0};
Vector4 ambient = {0, 0, 0, 1};
Vector4 diffuse_light0 = {1,1,1,1};
Vector4 diffuse = {0,0,0,1};
Vector4 specular_light0 = {1,1,1,1};
Vector4 specular = {0,0,0,1};
Vector3 spot_direction = {0.0, 0.0, -1.0};
for (unsigned int i = 0; i < 8; i++) {
GLenum current_light = GL_LIGHT0 + i;
glLightfv(current_light, GL_POSITION, position.ptr());
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
glLightf(current_light, GL_CONSTANT_ATTENUATION, 1);
glLightf(current_light, GL_LINEAR_ATTENUATION, 0);
glLightf(current_light, GL_QUADRATIC_ATTENUATION, 0);
glLightf(current_light, GL_SPOT_CUTOFF, 180.0);
glLightfv(current_light, GL_SPOT_DIRECTION, spot_direction.ptr());
glLightf(current_light, GL_SPOT_EXPONENT, 0.0);
glLightfv(current_light, GL_DIFFUSE, (i == 0 ? diffuse_light0.ptr() : diffuse.ptr()));
glLightfv(current_light, GL_SPECULAR, (i == 0 ? specular_light0.ptr() : specular.ptr()));
glDisable(current_light);
}
glDisable(GL_LIGHTING);
}
bool JGL::J3D::UsingLighting() {
if (!optional_lights.empty())
return true;
for (unsigned int i = 0; i < required_lights.size(); i++)
if (required_lights[i])
return true;
return false;
}
std::vector<Vector3> JGL::TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count) {
std::vector<Vector3> normals(vertex_count, Vector3(0, 0, 0));
for (size_t i = 0; i < index_count; i += 3) {
GLuint i1 = indices[i];
GLuint i2 = indices[i + 1];
GLuint i3 = indices[i + 2];
Vector3 v1 = vertices[i1];
Vector3 v2 = vertices[i2];
Vector3 v3 = vertices[i3];
Vector3 edge1 = v2 - v1;
Vector3 edge2 = v3 - v1;
Vector3 faceNormal = Vector3::Cross(edge1, edge2);
normals[i1] += faceNormal;
normals[i2] += faceNormal;
normals[i3] += faceNormal;
}
for (auto& normal : normals)
normal = normal.Normalized();
return normals;
}

9
src/logger/logger.cpp Normal file
View 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};
}

1118
src/renderer/J2D.cpp Normal file

File diff suppressed because it is too large Load Diff

608
src/renderer/J3D.cpp Normal file
View File

@@ -0,0 +1,608 @@
#include <JGL/JGL.h>
#include <JGL/logger/logger.h>
#include <J3ML/Geometry/AABB.hpp>
#include <J3ML/Geometry/OBB.hpp>
#include <J3ML/Algorithm/Bezier.hpp>
#include <JGL/types/Light.h>
#include "../internals/include/internals.h"
std::array<GLfloat, 16> JGL::OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far) {
std::array<GLfloat, 16> result{};
GLfloat f = 1.0f / std::tan(fovY * 0.5f * Math::Pi / 180.0f);
result[0] = f / aspect;
result[5] = f;
result[10] = (z_far + z_near) / (z_near - z_far);
result[11] = -1.0f;
result[14] = (2.0f * z_far * z_near) / (z_near - z_far);
return result;
}
void JGL::J3D::ChangeFOV(float fov) {
JGL::J3D::fov = fov;
}
void JGL::J3D::ChangeFarPlane(float far_plane) {
JGL::J3D::far_plane = far_plane;
}
void JGL::J3D::RequiredLight(const JGL::LightBase* light) {
bool success = false;
for (auto& i : required_lights)
if (i == nullptr) {
i = light;
success = true;
break;
}
if (!success)
Logger::Error("You cannot specify more than 8 required lights.");
}
void JGL::J3D::OptionalLights(const JGL::LightBase** lights, const size_t& light_count) {
for (size_t i = 0; i < light_count; i++)
optional_lights.push_back(lights[i]);
}
void JGL::J3D::Begin(bool two_pass) {
auto aspect = (float) OpenGLState::window_size.x / (float) OpenGLState::window_size.y;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
glMatrixMode(GL_MODELVIEW);
//Get what the draw color was before we did anything.
glGetFloatv(GL_CURRENT_COLOR, OpenGLState::oldColor);
glColor4fv(OpenGLState::baseColor);
if (!glIsEnabled(GL_DEPTH_TEST))
OpenGLState::wasDepthTestEnabled = false,
glEnable(GL_DEPTH_TEST);
else
OpenGLState::wasDepthTestEnabled = true;
OpenGLState::wasVertexArraysEnabled = false;
if (!glIsEnabled(GL_VERTEX_ARRAY))
OpenGLState::wasVertexArraysEnabled = false,
glEnableClientState(GL_VERTEX_ARRAY);
if (glIsEnabled(GL_NORMAL_ARRAY))
OpenGLState::wasNormalArrayEnabled = true,
glDisableClientState(GL_NORMAL_ARRAY);
if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
OpenGLState::wasTextureCoordArrayEnabled = true,
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (glIsEnabled(GL_TEXTURE_2D))
OpenGLState::wasTexture2DEnabled = true,
glDisable(GL_TEXTURE_2D);
OpenGLState::wasCullFaceEnabled = false;
if (glIsEnabled(GL_CULL_FACE))
OpenGLState::wasCullFaceEnabled = true,
glDisable(GL_CULL_FACE);
if (!glIsEnabled(GL_BLEND))
OpenGLState::wasBlendEnabled = false,
glEnable(GL_BLEND),
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
else
OpenGLState::wasBlendEnabled = true;
// Reset the lights.
required_lights = empty_light_array;
optional_lights = {};
glDisable(GL_LIGHTING);
if (!inJ2D)
inJ3D = true;
else
Logger::Error("Beginning J3D context inside of J2D context?");
}
void JGL::J3D::End() {
if (!OpenGLState::wasDepthTestEnabled)
glDisable(GL_DEPTH_TEST);
if (!OpenGLState::wasVertexArraysEnabled)
glDisableClientState(GL_VERTEX_ARRAY);
if (OpenGLState::wasTexture2DEnabled)
glEnable(GL_TEXTURE_2D);
if (!OpenGLState::wasBlendEnabled)
glDisable(GL_BLEND);
if (OpenGLState::wasCullFaceEnabled)
glEnable(GL_CULL_FACE);
if (OpenGLState::wasNormalArrayEnabled)
glEnableClientState(GL_NORMAL_ARRAY);
if (OpenGLState::wasTextureCoordArrayEnabled)
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (glIsEnabled(GL_LIGHTING)) {
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDisable(GL_LIGHT2);
glDisable(GL_LIGHT3);
glDisable(GL_LIGHT4);
glDisable(GL_LIGHT5);
glDisable(GL_LIGHT6);
glDisable(GL_LIGHT7);
}
required_lights = empty_light_array;
optional_lights = {};
//Put the draw color back how it was before.
glColor4fv(OpenGLState::oldColor);
inJ3D = false;
}
void JGL::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(OpenGLState::baseColor);
}
void JGL::J3D::WireframeSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int stacks) {
Sphere sphere = {position, radius};
BatchWireframeSphere(color,& sphere, 1, thickness, sectors, stacks);
}
void JGL::J3D::WireframeSphere(const Color4& color, const Sphere& sphere, float thickness, unsigned int sectors, unsigned int stacks) {
BatchWireframeSphere(color,& sphere, 1, thickness, sectors, stacks);
}
void JGL::J3D::BatchWireframeSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness, unsigned int sectors, unsigned int stacks) {
if (!inJ3D)
Logger::Error("Drawing J3D element before J3D begin.");
// Create one sphere with a radius of 1 about 0, 0.
float r = 1;
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
int index = 0;
for (int i = 0; i <= sectors; i++) {
float lat = J3ML::Math::Pi * (-0.5 + (float) i / sectors);
float z = J3ML::Math::Sin(lat);
float zr = J3ML::Math::Cos(lat);
for (int j = 0; j <= stacks; j++) {
float lng = 2 * J3ML::Math::Pi * (float) (j - 1) / stacks;
float x = J3ML::Math::Cos(lng);
float y = J3ML::Math::Sin(lng);
float pos_x = r * x * zr;
float pos_y = r * y * zr;
float pos_z = r * z;
vertices[index++] = Vector3(pos_x, pos_y, pos_z);
}
}
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
// Render each sphere in the batch at their given position and radius.
for(size_t i = 0; i < sphere_count; i++) {
glPushMatrix();
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
glPopMatrix();
}
glColor4fv(OpenGLState::baseColor);
}
void JGL::J3D::WireframeRevoSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
Sphere sphere = {position, radius};
BatchWireframeRevoSphere(color,& sphere, 1, thickness, sectors, revolutions, draw_stacks);
}
void JGL::J3D::WireframeRevoSphere(const Color4& color, const Sphere& sphere, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
BatchWireframeRevoSphere(color,& sphere, 1, thickness, sectors, revolutions, draw_stacks);
}
void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
float r = 1;
std::vector<Vector3> vertices;
vertices.reserve((sectors + 1) * (revolutions + 1));
std::vector<Vector3> cross_section(sectors + 1);
for (int i = 0; i <= sectors; i++) {
float lat = J3ML::Math::Pi * (-0.5 + (float)i / sectors);
float z = J3ML::Math::Sin(lat);
float zr = J3ML::Math::Cos(lat);
cross_section[i] = Vector3(0, zr * r, z * r);
}
// Revolve
for (int j = 0; j <= revolutions; j++) {
float lng = 2 * J3ML::Math::Pi * (float)j / revolutions;
float cosLng = J3ML::Math::Cos(lng);
float sinLng = J3ML::Math::Sin(lng);
for (const auto& point : cross_section) {
float pos_x = point.y * cosLng;
float pos_y = point.y * sinLng;
float pos_z = point.z;
vertices.emplace_back(pos_x, pos_y, pos_z);
}
}
glLineWidth(thickness);
glColor4ubv(color.ptr());
VRamList vertex_data(vertices.data(), vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
// Render each sphere in the batch at their given position and radius.
for(size_t i = 0; i < sphere_count; i++) {
glPushMatrix();
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
if (draw_stacks)
glRotatef(90, 0, 1, 0),
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glColor4fv(OpenGLState::baseColor);
}
void JGL::J3D::WireframeIcosphere(const Color4& color, const Vector3& position, float radius, float thickness,
unsigned int subdivisions) {
if (!inJ3D)
Logger::Error("Drawing J3D element before J3D begin.");
// NOTE2SELF: Code i'm borrowing this from uses float-packed-arrays rather than discrete Vectors
// working on translating that correctly...
// TODO: Revise this once J3ML::Geometry::Icosahedron is implemented.
const float h_angle = J3ML::Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
const float v_angle = J3ML::Math::Atan(1.0f / 2.f); // elevation = 26.565;
std::vector<Vector3> vertices; // array of 12 vertices (x,y,z)
unsigned int index = 0; // indices
float z, xy; // coords
float hAngle1 = -Math::Pi / 2.f - h_angle / 2.f; // start from -126 at 1st row
float hAngle2 = -Math::Pi / 2.f; // start from -90 deg at 2nd row
// the first top vertex at (0,0,r)
vertices[0] = position + Vector3{0,0,radius};
// compute 10 vertices at 1st and 2nd rows
for (int i = 1; i <= 5; ++i)
{
z = radius * Math::Sin(v_angle); // elevation
xy = radius * Math::Cos(v_angle); // length on XY plane
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle1), xy * Math::Sin(hAngle1), z} ;
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle2), xy * Math::Sin(hAngle2), -z};
// next horizontal angles
hAngle1 += h_angle;
hAngle2 += h_angle;
}
// the last bottom vertex at (0, 0, -r)
vertices[11] = position + Vector3{0,0, -radius};
//glLineWidth(thickness);
//glColor4ubv(color.ptr());
//glBindBuffer(GL_ARRAY_BUFFER, vertices.size());
//glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
//glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
//glColor4fv(baseColor);
std::vector<Vector3> tmpVertices;
std::vector<Vector3> tmpIndices;
std::vector<Vector2> newVs((subdivisions+1) * (subdivisions+2) / 2 * 3);
const Vector3 v1, v2, v3;
Vector3 newV1, newV2, newV3;
int i, j, k;
index = 0; // unsigned int
float a; // lerp alpha
unsigned int i1, i2; // indices
// copy prev arrays
tmpVertices = vertices;
//tmpIndices = indices;
// iterate each triangle of icosahedron
for (i = 0; i < tmpIndices.size(); i++)
{
//v1 = tmpVertices[tmpIndices[i]];
//v2 = tmpVertices[tmpIndices[i+1]];
//v3 = tmpVertices[tmpIndices[i+2]];
}
}
void JGL::J3D::WireframeIcosahedron(const Color4& color, const Vector3& position, float radius, float thickness) {
if (!inJ3D)
Logger::Error("Drawing J3D element before J3D begin.");
// TODO: Revise this once J3ML::Geometry::Icosahedron is implemented.
const float h_angle = J3ML::Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
const float v_angle = J3ML::Math::Atan(1.0f / 2.f); // elevation = 26.565;
std::array<Vector3, 12> vertices; // array of 12 vertices (x,y,z)
int index = 0; // indices
float z, xy; // coords
float hAngle1 = -Math::Pi / 2.f - h_angle / 2.f; // start from -126 at 1st row
float hAngle2 = -Math::Pi / 2.f; // start from -90 deg at 2nd row
// the first top vertex at (0,0,r)
vertices[0] = position + Vector3{0,0,radius};
// compute 10 vertices at 1st and 2nd rows
for (int i = 1; i <= 5; ++i)
{
z = radius * Math::Sin(v_angle); // elevation
xy = radius * Math::Cos(v_angle); // length on XY plane
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle1), xy * Math::Sin(hAngle1), z} ;
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle2), xy * Math::Sin(hAngle2), -z};
// next horizontal angles
hAngle1 += h_angle;
hAngle2 += h_angle;
}
// the last bottom vertex at (0, 0, -r)
vertices[11] = position + Vector3{0,0, -radius};
glLineWidth(thickness);
glColor4ubv(color.ptr());
//glBindBuffer(GL_ARRAY_BUFFER, vertices.size());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
glColor4fv(OpenGLState::baseColor);
}
void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const size_t& box_count, float thickness) {
glColor4ubv(color.ptr());
glLineWidth(thickness);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
for (size_t i = 0; i < box_count; i++) {
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
Vector3 center = boxes[i].Centroid();
glPushMatrix();
glTranslatef(center.x, center.y, center.z);
glScalef(delta.x, delta.y, delta.z);
glDrawArrays(GL_LINES, 0, ShapeCache::cube_vertex_data->GetLength());
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glColor4fv(OpenGLState::baseColor);
}
void JGL::J3D::WireframeAABB(const Color4& color, const Vector3& pos, const Vector3& radii, float thickness) {
AABB aabb = {Vector3(pos.x - radii.x, pos.y - radii.y, pos.z - radii.z), Vector3(pos.x + radii.x, pos.y + radii.y, pos.z + radii.z)};
BatchWireframeAABB(color, &aabb, 1, thickness);
}
void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_t& box_count) {
if (!inJ3D)
Logger::Error("Drawing J3D element before J3D begin.");
glColor4ubv(color.ptr());
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->GetHandle());
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
bool using_lights = false;
if (UsingLighting()) {
using_lights = true;
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_normal_data->GetHandle());
glNormalPointer(GL_FLOAT, sizeof(float), nullptr);
}
for (size_t i = 0; i < box_count; i++) {
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
Vector3 center = boxes[i].Centroid();
glPushMatrix();
glTranslatef(center.x, center.y, center.z);
glScalef(delta.x, delta.y, delta.z);
if (using_lights)
SelectLights(center);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
if (using_lights)
ResetLights();
glPopMatrix();
}
glColor4fv(OpenGLState::oldColor);
if (using_lights)
glDisable(GL_NORMAL_ARRAY);
glDisable(GL_CULL_FACE);
}
void JGL::J3D::FillAABB(const Color4& color, const Vector3& pos, const Vector3& radii) {
AABB box = {pos - radii, pos + radii};
BatchFillAABB(color, &box, 1);
}
void JGL::J3D::FillAABB(const Color4& color, const AABB& aabb) {
BatchFillAABB(color, &aabb, 1);
}
void JGL::J3D::FillSphere(const Color4& color, const Sphere& sphere, unsigned int sectors, unsigned int stacks) {
BatchFillSphere(color, &sphere, 1, sectors, stacks);
}
void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, unsigned int sectors, unsigned int stacks) {
if (!inJ3D)
Logger::Error("Drawing J3D element before J3D begin.");
float r = 1;
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
std::vector<unsigned int> indices; indices.reserve(sectors * stacks * 6);
float two_pi = 2 * J3ML::Math::Pi;
int index = 0;
for (int i = 0; i <= sectors; i++) {
float lat = J3ML::Math::Pi * (-0.5 + (float) i / sectors);
float z = J3ML::Math::Sin(lat);
float zr = J3ML::Math::Cos(lat);
for (int j = 0; j <= stacks; j++) {
float lng = two_pi * (float) (j - 1) / stacks;
float x = J3ML::Math::Cos(lng);
float y = J3ML::Math::Sin(lng);
float pos_x = r * x * zr;
float pos_y = r * y * zr;
float pos_z = r * z;
vertices[index++] = Vector3(pos_x, pos_y, pos_z);
}
}
for (int i = 0; i < sectors; i++) {
for (int j = 0; j < stacks; j++) {
int first_index = i * (stacks + 1) + j;
int second_index = first_index + stacks + 1;
indices.push_back(first_index);
indices.push_back(second_index);
indices.push_back(first_index + 1);
indices.push_back(second_index);
indices.push_back(second_index + 1);
indices.push_back(first_index + 1);
}
}
VRamList vertex_data(vertices.data(), vertices.size());
VRamList index_data(indices.data(), indices.size());
glColor4ubv(color.ptr());
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_data.GetHandle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
for (size_t i = 0; i < sphere_count; i++) {
const Vector3 position = spheres[i].Position;
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
glDrawElements(GL_TRIANGLES, index_data.GetLength(), GL_UNSIGNED_INT, nullptr);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glColor4fv(OpenGLState::oldColor);
}
void JGL::J3D::FillSphere(const Color4& color, const Vector3& position, float radius, unsigned int sectors, unsigned int stacks) {
Sphere sphere = {position, radius};
BatchFillSphere(color, &sphere, 1, sectors, stacks);
}
void JGL::J3D::WireframeAABB(const Color4& color, const AABB& aabb, float thickness) {
BatchWireframeAABB(color, &aabb, 1, thickness);
}
// TODO Make it work the same as AABB batching. I couldn't get rotation to do anything more than twitch in place :(.
void JGL::J3D::BatchWireframeOBB(const Color4& color, const OBB* boxes, const size_t& box_count, float thickness) {
std::array<Vector3, 8> corner_points;
std::array<GLuint, 24> indices =
{
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7
};
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), corner_points.data());
for (size_t i = 0; i < box_count; i++) {
boxes[i].GetCornerPoints(corner_points.data());
glPushMatrix();
glTranslatef(boxes[i].pos.x, boxes[i].pos.y, boxes[i].pos.z);
glDrawElements(GL_LINES, indices.size(), GL_UNSIGNED_INT, indices.data());
glPopMatrix();
}
glColor4fv(OpenGLState::oldColor);
}
void JGL::J3D::WireframeOBB(const Color4& color, const OBB& obb, float thickness) {
BatchWireframeOBB(color, &obb, 1, thickness);
}
/*
void JGL::J3D::WireframeOBB(const Color4& color, const Vector3& position, const Vector3& radii, const Matrix3x3& orientation, float thickness) {
WireframeOBB(color, OBB(position, radii, orientation. * Vector3::UnitX, rotation * Vector3::UnitY, rotation * Vector3::UnitZ), thickness);
}
*/
void JGL::J3D::DrawCubicBezierCurve(const Color4& color, const Vector3& controlA, const Vector3& pointA,
const Vector3& pointB, const Vector3& controlB, int subdivisions, float thickness) {
Vector3 last = controlA;
const Vector3& first = controlB;
for (int i = 0; i < subdivisions; ++i)
{
float alpha = (float) i / (float) subdivisions;
Vector3 step = J3ML::Algorithm::Bezier(alpha, controlA, pointA, pointB, controlB);
DrawLine(color, last, step, thickness);
last = step;
}
// Have to manually draw the last segment of the curve.
DrawLine(color, last, first, thickness);
}
void JGL::J3D::DrawVertexArray(const Color4& color, const VertexArray& vertex_array, const Vector3& position) {
if (!inJ3D)
Logger::Error("Drawing J3D element before J3D begin.");
glColor4ubv(color.ptr());
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vertex_array.GetVertices()->GetHandle());
glVertexPointer(3, GL_FLOAT, 0, nullptr);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
//glScalef(1,1,1);
glDrawArrays(GL_TRIANGLES, 0, vertex_array.GetVertices()->GetLength());
glPopMatrix();
//glDrawElements(GL_LINES, vertex_array.GetIndices()->GetLength(), GL_UNSIGNED_INT, nullptr);
//std::cout << vertex_array.GetVertices()->GetLength() << std::endl;
glColor4fv(OpenGLState::oldColor);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

View File

@@ -0,0 +1,252 @@
#include <JGL/JGL.h>
#include "../internals/include/internals.h"
#if __linux__
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#if _WIN32
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#include <JGL/types/Font.h>
#include <JGL/types/FontCache.h>
#include <JGL/logger/logger.h>
namespace JGL {
CachedFont* CacheFont(const Font& font, u32 size) {
glEnable(GL_TEXTURE_2D);
CachedFont* cachedFont;
FT_Set_Pixel_Sizes(font.face, 0, size);
Logger::Debug("Caching font data...");
GLuint texture_id;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
GLsizei width = 0;
GLsizei max_height = 0;
FT_ULong charcode;
FT_UInt gindex;
//We have to loop over the available glyphs twice as we need the
//final width and height of the texture_handle before we can construct it
//and subsequently upload the glyph data.
charcode = FT_Get_First_Char(font.face, &gindex);
//Strings are char-based so we only handle charcodes within the extended ASCII range.
while (gindex != 0 && charcode < 255) {
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
FT_GlyphSlot g = font.face->glyph;
width += g->bitmap.width;
max_height = std::max(max_height, (GLsizei) g->bitmap.rows);
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
}
fontCache.newFont(texture_id, width, max_height, size, font.index);
cachedFont = fontCache.getFont(size, font.index);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, max_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
GLsizei xoffset = 0;
charcode = FT_Get_First_Char(font.face, &gindex);
while (gindex != 0 && charcode < 255) {
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
FT_GlyphSlot g = font.face->glyph;
glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
GLfloat u0 = (GLfloat)xoffset / cachedFont->getTextureWidth();
GLfloat u1 = u0 + (GLfloat)g->bitmap.width / cachedFont->getTextureWidth();
GLfloat v0 = 0.0f;
GLfloat v1 = (GLfloat)g->bitmap.rows / cachedFont->getTextureHeight();
std::array<GLfloat, 12> texcoords
{
u0, v0,
u0, v1,
u1, v1,
u0, v0,
u1, v1,
u1, v0
};
cachedFont->appendGlyph(new CachedGlyph((char)charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
xoffset += g->bitmap.width;
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
}
glDisable(GL_TEXTURE_2D);
return cachedFont;
}
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
// Offset by height to render at "correct" location.
y += size;
bool round_text_coords_for_crisp_rendering = true;
// TODO: This currently does not account for non-integer scale factors.
if (round_text_coords_for_crisp_rendering)
{
x = J3ML::Math::Floor(x);
y = J3ML::Math::Floor(y);
}
CachedFont* cachedFont = fontCache.getFont(size, font.index);
if (font.face == nullptr)
Logger::Fatal("Drawing a string with an uninitialized font?");
//If the font doesn't exist in the cache yet.
if (!cachedFont)
cachedFont = CacheFont(font, size);
glColor4ubv(color.ptr());
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
//Texture parameters are restored when the texture_handle is bound
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTextureHandle());
std::vector<std::array<GLfloat, 12>> vertices(text.size());
std::vector<std::array<GLfloat, 12>> texcoords(text.size());
for (int i = 0; i < text.length(); i++) {
float x2, y2, w, h;
CachedGlyph* glyph = cachedFont->getGlyph(text.c_str()[i]);
if (glyph == nullptr)
continue;
x2 = x + glyph->x2offset * scale;
y2 = y - glyph->y2offset * scale; // Adjust y-coordinate
w = glyph->w * scale;
h = glyph->h * scale;
x += glyph->advanceX * scale;
y += glyph->advanceY * scale;
std::array<GLfloat, 12> glyph_vertices
{
x2, y2,
x2, y2 + h,
x2 + w, y2 + h,
x2, y2,
x2 + w, y2 + h,
x2 + w, y2
};
auto glyph_texcoords = glyph->getTexCoords();
vertices[i] = glyph_vertices;
texcoords[i] = glyph_texcoords;
}
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(OpenGLState::oldColor);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
void J3D::DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngleXYZ& angle, bool draw_back_face) {
// TODO: Determine the proper scale factor mathematically
// This number was arrived at holistically.
scale = scale * 0.002f;
scale = -scale;
float x = pos.x;
float y = pos.y;
float z = pos.z;
// TODO: this is broken because it causes the text to be shifted downwards.
/*
bool round_text_coords_for_crisp_rendering = true;
// TODO: This currently does not account for non-integer scale factors.
if (round_text_coords_for_crisp_rendering)
{
x = J3ML::Math::Floor(x);
y = J3ML::Math::Floor(y);
z = J3ML::Math::Floor(z);
}
*/
CachedFont* cachedFont = fontCache.getFont(size, font.index);
if (font.face == nullptr)
jlog::Fatal("Drawing a string with an uninitialized font?");
if (!cachedFont)
cachedFont = CacheFont(font, size);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glColor4ubv(color.ptr());
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTextureHandle());
std::vector<std::array<GLfloat, 18>> vertices(text.size());
std::vector<std::array<GLfloat, 12>> texcoords(text.size());
glPushMatrix();
glTranslatef(x, y, z);
glRotatef(angle.pitch, 1.0f, 0.0f, 0.0f);
glRotatef(angle.yaw, 0.0f, 1.0f, 0.0f);
glRotatef(angle.roll, 0.0f, 0.0f, 1.0f);
x = y = z = 0;
for (int i = 0; i < text.length(); i++) {
CachedGlyph* glyph = cachedFont->getGlyph(text[i]);
float x2 = x + glyph->x2offset * scale;
float y2 = y - glyph->y2offset * scale;
float w = glyph->w * scale;
float h = glyph->h * scale;
std::array<GLfloat, 18> glyph_vertices
{
x2, y2, z,
x2, y2 + h, z,
x2 + w, y2 + h, z,
x2, y2, z,
x2 + w, y2 + h, z,
x2 + w, y2, z
};
vertices[i] = glyph_vertices;
texcoords[i] = glyph->getTexCoords();
x += glyph->advanceX * scale;
y += glyph->advanceY * scale;
}
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
if (!draw_back_face)
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
if (!draw_back_face)
glDisable(GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(OpenGLState::oldColor);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
}

169
src/types/Font.cpp Normal file
View File

@@ -0,0 +1,169 @@
#include <vector>
#include <string>
#include <iostream>
#include <glad/glad.h>
#include <JGL/logger/logger.h>
#include <JGL/JGL.h>
#if __linux__
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#if _WIN32
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#include <JGL/types/Font.h>
#include <JGL/types/FontCache.h>
namespace JGL::Detail
{
FT_Library ft;
std::vector<Font> fonts;
bool InitTextEngine() {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // NOTE: This MUST be called for text rendering to work properly!!!
// Keep note of this, might cause problems later?
if (ft != nullptr)
Logger::Fatal("Error::FREETYPE: FT_Library was initialized but is already initialized.");
if (FT_Init_FreeType(&ft))
return true;
return false;
}
void UnloadFont(int font_index) {
auto iter = fonts.begin();
while (iter != fonts.end())
{
if (iter->index == font_index){
FT_Done_Face(iter->face);
iter = fonts.erase(iter);
} else ++iter;
}
}
}
namespace JGL {
bool InitTextEngine() {
return Detail::InitTextEngine();
}
Font::Font(const unsigned char* data, const size_t& size) {
if (Detail::ft == nullptr)
throw std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
if (FT_New_Memory_Face(Detail::ft, data, size, 0, &face))
throw std::runtime_error("Error::FREETYPE: Failed to load font!");
unsigned int new_index = 0;
for (const auto& f : Detail::fonts)
if (f.index >= new_index)
new_index = f.index + 1;
index = new_index;
Detail::fonts.push_back(*this);
std::cout << "Loaded font from memory at " << static_cast<const void*>(data) << " with index " << new_index << std::endl;
}
Font::Font(const std::filesystem::path& path) {
if (Detail::ft == nullptr)
throw std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
if (FT_New_Face(Detail::ft, path.string().c_str(), 0, &face))
throw std::runtime_error("Error::FREETYPE: Failed to load font!");
unsigned int new_index = 0;
for (const auto& f : Detail::fonts)
if (f.index >= new_index)
new_index = f.index + 1;
index = new_index;
Detail::fonts.push_back(*this);
std::cout << "Loaded font from " << path << " with index " << new_index << std::endl;
}
Font::~Font() {
//Detail::UnloadFont(this->index);
}
std::vector<Font> Font::GetLoadedFonts() {
return Detail::fonts;
}
Font Font::LoadTTF(const std::filesystem::path& path)
{
return Font(path);
}
Vector2 Font::MeasureString(const std::string &text, unsigned int ptSize) {
Vector2 extents = Vector2(0,0);
bool font_of_size_in_cache = false;
for(const auto& f : fontCache.getFonts()) {
if (f->getFontSize() == ptSize) {
font_of_size_in_cache = true;
break;
}
}
if (font_of_size_in_cache) {
CachedFont* font;
for (auto* f: fontCache.getFonts())
if (f->getFontSize() == ptSize)
font = f;
for (const char& c : text)
extents.x += font->getGlyph(c)->advanceX;
extents.y = ptSize;
return extents;
}
jlog::Warning("Measuring a font size that is not cached, Defaulting to Jupiteroid.");
FT_Set_Pixel_Sizes(Fonts::Jupiteroid.face, ptSize, ptSize);
for (const char& c : text) {
// TODO: Fix segfault
//FT_GlyphSlot slot = Fonts::Jupiteroid.face->glyph;
//auto glyph_index = FT_Get_Char_Index(Fonts::Jupiteroid.face, c);
FT_GlyphSlot slot = face->glyph;
auto glyph_index = FT_Get_Char_Index(this->face, c);
//auto error = FT_Load_Glyph(Fonts::Jupiteroid.face, glyph_index, FT_LOAD_DEFAULT);
auto error = FT_Load_Glyph(this->face, glyph_index, FT_LOAD_DEFAULT);
if (error)
continue;
Vector2 advance = {static_cast<float>(slot->advance.x >> 6),
static_cast<float>(slot->advance.y >> 6)};
extents += advance;
// Gives smaller results than we'd want.
if (extents.y < slot->metrics.height / 64)
extents.y = slot->metrics.height / 64;
// Just fucking hardcode it, we know the glyph height is roughly always the ptSize anyway.
if (extents.y < ptSize)
extents.y = ptSize;
}
return extents;
}
}

112
src/types/FontCache.cpp Normal file
View File

@@ -0,0 +1,112 @@
#include <JGL/types/FontCache.h>
using namespace JGL;
char CachedGlyph::getCharacter() const {
return character;
}
std::array<GLfloat, 12> CachedGlyph::getTexCoords() const {
return texcoords;
}
CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
character = c;
this->x2offset = x2offset;
this->y2offset = y2offset;
this->w = w;
this->h = h;
this->advanceX = advanceX;
this->advanceY = advanceY;
this->texcoords = texcoords;
}
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
glyphs.emplace(glyph->getCharacter(), glyph);
}
unsigned int JGL::CachedFont::getFontSize() const {
return font_size;
}
unsigned int JGL::CachedFont::getFontIndex() const {
return font_index;
}
CachedGlyph* JGL::CachedFont::getGlyph(char c) {
auto it = glyphs.find(c);
if (it != glyphs.end())
return it->second;
return nullptr;
}
CachedFont::CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index) {
this->texture = texture_id;
this->texture_width = texture_width;
this->texture_height = texture_height;
this->font_size = font_size;
this->font_index = font_index;
}
std::unordered_map<char, CachedGlyph*> CachedFont::getGlyphs() {
return glyphs;
}
const GLuint* CachedFont::getTextureHandle() {
return &texture;
}
GLsizei CachedFont::getTextureWidth() const {
return texture_width;
}
GLsizei CachedFont::getTextureHeight() const {
return texture_height;
}
void CachedFont::Erase() {
if (texture != 0)
glDeleteTextures(1, &texture);
}
CachedFont::~CachedFont() {
Erase();
}
void FontCache::appendFont(CachedFont* font) {
cachedFonts.push_back(font);
}
void FontCache::newFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index) {
auto* font = new CachedFont(texture_id, texture_width, texture_height, font_size, font_index);
cachedFonts.push_back(font);
}
void FontCache::eraseFont(CachedFont* font) {
for (int i = 0; i < cachedFonts.size(); i++) {
if (cachedFonts[i] == font) {
delete cachedFonts[i];
cachedFonts.erase(cachedFonts.begin() + i);
}
}
}
void FontCache::purgeCache() {
//Remove every font from the cache.
for (const auto& font : cachedFonts)
eraseFont(font);
}
std::vector<CachedFont*> FontCache::getFonts() {
return cachedFonts;
}
CachedFont* FontCache::getFont(unsigned int font_size, unsigned int font_index) {
if (cachedFonts.empty())
return nullptr;
for (auto* f : cachedFonts)
if (f->getFontIndex() == font_index && f->getFontSize() == font_size)
return f;
return nullptr;
}

64
src/types/Light.cpp Normal file
View File

@@ -0,0 +1,64 @@
#include <JGL/types/Light.h>
JGL::PointLight::PointLight(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation, float linear_attenuation, float quadratic_attenuation) {
this->position = Vector4(position, 1.0f);
this->ambient = ambient;
this->diffuse = diffuse;
this->specular = specular;
this->constant_attenuation = constant_attenuation;
this->linear_attenuation = linear_attenuation;
this->quadratic_attenuation = quadratic_attenuation;
}
float JGL::PointLight::GetAttenuationAtPosition(const Vector3& pos) const {
Vector3 light_pos = {position.x, position.y, position.z};
Vector3 vector_to_position = pos - light_pos;
float distance = vector_to_position.Length();
return 1.0f / (GetConstantAttenuation() + GetLinearAttenuation() * distance + GetQuadraticAttenuation() * distance * distance);
}
JGL::SpotLight::SpotLight(const Vector3& position, const Matrix3x3& ro_mat, float cone_size_degrees, float exponent, const Color4& ambient, const Color4& diffuse, const Color4& specular,
float constant_attenuation, float linear_attenuation, float quadratic_attenuation) {
this->position = Vector4(position, 1);
//TODO RotationMatrix to "Normalized direction vector."
orientation = ro_mat;
this->cut = cone_size_degrees;
this->exponent = exponent;
this->ambient = ambient;
this->diffuse = diffuse;
this->specular = specular;
this->constant_attenuation = constant_attenuation;
this->linear_attenuation = linear_attenuation;
this->quadratic_attenuation = quadratic_attenuation;
}
Vector4 JGL::LightBase::GetPosition() const {
return position;
}
Color4 JGL::LightBase::GetAmbient() const {
return ambient;
}
Color4 JGL::LightBase::GetDiffuse() const {
return diffuse;
}
Color4 JGL::LightBase::GetSpecular() const {
return specular;
}
float JGL::LightBase::GetConstantAttenuation() const {
return constant_attenuation;
}
float JGL::LightBase::GetLinearAttenuation() const {
return linear_attenuation;
}
float JGL::LightBase::GetQuadraticAttenuation() const {
return quadratic_attenuation;
}

31
src/types/Material.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include <JGL/types/Material.h>
#include <J3ML/LinearAlgebra/Vector4.hpp>
JGL::Material::Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine) {
ambient_ref = ambient_reflection;
diffuse_ref = diffuse_reflection;
specular_ref = specular_reflection;
emission = light_emission;
shininess = shine;
}
void JGL::Material::SetActiveMaterial(const Material& material) {
Vector4 ambient = { material.ambient_ref.RN(), material.ambient_ref.BN(), material.ambient_ref.GN(), material.ambient_ref.AN() };
Vector4 diffuse = { material.diffuse_ref.RN(), material.diffuse_ref.BN(), material.diffuse_ref.GN(), material.diffuse_ref.AN() };
Vector4 specular = { material.specular_ref.RN(), material.specular_ref.BN(), material.specular_ref.GN(), material.specular_ref.AN() };
Vector4 emission = { material.emission.RN(), material.emission.BN(), material.emission.GN(), material.emission.AN() };
// Determine which faces we're going to apply this material to.
GLenum face = GL_FRONT;
if (glIsEnabled(GL_CULL_FACE)) {
GLint current; glGetIntegerv(GL_CULL_FACE_MODE, &current);
if (current == GL_FRONT)
face = GL_BACK;
}
glMaterialfv(face, GL_AMBIENT, ambient.ptr());
glMaterialfv(face, GL_DIFFUSE, diffuse.ptr());
glMaterialfv(face, GL_SPECULAR, specular.ptr());
glMaterialfv(face, GL_EMISSION, emission.ptr());
glMaterialf(face, GL_SHININESS, material.shininess);
}

387
src/types/RenderTarget.cpp Normal file
View File

@@ -0,0 +1,387 @@
#include <JGL/types/RenderTarget.h>
#include <JGL/types/Texture.h>
#include <JGL/logger/logger.h>
#include <stdexcept>
const 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);
}
Vector2i JGL::RenderTarget::GetDimensions() const {
return size;
}
void JGL::RenderTarget::Erase() {
if (GetActiveGLFramebufferHandle() == framebuffer_object)
Logger::Warning("Deleting the framebuffer that's currently in use?");
if (using_depth)
glDeleteRenderbuffers(1, &depth_buffer);
glDeleteFramebuffers(1, &framebuffer_object);
if (MSAAEnabled())
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
}
Color4 JGL::RenderTarget::GetClearColor() const {
return clear_color;
}
/// Idk why you'd ever want to clear it out if you're rendering onto a texture you passed in :shrug:.
JGL::RenderTarget::RenderTarget(const JGL::Texture* texture, const Color4& clear_color) {
if (texture->GetDimensions().x < 1 || texture->GetDimensions().y < 1)
Logger::Fatal("Creating a render target where the color attachment is empty?");
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 = {(int) size.x, (int) size.y};
this->texture = texture;
texture_created_by_us = false;
}
JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
if (size.x < 1 || size.y < 1)
Logger::Fatal("Creating a render target where the color attachment is empty?");
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, viewport);
//Textures behave strangely if they're not square aaaaaaaaaaaaa.
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;
if (sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE)
SetMSAAEnabled(sample_rate);
}
std::vector<GLfloat> JGL::RenderTarget::GetPixels() const {
std::vector<GLfloat> data(GetDimensions().x * GetDimensions().y * 4);
GLuint current_fbo = GetActiveGLFramebufferHandle();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glReadPixels(0, 0, GetDimensions().x, GetDimensions().y, GL_RGBA, GL_FLOAT, data.data());
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
return data;
}
void JGL::RenderTarget::Resize(const Vector2i& new_size) {
if (!texture_created_by_us)
Logger::Error("Resizing a Render Target that does not own it's texture?");
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLfloat old_clear_color[4];
GLint old_viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, old_viewport);
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
/* If what was previously not part of the renderable area is big enough
* to just set the new size. */
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(biggest, 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::OwnsTexture() const {
return texture_created_by_us;
}
JGL::MSAA_SAMPLE_RATE JGL::RenderTarget::GetMSAASampleRate() const {
return msaa_sample_rate;
}
bool JGL::RenderTarget::MSAAEnabled() const {
return msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE;
}
bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
// If we'd be setting the same sample_rate we already have.
if (sample_rate == msaa_sample_rate)
return false;
// If we'd be rendering onto a texture and not a plain render target we don't want this.
if (!OwnsTexture())
return false;
// Remove it if they request no msaa or if what they requested is different than what they already have.
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE || msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE) {
if(using_depth)
glDeleteRenderbuffers(1, &msaa_depth_buffer);
glDeleteRenderbuffers(1, &msaa_render_buffer);
glDeleteFramebuffers(1, &msaa_framebuffer_object);
msaa_framebuffer_object = 0;
msaa_depth_buffer = 0;
msaa_render_buffer = 0;
msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
// Only return here if they specifically requested no MSAA. else continue to change mode.
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE)
return true;
}
GLuint current_fbo = GetActiveGLFramebufferHandle();
glGenFramebuffers(1, &msaa_framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, msaa_framebuffer_object);
GLint current_renderbuffer = 0;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &current_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);
return failure;
}
void JGL::RenderTarget::MSAABlit() const {
if (MSAAEnabled() && OwnsTexture()) {
// Save the GL state.
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint current_draw_fbo = 0;
GLint current_read_fbo = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &current_read_fbo);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_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, &current_texture);
glBindTexture(GL_TEXTURE_2D, GetJGLTexture()->GetGLTextureHandle());
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, current_texture);
}
}
void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget* destination) {
if (source.size != destination->size)
Logger::Warning("Blitting a render target but they're not the same size?");
// Save the GL state.
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint current_draw_fbo = 0;
GLint current_read_fbo = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &current_read_fbo);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_draw_fbo);
// Draw the contents of one into the other.
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.framebuffer_object);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination->framebuffer_object);
glBlitFramebuffer(0, 0, source.size.x, source.size.y, 0, 0, source.size.x, source.size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// Put the GL state back.
glBindFramebuffer(GL_READ_FRAMEBUFFER, current_read_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
}
// To avoid repeatedly allocating and deallocating.
JGL::RenderTarget* pixel = nullptr;
void JGL::RenderTarget::Blit(const Color4& color, const Vector2i& position, JGL::RenderTarget* destination) {
if (position.x > destination->size.x || position.y > destination->size.y)
Logger::Warning("Blitting outside of the renderable area of the destination.");
if (pixel == nullptr)
pixel = new RenderTarget({1,1});
GLint current_draw_fbo = 0;
GLint current_read_fbo = 0;
GLint viewport[4];
GLfloat clear_color[4];
GLuint current_fbo = GetActiveGLFramebufferHandle();
glGetIntegerv(GL_VIEWPORT, viewport);
glGetFloatv(GL_COLOR_CLEAR_VALUE, clear_color);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &current_read_fbo);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_draw_fbo);
SetActiveGLRenderTarget(*pixel);
glClearColor(color.RedChannelNormalized(), color.GreenChannelNormalized(), color.BlueChannelNormalized(), color.AlphaChannelNormalized());
glClear(GL_COLOR_BUFFER_BIT);
// Invert so it's relative to the top left corner.
int target_y = destination->size.y - position.y - 1;
glBindFramebuffer(GL_READ_FRAMEBUFFER, pixel->framebuffer_object);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination->framebuffer_object);
glBlitFramebuffer(0, 0, 1, 1, position.x, target_y, position.x + 1, target_y + 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, current_read_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
}
JGL::RenderTarget::RenderTarget(const JGL::RenderTarget& rhs) {
auto* this_render_target = new RenderTarget(rhs.size, rhs.clear_color, rhs.using_depth, rhs.msaa_sample_rate);
RenderTarget::Blit(rhs, this_render_target);
this->clear_color = this_render_target->clear_color;
this->size = this_render_target->size;
this->using_depth = this_render_target->using_depth;
this->texture_created_by_us = true;
this->texture = this_render_target->texture;
this->framebuffer_object = this_render_target->framebuffer_object;
this->depth_buffer = this_render_target->depth_buffer;
this->msaa_sample_rate = this_render_target->msaa_sample_rate;
this->msaa_framebuffer_object = this_render_target->msaa_framebuffer_object;
this->msaa_depth_buffer = this_render_target->msaa_depth_buffer;
this->msaa_render_buffer = this_render_target->msaa_render_buffer;
operator delete(this_render_target);
}

186
src/types/Skeleton.cpp Normal file
View File

@@ -0,0 +1,186 @@
#include <JGL/types/Skeleton.h>
#include <JGL/logger/logger.h>
#include <cstring>
using namespace JGL;
std::array<int, 4> JGL::SkeletalVertexAttribute::GetAffectingBoneIDs() const {
return bone_ids;
}
std::array<float, 4> JGL::SkeletalVertexAttribute::GetAffectingBoneWeights() const {
return bone_weights;
}
JGL::SkeletalVertexAttribute::SkeletalVertexAttribute(const std::vector<int>& ids, const std::vector<float>& weights) {
if (bone_ids.size() > 4 || bone_weights.size() > 4)
Logger::Fatal("Initialization of a skeletal vertex that is effected by more than 4 bones.");
memcpy(this->bone_ids.data(), bone_ids.data(), sizeof(int) * 4);
memcpy(this->bone_weights.data(), bone_weights.data(), sizeof(float) * 4);
}
bool JGL::Bone::IsRootBone() const {
if (parent_id == -1)
return true;
return false;
}
int JGL::Bone::GetID() const {
return id;
}
std::string JGL::Bone::GetName() const {
return name;
}
Matrix4x4 JGL::Bone::GetInverseBindMatrix() const {
return inverse_bind_matrix;
}
Matrix4x4 JGL::Bone::GetOffsetMatrix() const {
return offset_matrix;
}
Matrix4x4 JGL::Bone::GetFinalTransform() const {
return final_transform;
}
std::vector<int> JGL::Bone::GetChildren() const {
return children;
}
void Bone::SetParent(int parent_identifier) {
parent_id = parent_identifier;
}
void Bone::AppendChild(int new_child) {
children.push_back(new_child);
}
void Bone::SetID(int numeric_id) {
id = numeric_id;
}
void Bone::SetName(const std::string& string_id) {
name = string_id;
}
void Bone::SetInverseBindMatrix(const Matrix4x4& inverse_bind) {
inverse_bind_matrix = inverse_bind;
}
void Bone::SetOffsetMatrix(const Matrix4x4& offset) {
offset_matrix = offset;
}
void Bone::SetFinalTransformMatrix(const Matrix4x4& final) {
final_transform = final;
}
int Bone::GetParentID() const {
return parent_id;
}
Bone::Bone(int numeric_id, const std::string& string_id, int parent_bone, const std::vector<int>& children_ids, const Matrix4x4& inverse_bind, const Matrix4x4& offset, const Matrix4x4& final) {
id = numeric_id;
name = string_id;
parent_id = parent_bone;
inverse_bind_matrix = inverse_bind;
offset_matrix = offset;
final_transform = final;
children = children_ids;
}
Bone* Skeleton::GetRootBone() {
return &root;
}
Bone* Skeleton::FindBone(int id) {
if (root.GetID() == id)
return &root;
for (auto& bone : bones)
if (bone.GetID() == id)
return &bone;
// If we couldn't find it.
return nullptr;
}
Bone* Skeleton::FindBone(const std::string& string_id) {
if (root.GetName() == string_id)
return &root;
for (auto& bone : bones)
if (bone.GetName() == string_id)
return &bone;
return nullptr;
}
void Skeleton::AppendBone(const Bone& new_bone) {
bones.push_back(new_bone);
}
Skeleton::Skeleton(const Bone& root_bone, const std::vector<Bone>& children) {
root = root_bone;
bones = children;
}
float KeyFrame::GetTimeStamp() const {
return time_stamp;
}
Skeleton KeyFrame::GetSkeleton() const {
return pose;
}
KeyFrame::KeyFrame(const Skeleton& pose, float time_stamp) {
this->pose = pose;
this->time_stamp = time_stamp;
}
Animation::Animation(int id, float duration, const std::vector<KeyFrame>& key_frames, const std::vector<SkeletalVertexAttribute>& skeletal_vertex_attributes,
const std::string& name) {
length = duration;
this->key_frames = key_frames;
this->id = id;
this->name = name;
this->vertex_attributes = skeletal_vertex_attributes;
}
float Animation::GetDuratrion() const {
return length;
}
std::vector<KeyFrame> Animation::GetKeyFrames() const {
return key_frames;
}
void Animation::AppendKeyFrame(const KeyFrame& new_key) {
key_frames.push_back(new_key);
}
void Animation::SetDuration(float duration) {
length = duration;
}
int Animation::GetID() const {
return id;
}
std::string Animation::GetName() const {
return name;
}
void Animation::SetID(int identifier) {
id = identifier;
}
void Animation::SetName(const std::string& name_id) {
name = name_id;
}
std::vector<SkeletalVertexAttribute> Animation::GetSkeletalVertexAttributes() const {
return vertex_attributes;
}

192
src/types/Texture.cpp Normal file
View File

@@ -0,0 +1,192 @@
#include <JGL/types/Texture.h>
#include <iostream>
#include <JGL/types/RenderTarget.h>
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;
// Because in vram it'll be right side up.
texture_flags = TextureFlag::INVERT_Y;
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, &current_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;
}
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* this_texture = new Texture(rhs.GetDimensions());
auto this_render_target = RenderTarget(this);
auto rhs_render_target = RenderTarget(&rhs);
RenderTarget::Blit(rhs_render_target, &this_render_target);
this->texture_handle = this_texture->texture_handle;
this->texture_size = this_texture->texture_size;
this->texture_flags = this_texture->texture_flags;
this->texture_format = this_texture->texture_format;
this->texture_filtering_mode = this_texture->texture_filtering_mode;
this->texture_wrapping_mode = this_texture->texture_wrapping_mode;
// Free the memory of "this_texture" without calling the destructor.
// In 99% of cases you wouldn't want this. But in this scenario we do.
operator delete(this_texture);
}
}

302
src/types/VRamList.cpp Normal file
View File

@@ -0,0 +1,302 @@
#include <JGL/types/VRamList.h>
#include <JGL/logger/logger.h>
#include <cstring>
void JGL::VRamList::load(const GLfloat* data, const long& size) {
while (spin_lock) {}
spin_lock = true;
GLint current_array_buffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_array_buffer);
glGenBuffers(1, &list_handle);
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, current_array_buffer);
element_array_buffer = false;
num_elements = size / sizeof(GLfloat);
spin_lock = false;
}
void JGL::VRamList::load(const GLuint* data, const long& size) {
while (spin_lock) {}
spin_lock = true;
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);
glGenBuffers(1, &list_handle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_element_array_buffer);
element_array_buffer = true;
num_elements = size / sizeof(GLuint);
spin_lock = false;
}
void JGL::VRamList::Erase() {
if (list_handle == 0)
return;
while (spin_lock) {}
spin_lock = true;
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);
GLint current_array_buffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_array_buffer);
if (element_array_buffer && current_element_array_buffer == list_handle)
JGL::Logger::Warning("Erasing an element array buffer while it's in use?");
else if (!element_array_buffer && current_array_buffer == list_handle)
JGL::Logger::Warning("Erasing an array buffer while it's in use?");
glDeleteBuffers(1, &list_handle);
list_handle = 0;
spin_lock = false;
}
GLuint JGL::VRamList::GetHandle() const {
return list_handle;
}
bool JGL::VRamList::IsFloatArray() const {
return !element_array_buffer;
}
long JGL::VRamList::GetLength() const {
return num_elements;
}
size_t JGL::VRamList::GetDataSize() const {
if (element_array_buffer)
return sizeof(GLuint) * num_elements;
return sizeof(GLfloat) * num_elements;
}
void JGL::VRamList::SetData(void* data, const long& length) {
while (spin_lock) {}
spin_lock = true;
bool should_resize = (this->num_elements != length);
if (should_resize) {
glDeleteBuffers(1, &list_handle);
list_handle = 0;
spin_lock = false;
element_array_buffer ? load((GLuint*) data, sizeof(GLuint) * length) : load((GLfloat*) data, sizeof(GLfloat) * length);
return;
}
// if (!should resize)
GLint current_buffer = 0;
GLenum buffer_type = GL_ARRAY_BUFFER;
GLenum buffer_binding = GL_ARRAY_BUFFER_BINDING;
if (element_array_buffer)
buffer_type = GL_ELEMENT_ARRAY_BUFFER,
buffer_binding = GL_ELEMENT_ARRAY_BUFFER_BINDING;
glGetIntegerv(buffer_binding, &current_buffer);
glBindBuffer(buffer_type, list_handle);
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
if (!vram)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(vram, data, (element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat)) * length);
if (!glUnmapBuffer(buffer_type))
JGL::Logger::Fatal("We couldn't unmap the buffer?");
glBindBuffer(buffer_type, current_buffer);
spin_lock = false;
}
void JGL::VRamList::UpdateData(void* data, const long& offset, const long& length) {
while (spin_lock) {}
spin_lock = true;
if (offset + length > num_elements) {
JGL::Logger::Warning("Using UpdateData to out-of-bounds write the VRamList? I'll resize it for you, But this is slow.");
unsigned long oob_delta = (offset + length) - num_elements;
if (element_array_buffer) {
auto list_data = GetDataUI();
list_data.resize(list_data.size() + oob_delta);
memcpy(list_data.data() + (offset * sizeof(GLuint)), data, length * sizeof(GLuint));
spin_lock = false; // This is going unlock and relock really fast, But this code fixes something considered wrong anyway - Redacted.
return SetData(list_data.data(), list_data.size());
}
// if (!element_array_buffer)
auto list_data = GetDataF();
list_data.resize(list_data.size() + oob_delta);
memcpy(list_data.data() + (offset * sizeof(GLfloat)), data, length * sizeof(GLfloat));
spin_lock = false;
return SetData(list_data.data(), list_data.size());
}
GLint current_buffer = 0;
GLenum buffer_type = GL_ARRAY_BUFFER;
GLenum buffer_binding = GL_ARRAY_BUFFER_BINDING;
if (element_array_buffer)
buffer_type = GL_ELEMENT_ARRAY_BUFFER,
buffer_binding = GL_ELEMENT_ARRAY_BUFFER_BINDING;
glGetIntegerv(buffer_binding, &current_buffer);
glBindBuffer(buffer_type, list_handle);
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
if (!vram)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
memcpy(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(vram) + (offset * element_size)), data, length * element_size);
if (!glUnmapBuffer(buffer_type))
JGL::Logger::Fatal("We couldn't unmap the buffer?");
glBindBuffer(buffer_type, current_buffer);
spin_lock = false;
}
std::vector<GLfloat> JGL::VRamList::GetDataF() const {
while (spin_lock) {}
if (element_array_buffer)
JGL::Logger::Warning("Getting data as GLfloat but the buffer data is GLuint?");
bool vertex_array_enabled = glIsEnabled(GL_VERTEX_ARRAY);
if (!vertex_array_enabled)
glEnableClientState(GL_VERTEX_ARRAY);
GLint current_buffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_buffer);
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
std::vector<GLfloat> data(num_elements);
void* vram = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
if (vram == nullptr)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(data.data(), vram, num_elements * sizeof(GLfloat));
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, current_buffer);
if (!vertex_array_enabled)
glDisableClientState(GL_VERTEX_ARRAY);
return data;
}
std::vector<GLuint> JGL::VRamList::GetDataUI() const {
while (spin_lock) {}
if (!element_array_buffer)
JGL::Logger::Warning("Getting data as GLuint but the buffer data is GLfloat?");
GLint current_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
std::vector<GLuint> data(num_elements);
void* vram = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
if (vram == nullptr)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(data.data(), vram, num_elements * sizeof(GLuint));
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_buffer);
return data;
}
JGL::VRamList::VRamList(const GLfloat* data, const long& length) {
load(data, (long) sizeof(GLfloat) * length);
}
JGL::VRamList::VRamList(const GLuint* data, const long& length) {
load(data, (long) sizeof(GLuint) * length);
}
JGL::VRamList::VRamList(const Vector2* data, const long& length) {
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector2) * length);
}
JGL::VRamList::VRamList(const Vector3* data, const long& length) {
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector3) * length);
}
JGL::VRamList::VRamList(const Vector4* data, const long& length) {
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector4) * length);
}
void JGL::VRamList::SetData(const GLfloat* data, const long& length) {
SetData((void*) data, length);
}
void JGL::VRamList::SetData(const Vector2* data, const long& length) {
SetData((void*) data, length * 2);
}
void JGL::VRamList::SetData(const Vector3* data, const long& length) {
SetData((void*) data, length * 3);
}
void JGL::VRamList::SetData(const Vector4* data, const long& length) {
SetData((void*) data, length * 4);
}
void JGL::VRamList::SetData(const GLuint* data, const long& length) {
SetData((void*) data, length);
}
void JGL::VRamList::SetData(const Vector2i* data, const long& length) {
SetData((void*) data, length * 2);
}
void JGL::VRamList::UpdateData(const GLfloat* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length);
}
void JGL::VRamList::UpdateData(const Vector2* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 2);
}
void JGL::VRamList::UpdateData(const Vector3* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 3);
}
void JGL::VRamList::UpdateData(const Vector4* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 4);
}
void JGL::VRamList::UpdateData(const GLuint* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length);
}
void JGL::VRamList::UpdateData(const Vector2i* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 2);
}
JGL::VRamList::~VRamList() {
Erase();
}
JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
while (rhs.spin_lock) {}
if (rhs.element_array_buffer) {
auto data_array = rhs.GetDataUI();
this->load(data_array.data(), data_array.size());
}
auto data_array = rhs.GetDataF();
this->load(data_array.data(), data_array.size());
}

184
src/types/VertexArray.cpp Normal file
View File

@@ -0,0 +1,184 @@
#include <JGL/types/VertexArray.h>
#include <JGL/logger/logger.h>
#include "../internals/include/WavefrontOBJ.h"
using namespace JGL;
const VRamList* VertexArray::GetVertices() const {
return vertices;
}
const VRamList* VertexArray::GetIndices() const {
return indices;
}
const VRamList* VertexArray::GetNormals() const {
return normals;
}
const VRamList* VertexArray::GetTextureCoordinates() const {
return texture_coordinates;
}
std::vector<Vertex> VertexArray::GetLocalVertices() const {
return local_vertices;
}
std::vector<unsigned int> VertexArray::GetLocalIndices() const {
return local_indices;
}
std::vector<TextureCoordinate> VertexArray::GetLocalTextureCoordinates() const {
return local_texture_coordinates;
}
std::vector<Normal> VertexArray::GetLocalNormals() const {
return local_normals;
}
Sphere VertexArray::GetMESphere(const Vector3& scale, const Vector3& translate_part) const {
if (scale == Vector3::One)
return { me_sphere.Position + translate_part, me_sphere.Radius };
float scale_factor = 0;
if (scale.x > scale_factor)
scale_factor = scale.x;
if (scale.y > scale_factor)
scale_factor = scale.y;
if (scale.z > scale_factor)
scale_factor = scale.z;
return { me_sphere.Position + translate_part, me_sphere.Radius * scale_factor };
}
Sphere VertexArray::GetMESphere(const Matrix4x4& instance_matrix, bool translate) const {
Vector3 scale = instance_matrix.GetScale();
Vector3 origin = Vector3::Zero;
if (translate)
origin = instance_matrix.GetTranslatePart();
return GetMESphere(scale, origin);
}
void VertexArray::CreateMESphere() {
Sphere result = {Vector3::Zero, 0};
Vector3 minimum = {std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
Vector3 maximum = { std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest()};
for (const auto& vertex : local_vertices) {
if (vertex.x < minimum.x)
minimum.x = vertex.x;
if (vertex.x > maximum.x)
maximum.x = vertex.x;
if (vertex.y < minimum.y)
minimum.y = vertex.y;
if (vertex.y > maximum.y)
maximum.y = vertex.y;
if (vertex.z < minimum.z)
minimum.z = vertex.z;
if (vertex.z > maximum.z)
maximum.z = vertex.z;
}
result.Position = (minimum + maximum) * 0.5f;
for (const auto& vertex : local_vertices) {
float distance_squared = Vector3::DistanceSquared(result.Position, vertex);
if (distance_squared > result.Radius)
result.Radius = distance_squared;
}
result.Radius = std::sqrt(result.Radius);
me_sphere = result;
}
void VertexArray::CreateMEOBB() {
Vector3 minimum(std::numeric_limits<float>::max());
Vector3 maximum (std::numeric_limits<float>::min());
for (const auto& vertex : local_vertices) {
if (vertex.x < minimum.x)
minimum.x = vertex.x;
if (vertex.x > maximum.x)
maximum.x = vertex.x;
if (vertex.y < minimum.y)
minimum.y = vertex.y;
if (vertex.y > maximum.y)
maximum.y = vertex.y;
if (vertex.z < minimum.z)
minimum.z = vertex.z;
if (vertex.z > maximum.z)
maximum.z = vertex.z;
}
Vector3 position = (minimum + maximum) * 0.5f;
Vector3 half_extents = (maximum - minimum) * 0.5f;
me_obb = { position, half_extents, Vector3::UnitX, Vector3::UnitY, Vector3::UnitZ };
}
OBB VertexArray::GetMEOBB(const Matrix3x3& rotation_matrix, const Vector3& scale, const Vector3& translate_part) const {
Vector3 half_extents = me_obb.r.Mul(scale);
Vector3 axis0 = rotation_matrix * me_obb.axis[0];
Vector3 axis1 = rotation_matrix * me_obb.axis[1];
Vector3 axis2 = rotation_matrix * me_obb.axis[2];
Vector3 position = me_obb.pos + translate_part;
return { position, half_extents, axis0, axis1, axis2 };
}
OBB VertexArray::GetMEOBB(const Matrix4x4& instance_matrix, bool translate) const {
return GetMEOBB(instance_matrix.GetRotatePart(), instance_matrix.GetScale(), translate ? instance_matrix.GetTranslatePart() : Vector3::Zero);
}
AABB VertexArray::GetMEAABB(const Matrix3x3& rotation_matrix, const Vector3& scale, const Vector3& translate_part) const {
/* kind-of a cheat. It's faster to calculate the oriented bounding box and then put the axis-aligned one around that
* than to loop over the whole model like an idiot. You gain back all the speed with the simplicity of the physics anyways. - Redacted */
return GetMEOBB(rotation_matrix, scale, translate_part).MinimalEnclosingAABB();
}
AABB VertexArray::GetMEAABB(const Matrix4x4& instance_matrix, bool translate) const {
return GetMEAABB(instance_matrix.GetRotatePart(), instance_matrix.GetScale(), translate ? instance_matrix.GetTranslatePart() : Vector3::Zero);
}
VertexArray::VertexArray(const Vector3* vertex_positions, const long& vp_length, const unsigned int* vertex_indices, const long& vi_length,
const Normal* vertex_normals, const long& vn_length, const TextureCoordinate* texture_coordinates, const long& vt_length) {
// TODO decimator. This is a total waste of memory as it sits.
this->vertices = new VRamList(vertex_positions, vp_length);
local_vertices.resize(vp_length);
memcpy(local_vertices.data(), vertex_positions, sizeof(Vector3) * vp_length);
if (vertex_indices && vi_length) {
indices = new VRamList(vertex_indices, vi_length);
local_indices.resize(vi_length);
memcpy(local_indices.data(), vertex_indices, sizeof(unsigned int) * vi_length);
}
if (vertex_normals && vn_length) {
normals = new VRamList(vertex_normals, vn_length);
local_normals.resize(vn_length);
memcpy(local_normals.data(), vertex_indices, sizeof(Normal) * vn_length);
}
if (texture_coordinates && vt_length) {
this->texture_coordinates = new VRamList(texture_coordinates, vt_length);
local_texture_coordinates.resize(vt_length);
memcpy(local_texture_coordinates.data(), texture_coordinates, sizeof(TextureCoordinate) * vt_length);
}
}
VertexArray::VertexArray(const std::vector<Vertex>& vertex_positions, const std::vector<unsigned int>& vertex_indices, const std::vector<Normal>& vertex_normals, const std::vector<TextureCoordinate>& texture_coordinates) {
*this = VertexArray(vertex_positions.data(), vertex_positions.size(), vertex_indices.data(), vertex_indices.size(), vertex_normals.data(), vertex_normals.size(), texture_coordinates.data(), texture_coordinates.size());
}
bool VertexArray::Static() {
return animations.empty();
}
VertexArray VertexArray::LoadWavefrontOBJ(const std::string& file_text) {
return JGL::LoadWavefrontOBJ(file_text);
}