Compare commits

...

149 Commits

Author SHA1 Message Date
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
46 changed files with 7790 additions and 1050 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-4.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,6 +57,8 @@ 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")
@@ -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.

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,668 @@
//
// 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 <J3ML/J3ML.hpp>
#include <JGL/types/Font.h>
// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
/// OpenGL Wrapper for rendering 2D & 3D graphics in both a 2D and 3D context.
namespace JGL {
using namespace J3ML::LinearAlgebra;
using namespace J3ML::Geometry;
using J3ML::LinearAlgebra::Vector2;
using J3ML::LinearAlgebra::Vector3;
using J3ML::LinearAlgebra::Matrix3x3;
using J3ML::LinearAlgebra::Matrix4x4;
using J3ML::LinearAlgebra::AxisAngle;
using J3ML::LinearAlgebra::Quaternion;
using J3ML::Geometry::Sphere;
using J3ML::Geometry::OBB;
using J3ML::Geometry::Capsule;
using J3ML::Geometry::TriangleMesh;
using J3ML::Geometry::Plane;
[[nodiscard]] bool Init(const Vector2& window_size, float fovY, float far_plane);
struct HSV {
float hue;
float saturation;
float value;
};
/// @param window_size
void Update(const Vector2& window_size);
struct Triangle2D
{
Vector2 A;
Vector2 B;
Vector2 C;
};
inline void PurgeFontCache() { JGL::fontCache.purgeCache(); }
struct Triangle3D
{
Vector3 A;
Vector3 B;
Vector3 C;
};
bool Update(const Vector2& window_size);
bool InitTextEngine();
int LoadFont(const std::string& font_path);
void UnloadFont(int font_index);
// TODO: implement correct coloring
std::array<GLfloat, 16> OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far);
/// Returns true if the graphics driver meets the requirements (GL Version & Extensions).
bool MeetsRequirements();
/// Drawing functions for primitive 2D Shapes.
/// Each function is overloaded with Color3 and Color4 for optional transparency.
namespace 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.
void Begin();
/// Closes a 2-D rendering context with the underlying graphics system (In this case & by default OpenGL).
/// @see Begin().
void End();
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);
/// 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);
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @see Begin().
void End();
/// 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);
/// Provide a list of lights to be used in 2D space. Typically directly after J2D::Begin();
/// 8 lights maximum for now. Some kind of light sorting will eventually be needed per j2d element.
void LightArray(LightBase*, size_t light_count);
///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 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);
/// 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 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);
/// 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);
/// 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 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);
/// 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 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);
/// 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 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 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 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 an outline of a rectangle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @param thickness The width at which to render the lines.
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
/// Draws an outline of a 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 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 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 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 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 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);
// 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 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);
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);
/// 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);
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
void DrawMatrixGizmo (const Matrix4x4&);
void DrawAxisAngleGizmo (const AxisAngle&, const Vector3&);
void DrawQuaternionGizmo (const Quaternion&, const Vector3&);
}
/// Draws a filled rectangle with chamfered (beveled) corners on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param pos The top-left corner of the rectangle.
/// @param size The width and height of the rectangle.
/// @param radius The corner-rounding radius (in radians).
void FillChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5);
/// Draws a render-target (runtime-modifiable texture) to the screen.
/// @param render_target A RenderTarget instance to be displayed.
/// @param position The position at which to render this object from it's center-point, defined by the origin parameter.
/// @param rad_rotation The amount of radians to rotate this render-target about it's center-point.
/// @param origin The center-point in the image to use for rendering, rotation, and scaling. Top-left is {0,0} and bottom right is {1, 1}.
/// @param scale The amount (in both x, and y axis) to scale the image, with {1,1} being default scaling.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
void DrawRenderTarget(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawRenderTarget(const RenderTarget* render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialRenderTarget(const RenderTarget&, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialRenderTarget(const RenderTarget*, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a sprite (technically, actually a render target) to the screen.
/// @note This similar overload exists because we expect someone will be an idiot and turn all of their sprites into RenderTargets. ~william
/// @param render_target A RenderTarget instance to be displayed.
/// @param position The position at which to render this object from it's center-point, defined by the origin parameter.
/// @param rad_rotation The amount of radians to rotate this render-target about it's center-point.
/// @param origin The center-point in the image to use for rendering, rotation, and scaling. Top-left is {0,0} and bottom right is {1, 1}.
/// @param scale The amount (in both x, and y axis) to scale the image, with {1,1} being default scaling.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
/// @see DrawSprite
void DrawSprite(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const RenderTarget* render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
/// @param texture A texture instance to be displayed.
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param origin The center point around which the image should have all transformations applied to it.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
/// @see class Texture
void DrawSprite(const Texture& texture, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture& texture, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, float positionX, float positionY, float rad_rotation = 0,
float originX = 0, float originY = 0,float scaleX = 1, float scaleY = 1,
const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
/// @param texture A texture instance to be displayed.
/// @param alpha_mask A texture which determines how much of the sprite you can see. Grayscale image exported as "8bpc RGBA".
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param origin The center point around which the image should have all transformations applied to it.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
/// @see class Texture
void DrawSprite(const Texture& texture, const Texture& alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, const Texture* alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture& texture, const Texture& alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawSprite(const Texture* texture, const Texture* alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a piece of a sprite to the screen, similar to DrawSprite.
/// @param texture A texture instance to be displayed.
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param sub_texture_position The top left corner of the sub-texture to be drawn.
/// @param sub_texture_size The size of the sub-texture in px.
/// @param origin The center point around which the image should have all transformations applied to it.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param inversion @see Direction
void DrawPartialSprite(const Texture& texture, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialSprite(const Texture* texture, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, float rad_rotation = 0,
const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialSprite(const Texture& texture, float positionX, float positionY, float sub_texture_positionX, float sub_texture_positionY, unsigned int sub_texture_sizeX, unsigned int sub_texture_sizeY,
float rad_rotation = 0, float originX = 0, float originY = 0, float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
void DrawPartialSprite(const Texture* texture, float positionX, float positionY, float sub_texture_positionX, float sub_texture_positionY, unsigned int sub_texture_sizeX, unsigned int sub_texture_sizeY,
float rad_rotation = 0, float originX = 0, float originY = 0, float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
/// To save v-ram, Use if a sprite would be identical if mirrored horizontally, vertically, or both. For example, a circle.
/// Assumes the input texture is the top left quadrant. You can use "SoftwareTexture" to invert it correctly so that's the case.
/// @param texture A texture instance to be displayed.
/// @param position The point at which to draw the sprite (from the top-left down).
/// @param mirror_axis The axes to mirror across, Vertical and Horizontal or both only.
/// @param rad_rotation The rotation of the final result.
/// @param origin The point at which transformations are done about.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
void DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis = Direction::Horizontal | Direction::Vertical, float rad_rotation = 0, const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White);
void DrawMirrorSprite(const Texture* texture, const Vector2& position, Direction mirror_axis = Direction::Horizontal | Direction::Vertical, float rad_rotation = 0, const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White);
/// Draws an outline of a circle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param center The point in cartesian space at which to draw the circle. This will by-definition be the centroid of this circle.
/// @param radius The radius of the circle to be drawn. AKA Half the diameter.
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
/// @param thickness The line-width of the circle to be rendered at.
void OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
/// Draws a filled circle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param center The point in cartesian space at which to draw the circle. This will by-definition be the centroid of this circle.
/// @param radius The radius of the circle to be drawn. AKA Half the diameter.
/// @param subdivisions The accuracy of the approximation of the circle, measured in iteration steps taken.
void FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 8);
/// Draws an outline of a triangle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param tri The triangle defined by its vertices (A, B, and C).
/// @param thickness The line-width of the triangle to be rendered at.
void OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness = 1);
void OutlineTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC, float thickness = 1);
/// Draws a filled triangle on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param tri The triangle defined by its vertices (A, B, and C).
void FillTriangle(const Color4& color, const Triangle2D& tri);
void FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC);
/// Fills a triangle defined by the provided vertices with a gradient that transitions smoothly between the three specified colors at each corner.
/// @param a_color The color at vertex A of the triangle.
/// @param b_color The color at vertex B of the triangle.
/// @param c_color The color at vertex C of the triangle.
/// @param tri The triangle defined by its vertices (A, B, and C).
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri);
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Vector2& tri_a, const Vector2& tri_b, const Vector2& tri_c);
/// Draws a smooth, curved line segment between two control points, with the curve controlled by the two inner points.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param controlA The first control point, which can be considered the start of the line.
/// @param pointA The first inner point, which controls the contour of the curve.
/// @param pointB The second inner point, which controls the contour of the curve.
/// @param controlB The second control point, which can be considered the end of the line.
/// @param subdivisions The accuracy of the approximation of the curve, measured in iteration steps taken.
/// @param thickness The line-width to draw the curve with.
/// @see J3ML::Algorithm::Bezier
void DrawCubicBezierCurve(const Color4& color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
int subdivisions = 10, float thickness = 1);
/// Draws a series of points where the last point always connects to the first point.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param points The array of vector2's to draw as a polygon.
/// @param point_count The number of points
/// @param thickness The line-width of the polygon
void OutlinePolygon(const Color4& color, const Vector2* points, int point_count, float thickness = 1);
/// Draws a text string on the screen with a given point-size and font.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param text The text to be rendered.
/// @param x The position on the screen at which to draw the text, from the top-left.
/// @param y The position on the screen at which to draw the text, from the top-left.
/// @param scale The value (in both axes) to scale the text by. Defaults to {1,1}.
/// @param size The point-size at which to render the font out. Re-using the same point-size allows efficient glyph caching.
/// @param font The font to use for rendering. @see Font.
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font);
/// 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 primitive 3D Shapes.
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 LightArray(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).
/// @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 3D context to render your content, then close when completed.
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 2D content in between our calls.
void Begin();
/// 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, const EulerAngleXYZ& angle = {0, 0, 0}, bool draw_back_face = false);
/// 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&);
}

9
include/JGL/ShapeCache.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <JGL/types/VRamList.h>
#include <array>
namespace JGL::ShapeCache {
inline VRamList* cube_vertex_data = nullptr;
inline VRamList* cube_index_data = nullptr;
void Init();
}

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

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

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

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

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

@@ -0,0 +1,65 @@
#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;
}
class JGL::LightBase {
protected:
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;
float linear_attenuation;
float quadratic_attenuation;
public:
[[nodiscard]] Vector3 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 override;
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.
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,4 @@
/// A simple wrapper for OpenGL materials. Lets you set things such as the "shininess" of your elements.
class Material {
};

View File

@@ -0,0 +1,72 @@
#pragma once
#include <glad/glad.h>
#include <Color4.hpp>
#include <Colors.hpp>
#include <JGL/types/Enums.h>
#include <J3ML/LinearAlgebra/Vector2.hpp>
namespace JGL {
class RenderTarget;
class Texture; // Forward declare.
}
class JGL::RenderTarget {
private:
Color4 clear_color{0,0,0,0};
/// "Size" in this sense is the "Renderable Area" because OpenGL textures behave strangely if they're not square.
Vector2 size{0, 0};
bool using_depth = false;
bool texture_created_by_us = false;
GLuint framebuffer_object = 0;
GLuint depth_buffer = 0;
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:
static GLuint GetActiveGLFramebufferHandle();
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
/** Change the size of the renderable area of the Render Target. **/
/// @param new_size new size in px.
void Resize(const Vector2& new_size);
void SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
/// If you're using raw OpenGL commands to draw to this outside of J2D or J3D don't forget to do this.
/// Blits the MSAA FBO onto the regular FBO if MSAA is enabled and or If you're rendering to a texture which uses mipmaps,
/// It regenerates them so what you drew doesn't disappear at a distance. Otherwise it does nothing.
void Blit() const;
/// Blit a render target onto another. Will break if they're not the same size.
static void Blit(const RenderTarget& source, RenderTarget* destination);
/// Blit 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 Vector2& position, RenderTarget* destination);
[[nodiscard]] bool TextureCreatedByRenderTarget() const;
public:
[[nodiscard]] Vector2 GetDimensions() const;
[[nodiscard]] MSAA_SAMPLE_RATE GetMSAASampleRate() const;
/// Returns whether or not MSAA is enabled, If it is and you're not using J2D || J3D Begin / End,
/// You need to run "Blit()" after rendering to your FBO before you show it.
/// @note Also, If the texture wasn't made by the RenderTarget you don't want this. It would destroy the texture.
[[nodiscard]] bool MSAAEnabled() const;
[[nodiscard]] const Texture* GetJGLTexture() const;
[[nodiscard]] GLuint GetGLTextureHandle() const;
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
[[nodiscard]] Color4 GetClearColor() const;
/// Get the data back from the FBO. This is *not* async friendly.
[[nodiscard]] std::vector<GLfloat> GetData() const;
public:
/// Copy constructor. Will always set "texture_created_by_us" to true and use our own texture to avoid memleaks.
RenderTarget(const RenderTarget& rhs);
/// Create a render target for a texture that already exists. For adding to an existing texture.
explicit RenderTarget(const Texture* texture, const Color4& clear_color = Colors::Black);
/// Create a Render Target with a brand new texture. Want to render JGL elements onto a texture and display it as a sprite?
explicit RenderTarget(const Vector2& size, const Color4& clear_color = Colors::Black, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
~RenderTarget();
};

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() = default;
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,98 @@
#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]] VRamList GetVertices() const;
[[nodiscard]] VRamList GetIndices() const;
[[nodiscard]] VRamList GetNormals() const;
[[nodiscard]] 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:
/// 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 = {});
};
using namespace JGL;
static VertexArray Animate(int animation_id, float animation_time);
static VertexArray Animate(const AnimationState& anim_state);

279
main.cpp
View File

@@ -1,36 +1,71 @@
#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>
using J3ML::LinearAlgebra::Vector2;
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;
}
JGL::Font FreeSans;
JGL::Font Jupiteroid;
float fps = 0.0f;
class Gizmo
{
public:
Gizmo() {}
Gizmo(const Vector2& pos) : position(pos) {}
bool dragging = false;
bool hovered = false;
Vector2 position;
float range = 6.f;
void Grab() {
if (hovered)
dragging = true;
}
void Release() {
dragging = false;
}
void Update(const Vector2& mouse) {
if (dragging)
position = position.Lerp(mouse, 0.25f);
hovered = mouse.Distance(position) < range;
}
void Draw() {
if (dragging)
J2D::DrawPoint(Colors::White, position, 4.f);
else if (hovered)
J2D::DrawPoint(Colors::Reds::Crimson, position, 6.f);
else
J2D::DrawPoint(Colors::Reds::Salmon, position, 3.f);
J2D::DrawString(Colors::White, std::format("{:.1f},{:.1f}", position.x, position.y), position.x, position.y, 1.f, 10, FreeSans);
}
};
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,76 +92,199 @@ struct point {
GLfloat t;
};
int FreeSans;
int Jupiteroid;
Gizmo a({250, 150});
Gizmo b({200, 250});
Gizmo c({350, 300});
Gizmo d({450, 250});
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.");
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
Jupiteroid = JGL::Font("assets/fonts/Jupiteroid.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;
float sprite_radians = 0;
bool fov_increasing = true;
int blit_pos = 0;
void display() {
textAngle.y += 2.0f;
float dt = 1.f / fps;
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
/* if rendering to screen space directly. */
///All 3D elements of the scene and JGL elements *must* be rendered before the 2d stuff.
// 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, 16, 16, true);
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.1f, 0.1f, 0.1f});
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 {
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;}
@@ -136,14 +294,19 @@ public:
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(false);
while (window->isAlive()) {
window->pollEvents();
window->refresh();
while (window->IsAlive()) {
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
window->PollEvents();
window->Refresh();
std::chrono::high_resolution_clock::time_point stop = std::chrono::high_resolution_clock::now();
std::chrono::duration<float> frame_time = stop - start;
fps = 1.0f / frame_time.count();
}
return 0;
}

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

File diff suppressed because it is too large Load Diff

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();
}
}

38
src/ShapeCache.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include <JGL/ShapeCache.h>
void JGL::ShapeCache::Init() {
if (!cube_vertex_data) {
std::array<Vector3, 24> vertices {
Vector3(-1, 1, -1), Vector3(1, 1, -1),
Vector3(1, 1, -1), Vector3(1, 1, 1),
Vector3(1, 1, 1), Vector3(-1, 1, 1),
Vector3(-1, 1, 1), Vector3(-1, 1, -1),
Vector3(-1, -1, -1), Vector3(1, -1, -1),
Vector3(1, -1, -1), Vector3(1, -1, 1),
Vector3(1, -1, 1), Vector3(-1, -1, 1),
Vector3(-1, -1, 1), Vector3(-1, -1, -1),
Vector3(-1, -1, -1), Vector3(-1, 1, -1),
Vector3(1, -1, -1), Vector3(1, 1, -1),
Vector3(1, -1, 1), Vector3(1, 1, 1),
Vector3(-1, -1, 1), Vector3(-1, 1, 1)
};
cube_vertex_data = new VRamList(vertices.data(), vertices.size());
}
if (!cube_index_data) {
std::array<GLuint, 36> indices {
0, 1, 3, 0, 3, 5,
8, 9, 11, 8, 11, 13,
5, 3, 11, 5, 11, 13,
0, 1, 9, 0, 9, 8,
0, 5, 13, 0, 13, 8,
1, 3, 11, 1, 11, 9
};
cube_index_data = new VRamList(indices.data(), indices.size());
}
}

251
src/TextRendering.cpp Normal file
View File

@@ -0,0 +1,251 @@
#include <JGL/JGL.h>
#if __linux__
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#if _WIN32
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#include <JGL/types/Font.h>
#include <JGL/types/FontCache.h>
#include <JGL/logger/logger.h>
namespace JGL {
CachedFont* CacheFont(const Font& font, u32 size) {
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);
glColor4f(1, 1, 1, 1);
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);
glColor4f(1, 1, 1, 1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
}

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

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

@@ -0,0 +1,154 @@
#include <vector>
#include <string>
#include <iostream>
#include <glad/glad.h>
#include <JGL/logger/logger.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 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!");
Font font;
if (FT_New_Face(Detail::ft, path.string().c_str(), 0, &face)) {
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
throw std::runtime_error("Error::FREETYPE: Failed to load font!");
//return -1;
}
unsigned int newIndex = 0;
for (const auto& f : Detail::fonts)
if (f.index >= newIndex)
newIndex = f.index + 1;
index = newIndex;
Detail::fonts.push_back(font);
std::cout << "Loaded font from " << path << " with index " << newIndex << std::endl;
//return newIndex;
}
Font::~Font() {
//Detail::UnloadFont(this->index);
}
std::vector<Font> Font::GetLoadedFonts() {
return Detail::fonts;
}
Font Font::LoadTTF(const std::filesystem::path& path)
{
return Font(path);
}
Vector2 Font::MeasureString(const std::string &text, unsigned int ptSize) {
Vector2 extents = Vector2(0,0);
bool font_of_size_in_cache = false;
for(const auto& f : fontCache.getFonts()) {
if (f->getFontSize() == ptSize) {
font_of_size_in_cache = true;
break;
}
}
if (font_of_size_in_cache) {
CachedFont* font;
for (auto* f: fontCache.getFonts())
if (f->getFontSize() == ptSize)
font = f;
for (const char& c : text)
extents.x += font->getGlyph(c)->advanceX;
extents.y = ptSize;
return extents;
}
jlog::Warning("Measuring a font size that is not cached, This is *super* slow.");
FT_Set_Pixel_Sizes(this->face, ptSize, ptSize);
for (const char& c : text) {
FT_GlyphSlot slot = face->glyph;
auto glyph_index = FT_Get_Char_Index(this->face, c);
auto error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if (error)
continue;
Vector2 advance = {static_cast<float>(slot->advance.x >> 6),
static_cast<float>(slot->advance.y >> 6)};
extents += advance;
// Gives smaller results than we'd want.
if (extents.y < slot->metrics.height / 64)
extents.y = slot->metrics.height / 64;
// Just fucking hardcode it, we know the glyph height is roughly always the ptSize anyway.
if (extents.y < ptSize)
extents.y = ptSize;
}
return extents;
}
}

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;
}
Vector3 JGL::LightBase::GetPosition() const {
return {position.x, position.y, position.z};
}
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;
}

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

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

@@ -0,0 +1,388 @@
#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);
}
Vector2 JGL::RenderTarget::GetDimensions() const {
return size;
}
void JGL::RenderTarget::Erase() {
if (GetActiveGLFramebufferHandle() == framebuffer_object)
Logger::Warning("Deleting the framebuffer that's currently in use?");
if (using_depth)
glDeleteRenderbuffers(1, &depth_buffer);
glDeleteFramebuffers(1, &framebuffer_object);
if (MSAAEnabled())
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
}
Color4 JGL::RenderTarget::GetClearColor() const {
return clear_color;
}
/// Idk why you'd ever want to clear it out if you're rendering onto a texture you passed in :shrug:.
JGL::RenderTarget::RenderTarget(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 = texture->GetDimensions();
this->texture = texture;
texture_created_by_us = false;
}
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
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::GetData() const {
std::vector<GLfloat> data(GetDimensions().x * GetDimensions().y * 4);
GLuint current_fbo = GetActiveGLFramebufferHandle();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glReadPixels(0, 0, GetDimensions().x, GetDimensions().y, GL_RGBA, GL_FLOAT, data.data());
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
return data;
}
void JGL::RenderTarget::Resize(const Vector2& new_size) {
if (!texture_created_by_us)
Logger::Fatal("Resizing a texture that already existed?");
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLfloat old_clear_color[4];
GLint old_viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, old_viewport);
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
/* If what was previously not part of the renderable area is big enough to
* just set the new size without reading data back */
if (new_size.x <= texture->GetDimensions().x && new_size.y <= texture->GetDimensions().y) {
size = new_size;
// Clear.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
auto cc = GetClearColor();
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
glViewport(0,0, size.x, size.y);
glClear(GL_COLOR_BUFFER_BIT);
if (using_depth)
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
return;
}
//If we have to remake the texture.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
// Erase it.
delete texture;
unsigned int biggest;
if (new_size.x >= new_size.y)
biggest = new_size.x;
else
biggest = new_size.y;
auto cc = GetClearColor();
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
glViewport(0,0, size.x, size.y);
texture = new Texture(Vector2((float) biggest, (float) biggest));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 0);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
size = new_size;
//Disable & Re-enable MSAA so the msaa buffer is remade with the correct dimensions.
if (MSAAEnabled()) {
MSAA_SAMPLE_RATE current_sample_rate = msaa_sample_rate;
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
SetMSAAEnabled(current_sample_rate);
}
}
JGL::RenderTarget::~RenderTarget() {
Erase();
if (texture_created_by_us)
delete texture;
}
bool JGL::RenderTarget::TextureCreatedByRenderTarget() const {
return texture_created_by_us;
}
JGL::MSAA_SAMPLE_RATE JGL::RenderTarget::GetMSAASampleRate() const {
return msaa_sample_rate;
}
bool JGL::RenderTarget::MSAAEnabled() const {
return msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE;
}
void JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
// If we'd be setting the same sample_rate we already have.
if (sample_rate == msaa_sample_rate)
return;
// If we'd be rendering onto a texture and not a plain render target we don't want this.
if (!TextureCreatedByRenderTarget())
return;
// Remove it if they request no msaa or if what they requested is different than what they already have.
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE || msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE) {
if(using_depth)
glDeleteRenderbuffers(1, &msaa_depth_buffer);
glDeleteRenderbuffers(1, &msaa_render_buffer);
glDeleteFramebuffers(1, &msaa_framebuffer_object);
msaa_framebuffer_object = 0;
msaa_depth_buffer = 0;
msaa_render_buffer = 0;
msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
// Only return here if they specifically requested no MSAA. else continue to change mode.
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE)
return;
}
GLuint current_fbo = GetActiveGLFramebufferHandle();
glGenFramebuffers(1, &msaa_framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, msaa_framebuffer_object);
GLint current_renderbuffer = 0;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &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);
}
void JGL::RenderTarget::Blit() const {
if (MSAAEnabled() && TextureCreatedByRenderTarget()) {
// Save the GL state.
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint current_draw_fbo = 0;
GLint current_read_fbo = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &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) {
//TODO allow blitting onto an FBO that is bigger but not smaller.
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 Vector2& 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);
}
}

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

@@ -0,0 +1,297 @@
#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?");
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);
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());
return;
}
auto data_array = rhs.GetDataF();
this->load(data_array.data(), data_array.size());
}

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

@@ -0,0 +1,191 @@
#include <JGL/types/VertexArray.h>
using namespace JGL;
VRamList VertexArray::GetVertices() const {
return vertices;
}
VRamList VertexArray::GetIndices() const {
return indices;
}
JGL::VRamList VertexArray::GetNormals() const {
return normals;
}
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.
vertices = VRamList(vertex_positions, vp_length);
if (vertex_indices && vi_length) {
indices = 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 = 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 = VRamList(texture_coordinates, vt_length);
local_normals.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) {
vertices = VRamList(vertex_positions.data(), vertex_positions.size());
local_vertices = vertex_positions;
if (!vertex_indices.empty()) {
indices = VRamList(vertex_indices.data(), vertex_indices.size());
local_indices = vertex_indices;
}
if (!vertex_normals.empty()) {
normals = VRamList(vertex_normals.data(), vertex_normals.size());
local_normals = vertex_normals;
}
if (!texture_coordinates.empty()){
this->texture_coordinates = VRamList(texture_coordinates.data(), texture_coordinates.size());
local_texture_coordinates = texture_coordinates;
}
}
bool VertexArray::Static() {
return animations.empty();
}