30 Commits

Author SHA1 Message Date
Sebastian 159255adda midi node design changes 2026-07-19 02:38:33 +02:00
Sebastian c7c489fde5 signal timing needs work 2026-07-18 02:07:50 +02:00
Sebastian 1f7f5314a3 midi modes added, context menu adapted 2026-07-17 02:03:27 +02:00
Sebastian 1f2cbc4c31 modifier chains implemented for notes 2026-07-17 01:07:09 +02:00
Sebastian 183d89ceaf modifier chains added 2026-07-17 00:13:01 +02:00
Sebastian 0be3d6cd77 changed node font to Inter 2026-07-16 00:23:32 +02:00
Sebastian 4613bfd072 fixed connector mismatch after breaking it after fixing it last time 2026-07-14 02:19:29 +02:00
Sebastian 585e5e1167 connectors fixed 2026-07-02 08:28:21 +02:00
Sebastian 30408393e7 debugging connector problem 2026-06-30 10:54:45 +02:00
Sebastian e9c8cc9aea connectors need fixing 2026-06-28 23:45:54 +02:00
Sebastian 03b2989130 penpot file added 2026-06-28 00:46:18 +02:00
Sebastian e9c2872187 more textures and ui refinements 2026-06-28 00:34:57 +02:00
Sebastian b9ad5293bf blocker not showing 2026-06-27 03:13:40 +02:00
Sebastian e4b2df21bc small steps forward - placement of edge buttons changed and one more texture added 2026-06-27 01:35:20 +02:00
Sebastian 970faad32d wip 2026-06-26 19:32:00 +02:00
Sebastian 0fb517f282 position fixed finally 2026-06-26 17:43:45 +02:00
Sebastian 9fefa903bd still wrong position 2026-06-26 10:26:41 +02:00
Sebastian 3f8984b69f delete button texturized but still at incorrect position 2026-06-26 02:23:08 +02:00
Sebastian 9ea1305c27 ui improvements and texture tests 2026-06-26 01:50:32 +02:00
Sebastian 7c7c3b37ff ui improvements for modifier value changes 2026-06-25 19:34:23 +02:00
Sebastian 792e537f2b removed orbits unified ctrl/alt/shift modifiers for alle node types 2026-06-25 11:41:55 +02:00
Sebastian 5c433111e2 standard values for midi nodes added 2026-06-25 08:53:11 +02:00
Sebastian c15188d456 copy paste repaired 2026-06-24 23:37:47 +02:00
Sebastian a76954b6f7 clipboard singleton 2026-06-24 18:11:34 +02:00
Sebastian b02eb7e1d4 cleanup and copy/paste bug identified 2026-06-24 11:04:28 +02:00
Sebastian ce675b1430 virtual ports working - ui needs some work 2026-06-24 00:38:49 +02:00
Sebastian 3de17a3b43 Merge branch 'refactor-orbit-ui' into orbit-ui 2026-06-23 09:52:30 +02:00
Sebastian d69368322e show ui only on selected nodes 2026-05-04 13:42:31 +02:00
Sebastian @ HfG 2cc6839009 upgrade to libremidi 5.1, raylib and raygui latest 2025-06-13 19:16:35 +02:00
Sebastian @ HfG 62454960d1 cmath define added for windows - failing at coroutine handle void 2025-06-13 19:14:16 +02:00
71 changed files with 3499 additions and 1403 deletions
+6 -2
View File
@@ -9,13 +9,17 @@ LDFLAGS := -Llib -L/usr/lib -L/usr/local/lib
SRCS := $(wildcard src/*.cpp) SRCS := $(wildcard src/*.cpp)
OBJECTS := $(patsubst src/%.cpp,build/%.o, $(SRCS)) OBJECTS := $(patsubst src/%.cpp,build/%.o, $(SRCS))
DEPENDS := $(patsubst src/%.cpp,build/%.d, $(SRCS))
viseq: $(OBJECTS) viseq: $(OBJECTS)
$(CXX) $(OBJECTS) -o $@ $(LDFLAGS) $(LDLIBS) $(CXX) $(OBJECTS) -o $@ $(LDFLAGS) $(LDLIBS)
$(OBJECTS): build/%.o : src/%.cpp -include $(DEPENDS)
#$(OBJECTS): build/%.o : src/%.cpp
build/%.o: src/%.cpp Makefile
@mkdir -p build @mkdir -p build
$(CXX) -c $< -o $@ $(CXXFLAGS) $(CXXINC) $(CXX) -c $< -o $@ $(CXXFLAGS) $(CXXINC) -MMD -MP
clean: clean:
rm -f build/* rm -f build/*
@@ -32,6 +32,7 @@ NAMESPACE_LIBREMIDI {
} }
#endif #endif
#include <init/Microsoft.Windows.Devices.Midi2.Initialization.hpp>
// clang-format on // clang-format on
namespace midi2 = winrt::Microsoft::Windows::Devices::Midi2; namespace midi2 = winrt::Microsoft::Windows::Devices::Midi2;
+27
View File
@@ -0,0 +1,27 @@
## style: dark
Classical dark style with an extra high-def colour touch! Elegant and professional, perfect for the expensive tools!
![dark style table](style_dark.png)
## style: provided files
Several options are provided to add the style to a `raygui` application, choose the one that better fits the project.
| file name | description |
| :-------- | :---------- |
| `style_dark.rgs` | Binary style file (raygui 4.0), font data compressed (recs, glyphs) |
| `style_dark.txt.rgs` | Text style file, no font data, requires external font provided |
| `style_dark.old.rgs` | Binary style file (raygui 3.x), font data uncompressed (recs, glyphs) |
| `style_dark.h` | Embeddable style as code file, self-contained, includes font data |
| `style_dark.png` | Style table image, contains `rGSf` chunk with binary `rgs` file data |
## screenshot
![dark style screen](screenshot.png)
## about font
"Pixel Operator" font by de Jayvee Enaguas.
CC0 1.0 Universal, downloaded from dafont.com: [pixel-operator](https://www.dafont.com/pixel-operator.font)
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 107 KiB

+218 -218
View File
@@ -7,7 +7,7 @@
// more info and bugs-report: github.com/raysan5/raygui // // more info and bugs-report: github.com/raysan5/raygui //
// feedback and support: ray[at]raylibtech.com // // feedback and support: ray[at]raylibtech.com //
// // // //
// Copyright (c) 2020-2024 raylib technologies (@raylibtech) // // Copyright (c) 2020-2025 raylib technologies (@raylibtech) //
// // // //
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
@@ -15,144 +15,144 @@
// Custom style name: Dark // Custom style name: Dark
static const GuiStyleProp darkStyleProps[DARK_STYLE_PROPS_COUNT] = { static const GuiStyleProp darkStyleProps[DARK_STYLE_PROPS_COUNT] = {
{ 0, 0, (long int)0x878787ff }, // DEFAULT_BORDER_COLOR_NORMAL { 0, 0, (int)0x878787ff }, // DEFAULT_BORDER_COLOR_NORMAL
{ 0, 1, (long int)0x2c2c2cff }, // DEFAULT_BASE_COLOR_NORMAL { 0, 1, (int)0x2c2c2cff }, // DEFAULT_BASE_COLOR_NORMAL
{ 0, 2, (long int)0xc3c3c3ff }, // DEFAULT_TEXT_COLOR_NORMAL { 0, 2, (int)0xc3c3c3ff }, // DEFAULT_TEXT_COLOR_NORMAL
{ 0, 3, (long int)0xe1e1e1ff }, // DEFAULT_BORDER_COLOR_FOCUSED { 0, 3, (int)0xe1e1e1ff }, // DEFAULT_BORDER_COLOR_FOCUSED
{ 0, 4, (long int)0x848484ff }, // DEFAULT_BASE_COLOR_FOCUSED { 0, 4, (int)0x848484ff }, // DEFAULT_BASE_COLOR_FOCUSED
{ 0, 5, (long int)0x181818ff }, // DEFAULT_TEXT_COLOR_FOCUSED { 0, 5, (int)0x181818ff }, // DEFAULT_TEXT_COLOR_FOCUSED
{ 0, 6, (long int)0x000000ff }, // DEFAULT_BORDER_COLOR_PRESSED { 0, 6, (int)0x000000ff }, // DEFAULT_BORDER_COLOR_PRESSED
{ 0, 7, (long int)0xefefefff }, // DEFAULT_BASE_COLOR_PRESSED { 0, 7, (int)0xefefefff }, // DEFAULT_BASE_COLOR_PRESSED
{ 0, 8, (long int)0x202020ff }, // DEFAULT_TEXT_COLOR_PRESSED { 0, 8, (int)0x202020ff }, // DEFAULT_TEXT_COLOR_PRESSED
{ 0, 9, (long int)0x6a6a6aff }, // DEFAULT_BORDER_COLOR_DISABLED { 0, 9, (int)0x6a6a6aff }, // DEFAULT_BORDER_COLOR_DISABLED
{ 0, 10, (long int)0x818181ff }, // DEFAULT_BASE_COLOR_DISABLED { 0, 10, (int)0x818181ff }, // DEFAULT_BASE_COLOR_DISABLED
{ 0, 11, (long int)0x606060ff }, // DEFAULT_TEXT_COLOR_DISABLED { 0, 11, (int)0x606060ff }, // DEFAULT_TEXT_COLOR_DISABLED
{ 0, 16, (long int)0x00000010 }, // DEFAULT_TEXT_SIZE { 0, 16, (int)0x00000010 }, // DEFAULT_TEXT_SIZE
{ 0, 17, (long int)0x00000000 }, // DEFAULT_TEXT_SPACING { 0, 17, (int)0x00000000 }, // DEFAULT_TEXT_SPACING
{ 0, 18, (long int)0x9d9d9dff }, // DEFAULT_LINE_COLOR { 0, 18, (int)0x9d9d9dff }, // DEFAULT_LINE_COLOR
{ 0, 19, (long int)0x3c3c3cff }, // DEFAULT_BACKGROUND_COLOR { 0, 19, (int)0x3c3c3cff }, // DEFAULT_BACKGROUND_COLOR
{ 0, 20, (long int)0x00000018 }, // DEFAULT_TEXT_LINE_SPACING { 0, 20, (int)0x00000018 }, // DEFAULT_TEXT_LINE_SPACING
{ 1, 5, (long int)0xf7f7f7ff }, // LABEL_TEXT_COLOR_FOCUSED { 1, 5, (int)0xf7f7f7ff }, // LABEL_TEXT_COLOR_FOCUSED
{ 1, 8, (long int)0x898989ff }, // LABEL_TEXT_COLOR_PRESSED { 1, 8, (int)0x898989ff }, // LABEL_TEXT_COLOR_PRESSED
{ 4, 5, (long int)0xb0b0b0ff }, // SLIDER_TEXT_COLOR_FOCUSED { 4, 5, (int)0xb0b0b0ff }, // SLIDER_TEXT_COLOR_FOCUSED
{ 5, 5, (long int)0x848484ff }, // PROGRESSBAR_TEXT_COLOR_FOCUSED { 5, 5, (int)0x848484ff }, // PROGRESSBAR_TEXT_COLOR_FOCUSED
{ 9, 5, (long int)0xf5f5f5ff }, // TEXTBOX_TEXT_COLOR_FOCUSED { 9, 5, (int)0xf5f5f5ff }, // TEXTBOX_TEXT_COLOR_FOCUSED
{ 10, 5, (long int)0xf6f6f6ff }, // VALUEBOX_TEXT_COLOR_FOCUSED { 10, 5, (int)0xf6f6f6ff }, // VALUEBOX_TEXT_COLOR_FOCUSED
}; };
// WARNING: This style uses a custom font: "PixelOperator.ttf" (size: 16, spacing: 0) // WARNING: This style uses a custom font: "PixelOperator.ttf" (size: 16, spacing: 0)
#define DARK_STYLE_FONT_ATLAS_COMP_SIZE 2126 #define DARK_STYLE_FONT_ATLAS_COMP_SIZE 2138
// Font atlas image pixels data: DEFLATE compressed // Font atlas image pixels data: DEFLATE compressed
static unsigned char darkFontData[DARK_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed, static unsigned char darkFontData[DARK_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
0xdd, 0xdb, 0x72, 0xa4, 0x3a, 0x12, 0x05, 0x50, 0xfd, 0xff, 0x4f, 0xe7, 0x3c, 0x4c, 0x4c, 0x4c, 0x74, 0x9c, 0xd3, 0x20, 0xdd, 0xdb, 0x92, 0xa5, 0xba, 0x0d, 0x00, 0x50, 0xff, 0xff, 0x4f, 0x2b, 0x0f, 0xa9, 0x54, 0x32, 0x95, 0xd3, 0x80, 0x64,
0xa5, 0x52, 0x17, 0xec, 0xd5, 0xeb, 0xcd, 0xe5, 0x76, 0x51, 0xa0, 0x94, 0x84, 0x28, 0x36, 0xd1, 0x00, 0x00, 0x00, 0x80, 0xd9, 0x98, 0x9e, 0x35, 0xeb, 0xad, 0x77, 0x4f, 0xc3, 0x36, 0x96, 0x6f, 0x80, 0x1c, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xeb,
0x5f, 0x2f, 0xfe, 0xf5, 0x27, 0xf1, 0xd7, 0xdf, 0x8c, 0xee, 0xbf, 0xf3, 0xfc, 0xf3, 0xff, 0xbd, 0x1a, 0x0f, 0xef, 0xd5, 0xc5, 0x3f, 0xfe, 0x24, 0x7e, 0xfc, 0xcd, 0x78, 0xfc, 0x77, 0xae, 0x7f, 0xfe, 0x9f, 0x4f, 0xe3, 0xe2, 0x58, 0xcf, 0xce,
0xb7, 0xad, 0xa3, 0xef, 0x1b, 0x03, 0x7b, 0xe2, 0xdf, 0xb7, 0x2f, 0xba, 0xff, 0xee, 0xdf, 0x3e, 0xdf, 0xf8, 0xef, 0x3f, 0x35, 0x7b, 0xdc, 0x48, 0x94, 0xc4, 0x3f, 0x9f, 0x5f, 0x3c, 0xfe, 0xbb, 0x3f, 0x7d, 0xbf, 0xfc, 0xef, 0x5f, 0xfd, 0xa5,
0xfd, 0xa5, 0xe7, 0xad, 0x8f, 0xa1, 0xfd, 0x3e, 0xfe, 0x7f, 0xc6, 0x8e, 0x62, 0x2c, 0xd9, 0xf7, 0xef, 0x5b, 0x37, 0xbe, 0xeb, 0xb3, 0x8f, 0x54, 0xb9, 0xe7, 0xff, 0x4f, 0xee, 0x2a, 0xc6, 0x92, 0xb2, 0xbf, 0x3f, 0xbb, 0xfc, 0xb9, 0x77, 0xfe,
0xed, 0x95, 0xff, 0x27, 0x1e, 0x3e, 0x4f, 0xe6, 0x28, 0xf5, 0xd4, 0xd6, 0x0d, 0xf5, 0x1f, 0x5d, 0x95, 0x18, 0xa5, 0x2d, 0x9f, 0xb8, 0xf8, 0x3e, 0x95, 0xab, 0xf4, 0x24, 0xb6, 0x4e, 0x88, 0xff, 0x78, 0x14, 0x89, 0xd1, 0x5a, 0x73, 0xfe, 0x7b,
0xe7, 0xff, 0xef, 0x1a, 0x85, 0x3d, 0x55, 0x76, 0x4f, 0x3e, 0x55, 0xfa, 0xf8, 0xfe, 0x78, 0x6a, 0xfd, 0xe3, 0x3d, 0x60, 0xd4, 0x68, 0x6c, 0xa9, 0xaa, 0x25, 0x79, 0x15, 0xe9, 0xf9, 0xf2, 0xb8, 0xaa, 0xfd, 0xf9, 0x16, 0x30, 0x5a, 0xbe, 0xcb,
0x94, 0x7c, 0x96, 0xf9, 0xd6, 0x18, 0xd3, 0xbf, 0xdd, 0xd7, 0x92, 0x6a, 0x3e, 0xd5, 0xcc, 0x2b, 0xad, 0xe4, 0x28, 0x9d, 0x7c, 0x6d, 0x8c, 0xe9, 0xdf, 0x7e, 0x56, 0x93, 0x7a, 0xbe, 0xd5, 0xcc, 0x27, 0xa3, 0xe5, 0x2a, 0xbd, 0x11, 0xff, 0x51,
0xa8, 0xff, 0x48, 0xf7, 0x54, 0x31, 0x58, 0xd1, 0x15, 0x7b, 0x30, 0xd3, 0x0f, 0xb7, 0x8d, 0xf5, 0x1f, 0xa5, 0x73, 0x97, 0x6e, 0xa9, 0x22, 0x19, 0xd1, 0x1d, 0x25, 0x58, 0x69, 0x87, 0xc7, 0xc6, 0xf8, 0x8f, 0xd6, 0xb1, 0x4b, 0xb4, 0xd5, 0xb9,
0x28, 0x6b, 0x73, 0x27, 0xea, 0xff, 0x79, 0xd4, 0x6e, 0x25, 0xed, 0x26, 0x5e, 0xf6, 0x51, 0x6d, 0x2d, 0xaf, 0x9d, 0xa7, 0x37, 0xe2, 0xff, 0xba, 0xd7, 0x1e, 0x2d, 0xf5, 0x26, 0x6e, 0xca, 0xa8, 0x37, 0x96, 0xd7, 0x8e, 0x53, 0x57, 0xc7, 0xff,
0xae, 0xae, 0xff, 0xe7, 0xdf, 0x1c, 0x1d, 0x6f, 0x63, 0x70, 0xec, 0xae, 0xd8, 0x4f, 0xb9, 0xf1, 0xbf, 0x7e, 0x3f, 0xc6, 0xf5, 0x6f, 0x66, 0xfb, 0xdb, 0x48, 0xf6, 0xdd, 0x1d, 0xe5, 0x54, 0xeb, 0xff, 0xfb, 0xcb, 0x31, 0x7e, 0xec, 0x9b, 0xab,
0x5f, 0xc7, 0xe6, 0xec, 0x3c, 0x64, 0x64, 0x0f, 0xc7, 0xe0, 0xd9, 0xd5, 0xec, 0x08, 0x7b, 0x72, 0xfc, 0xef, 0x9b, 0x0b, 0xe3, 0x90, 0x4c, 0x09, 0x47, 0x72, 0x76, 0x35, 0xdb, 0xc3, 0xbe, 0xd9, 0xff, 0x3f, 0x1b, 0x0b, 0x8a, 0xff, 0xb5, 0xf1,
0xaa, 0xff, 0xb5, 0xf5, 0x9f, 0xf9, 0x24, 0xd1, 0xb9, 0x05, 0x99, 0x31, 0xb1, 0x5d, 0x50, 0xff, 0xa3, 0xfd, 0xd0, 0xf3, 0x5f, 0xf9, 0x26, 0xf1, 0xf0, 0x0c, 0x2a, 0x7d, 0xe2, 0x38, 0x20, 0xfe, 0xb3, 0xed, 0xd0, 0x75, 0x59, 0x75, 0x8d, 0xe5,
0xbe, 0xaa, 0x9a, 0xcb, 0x8f, 0xae, 0x4b, 0xf4, 0x9d, 0x61, 0xef, 0x6b, 0x85, 0xe3, 0x73, 0xa3, 0xf1, 0xfa, 0x1f, 0xef, 0xb3, 0xeb, 0x12, 0xcf, 0x66, 0xd8, 0xfb, 0x6a, 0x61, 0x7e, 0x6c, 0x94, 0x8f, 0xff, 0x7c, 0xeb, 0x79, 0xf7, 0xd7, 0xb2,
0x3d, 0xdf, 0xfe, 0xda, 0xe8, 0x5e, 0xfd, 0xfb, 0x99, 0xdd, 0xfc, 0x1e, 0xdf, 0x57, 0xff, 0x91, 0x18, 0x53, 0xce, 0xd7, 0xa5, 0xfa, 0xf3, 0xcc, 0x6e, 0xbe, 0xc4, 0xf7, 0xc5, 0x7f, 0x14, 0xfa, 0x94, 0xf7, 0xe3, 0xb9, 0x27, 0xfe, 0xa3, 0xb0,
0x73, 0x4d, 0xfd, 0x47, 0x62, 0xe5, 0xa2, 0x95, 0xad, 0xf2, 0xe5, 0xd6, 0x25, 0xea, 0xd6, 0x0c, 0xce, 0x1f, 0x81, 0xf7, 0x72, 0x31, 0xda, 0x56, 0xf9, 0x6a, 0xeb, 0x12, 0x7d, 0x6b, 0x06, 0xef, 0x5f, 0x81, 0xfb, 0xf8, 0xbf, 0x9b, 0x0f, 0xbe,
0xfa, 0x7f, 0x3b, 0x1f, 0x3c, 0x3f, 0xfe, 0xc7, 0x15, 0xe3, 0x7f, 0xa4, 0xd7, 0x86, 0x5b, 0xa2, 0xf7, 0xfd, 0x5a, 0xfd, 0xdf, 0xff, 0xc7, 0x11, 0xfd, 0x7f, 0x94, 0xd7, 0x86, 0x47, 0xa1, 0xf5, 0xfd, 0x5a, 0xfc, 0x47, 0x21, 0x66, 0xa2, 0x65,
0x47, 0xa2, 0x66, 0xa2, 0xe4, 0xbc, 0xbc, 0x2d, 0x59, 0xcb, 0xab, 0x5d, 0x33, 0xdc, 0x73, 0xb4, 0xde, 0x46, 0xd1, 0xaa, 0x5e, 0x3e, 0x96, 0xac, 0xe5, 0xf5, 0xae, 0x19, 0xee, 0xb9, 0x5a, 0x77, 0xbd, 0x68, 0xd7, 0xac, 0xe6, 0x77, 0xc5, 0xff,
0xb3, 0x9a, 0x9f, 0x55, 0xff, 0xad, 0x60, 0xfc, 0xef, 0x9b, 0x03, 0xcc, 0x7e, 0x8e, 0xf8, 0xd8, 0xe8, 0x5f, 0x59, 0xff, 0x68, 0xe8, 0xff, 0x9f, 0x8d, 0x01, 0x66, 0xbf, 0x47, 0x7c, 0xac, 0xf7, 0xef, 0x8c, 0xff, 0x5d, 0x2b, 0xf6, 0xeb, 0x6b,
0xbb, 0x56, 0xec, 0xd7, 0xb7, 0xc6, 0xb8, 0xe2, 0xc8, 0x58, 0xff, 0xaf, 0x9c, 0xff, 0xe7, 0xd7, 0x00, 0xc6, 0xce, 0x63, 0x63, 0x1c, 0x71, 0x65, 0xac, 0xff, 0x77, 0x8e, 0xff, 0xeb, 0x6b, 0x00, 0xb9, 0x79, 0x4c, 0x1c, 0x1a, 0xfd, 0x95, 0x39,
0xe2, 0xd2, 0xea, 0xcf, 0x9c, 0x33, 0x57, 0x5d, 0xb1, 0xaf, 0xfd, 0x36, 0x41, 0x24, 0xbe, 0xab, 0x51, 0xb3, 0x8a, 0xb3, 0x73, 0xd7, 0x1d, 0xfb, 0xde, 0xa7, 0x09, 0xa2, 0xf0, 0xac, 0x46, 0xcf, 0x2a, 0xce, 0xea, 0x6b, 0x90, 0xef, 0xff, 0x77,
0xfa, 0x18, 0x8c, 0x8f, 0xff, 0xbb, 0xae, 0xff, 0xbf, 0xcf, 0xb9, 0xef, 0x18, 0xff, 0xdb, 0xeb, 0xe8, 0x7e, 0xcb, 0xf6, 0xdd, 0xff, 0xbf, 0x1f, 0x73, 0x9f, 0xd1, 0xff, 0x8f, 0xdb, 0xde, 0xfd, 0x94, 0xf3, 0x01, 0xf6, 0xb6, 0x00, 0x21, 0xfa,
0x00, 0x7b, 0x7b, 0x80, 0x50, 0xfd, 0xe0, 0x7b, 0xc4, 0x80, 0xfa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x73, 0xc4, 0x80, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x9f, 0xcf,
0x00, 0x00, 0x00, 0x0a, 0xbf, 0x9f, 0x5f, 0x9f, 0x63, 0x30, 0x9e, 0x84, 0xbd, 0x3e, 0x81, 0x7d, 0x26, 0x13, 0x38, 0xbb, 0xef, 0xcf, 0x63, 0x90, 0xcf, 0x84, 0xbd, 0x3e, 0x03, 0xfb, 0x4c, 0x4e, 0xe0, 0x6a, 0x09, 0x75, 0xfd, 0xc5, 0xeb, 0xdc,
0x87, 0xaa, 0xfe, 0xe2, 0x73, 0x76, 0xfc, 0x48, 0xd2, 0x42, 0x7f, 0xcb, 0x88, 0xe1, 0xa7, 0x1f, 0x54, 0x26, 0x0a, 0x64, 0xf1, 0x99, 0x4c, 0x0b, 0xcf, 0x6b, 0x46, 0xa4, 0x77, 0x3f, 0xe8, 0xcc, 0x28, 0x50, 0xc9, 0x69, 0x30, 0x92, 0x75, 0xa2,
0x32, 0x0d, 0xda, 0x60, 0x9b, 0xa8, 0xcd, 0x52, 0x1a, 0xdb, 0xfa, 0x3d, 0x2d, 0xfe, 0x0b, 0xf5, 0x7f, 0xfe, 0x95, 0x96, 0x37, 0x97, 0x52, 0xee, 0xec, 0xf7, 0xd4, 0xf8, 0x2f, 0xc4, 0xff, 0xfb, 0x9f, 0x8c, 0x42, 0xfe, 0x9e, 0x9d, 0xf1, 0x9f,
0xc8, 0xef, 0xd9, 0x59, 0xff, 0xa3, 0x6d, 0x2f, 0x97, 0x8f, 0x3b, 0x37, 0x96, 0xec, 0x4e, 0x14, 0x8b, 0xc2, 0x63, 0xb8, 0xad, 0x7b, 0xb5, 0xfc, 0xb8, 0x73, 0x7d, 0xc9, 0xee, 0x8c, 0x62, 0xd1, 0x78, 0x0d, 0xf7, 0xf5, 0xab, 0x7f, 0xe6, 0xd0,
0x6f, 0x5c, 0xfd, 0x33, 0x43, 0x67, 0x47, 0xbb, 0x9e, 0xa9, 0xff, 0xd1, 0xec, 0xd3, 0x78, 0xe8, 0x85, 0xef, 0xa9, 0xff, 0xd9, 0x51, 0xaf, 0x67, 0xe2, 0x3f, 0x9b, 0xfb, 0x34, 0x2e, 0x5a, 0xe1, 0x73, 0xe2, 0x7f, 0x6c, 0x89, 0xff, 0xf8, 0x48,
0xb6, 0xa5, 0xfe, 0xe3, 0x23, 0xf5, 0x5f, 0x9d, 0x24, 0x53, 0x95, 0x42, 0x9e, 0x49, 0xbe, 0x19, 0x3f, 0x86, 0xf9, 0x84, 0xfc, 0x77, 0x67, 0x92, 0xe9, 0xca, 0x42, 0x5e, 0xc9, 0x7c, 0x93, 0xbf, 0x86, 0xf5, 0x0c, 0xbf, 0xd5, 0x1a, 0xf7, 0x9d,
0xdf, 0x6c, 0x8b, 0xfb, 0x4e, 0xfd, 0x67, 0xda, 0xd6, 0x73, 0xce, 0xaa, 0xfa, 0x7f, 0xdf, 0xb7, 0x99, 0xd1, 0x64, 0xfe, 0xf8, 0xaf, 0xd4, 0xad, 0xeb, 0x3c, 0xab, 0xe2, 0xff, 0xbe, 0x6c, 0x2b, 0xbd, 0xc9, 0xfc, 0xcf, 0x7b, 0x22, 0x7f, 0x4f,
0xe7, 0x35, 0x95, 0xbf, 0x27, 0x47, 0xf7, 0xed, 0x39, 0x5a, 0x6b, 0xdb, 0xca, 0xec, 0x58, 0xf9, 0x95, 0xfa, 0x8f, 0xe4, 0x1e, 0xdd, 0xbb, 0x7d, 0xb4, 0xd6, 0xd6, 0x95, 0xd9, 0xbe, 0xf2, 0x2b, 0xf1, 0x1f, 0xc5, 0xbf, 0x12, 0x37, 0x2d, 0x4a,
0x5f, 0x89, 0x97, 0x1e, 0xa5, 0x36, 0x81, 0xbd, 0x26, 0xb5, 0x6d, 0x6f, 0xfd, 0x57, 0x3f, 0xf7, 0xe7, 0x8e, 0xfa, 0x3f, 0x6f, 0x06, 0xf6, 0x9e, 0xac, 0x6d, 0x7b, 0xe3, 0xbf, 0x7b, 0xdf, 0x9f, 0x33, 0xe2, 0xff, 0xfd, 0x3c, 0xba, 0xab, 0xe6,
0x9f, 0xa3, 0xbb, 0xea, 0x1c, 0xae, 0x76, 0xac, 0xfc, 0xd9, 0xe3, 0xff, 0x7b, 0x2f, 0xb9, 0xa3, 0x7d, 0xcc, 0x8c, 0xf4, 0x70, 0xbd, 0x7d, 0xe5, 0xef, 0xee, 0xff, 0xef, 0x5b, 0xc9, 0x1d, 0xf5, 0x63, 0xa6, 0xa7, 0x7f, 0xb3, 0xff, 0x7f, 0xef,
0x27, 0xc7, 0xff, 0x73, 0x3f, 0x3f, 0x5b, 0xff, 0x55, 0xad, 0x3d, 0x36, 0xce, 0x4c, 0xb2, 0x63, 0xe5, 0xce, 0x55, 0xb2, 0xe7, 0xef, 0xc6, 0x7f, 0x57, 0x6d, 0x8f, 0x8d, 0x23, 0x93, 0x6a, 0x5f, 0xb9, 0x73, 0x95, 0x6c, 0xf7, 0xfc, 0x7f, 0xd5,
0xdd, 0xe7, 0xff, 0xab, 0x3e, 0x59, 0x1b, 0x9e, 0x4d, 0xc4, 0xb5, 0xf5, 0x3f, 0xb3, 0x0a, 0xb9, 0x6e, 0xbe, 0x70, 0x66, 0x37, 0x1b, 0xe9, 0xd1, 0x44, 0x1c, 0x1b, 0xff, 0x33, 0xab, 0x90, 0xeb, 0xc6, 0x0b, 0xef, 0x8c, 0xff, 0x6b, 0xfb, 0xdb,
0xfe, 0x9f, 0x7b, 0xbe, 0x6d, 0xe6, 0xa9, 0x80, 0xb7, 0x8d, 0xff, 0xbb, 0xae, 0x92, 0xb5, 0xcd, 0x35, 0xb9, 0xf7, 0xbd, 0x56, 0x76, 0x05, 0x3c, 0xad, 0xff, 0xdf, 0x75, 0x97, 0x6c, 0x6c, 0x8e, 0xc9, 0xbd, 0xc7, 0xea, 0xdc, 0xa5, 0x2e, 0x9f,
0x2a, 0x9f, 0x52, 0x37, 0x9e, 0xdf, 0x1f, 0xc5, 0x33, 0xbc, 0xaf, 0xd7, 0x7f, 0x7e, 0x95, 0xbf, 0x15, 0xad, 0x4a, 0x9e, 0xbf, 0x3f, 0x9a, 0x47, 0x78, 0x5f, 0x8f, 0xff, 0xfa, 0x2a, 0xff, 0x68, 0x5a, 0x95, 0x7c, 0x6f, 0xfc, 0xbf, 0x7b, 0xa7,
0x9b, 0xff, 0xef, 0x7e, 0xd2, 0x49, 0xe6, 0x5d, 0x6a, 0xfa, 0xdf, 0xbe, 0xab, 0xc2, 0xb5, 0xa3, 0xc0, 0xdf, 0xaf, 0x36, 0x93, 0xca, 0x51, 0x7a, 0xda, 0xdf, 0x67, 0x77, 0x85, 0x7b, 0x7b, 0x81, 0x9f, 0xef, 0x36, 0x44, 0x53, 0xcf, 0xd1, 0x95,
0x44, 0xd1, 0xc8, 0x51, 0x95, 0xdf, 0xff, 0xe7, 0xb6, 0x8d, 0x3f, 0xf1, 0x6c, 0xfc, 0x4a, 0x7c, 0x0c, 0x3e, 0x4f, 0xff, 0xbf, 0xff, 0xcf, 0x73, 0xcb, 0xef, 0x78, 0x96, 0xbf, 0x13, 0x1f, 0xc9, 0xfd, 0xf4, 0xdf, 0x88, 0xff, 0xca, 0x91, 0x2b,
0x44, 0xfd, 0x67, 0xde, 0x39, 0xf3, 0xbf, 0x46, 0x8f, 0x61, 0x65, 0xfd, 0x9f, 0xeb, 0x01, 0xe4, 0x6e, 0xc2, 0x8d, 0xb3, 0xff, 0x2b, 0x7b, 0x0d, 0x3b, 0xe3, 0xff, 0xbd, 0x16, 0x40, 0xde, 0x4d, 0x38, 0x71, 0x14, 0x03, 0xfc, 0x9e, 0x16, 0xc0,
0x18, 0xe0, 0xe7, 0xf4, 0x00, 0x9e, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xee, 0x37, 0xb1, 0x7f, 0xce,
0xec, 0xbe, 0x13, 0xfb, 0xef, 0xd9, 0x5c, 0x99, 0xd4, 0xf8, 0xf1, 0xfb, 0xa4, 0x77, 0x26, 0xe6, 0xb7, 0x97, 0x14, 0xb2, 0xcd, 0x55, 0xc9, 0x1a, 0x9f, 0x7f, 0x4f, 0x7a, 0x67, 0xc6, 0xfc, 0x71, 0x93, 0x85, 0xec, 0xfa, 0xb7, 0xfe, 0xfc, 0xa4,
0xe7, 0xdf, 0xfa, 0xf3, 0x95, 0x8a, 0x3c, 0xde, 0x28, 0xbc, 0x6b, 0xfd, 0x29, 0x93, 0xe4, 0x39, 0x4b, 0x71, 0x34, 0x77, 0x23, 0x1f, 0x6f, 0x34, 0xbe, 0xb5, 0x9e, 0xc9, 0xe5, 0x1d, 0x85, 0x6c, 0x03, 0x57, 0x6f, 0xc6, 0xe6, 0xae, 0x41, 0xee,
0xe0, 0x7d, 0x0f, 0x8f, 0x1f, 0x97, 0x99, 0xd7, 0x5a, 0x61, 0x9a, 0x42, 0x24, 0xd2, 0x5e, 0xde, 0xf6, 0x7a, 0x7f, 0x36, 0x18, 0xd1, 0x9e, 0xcf, 0x2c, 0xd2, 0xd9, 0x63, 0xfe, 0xf7, 0x9c, 0x9f, 0x67, 0xfa, 0x8d, 0xf2, 0x9b, 0xc6, 0x77, 0xb9,
0x70, 0x94, 0x6d, 0xf1, 0x58, 0x1d, 0x55, 0x65, 0x27, 0xdf, 0x9e, 0x98, 0x3f, 0x9f, 0xbc, 0x13, 0x2f, 0xad, 0xae, 0xbf, 0xcc, 0xf2, 0xf9, 0x11, 0x2a, 0x39, 0xf3, 0xf2, 0x79, 0x36, 0x4f, 0xcf, 0x98, 0x3f, 0x9f, 0x79, 0x27, 0x6e, 0xea, 0xe4,
0xfe, 0x7b, 0x92, 0x23, 0xd6, 0xe7, 0x18, 0xf5, 0xfc, 0x34, 0x93, 0x7a, 0x31, 0x96, 0xc1, 0x36, 0xd7, 0x06, 0x56, 0x8f, 0xf3, 0x5a, 0xfa, 0x24, 0x73, 0x44, 0x4f, 0x06, 0xa1, 0xda, 0x37, 0x8e, 0xe9, 0xda, 0x5a, 0xb9, 0xde, 0x99, 0x23, 0xc4,
0x50, 0x6d, 0xb2, 0x42, 0x62, 0xaa, 0xa5, 0xcc, 0x67, 0xff, 0xbd, 0x6f, 0x69, 0x1b, 0x1c, 0xb9, 0x6e, 0x48, 0xcc, 0x8c, 0xf4, 0xfb, 0xfc, 0x95, 0xfa, 0x1e, 0x93, 0xd7, 0xbd, 0xfe, 0x8d, 0x67, 0xb2, 0x10, 0x44, 0xa9, 0xa7, 0xeb, 0x2c, 0xc1,
0xce, 0xfa, 0xaa, 0xfe, 0x69, 0x1b, 0xec, 0x6f, 0x32, 0x79, 0x75, 0x51, 0x9a, 0x44, 0x91, 0xff, 0x3f, 0x91, 0x48, 0x6d, 0xeb, 0x4f, 0xf2, 0x19, 0x33, 0xe3, 0x61, 0x7c, 0x75, 0xff, 0x74, 0x24, 0xdb, 0x9b, 0x4a, 0xbe, 0xba, 0x99, 0x5d, 0x33,
0x6e, 0xc9, 0x2c, 0xbe, 0x7c, 0x46, 0x7c, 0x26, 0xa7, 0x2a, 0x16, 0xef, 0xd9, 0x4c, 0xfd, 0xb7, 0x43, 0xf5, 0x9f, 0x49, 0xe6, 0xc6, 0x88, 0xe3, 0x22, 0xbb, 0x52, 0x3e, 0xfa, 0x7f, 0xee, 0x6f, 0x62, 0x32, 0xfe, 0xa3, 0x98, 0x59, 0xa8, 0x1e,
0x3d, 0x38, 0x9f, 0x98, 0x1d, 0xa9, 0xda, 0xdd, 0x5b, 0xff, 0xd1, 0xd1, 0x7f, 0x65, 0x66, 0xd7, 0x51, 0x78, 0xce, 0xf0, 0x23, 0xd9, 0xf8, 0x9f, 0xbf, 0x0a, 0xbb, 0xe2, 0xbf, 0x92, 0xf5, 0xe0, 0xfd, 0x8c, 0xd9, 0xb5, 0x9e, 0x70, 0x6f, 0xfc,
0x3e, 0xe3, 0xad, 0x1e, 0xff, 0xdb, 0xe3, 0x7e, 0x1a, 0x4f, 0x75, 0x5b, 0x3f, 0x42, 0x65, 0x7a, 0x93, 0xb1, 0xfa, 0x5f, 0xc7, 0x83, 0xf6, 0x6b, 0xa4, 0xe7, 0x2f, 0xa3, 0x90, 0xe1, 0xfc, 0xf9, 0xec, 0x22, 0x5a, 0xfb, 0xff, 0x71, 0x59, 0x26,
0xdd, 0x63, 0xcd, 0x3c, 0x07, 0x29, 0x3e, 0x37, 0xfe, 0x9f, 0x49, 0xcc, 0x8e, 0xc4, 0xd9, 0x75, 0xe6, 0x7d, 0xeb, 0xd7, 0xf1, 0xc2, 0xf8, 0xbf, 0xb6, 0xdf, 0x5b, 0x2e, 0xfe, 0x67, 0x5a, 0xa7, 0xfd, 0xfd, 0x7f, 0xad, 0x5f, 0x3b, 0xb9, 0xff,
0x5e, 0xa2, 0xb0, 0xfe, 0x33, 0x3d, 0x40, 0xbe, 0xfe, 0x77, 0xce, 0xa6, 0xb3, 0x79, 0x93, 0x31, 0xdd, 0x86, 0xce, 0xd4, 0x7f, 0x27, 0x63, 0x76, 0x14, 0xe6, 0xd9, 0x95, 0xe3, 0xc6, 0xe4, 0xc8, 0xe0, 0xd9, 0x5c, 0x30, 0x1a, 0xe6, 0xab, 0x1d,
0x7f, 0xe5, 0xd3, 0x96, 0x56, 0x24, 0xe6, 0x8e, 0x3f, 0xd9, 0xf1, 0xd4, 0xf8, 0xdf, 0x52, 0xe3, 0x7f, 0x6e, 0x9c, 0xa8, 0xf1, 0xdf, 0x3f, 0xc2, 0xae, 0xcc, 0xad, 0x6a, 0xfd, 0x7f, 0xb4, 0xce, 0xff, 0x23, 0xdd, 0xce, 0xcf, 0xc5, 0x7f, 0xe7,
0x3b, 0xf6, 0xb5, 0x73, 0xe5, 0xf7, 0xfa, 0x8f, 0x0d, 0xef, 0xb6, 0xaf, 0xfe, 0x33, 0x3d, 0x61, 0x2c, 0x9b, 0xff, 0x67, 0x6e, 0x4b, 0x2b, 0x32, 0xe6, 0xe6, 0x77, 0x76, 0x7c, 0xab, 0xff, 0x1f, 0xa5, 0xfe, 0xbf, 0xd6, 0x7b, 0xcd, 0xd4, 0xca,
0xab, 0x25, 0x86, 0xe7, 0xd7, 0x3b, 0x13, 0x73, 0x33, 0xeb, 0xcc, 0xf7, 0xd7, 0x7f, 0xe5, 0x33, 0x4c, 0xda, 0x54, 0xfa, 0xd8, 0x90, 0xeb, 0x2e, 0x37, 0xfe, 0x5f, 0x3d, 0xca, 0xce, 0xcf, 0x28, 0x63, 0x53, 0xfb, 0xd4, 0x3d, 0xf7, 0xab, 0x45,
0x72, 0x94, 0x8e, 0xc8, 0xfb, 0xc6, 0xff, 0x15, 0xb3, 0xe9, 0x4c, 0xfa, 0xfe, 0x3d, 0xeb, 0x7f, 0xad, 0xf8, 0x88, 0xb5, 0x4b, 0xa4, 0xc7, 0xd7, 0x3b, 0x33, 0xe6, 0x56, 0xd6, 0x9e, 0xcf, 0x8f, 0xff, 0xce, 0x3d, 0x4c, 0x2a, 0x77, 0x17, 0xa2,
0xe3, 0x79, 0x88, 0x2b, 0x66, 0x85, 0x27, 0xce, 0xff, 0xab, 0x12, 0xd8, 0x73, 0xe7, 0xff, 0xd5, 0x2b, 0xf2, 0x73, 0xc7, 0xa1, 0x6f, 0x5e, 0xdd, 0xff, 0xcf, 0xce, 0xff, 0x2b, 0xb9, 0xf4, 0xf7, 0xac, 0xff, 0x8d, 0xa5, 0x6b, 0x3f, 0xd1, 0x7a,
0xf2, 0xde, 0xf1, 0x3f, 0xd7, 0x42, 0x62, 0x68, 0x7c, 0x6e, 0x9f, 0xaa, 0xff, 0x5b, 0xbe, 0xd1, 0x50, 0xd1, 0x6f, 0x45, 0x3f, 0x71, 0x1c, 0xd0, 0x7e, 0x77, 0x66, 0x89, 0x7f, 0x63, 0xfe, 0xdf, 0x95, 0x81, 0x7d, 0x94, 0xef, 0x09, 0xd5, 0xd7,
0x49, 0xef, 0x96, 0x79, 0x6e, 0x4b, 0xe5, 0x3c, 0xaa, 0x72, 0xfd, 0x6a, 0xe6, 0xfa, 0xff, 0xcc, 0xb7, 0x53, 0x56, 0xbf, 0xff, 0x67, 0x6b, 0x60, 0x1c, 0xd3, 0xf7, 0x8f, 0xc7, 0x7b, 0xe8, 0xc4, 0x4b, 0xd1, 0x7f, 0x5a, 0xfc, 0x9f, 0xf2, 0x44,
0x5b, 0xfe, 0xfa, 0xff, 0xda, 0xfa, 0x8f, 0xe2, 0x2d, 0xe6, 0x9e, 0x5e, 0xea, 0xe6, 0xf7, 0xd3, 0x7e, 0xee, 0x38, 0x82, 0x43, 0x47, 0xbb, 0x15, 0x2d, 0xad, 0x5b, 0x65, 0xdf, 0x96, 0xce, 0x71, 0xd4, 0xfc, 0xfc, 0x7f, 0xcd, 0xba, 0xfa, 0x1b,
0x6a, 0x59, 0xeb, 0x39, 0x71, 0x3e, 0xc4, 0xef, 0x9a, 0x33, 0xf3, 0xd3, 0xbf, 0xe1, 0x6d, 0x3f, 0x18, 0x9b, 0x01, 0x00, 0xc7, 0x98, 0xb9, 0x23, 0x3b, 0x1f, 0xff, 0xb1, 0xbc, 0xe4, 0xe4, 0x23, 0xfe, 0x4e, 0x2b, 0x75, 0xde, 0xf1, 0xfe, 0xe6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xef, 0xde, 0xc3, 0x14, 0xaf, 0x77, 0x38, 0xbc, 0x65, 0x4b, 0xda, 0x13, 0x1b, 0x9f, 0xb5, 0x13, 0xa1, 0xc4, 0xd1, 0xf3, 0x21, 0xd7, 0x03, 0xfe, 0xe6, 0xf9, 0xd0, 0xdf, 0xfa, 0x1c,
0x64, 0x72, 0x29, 0x5b, 0x69, 0xce, 0x5d, 0x4b, 0x24, 0xf3, 0x67, 0xb7, 0xae, 0x77, 0xaf, 0xac, 0xff, 0x64, 0xb3, 0x69, 0xbc, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x7d, 0x3b, 0xa4, 0x92, 0x59,
0xe6, 0x99, 0xc4, 0xf9, 0xcc, 0x3e, 0x3e, 0x7b, 0x34, 0xdf, 0x32, 0x3c, 0x22, 0x91, 0xc6, 0x5a, 0x79, 0xbc, 0x5a, 0x6a, 0x72, 0x34, 0xbf, 0x8b, 0x9e, 0xcf, 0xad, 0x5f, 0x3d, 0xbb, 0xbb, 0xf7, 0xa5, 0x6b, 0xf9, 0x79, 0x6b, 0xe5, 0x34, 0x97,
0xdf, 0x65, 0x5b, 0x59, 0x6f, 0x0f, 0xd0, 0x9f, 0x0f, 0x53, 0x7f, 0x8f, 0x69, 0xa4, 0xf6, 0x79, 0x4d, 0x32, 0xff, 0x4c, 0x8f, 0x28, 0x97, 0x53, 0xed, 0x7e, 0xff, 0x83, 0x38, 0xf2, 0x6a, 0xde, 0x65, 0x75, 0x8d, 0x42, 0x3e, 0xd5, 0xce, 0xeb,
0x5b, 0x6a, 0xe9, 0x04, 0xe2, 0x6c, 0xab, 0xe9, 0xfd, 0x5b, 0x31, 0xfd, 0x97, 0xdf, 0xb3, 0x5a, 0xe3, 0x73, 0x47, 0x33, 0x35, 0x4a, 0x65, 0xb7, 0xab, 0x96, 0x3d, 0x7f, 0x3b, 0x34, 0x36, 0xbc, 0x4f, 0x59, 0x8b, 0x85, 0x5a, 0x6e, 0xc3, 0xb9,
0x9b, 0x17, 0x5f, 0x7d, 0xbc, 0x6a, 0xd3, 0xdb, 0x6a, 0x7a, 0x80, 0x8a, 0xfa, 0xaf, 0xdb, 0xca, 0xfd, 0xf7, 0xc6, 0x46, 0xdc, 0x61, 0xb1, 0xf8, 0x9b, 0xe5, 0xca, 0x6f, 0x7e, 0x3f, 0x89, 0xfb, 0x6c, 0xab, 0xf1, 0xb9, 0xab, 0x59, 0xcd, 0xf8,
0xf2, 0x7e, 0xfa, 0xf8, 0xfc, 0xfd, 0xa7, 0xf1, 0xd1, 0x24, 0x81, 0x5c, 0xca, 0xe4, 0xae, 0x4f, 0x95, 0xcb, 0xe5, 0xca, 0xde, 0x7d, 0xbd, 0xea, 0xb5, 0xe5, 0x84, 0x5a, 0xb6, 0x7e, 0x67, 0x89, 0x37, 0xde, 0x6e, 0xad, 0x66, 0xc4, 0x8d, 0xcf,
0xa7, 0xb7, 0xed, 0x1c, 0xff, 0x33, 0x49, 0x52, 0x99, 0xb4, 0xd0, 0xea, 0x57, 0xb2, 0xbd, 0x65, 0xae, 0xfe, 0x33, 0x99, 0xbf, 0x73, 0x1a, 0x1f, 0xcd, 0x05, 0x50, 0xcb, 0x13, 0xb9, 0xeb, 0x5b, 0x55, 0x8e, 0x14, 0xa5, 0x3d, 0x9b, 0xc6, 0xf6,
0x4d, 0x51, 0x94, 0x67, 0x5c, 0xf7, 0xdc, 0x93, 0x48, 0xce, 0xaf, 0x4f, 0x1e, 0xcd, 0x78, 0x4d, 0x25, 0xaf, 0xca, 0xd8, 0xec, 0x10, 0xf9, 0xec, 0xe7, 0xa3, 0x94, 0xef, 0xb3, 0xfb, 0x93, 0xca, 0x15, 0xa9, 0xc7, 0xff, 0x55, 0x39, 0x55, 0x3e,
0xdd, 0xfb, 0x4a, 0x4c, 0x26, 0x3e, 0x44, 0xd7, 0xf1, 0x8e, 0xe9, 0xb1, 0x70, 0xd7, 0xd3, 0x02, 0x33, 0xcf, 0xa4, 0x68, 0x99, 0xed, 0xff, 0xc7, 0xf2, 0x7d, 0x18, 0x4e, 0xb9, 0x9a, 0x77, 0xfd, 0x7f, 0xb4, 0xed, 0x98, 0xb4, 0xf7, 0x93, 0x1d,
0xc9, 0xd4, 0xcc, 0x28, 0x9b, 0xe1, 0x57, 0xbf, 0xb2, 0xa2, 0xfe, 0xe3, 0xe1, 0x3c, 0xb9, 0xfa, 0x99, 0x65, 0xd5, 0x47, 0xe5, 0xda, 0x11, 0x0b, 0xbb, 0xf6, 0xfb, 0x8b, 0x74, 0xad, 0x18, 0xe9, 0x1c, 0x7b, 0xf5, 0xd9, 0xd7, 0xae, 0x4f, 0x56,
0xb3, 0xa7, 0x67, 0xf8, 0x62, 0xfd, 0xaf, 0x9d, 0xa7, 0xd5, 0x9c, 0xff, 0x47, 0xfa, 0x59, 0x3c, 0x77, 0xb6, 0x98, 0xe8, 0xc4, 0x7f, 0x5c, 0xcc, 0x93, 0xbb, 0x77, 0x1d, 0xeb, 0xbe, 0x9a, 0x4f, 0x5a, 0x86, 0x2f, 0xc6, 0xff, 0x8e, 0xf8, 0x99,
0x4c, 0x77, 0xfe, 0x69, 0xf5, 0xbf, 0x77, 0x1f, 0x57, 0xf7, 0xe6, 0xcf, 0x33, 0xec, 0xf6, 0xd1, 0xfa, 0x9f, 0x49, 0x8b, 0x9d, 0xff, 0x47, 0x79, 0x37, 0x9d, 0x33, 0x6b, 0x4c, 0x3c, 0xcc, 0xe8, 0xfc, 0xdb, 0xe2, 0x7f, 0x6f, 0x19, 0x77, 0xb7,
0xaf, 0x39, 0x5f, 0x79, 0x5f, 0xff, 0xaf, 0x5c, 0xd9, 0xb8, 0xa3, 0xfe, 0x6f, 0xa9, 0xf2, 0xb1, 0x7d, 0xbe, 0xb6, 0xfe, 0xe6, 0xd7, 0x23, 0xec, 0xf1, 0xd1, 0xf8, 0x9f, 0xdd, 0xef, 0x6d, 0x7e, 0xee, 0x7a, 0xbf, 0xfe, 0xdf, 0xb9, 0xb2, 0x71,
0xcf, 0xd7, 0xd0, 0x6c, 0xf2, 0xfb, 0xf9, 0x6d, 0x8f, 0xb2, 0xf3, 0xff, 0x9a, 0x75, 0xa1, 0xea, 0x79, 0xc4, 0x6d, 0x3d, 0x46, 0xfc, 0x9f, 0x12, 0xe5, 0xb9, 0x32, 0x5f, 0x1b, 0xff, 0xef, 0xc7, 0x50, 0x57, 0x1f, 0xf6, 0xde, 0xb9, 0x47, 0xdb,
0xe8, 0xaa, 0xa7, 0xab, 0xbd, 0xcd, 0x1d, 0xaa, 0xcf, 0x77, 0xef, 0x18, 0xff, 0x43, 0xfd, 0x2f, 0x58, 0x0b, 0xaf, 0x1d, 0xfc, 0xff, 0x7e, 0x97, 0xe4, 0xdc, 0xdd, 0x9d, 0xbd, 0xab, 0x49, 0x3b, 0x4b, 0xbd, 0x73, 0xcf, 0xe1, 0xa7, 0x63, 0x87,
0x25, 0xf3, 0x2b, 0xcc, 0x33, 0xfd, 0xc9, 0xf8, 0xb3, 0xec, 0x6b, 0x57, 0xc9, 0x32, 0x7d, 0x68, 0xcf, 0x2b, 0xf9, 0x27, 0xee, 0xf9, 0xee, 0x19, 0xfd, 0x7f, 0x88, 0xff, 0x05, 0x6b, 0xe1, 0x27, 0xf4, 0x92, 0xab, 0xee, 0xe5, 0xe5, 0xb3, 0xd8,
0x6e, 0x7c, 0x75, 0xfe, 0xdf, 0xf3, 0x54, 0xa0, 0x6f, 0xd5, 0x7f, 0x24, 0xd7, 0xb7, 0xee, 0xa8, 0xff, 0xb5, 0x57, 0x06, 0xf7, 0x7e, 0x32, 0x5b, 0x52, 0xf9, 0xfb, 0xff, 0x5f, 0x1f, 0xff, 0x3f, 0xd9, 0xe1, 0xe7, 0x5b, 0xf1, 0x1f, 0xc5, 0x15,
0xd6, 0x5f, 0xcb, 0xbf, 0x79, 0xfe, 0xbf, 0xa2, 0xcf, 0xfb, 0x76, 0xfd, 0x7f, 0x61, 0x0e, 0xbd, 0xe6, 0x5b, 0x28, 0xe7, 0xc5, 0x33, 0xe2, 0x3f, 0x36, 0x8e, 0x6a, 0x57, 0xdc, 0xcb, 0x3f, 0x79, 0xfc, 0xdf, 0xbf, 0x13, 0xd4, 0xd7, 0xe3, 0xff,
0xea, 0x7f, 0x6e, 0xdc, 0x56, 0xff, 0x2b, 0x56, 0x8c, 0xf3, 0x9f, 0x7a, 0xc5, 0xf9, 0x7f, 0xef, 0x4c, 0xe3, 0xe7, 0xd7, 0x0b, 0x63, 0xe8, 0x35, 0x4f, 0xa1, 0xbc, 0x17, 0xff, 0x73, 0x77, 0x86, 0x4f, 0x1e, 0xff, 0x9f, 0x1e, 0xff, 0xb3, 0x57,
0x7f, 0x7d, 0xd2, 0xf9, 0x9a, 0xf3, 0xcd, 0x76, 0xe9, 0x77, 0x61, 0xee, 0xfa, 0x4e, 0xf2, 0x9e, 0x16, 0xb3, 0x66, 0xed, 0x25, 0x36, 0xcd, 0xff, 0x9f, 0x8e, 0x34, 0x7e, 0x7f, 0xfc, 0x8f, 0xad, 0x7b, 0xf7, 0xd7, 0xe7, 0x9b, 0xe3, 0xd0, 0x67,
0x23, 0xf3, 0x94, 0xde, 0xda, 0xa7, 0x39, 0xc5, 0xa2, 0x4a, 0xcf, 0x5d, 0xe5, 0xdd, 0x73, 0xfd, 0x7f, 0xef, 0x37, 0x8a, 0x61, 0xce, 0x79, 0x8a, 0xe3, 0xfd, 0x99, 0xcd, 0xfc, 0xae, 0xa8, 0xeb, 0xef, 0xff, 0x8f, 0x65, 0xfd, 0x7f, 0xef, 0x93,
0xaa, 0xb7, 0x50, 0xfd, 0x7f, 0xa3, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdb, 0x2d, 0xbb, 0xee, 0xff, 0xef, 0x7d, 0xa2, 0xa8, 0xfb, 0x0c, 0xc5, 0xff, 0x37, 0xda, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0xee, 0xd0, 0xdb, 0x9b, 0xa8, 0x5f, 0x9f, 0x82, 0x71, 0x7b, 0xa2, 0xfe, 0xdb, 0x5d, 0x33, 0xed, 0xda, 0x44, 0xfd, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x73, 0xf2, 0x2b, 0x72, 0xeb, 0xf7, 0xe7, 0xc3, 0x38, 0x3d, 0xb7, 0xfe,
0x95, 0x4c, 0xf4, 0xbd, 0x44, 0xfd, 0xdf, 0x78, 0xc7, 0xc7, 0x6d, 0x89, 0xfa, 0x75, 0x77, 0x4e, 0xdf, 0x9e, 0xa8, 0xdf, 0xdd, 0xfb, 0x33, 0xe3, 0xd8, 0xdc, 0xfa, 0xe3, 0x51, 0x8e, 0xa2, 0xef, 0xe5, 0xd6, 0xf7, 0xee, 0xc7, 0xd3, 0xb7, 0x64,
0x5e, 0xf2, 0x87, 0x6e, 0x4e, 0xd4, 0xcf, 0xdf, 0x3b, 0x75, 0x6b, 0xa2, 0x3e, 0x6b, 0xef, 0x98, 0xec, 0xed, 0xfb, 0xe3, 0xd6, 0xe5, 0xd6, 0xef, 0x7b, 0x87, 0xfa, 0xf4, 0xdc, 0xfa, 0xe3, 0x26, 0x13, 0xd1, 0xc9, 0xb9, 0xf5, 0xeb, 0x6f, 0x51,
0xe0, 0x31, 0x5b, 0x75, 0x77, 0x69, 0x7c, 0xf4, 0xce, 0xcf, 0xf1, 0x8c, 0xa6, 0x15, 0x3d, 0x4a, 0xe5, 0x5d, 0x9a, 0xeb, 0x9d, 0x9a, 0x5b, 0x9f, 0xb5, 0xef, 0x4e, 0x3e, 0x6d, 0xfb, 0xe3, 0xc5, 0x6b, 0xf6, 0x46, 0x36, 0x84, 0x93, 0x6b, 0x64,
0x13, 0xf5, 0x7f, 0x4a, 0xbd, 0xee, 0x4a, 0xd4, 0x7f, 0xcf, 0x19, 0x8b, 0x4d, 0xdb, 0x1f, 0x43, 0xf3, 0xc6, 0xb5, 0x89, 0x3e, 0x5b, 0xd3, 0x8a, 0x16, 0xa5, 0xf3, 0x7d, 0xcd, 0xb3, 0x73, 0xeb, 0x7f, 0x3d, 0xc6, 0xeb, 0xd9, 0x58, 0xa3, 0x9c,
0x5a, 0xcf, 0xfd, 0xe8, 0xbd, 0xcf, 0x47, 0xf8, 0x76, 0xa2, 0xf6, 0x6f, 0xab, 0xff, 0x55, 0xfb, 0x29, 0x8a, 0xaa, 0xae, 0xf3, 0xbe, 0xef, 0x5d, 0xed, 0x48, 0x8d, 0x1b, 0xd7, 0xe6, 0xd6, 0xba, 0x6e, 0x47, 0xcf, 0xdd, 0x29, 0xe1, 0xdb, 0xb9,
0xf7, 0x95, 0x7d, 0x59, 0x41, 0x75, 0xf5, 0x1f, 0xe5, 0xaf, 0xed, 0x4d, 0xd4, 0xca, 0xae, 0x27, 0xa8, 0xff, 0xef, 0xac, 0xb5, 0xc5, 0x7f, 0x4f, 0xab, 0x1b, 0x4d, 0x51, 0xf7, 0xf4, 0x93, 0x7d, 0x59, 0x83, 0xfa, 0xe2, 0x3f, 0xda, 0x3f, 0xdb,
0x01, 0xe4, 0xd6, 0xad, 0xe6, 0x12, 0x75, 0x4f, 0xb6, 0x80, 0x9d, 0x89, 0x5a, 0x5f, 0xaf, 0xff, 0xcc, 0xac, 0x5c, 0xfd, 0x9b, 0x5b, 0xab, 0xba, 0x9e, 0x20, 0xfe, 0x7f, 0x57, 0x3b, 0x90, 0x99, 0xd1, 0x3e, 0x29, 0xf7, 0x37, 0x6b, 0xc0, 0xce,
0xdf, 0x39, 0xff, 0x8f, 0xb2, 0x57, 0x32, 0xbd, 0x46, 0x7e, 0xfd, 0xff, 0xcb, 0x4f, 0xd4, 0xfa, 0x99, 0xf5, 0x7f, 0x47, 0xdc, 0x5a, 0x5f, 0x8f, 0xff, 0x4a, 0xff, 0x20, 0xfe, 0x7f, 0xcf, 0xf8, 0xbf, 0xaf, 0x2f, 0xaf, 0xaf, 0xff, 0x7f, 0x79,
0xa2, 0xae, 0xfa, 0x3f, 0x33, 0xff, 0x5f, 0xf7, 0x54, 0x82, 0x9d, 0x89, 0xba, 0xc6, 0xff, 0x55, 0x15, 0x71, 0x77, 0x95, 0x6f, 0xad, 0xdf, 0x19, 0xff, 0x67, 0xe4, 0xd6, 0x15, 0xff, 0xef, 0x8c, 0xff, 0x6b, 0xfb, 0x13, 0xac, 0x58, 0xcd, 0xed,
0xdf, 0x95, 0x9b, 0xfb, 0xcd, 0xf3, 0xff, 0xdc, 0x93, 0x40, 0xb3, 0x3d, 0xc0, 0xbe, 0x84, 0xd6, 0x13, 0x89, 0xfa, 0x12, 0x9d, 0x4d, 0x88, 0xff, 0xd5, 0x75, 0xe7, 0xa4, 0x9d, 0x21, 0xc4, 0x78, 0x7d, 0xfe, 0x5f, 0xdb, 0x13, 0xb4, 0xda, 0x02,
0x75, 0x67, 0x8e, 0xd7, 0xf3, 0xec, 0xef, 0x9b, 0xd7, 0x63, 0x6e, 0x9f, 0xff, 0xd7, 0x5e, 0xab, 0xf9, 0xe7, 0x9a, 0xd2, 0xec, 0xcb, 0xd5, 0xfa, 0x46, 0x6e, 0x7d, 0xb9, 0x75, 0x67, 0xae, 0xd7, 0xf5, 0xe8, 0xef, 0x9b, 0xf7, 0x63, 0x4e, 0x1f,
0xea, 0x15, 0xef, 0x55, 0xf3, 0xff, 0xda, 0x2b, 0x5b, 0x12, 0x75, 0xab, 0x8f, 0xda, 0x6f, 0x5f, 0xff, 0x3b, 0xdb, 0xd3, 0xff, 0xf7, 0xde, 0xab, 0xf9, 0xff, 0x35, 0xa5, 0xd5, 0x2b, 0xde, 0xab, 0xc6, 0xff, 0x2b, 0xda, 0xd8, 0x37, 0x4b, 0x63,
0xc0, 0xee, 0x79, 0xed, 0xf9, 0x9e, 0x10, 0xf8, 0xda, 0x37, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xbd, 0xa3, 0xfe, 0x33, 0x8c, 0xa6, 0xd1, 0x1f, 0xef, 0xb4, 0x1a, 0xb0, 0x66, 0x9c, 0xf1, 0x7e, 0x4b, 0x08, 0x7c,
0xed, 0x49, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0xf9, 0xef, 0x3f, 0xfb, 0x01, 0xd4, 0x3f, 0x00, 0x00, 0x00, 0x80, 0x93, 0xfc, 0xfb, 0x9f, 0x72, 0x00, 0xf1, 0x0f, 0xfc, 0x75, 0xf1, 0xff, 0x2f };
0xf0, 0xeb, 0xea, 0xff, 0x3f };
// Font glyphs rectangles data (on atlas) // Font glyphs rectangles data (on atlas)
static const Rectangle darkFontRecs[189] = { static const Rectangle darkFontRecs[189] = {
@@ -257,100 +257,100 @@ static const Rectangle darkFontRecs[189] = {
{ 218, 52, 6 , 9 }, { 218, 52, 6 , 9 },
{ 232, 52, 5 , 9 }, { 232, 52, 5 , 9 },
{ 245, 52, 5 , 12 }, { 245, 52, 5 , 12 },
{ 258, 52, 5 , 9 }, { 258, 52, 0 , 0 },
{ 271, 52, 5 , 10 }, { 266, 52, 5 , 10 },
{ 284, 52, 7 , 9 }, { 279, 52, 7 , 9 },
{ 299, 52, 5 , 9 }, { 294, 52, 0 , 0 },
{ 312, 52, 6 , 5 }, { 302, 52, 6 , 5 },
{ 326, 52, 5 , 3 }, { 316, 52, 5 , 3 },
{ 339, 52, 7 , 9 }, { 329, 52, 7 , 9 },
{ 354, 52, 5 , 9 }, { 344, 52, 0 , 0 },
{ 367, 52, 4 , 4 }, { 352, 52, 4 , 4 },
{ 379, 52, 5 , 7 }, { 364, 52, 5 , 7 },
{ 392, 52, 5 , 9 }, { 377, 52, 0 , 0 },
{ 405, 52, 5 , 9 }, { 385, 52, 0 , 0 },
{ 418, 52, 5 , 12 }, { 393, 52, 5 , 12 },
{ 431, 52, 5 , 9 }, { 406, 52, 5 , 9 },
{ 444, 52, 7 , 9 }, { 419, 52, 7 , 9 },
{ 459, 52, 1 , 1 }, { 434, 52, 1 , 1 },
{ 468, 52, 5 , 10 }, { 443, 52, 5 , 10 },
{ 481, 52, 5 , 9 }, { 456, 52, 0 , 0 },
{ 494, 52, 5 , 9 }, { 464, 52, 0 , 0 },
{ 4, 76, 6 , 5 }, { 472, 52, 6 , 5 },
{ 18, 76, 9 , 9 }, { 486, 52, 9 , 9 },
{ 35, 76, 9 , 7 }, { 4, 76, 9 , 7 },
{ 52, 76, 5 , 11 }, { 21, 76, 5 , 11 },
{ 65, 76, 5 , 9 }, { 34, 76, 5 , 9 },
{ 78, 76, 5 , 12 }, { 47, 76, 5 , 12 },
{ 91, 76, 5 , 12 }, { 60, 76, 5 , 12 },
{ 104, 76, 5 , 12 }, { 73, 76, 5 , 12 },
{ 117, 76, 6 , 12 }, { 86, 76, 6 , 12 },
{ 131, 76, 5 , 11 }, { 100, 76, 5 , 11 },
{ 144, 76, 5 , 13 }, { 113, 76, 5 , 13 },
{ 157, 76, 9 , 9 }, { 126, 76, 9 , 9 },
{ 174, 76, 5 , 12 }, { 143, 76, 5 , 12 },
{ 187, 76, 5 , 12 }, { 156, 76, 5 , 12 },
{ 200, 76, 5 , 12 }, { 169, 76, 5 , 12 },
{ 213, 76, 5 , 12 }, { 182, 76, 5 , 12 },
{ 226, 76, 5 , 11 }, { 195, 76, 5 , 11 },
{ 239, 76, 2 , 12 }, { 208, 76, 2 , 12 },
{ 249, 76, 2 , 12 }, { 218, 76, 2 , 12 },
{ 259, 76, 3 , 12 }, { 228, 76, 3 , 12 },
{ 270, 76, 3 , 11 }, { 239, 76, 3 , 11 },
{ 281, 76, 6 , 9 }, { 250, 76, 6 , 9 },
{ 295, 76, 6 , 12 }, { 264, 76, 6 , 12 },
{ 309, 76, 5 , 12 }, { 278, 76, 5 , 12 },
{ 322, 76, 5 , 12 }, { 291, 76, 5 , 12 },
{ 335, 76, 5 , 12 }, { 304, 76, 5 , 12 },
{ 348, 76, 6 , 12 }, { 317, 76, 6 , 12 },
{ 362, 76, 5 , 11 }, { 331, 76, 5 , 11 },
{ 375, 76, 5 , 5 }, { 344, 76, 5 , 5 },
{ 388, 76, 7 , 9 }, { 357, 76, 7 , 9 },
{ 403, 76, 5 , 12 }, { 372, 76, 5 , 12 },
{ 416, 76, 5 , 12 }, { 385, 76, 5 , 12 },
{ 429, 76, 5 , 12 }, { 398, 76, 5 , 12 },
{ 442, 76, 5 , 11 }, { 411, 76, 5 , 11 },
{ 455, 76, 5 , 12 }, { 424, 76, 5 , 12 },
{ 468, 76, 5 , 9 }, { 437, 76, 5 , 9 },
{ 481, 76, 5 , 9 }, { 450, 76, 5 , 9 },
{ 494, 76, 5 , 10 }, { 463, 76, 5 , 10 },
{ 4, 100, 5 , 10 }, { 476, 76, 5 , 10 },
{ 17, 100, 5 , 10 }, { 489, 76, 5 , 10 },
{ 30, 100, 6 , 10 }, { 4, 100, 6 , 10 },
{ 44, 100, 5 , 9 }, { 18, 100, 5 , 9 },
{ 57, 100, 5 , 11 }, { 31, 100, 5 , 11 },
{ 70, 100, 9 , 7 }, { 44, 100, 9 , 7 },
{ 61, 100, 5 , 10 },
{ 74, 100, 5 , 10 },
{ 87, 100, 5 , 10 }, { 87, 100, 5 , 10 },
{ 100, 100, 5 , 10 }, { 100, 100, 5 , 10 },
{ 113, 100, 5 , 10 }, { 113, 100, 5 , 9 },
{ 126, 100, 5 , 10 }, { 126, 100, 2 , 10 },
{ 139, 100, 5 , 9 }, { 136, 100, 2 , 10 },
{ 152, 100, 2 , 10 }, { 146, 100, 3 , 10 },
{ 162, 100, 2 , 10 }, { 157, 100, 3 , 9 },
{ 172, 100, 3 , 10 }, { 168, 100, 6 , 9 },
{ 183, 100, 3 , 9 }, { 182, 100, 6 , 10 },
{ 194, 100, 6 , 9 }, { 196, 100, 5 , 10 },
{ 208, 100, 6 , 10 }, { 209, 100, 5 , 10 },
{ 222, 100, 5 , 10 }, { 222, 100, 5 , 10 },
{ 235, 100, 5 , 10 }, { 235, 100, 6 , 10 },
{ 248, 100, 5 , 10 }, { 249, 100, 5 , 9 },
{ 261, 100, 6 , 10 }, { 262, 100, 5 , 5 },
{ 275, 100, 5 , 9 }, { 275, 100, 7 , 7 },
{ 288, 100, 5 , 5 }, { 290, 100, 5 , 10 },
{ 301, 100, 7 , 7 }, { 303, 100, 5 , 10 },
{ 316, 100, 5 , 10 }, { 316, 100, 5 , 10 },
{ 329, 100, 5 , 10 }, { 329, 100, 5 , 9 },
{ 342, 100, 5 , 10 }, { 342, 100, 5 , 12 },
{ 355, 100, 5 , 9 }, { 355, 100, 5 , 11 },
{ 368, 100, 5 , 12 }, { 368, 100, 5 , 11 },
{ 381, 100, 5 , 11 },
{ 394, 100, 5 , 11 },
}; };
// Font glyphs info data // Font glyphs info data
// NOTE: No glyphs.image data provided // NOTE: No glyphs.image data provided
static const GlyphInfo darkFontGlyphs[189] = { static const GlyphInfo darkFontGlyphs[189] = {
{ 32, 0, 13, 4, { 0 }}, { 32, 0, 0, 4, { 0 }},
{ 33, 2, 4, 5, { 0 }}, { 33, 2, 4, 5, { 0 }},
{ 34, 2, 4, 7, { 0 }}, { 34, 2, 4, 7, { 0 }},
{ 35, 1, 4, 8, { 0 }}, { 35, 1, 4, 8, { 0 }},
@@ -451,25 +451,25 @@ static const GlyphInfo darkFontGlyphs[189] = {
{ 8364, 1, 4, 8, { 0 }}, { 8364, 1, 4, 8, { 0 }},
{ 165, 1, 4, 7, { 0 }}, { 165, 1, 4, 7, { 0 }},
{ 352, 1, 1, 7, { 0 }}, { 352, 1, 1, 7, { 0 }},
{ 167, 2, 4, 9, { 0 }}, { 167, 0, 0, 0, { 0 }},
{ 353, 1, 3, 7, { 0 }}, { 353, 1, 3, 7, { 0 }},
{ 169, 1, 4, 9, { 0 }}, { 169, 1, 4, 9, { 0 }},
{ 170, 2, 4, 9, { 0 }}, { 170, 0, 0, 0, { 0 }},
{ 171, 1, 6, 8, { 0 }}, { 171, 1, 6, 8, { 0 }},
{ 172, 1, 8, 7, { 0 }}, { 172, 1, 8, 7, { 0 }},
{ 174, 1, 4, 9, { 0 }}, { 174, 1, 4, 9, { 0 }},
{ 175, 2, 4, 9, { 0 }}, { 175, 0, 0, 0, { 0 }},
{ 176, 1, 4, 6, { 0 }}, { 176, 1, 4, 6, { 0 }},
{ 177, 1, 6, 7, { 0 }}, { 177, 1, 6, 7, { 0 }},
{ 178, 2, 4, 9, { 0 }}, { 178, 0, 0, 0, { 0 }},
{ 179, 2, 4, 9, { 0 }}, { 179, 0, 0, 0, { 0 }},
{ 381, 1, 1, 7, { 0 }}, { 381, 1, 1, 7, { 0 }},
{ 181, 1, 6, 7, { 0 }}, { 181, 1, 6, 7, { 0 }},
{ 182, 1, 4, 9, { 0 }}, { 182, 1, 4, 9, { 0 }},
{ 183, 2, 8, 5, { 0 }}, { 183, 2, 8, 5, { 0 }},
{ 382, 1, 3, 7, { 0 }}, { 382, 1, 3, 7, { 0 }},
{ 185, 2, 4, 9, { 0 }}, { 185, 0, 0, 0, { 0 }},
{ 186, 2, 4, 9, { 0 }}, { 186, 0, 0, 0, { 0 }},
{ 187, 1, 6, 8, { 0 }}, { 187, 1, 6, 8, { 0 }},
{ 338, 1, 4, 11, { 0 }}, { 338, 1, 4, 11, { 0 }},
{ 339, 1, 6, 11, { 0 }}, { 339, 1, 6, 11, { 0 }},
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.
+845 -381
View File
File diff suppressed because it is too large Load Diff
+91 -73
View File
@@ -1,22 +1,22 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib v5.5-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) * raylib v5.6-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
* *
* FEATURES: * FEATURES:
* - NO external dependencies, all required libraries included with raylib * - NO external dependencies, all required libraries included with raylib
* - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly, * - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly,
* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5. * MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5.
* - Written in plain C code (C99) in PascalCase/camelCase notation * - Written in plain C code (C99) in PascalCase/camelCase notation
* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3 or ES2 - choose at compile) * - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile)
* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] * - Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
* - Multiple Fonts formats supported (TTF, XNA fonts, AngelCode fonts) * - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite fonts)
* - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) * - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC)
* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! * - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more!
* - Flexible Materials system, supporting classic maps and PBR maps * - Flexible Materials system, supporting classic maps and PBR maps
* - Animated 3D models supported (skeletal bones animation) (IQM) * - Animated 3D models supported (skeletal bones animation) (IQM, M3D, GLTF)
* - Shaders support, including Model shaders and Postprocessing shaders * - Shaders support, including Model shaders and Postprocessing shaders
* - Powerful math module for Vector, Matrix and Quaternion operations: [raymath] * - Powerful math module for Vector, Matrix and Quaternion operations: [raymath]
* - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, XM, MOD) * - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, QOA, XM, MOD)
* - VR stereo rendering with configurable HMD device parameters * - VR stereo rendering with configurable HMD device parameters
* - Bindings to multiple programming languages available! * - Bindings to multiple programming languages available!
* *
@@ -27,29 +27,35 @@
* - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2) * - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2)
* *
* DEPENDENCIES (included): * DEPENDENCIES (included):
* [rcore] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input (PLATFORM_DESKTOP) * [rcore][GLFW] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input
* [rlgl] glad (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading (PLATFORM_DESKTOP) * [rcore][RGFW] rgfw (ColleagueRiley - github.com/ColleagueRiley/RGFW) for window/context management and input
* [rlgl] glad/glad_gles2 (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading
* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management * [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management
* *
* OPTIONAL DEPENDENCIES (included): * OPTIONAL DEPENDENCIES (included):
* [rcore] msf_gif (Miles Fogle) for GIF recording * [rcore] msf_gif (Miles Fogle) for GIF recording
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm * [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm * [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm
* [rcore] rprand (Ramon Snatamaria) for pseudo-random numbers generation
* [rtextures] qoi (Dominic Szablewski - https://phoboslab.org) for QOI image manage
* [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) * [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
* [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG) * [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG)
* [rtextures] stb_image_resize (Sean Barret) for image resizing algorithms * [rtextures] stb_image_resize2 (Sean Barret) for image resizing algorithms
* [rtextures] stb_perlin (Sean Barret) for Perlin Noise image generation
* [rtext] stb_truetype (Sean Barret) for ttf fonts loading * [rtext] stb_truetype (Sean Barret) for ttf fonts loading
* [rtext] stb_rect_pack (Sean Barret) for rectangles packing * [rtext] stb_rect_pack (Sean Barret) for rectangles packing
* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation * [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation
* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL) * [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL)
* [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF) * [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF)
* [rmodels] Model3D (bzt) for models loading (M3D, https://bztsrc.gitlab.io/model3d) * [rmodels] m3d (bzt) for models loading (M3D, https://bztsrc.gitlab.io/model3d)
* [rmodels] vox_loader (Johann Nadalutti) for models loading (VOX)
* [raudio] dr_wav (David Reid) for WAV audio file loading * [raudio] dr_wav (David Reid) for WAV audio file loading
* [raudio] dr_flac (David Reid) for FLAC audio file loading * [raudio] dr_flac (David Reid) for FLAC audio file loading
* [raudio] dr_mp3 (David Reid) for MP3 audio file loading * [raudio] dr_mp3 (David Reid) for MP3 audio file loading
* [raudio] stb_vorbis (Sean Barret) for OGG audio loading * [raudio] stb_vorbis (Sean Barret) for OGG audio loading
* [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading * [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading
* [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading * [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading
* [raudio] qoa (Dominic Szablewski - https://phoboslab.org) for QOA audio manage
* *
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
@@ -57,7 +63,7 @@
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software: * BSD-like license that allows static linking with closed source software:
* *
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) * Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software. * will the authors be held liable for any damages arising from the use of this software.
@@ -82,9 +88,9 @@
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback #include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
#define RAYLIB_VERSION_MAJOR 5 #define RAYLIB_VERSION_MAJOR 5
#define RAYLIB_VERSION_MINOR 5 #define RAYLIB_VERSION_MINOR 6
#define RAYLIB_VERSION_PATCH 0 #define RAYLIB_VERSION_PATCH 0
#define RAYLIB_VERSION "5.5-dev" #define RAYLIB_VERSION "5.6-dev"
// Function specifiers in case library is build/used as a shared library // Function specifiers in case library is build/used as a shared library
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
@@ -737,7 +743,7 @@ typedef enum {
GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right
} GamepadButton; } GamepadButton;
// Gamepad axis // Gamepad axes
typedef enum { typedef enum {
GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis
GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis
@@ -795,7 +801,8 @@ typedef enum {
SHADER_LOC_MAP_BRDF, // Shader location: sampler2d texture: brdf SHADER_LOC_MAP_BRDF, // Shader location: sampler2d texture: brdf
SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: boneIds SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: boneIds
SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: boneWeights SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: boneWeights
SHADER_LOC_BONE_MATRICES // Shader location: array of matrices uniform: boneMatrices SHADER_LOC_BONE_MATRICES, // Shader location: array of matrices uniform: boneMatrices
SHADER_LOC_VERTEX_INSTANCE_TX // Shader location: vertex attribute: instanceTransform
} ShaderLocationIndex; } ShaderLocationIndex;
#define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO #define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO
@@ -811,6 +818,10 @@ typedef enum {
SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int)
SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int)
SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int)
SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int
SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int)
SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int)
SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int)
SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d
} ShaderUniformDataType; } ShaderUniformDataType;
@@ -877,8 +888,7 @@ typedef enum {
CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces
CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces
CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces
CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE // Layout is defined by a 4x3 cross with cubemap faces
CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirrectangular map)
} CubemapLayout; } CubemapLayout;
// Font type, defines generation method // Font type, defines generation method
@@ -944,7 +954,7 @@ typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args);
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
@@ -965,36 +975,36 @@ RLAPI void CloseWindow(void); // Close windo
RLAPI bool WindowShouldClose(void); // Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) RLAPI bool WindowShouldClose(void); // Check if application should close (KEY_ESCAPE pressed or windows close icon clicked)
RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully
RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen
RLAPI bool IsWindowHidden(void); // Check if window is currently hidden (only PLATFORM_DESKTOP) RLAPI bool IsWindowHidden(void); // Check if window is currently hidden
RLAPI bool IsWindowMinimized(void); // Check if window is currently minimized (only PLATFORM_DESKTOP) RLAPI bool IsWindowMinimized(void); // Check if window is currently minimized
RLAPI bool IsWindowMaximized(void); // Check if window is currently maximized (only PLATFORM_DESKTOP) RLAPI bool IsWindowMaximized(void); // Check if window is currently maximized
RLAPI bool IsWindowFocused(void); // Check if window is currently focused (only PLATFORM_DESKTOP) RLAPI bool IsWindowFocused(void); // Check if window is currently focused
RLAPI bool IsWindowResized(void); // Check if window has been resized last frame RLAPI bool IsWindowResized(void); // Check if window has been resized last frame
RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled
RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags (only PLATFORM_DESKTOP) RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags
RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags
RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP) RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed, resizes monitor to match window resolution
RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP) RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed, resizes window to match monitor resolution
RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable
RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable
RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP) RLAPI void RestoreWindow(void); // Restore window from being minimized/maximized
RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit)
RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit)
RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP and PLATFORM_WEB) RLAPI void SetWindowTitle(const char *title); // Set title for window
RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) RLAPI void SetWindowPosition(int x, int y); // Set window position on screen
RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window
RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
RLAPI void SetWindowMaxSize(int width, int height); // Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) RLAPI void SetWindowMaxSize(int width, int height); // Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE)
RLAPI void SetWindowSize(int width, int height); // Set window dimensions RLAPI void SetWindowSize(int width, int height); // Set window dimensions
RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP) RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f]
RLAPI void SetWindowFocused(void); // Set window focused (only PLATFORM_DESKTOP) RLAPI void SetWindowFocused(void); // Set window focused
RLAPI void *GetWindowHandle(void); // Get native window handle RLAPI void *GetWindowHandle(void); // Get native window handle
RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenWidth(void); // Get current screen width
RLAPI int GetScreenHeight(void); // Get current screen height RLAPI int GetScreenHeight(void); // Get current screen height
RLAPI int GetRenderWidth(void); // Get current render width (it considers HiDPI) RLAPI int GetRenderWidth(void); // Get current render width (it considers HiDPI)
RLAPI int GetRenderHeight(void); // Get current render height (it considers HiDPI) RLAPI int GetRenderHeight(void); // Get current render height (it considers HiDPI)
RLAPI int GetMonitorCount(void); // Get number of connected monitors RLAPI int GetMonitorCount(void); // Get number of connected monitors
RLAPI int GetCurrentMonitor(void); // Get current connected monitor RLAPI int GetCurrentMonitor(void); // Get current monitor where window is placed
RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position
RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (current video mode used by monitor) RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (current video mode used by monitor)
RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (current video mode used by monitor) RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (current video mode used by monitor)
@@ -1006,6 +1016,7 @@ RLAPI Vector2 GetWindowScaleDPI(void); // Get window
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the specified monitor RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the specified monitor
RLAPI void SetClipboardText(const char *text); // Set clipboard text content RLAPI void SetClipboardText(const char *text); // Set clipboard text content
RLAPI const char *GetClipboardText(void); // Get clipboard text content RLAPI const char *GetClipboardText(void); // Get clipboard text content
RLAPI Image GetClipboardImage(void); // Get clipboard image content
RLAPI void EnableEventWaiting(void); // Enable waiting for events on EndDrawing(), no automatic event polling RLAPI void EnableEventWaiting(void); // Enable waiting for events on EndDrawing(), no automatic event polling
RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling
@@ -1044,13 +1055,13 @@ RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR s
// NOTE: Shader functionality is not available on OpenGL 1.1 // NOTE: Shader functionality is not available on OpenGL 1.1
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
RLAPI bool IsShaderReady(Shader shader); // Check if a shader is ready RLAPI bool IsShaderValid(Shader shader); // Check if a shader is valid (loaded on GPU)
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location
RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector
RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4) RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4)
RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value for texture (sampler2d) RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value and bind the texture (sampler2d)
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
// Screen-space-related functions // Screen-space-related functions
@@ -1112,7 +1123,7 @@ RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText() RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
//------------------------------------------------------------------ //------------------------------------------------------------------
// File system functions // File system functions
@@ -1142,8 +1153,11 @@ RLAPI long GetFileModTime(const char *fileName); // Get file mo
// Compression/Encoding functionality // Compression/Encoding functionality
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree() RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree() RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree() RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree() RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree()
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
// Automation events functionality // Automation events functionality
RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
@@ -1161,12 +1175,13 @@ RLAPI void PlayAutomationEvent(AutomationEvent event);
// Input-related functions: keyboard // Input-related functions: keyboard
RLAPI bool IsKeyPressed(int key); // Check if a key has been pressed once RLAPI bool IsKeyPressed(int key); // Check if a key has been pressed once
RLAPI bool IsKeyPressedRepeat(int key); // Check if a key has been pressed again (Only PLATFORM_DESKTOP) RLAPI bool IsKeyPressedRepeat(int key); // Check if a key has been pressed again
RLAPI bool IsKeyDown(int key); // Check if a key is being pressed RLAPI bool IsKeyDown(int key); // Check if a key is being pressed
RLAPI bool IsKeyReleased(int key); // Check if a key has been released once RLAPI bool IsKeyReleased(int key); // Check if a key has been released once
RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed
RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty
RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty
RLAPI const char *GetKeyName(int key); // Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)
RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC)
// Input-related functions: gamepads // Input-related functions: gamepads
@@ -1177,10 +1192,10 @@ RLAPI bool IsGamepadButtonDown(int gamepad, int button);
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
RLAPI int GetGamepadAxisCount(int gamepad); // Get gamepad axis count for a gamepad RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get axis movement value for a gamepad axis RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis
RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB) RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB)
RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor); // Set gamepad vibration for both motors RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
// Input-related functions: mouse // Input-related functions: mouse
RLAPI bool IsMouseButtonPressed(int button); // Check if a mouse button has been pressed once RLAPI bool IsMouseButtonPressed(int button); // Check if a mouse button has been pressed once
@@ -1211,7 +1226,7 @@ RLAPI int GetTouchPointCount(void); // Get number of t
RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected
RLAPI int GetGestureDetected(void); // Get latest detected gesture RLAPI int GetGestureDetected(void); // Get latest detected gesture
RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
RLAPI float GetGestureDragAngle(void); // Get gesture drag angle RLAPI float GetGestureDragAngle(void); // Get gesture drag angle
RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
@@ -1249,7 +1264,9 @@ RLAPI void DrawCircleV(Vector2 center, float radius, Color color);
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version) RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version)
RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse
RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse (Vector version)
RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline
RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse outline (Vector version)
RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
@@ -1258,7 +1275,7 @@ RLAPI void DrawRectangleRec(Rectangle rec, Color color);
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight); // Draw a gradient-filled rectangle with custom vertex colors RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
@@ -1295,13 +1312,13 @@ RLAPI Vector2 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vect
RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles
RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles
RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle
RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2); // Check if circle collides with a line created betweeen two points [p1] and [p2]
RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle
RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle
RLAPI bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]
RLAPI bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount); // Check if point is within a polygon described by array of vertices RLAPI bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount); // Check if point is within a polygon described by array of vertices
RLAPI bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint); // Check the collision between two lines defined by two points each, returns collision point by reference RLAPI bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint); // Check the collision between two lines defined by two points each, returns collision point by reference
RLAPI bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]
RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2); // Check if circle collides with a line created betweeen two points [p1] and [p2]
RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@@ -1317,7 +1334,7 @@ RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *f
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png' RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data
RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot) RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot)
RLAPI bool IsImageReady(Image image); // Check if an image is ready RLAPI bool IsImageValid(Image image); // Check if an image is valid (data and parameters)
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success
RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer
@@ -1391,8 +1408,8 @@ RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color c
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
RLAPI void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center) RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
RLAPI void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination) RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination) RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
@@ -1403,9 +1420,9 @@ RLAPI Texture2D LoadTexture(const char *fileName);
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
RLAPI bool IsTextureReady(Texture2D texture); // Check if a texture is ready RLAPI bool IsTextureValid(Texture2D texture); // Check if a texture is valid (loaded in GPU)
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI bool IsRenderTextureReady(RenderTexture2D target); // Check if a render texture is ready RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data
@@ -1452,7 +1469,7 @@ RLAPI Font LoadFont(const char *fileName);
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
RLAPI bool IsFontReady(Font font); // Check if a font is ready RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked)
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use
RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM) RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM)
@@ -1487,7 +1504,8 @@ RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); // Get p
RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
// Text strings management functions (no UTF-8 strings, only byte chars) // Text strings management functions (no UTF-8 strings, only byte chars)
// NOTE: Some strings allocate memory internally for returned strings, just be careful! // WARNING 1: Most of these functions use internal static buffers, it's recommended to store returned data on user-side for re-use
// WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree()
RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
@@ -1495,18 +1513,18 @@ RLAPI const char *TextFormat(const char *text, ...);
RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string
RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!)
RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!)
RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter
RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor! RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor!
RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string
RLAPI const char *TextToUpper(const char *text); // Get upper case version of provided string RLAPI char *TextToUpper(const char *text); // Get upper case version of provided string
RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string RLAPI char *TextToLower(const char *text); // Get lower case version of provided string
RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
RLAPI const char *TextToSnake(const char *text); // Get Snake case notation version of provided string RLAPI char *TextToSnake(const char *text); // Get Snake case notation version of provided string
RLAPI const char *TextToCamel(const char *text); // Get Camel case notation version of provided string RLAPI char *TextToCamel(const char *text); // Get Camel case notation version of provided string
RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported) RLAPI int TextToInteger(const char *text); // Get integer value from text
RLAPI float TextToFloat(const char *text); // Get float value from text (negative values not supported) RLAPI float TextToFloat(const char *text); // Get float value from text
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Basic 3d Shapes Drawing Functions (Module: models) // Basic 3d Shapes Drawing Functions (Module: models)
@@ -1542,7 +1560,7 @@ RLAPI void DrawGrid(int slices, float spacing);
// Model management functions // Model management functions
RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials) RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials)
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material) RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material)
RLAPI bool IsModelReady(Model model); // Check if a model is ready RLAPI bool IsModelValid(Model model); // Check if a model is valid (loaded in GPU, VAO/VBOs)
RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM)
RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes)
@@ -1585,18 +1603,18 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
// Material loading/unloading functions // Material loading/unloading functions
RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file
RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
RLAPI bool IsMaterialReady(Material material); // Check if a material is ready RLAPI bool IsMaterialValid(Material material); // Check if a material is valid (shader assigned, map textures loaded in GPU)
RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM)
RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh
// Model animations loading/unloading functions // Model animations loading/unloading functions
RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount); // Load model animations from file RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount); // Load model animations from file
RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose (CPU)
RLAPI void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices (GPU skinning)
RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data
RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data
RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match
RLAPI void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)
// Collision detection functions // Collision detection functions
RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres
@@ -1623,11 +1641,11 @@ RLAPI float GetMasterVolume(void); // Get mas
// Wave/Sound loading/unloading functions // Wave/Sound loading/unloading functions
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
RLAPI bool IsWaveReady(Wave wave); // Checks if wave data is ready RLAPI bool IsWaveValid(Wave wave); // Checks if wave data is valid (data loaded and parameters)
RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSound(const char *fileName); // Load sound from file
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data
RLAPI bool IsSoundReady(Sound sound); // Checks if a sound is ready RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized)
RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data
RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadWave(Wave wave); // Unload wave data
RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void UnloadSound(Sound sound); // Unload sound
@@ -1653,7 +1671,7 @@ RLAPI void UnloadWaveSamples(float *samples); // Unload
// Music management functions // Music management functions
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data
RLAPI bool IsMusicReady(Music music); // Checks if a music stream is ready RLAPI bool IsMusicValid(Music music); // Checks if a music stream is valid (context and buffers initialized)
RLAPI void UnloadMusicStream(Music music); // Unload music stream RLAPI void UnloadMusicStream(Music music); // Unload music stream
RLAPI void PlayMusicStream(Music music); // Start music playing RLAPI void PlayMusicStream(Music music); // Start music playing
RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing
@@ -1670,7 +1688,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur
// AudioStream management functions // AudioStream management functions
RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data)
RLAPI bool IsAudioStreamReady(AudioStream stream); // Checks if an audio stream is ready RLAPI bool IsAudioStreamValid(AudioStream stream); // Checks if an audio stream is valid (buffers initialized)
RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data
RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
@@ -1685,10 +1703,10 @@ RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data
RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives the samples as 'float' RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo)
RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream
RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo)
RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline
#if defined(__cplusplus) #if defined(__cplusplus)
+389 -6
View File
@@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raymath v1.5 - Math functions to work with Vector2, Vector3, Matrix and Quaternions * raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions
* *
* CONVENTIONS: * CONVENTIONS:
* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all * - Matrix structure is defined as row-major (memory layout) but parameters naming AND all
@@ -12,7 +12,7 @@
* - Functions are always self-contained, no function use another raymath function inside, * - Functions are always self-contained, no function use another raymath function inside,
* required code is directly re-implemented inside * required code is directly re-implemented inside
* - Functions input parameters are always received by value (2 unavoidable exceptions) * - Functions input parameters are always received by value (2 unavoidable exceptions)
* - Functions use always a "result" variable for return * - Functions use always a "result" variable for return (except C++ operators)
* - Functions are always defined inline * - Functions are always defined inline
* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience) * - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)
* - No compound literals used to make sure libray is compatible with C++ * - No compound literals used to make sure libray is compatible with C++
@@ -27,10 +27,12 @@
* Define static inline functions code, so #include header suffices for use. * Define static inline functions code, so #include header suffices for use.
* This may use up lots of memory. * This may use up lots of memory.
* *
* #define RAYMATH_DISABLE_CPP_OPERATORS
* Disables C++ operator overloads for raymath types.
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5) * Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software. * will the authors be held liable for any damages arising from the use of this software.
@@ -302,6 +304,14 @@ RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2)
return result; return result;
} }
// Calculate two vectors cross product
RMAPI float Vector2CrossProduct(Vector2 v1, Vector2 v2)
{
float result = (v1.x*v2.y - v1.y*v2.x);
return result;
}
// Calculate distance between two vectors // Calculate distance between two vectors
RMAPI float Vector2Distance(Vector2 v1, Vector2 v2) RMAPI float Vector2Distance(Vector2 v1, Vector2 v2)
{ {
@@ -318,8 +328,9 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)
return result; return result;
} }
// Calculate angle between two vectors // Calculate the signed angle from v1 to v2, relative to the origin (0, 0)
// NOTE: Angle is calculated from origin point (0, 0) // NOTE: Coordinate system convention: positive X right, positive Y down,
// positive angles appear clockwise, and negative angles appear counterclockwise
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
{ {
float result = 0.0f; float result = 0.0f;
@@ -1457,19 +1468,35 @@ RMAPI int Vector4Equals(Vector4 p, Vector4 q)
RMAPI float MatrixDeterminant(Matrix mat) RMAPI float MatrixDeterminant(Matrix mat)
{ {
float result = 0.0f; float result = 0.0f;
/*
// Cache the matrix values (speed optimization) // Cache the matrix values (speed optimization)
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
// NOTE: It takes 72 multiplication to calculate 4x4 matrix determinant
result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
*/
// Using Laplace expansion (https://en.wikipedia.org/wiki/Laplace_expansion),
// previous operation can be simplified to 40 multiplications, decreasing matrix
// size from 4x4 to 2x2 using minors
// Cache the matrix values (speed optimization)
float m0 = mat.m0, m1 = mat.m1, m2 = mat.m2, m3 = mat.m3;
float m4 = mat.m4, m5 = mat.m5, m6 = mat.m6, m7 = mat.m7;
float m8 = mat.m8, m9 = mat.m9, m10 = mat.m10, m11 = mat.m11;
float m12 = mat.m12, m13 = mat.m13, m14 = mat.m14, m15 = mat.m15;
result = (m0*((m5*(m10*m15 - m11*m14) - m9*(m6*m15 - m7*m14) + m13*(m6*m11 - m7*m10))) -
m4*((m1*(m10*m15 - m11*m14) - m9*(m2*m15 - m3*m14) + m13*(m2*m11 - m3*m10))) +
m8*((m1*(m6*m15 - m7*m14) - m5*(m2*m15 - m3*m14) + m13*(m2*m7 - m3*m6))) -
m12*((m1*(m6*m11 - m7*m10) - m5*(m2*m11 - m3*m10) + m9*(m2*m7 - m3*m6))));
return result; return result;
} }
@@ -2567,7 +2594,13 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
if (!FloatEquals(det, 0)) if (!FloatEquals(det, 0))
{ {
clone.m0 /= s.x; clone.m0 /= s.x;
clone.m4 /= s.x;
clone.m8 /= s.x;
clone.m1 /= s.y;
clone.m5 /= s.y; clone.m5 /= s.y;
clone.m9 /= s.y;
clone.m2 /= s.z;
clone.m6 /= s.z;
clone.m10 /= s.z; clone.m10 /= s.z;
// Extract rotation // Extract rotation
@@ -2580,4 +2613,354 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
} }
} }
#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS)
// Optional C++ math operators
//-------------------------------------------------------------------------------
// Vector2 operators
static constexpr Vector2 Vector2Zeros = { 0, 0 };
static constexpr Vector2 Vector2Ones = { 1, 1 };
static constexpr Vector2 Vector2UnitX = { 1, 0 };
static constexpr Vector2 Vector2UnitY = { 0, 1 };
inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs)
{
return Vector2Add(lhs, rhs);
}
inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs)
{
lhs = Vector2Add(lhs, rhs);
return lhs;
}
inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs)
{
return Vector2Subtract(lhs, rhs);
}
inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs)
{
lhs = Vector2Subtract(lhs, rhs);
return lhs;
}
inline Vector2 operator * (const Vector2& lhs, const float& rhs)
{
return Vector2Scale(lhs, rhs);
}
inline const Vector2& operator *= (Vector2& lhs, const float& rhs)
{
lhs = Vector2Scale(lhs, rhs);
return lhs;
}
inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs)
{
return Vector2Multiply(lhs, rhs);
}
inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs)
{
lhs = Vector2Multiply(lhs, rhs);
return lhs;
}
inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs)
{
return Vector2Transform(lhs, rhs);
}
inline const Vector2& operator *= (Vector2& lhs, const Matrix& rhs)
{
lhs = Vector2Transform(lhs, rhs);
return lhs;
}
inline Vector2 operator / (const Vector2& lhs, const float& rhs)
{
return Vector2Scale(lhs, 1.0f/rhs);
}
inline const Vector2& operator /= (Vector2& lhs, const float& rhs)
{
lhs = Vector2Scale(lhs, 1.0f/rhs);
return lhs;
}
inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs)
{
return Vector2Divide(lhs, rhs);
}
inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs)
{
lhs = Vector2Divide(lhs, rhs);
return lhs;
}
inline bool operator == (const Vector2& lhs, const Vector2& rhs)
{
return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y);
}
inline bool operator != (const Vector2& lhs, const Vector2& rhs)
{
return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y);
}
// Vector3 operators
static constexpr Vector3 Vector3Zeros = { 0, 0, 0 };
static constexpr Vector3 Vector3Ones = { 1, 1, 1 };
static constexpr Vector3 Vector3UnitX = { 1, 0, 0 };
static constexpr Vector3 Vector3UnitY = { 0, 1, 0 };
static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 };
inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs)
{
return Vector3Add(lhs, rhs);
}
inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs)
{
lhs = Vector3Add(lhs, rhs);
return lhs;
}
inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs)
{
return Vector3Subtract(lhs, rhs);
}
inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs)
{
lhs = Vector3Subtract(lhs, rhs);
return lhs;
}
inline Vector3 operator * (const Vector3& lhs, const float& rhs)
{
return Vector3Scale(lhs, rhs);
}
inline const Vector3& operator *= (Vector3& lhs, const float& rhs)
{
lhs = Vector3Scale(lhs, rhs);
return lhs;
}
inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs)
{
return Vector3Multiply(lhs, rhs);
}
inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs)
{
lhs = Vector3Multiply(lhs, rhs);
return lhs;
}
inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs)
{
return Vector3Transform(lhs, rhs);
}
inline const Vector3& operator *= (Vector3& lhs, const Matrix& rhs)
{
lhs = Vector3Transform(lhs, rhs);
return lhs;
}
inline Vector3 operator / (const Vector3& lhs, const float& rhs)
{
return Vector3Scale(lhs, 1.0f/rhs);
}
inline const Vector3& operator /= (Vector3& lhs, const float& rhs)
{
lhs = Vector3Scale(lhs, 1.0f/rhs);
return lhs;
}
inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs)
{
return Vector3Divide(lhs, rhs);
}
inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs)
{
lhs = Vector3Divide(lhs, rhs);
return lhs;
}
inline bool operator == (const Vector3& lhs, const Vector3& rhs)
{
return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z);
}
inline bool operator != (const Vector3& lhs, const Vector3& rhs)
{
return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z);
}
// Vector4 operators
static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 };
static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 };
static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 };
static constexpr Vector4 Vector4UnitY = { 0, 1, 0, 0 };
static constexpr Vector4 Vector4UnitZ = { 0, 0, 1, 0 };
static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 };
inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs)
{
return Vector4Add(lhs, rhs);
}
inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs)
{
lhs = Vector4Add(lhs, rhs);
return lhs;
}
inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs)
{
return Vector4Subtract(lhs, rhs);
}
inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs)
{
lhs = Vector4Subtract(lhs, rhs);
return lhs;
}
inline Vector4 operator * (const Vector4& lhs, const float& rhs)
{
return Vector4Scale(lhs, rhs);
}
inline const Vector4& operator *= (Vector4& lhs, const float& rhs)
{
lhs = Vector4Scale(lhs, rhs);
return lhs;
}
inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs)
{
return Vector4Multiply(lhs, rhs);
}
inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs)
{
lhs = Vector4Multiply(lhs, rhs);
return lhs;
}
inline Vector4 operator / (const Vector4& lhs, const float& rhs)
{
return Vector4Scale(lhs, 1.0f/rhs);
}
inline const Vector4& operator /= (Vector4& lhs, const float& rhs)
{
lhs = Vector4Scale(lhs, 1.0f/rhs);
return lhs;
}
inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs)
{
return Vector4Divide(lhs, rhs);
}
inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs)
{
lhs = Vector4Divide(lhs, rhs);
return lhs;
}
inline bool operator == (const Vector4& lhs, const Vector4& rhs)
{
return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w);
}
inline bool operator != (const Vector4& lhs, const Vector4& rhs)
{
return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w);
}
// Quaternion operators
static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 };
static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 };
static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 };
inline Quaternion operator + (const Quaternion& lhs, const float& rhs)
{
return QuaternionAddValue(lhs, rhs);
}
inline const Quaternion& operator += (Quaternion& lhs, const float& rhs)
{
lhs = QuaternionAddValue(lhs, rhs);
return lhs;
}
inline Quaternion operator - (const Quaternion& lhs, const float& rhs)
{
return QuaternionSubtractValue(lhs, rhs);
}
inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs)
{
lhs = QuaternionSubtractValue(lhs, rhs);
return lhs;
}
inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs)
{
return QuaternionTransform(lhs, rhs);
}
inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs)
{
lhs = QuaternionTransform(lhs, rhs);
return lhs;
}
// Matrix operators
inline Matrix operator + (const Matrix& lhs, const Matrix& rhs)
{
return MatrixAdd(lhs, rhs);
}
inline const Matrix& operator += (Matrix& lhs, const Matrix& rhs)
{
lhs = MatrixAdd(lhs, rhs);
return lhs;
}
inline Matrix operator - (const Matrix& lhs, const Matrix& rhs)
{
return MatrixSubtract(lhs, rhs);
}
inline const Matrix& operator -= (Matrix& lhs, const Matrix& rhs)
{
lhs = MatrixSubtract(lhs, rhs);
return lhs;
}
inline Matrix operator * (const Matrix& lhs, const Matrix& rhs)
{
return MatrixMultiply(lhs, rhs);
}
inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs)
{
lhs = MatrixMultiply(lhs, rhs);
return lhs;
}
//-------------------------------------------------------------------------------
#endif // C++ operators
#endif // RAYMATH_H #endif // RAYMATH_H
+600 -193
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+122
View File
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
inkscape:export-filename="blocker_closed.png"
inkscape:export-xdpi="24"
inkscape:export-ydpi="24"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
sodipodi:docname="block.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showguides="true"
inkscape:zoom="1.1398148"
inkscape:cx="87.294883"
inkscape:cy="268.026"
inkscape:window-width="2560"
inkscape:window-height="1414"
inkscape:window-x="2560"
inkscape:window-y="1106"
inkscape:window-maximized="1"
inkscape:current-layer="g5">
<sodipodi:guide
position="0,256"
orientation="0,1"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="256,256"
orientation="1,0"
id="guide2"
inkscape:locked="false" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Blocker Open"
inkscape:groupmode="layer"
id="layer1"
style="display:none">
<rect
style="fill:#b4d273;fill-opacity:1;fill-rule:evenodd;stroke-width:0.742756"
id="rect1"
width="282.46313"
height="512"
x="114.76843"
y="0"
ry="141.23157" />
<rect
style="fill:#d6d6d6;fill-opacity:1;fill-rule:evenodd;stroke-width:0.950718"
id="rect2"
width="379.43814"
height="45.092152"
x="-445.71906"
y="233.45392"
transform="rotate(-90)" />
<circle
style="fill:#d6d6d6;fill-opacity:1"
id="path1"
cx="255.99994"
cy="106.15759"
r="56.149471" />
<circle
style="fill:#d6d6d6;fill-opacity:1"
id="path1-0"
cx="256"
cy="407.41348"
r="56.149471" />
</g>
<g
inkscape:label="Blocker Closed"
inkscape:groupmode="layer"
id="g5"
transform="rotate(-90,256,256)">
<rect
style="fill:#c35355;fill-opacity:1;fill-rule:evenodd;stroke-width:0.742756"
id="rect3"
width="282.46313"
height="512"
x="114.76843"
y="0"
ry="141.23157" />
<rect
style="fill:#d6d6d6;fill-opacity:1;fill-rule:evenodd;stroke-width:0.950718"
id="rect4"
width="379.43814"
height="45.092152"
x="-445.71906"
y="233.45392"
transform="rotate(-90)" />
<circle
style="fill:#d6d6d6;fill-opacity:1"
id="circle4"
cx="255.99994"
cy="106.15759"
r="56.149471" />
<circle
style="fill:#d6d6d6;fill-opacity:1"
id="circle5"
cx="256"
cy="407.41348"
r="56.149471" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

+81
View File
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
inkscape:export-filename="round-delete.png"
inkscape:export-xdpi="24"
inkscape:export-ydpi="24"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
sodipodi:docname="textures.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showguides="true"
inkscape:zoom="1.1398148"
inkscape:cx="87.73355"
inkscape:cy="268.026"
inkscape:window-width="2560"
inkscape:window-height="1414"
inkscape:window-x="2560"
inkscape:window-y="1106"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<sodipodi:guide
position="0,256"
orientation="0,1"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="256,256"
orientation="1,0"
id="guide2"
inkscape:locked="false" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<circle
style="fill:#c35355;fill-opacity:1"
id="path2"
cx="256"
cy="256"
r="256" />
<rect
style="fill:#d6d6d6;fill-opacity:1;fill-rule:evenodd"
id="rect2"
width="419.79556"
height="45.092152"
x="-571.93646"
y="-22.546076"
transform="rotate(-135)" />
<rect
style="fill:#d6d6d6;fill-opacity:1;fill-rule:evenodd"
id="rect2-0"
width="419.79556"
height="45.092152"
x="-209.89778"
y="339.49261"
transform="rotate(-45)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.
Binary file not shown.
+96
View File
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
inkscape:export-filename="textures/split.png"
inkscape:export-xdpi="24"
inkscape:export-ydpi="24"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
sodipodi:docname="split.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showguides="true"
inkscape:zoom="0.80597077"
inkscape:cx="-42.805522"
inkscape:cy="129.65731"
inkscape:window-width="2560"
inkscape:window-height="1414"
inkscape:window-x="2560"
inkscape:window-y="1106"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<sodipodi:guide
position="0,256"
orientation="0,1"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="256,256"
orientation="1,0"
id="guide2"
inkscape:locked="false" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#b4d273;fill-opacity:1;fill-rule:evenodd;stroke-width:0.742756"
id="rect1"
width="282.46313"
height="512"
x="-1027.9529"
y="0"
ry="141.23157" />
<circle
style="fill:#b4d273;fill-opacity:1"
id="path2"
cx="256"
cy="256"
r="256" />
<circle
style="fill:#d6d6d6;fill-opacity:1;stroke-width:0.832073"
id="path2-7"
cx="256"
cy="256"
r="213.01056" />
<rect
style="fill:#b4d273;fill-opacity:1;fill-rule:evenodd"
id="rect2"
width="45.621445"
height="300.92609"
x="233.18927"
y="105.53696"
ry="22.810722" />
<rect
style="fill:#b4d273;fill-opacity:1;fill-rule:evenodd"
id="rect2-6"
width="45.621445"
height="300.92609"
x="233.18927"
y="-406.46304"
ry="22.810722"
transform="rotate(90)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+81
View File
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
inkscape:export-filename="round-delete.png"
inkscape:export-xdpi="24"
inkscape:export-ydpi="24"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
sodipodi:docname="textures.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showguides="true"
inkscape:zoom="1.1398148"
inkscape:cx="87.73355"
inkscape:cy="268.026"
inkscape:window-width="2560"
inkscape:window-height="1414"
inkscape:window-x="2560"
inkscape:window-y="1106"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<sodipodi:guide
position="0,256"
orientation="0,1"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="256,256"
orientation="1,0"
id="guide2"
inkscape:locked="false" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<circle
style="fill:#c35355;fill-opacity:1"
id="path2"
cx="256"
cy="256"
r="256" />
<rect
style="fill:#d6d6d6;fill-opacity:1;fill-rule:evenodd"
id="rect2"
width="419.79556"
height="45.092152"
x="-571.93646"
y="-22.546076"
transform="rotate(-135)" />
<rect
style="fill:#d6d6d6;fill-opacity:1;fill-rule:evenodd"
id="rect2-0"
width="419.79556"
height="45.092152"
x="-209.89778"
y="339.49261"
transform="rotate(-45)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

+41 -5
View File
@@ -1,14 +1,17 @@
#include "app-manager.h" #include "app-manager.h"
#include "datatypes.h"
#include "interaction-manager.h" #include "interaction-manager.h"
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "graph-manager.h" #include "graph-manager.h"
#include "signal-manager.h"
#include "midi-node.h" #include "midi-node.h"
#include "state.h" #include "state.h"
#include "ui.h" #include "ui.h"
#include <memory> #include <memory>
#include <fstream> #include <fstream>
#include <raylib.h>
namespace VISEQ::APP{ namespace VISEQ::APP{
void AppManager::init(){ void AppManager::init(){
@@ -18,10 +21,35 @@ namespace VISEQ::APP{
canvas->camera.zoom = 1.0f; canvas->camera.zoom = 1.0f;
} }
void AppManager::loadTextures(){
TEXTURES::tex_connector = LoadTexture("resources/textures/connector.png");
TEXTURES::tex_connector_hover = LoadTexture("resources/textures/connector_hover.png");
TEXTURES::tex_connector_pressed = LoadTexture("resources/textures/connector_pressed.png");
TEXTURES::tex_connector_connected = LoadTexture("resources/textures/connector_connected.png");
TEXTURES::tex_delete = LoadTexture("resources/textures/delete.png");
TEXTURES::tex_split = LoadTexture("resources/textures/split.png");
TEXTURES::tex_blocker_open = LoadTexture("resources/textures/blocker_open.png");
TEXTURES::tex_blocker_closed= LoadTexture("resources/textures/blocker_closed.png");
TEXTURES::tex_delete_hover = LoadTexture("resources/textures/delete_hover.png");
TEXTURES::tex_split_hover = LoadTexture("resources/textures/split_hover.png");
TEXTURES::tex_blocker_open_hover = LoadTexture("resources/textures/blocker_open_hover.png");
TEXTURES::tex_blocker_closed_hover = LoadTexture("resources/textures/blocker_closed_hover.png");
TEXTURES::tex_delete_pressed = LoadTexture("resources/textures/delete_pressed.png");
TEXTURES::tex_split_pressed = LoadTexture("resources/textures/split_pressed.png");
TEXTURES::tex_blocker_open_pressed = LoadTexture("resources/textures/blocker_open_pressed.png");
TEXTURES::tex_blocker_closed_pressed = LoadTexture("resources/textures/blocker_closed_pressed.png");
}
void AppManager::close(){ void AppManager::close(){
std::ofstream file("state.json"); std::ofstream file("state.json");
file << json(*this); file << json(*this);
std::cout << std::setw(4) << json(*this) << std::endl; std::cout << std::setw(4) << json(*this) << std::endl;
sm->midi.all_notes_off();
for(auto &p : sm->midi.midi_outs){
p.second->close_port();
}
} }
void AppManager::startSignals(){ void AppManager::startSignals(){
@@ -110,11 +138,19 @@ namespace VISEQ::APP{
for(auto& n : gm->getMidiNodes()){ for(auto& n : gm->getMidiNodes()){
auto nc = std::dynamic_pointer_cast<MidiNode>(n.lock()); auto nc = std::dynamic_pointer_cast<MidiNode>(n.lock());
for(auto& mo : sm->midi.midi_out_ports){ for(auto& mo : sm->midi.midi_out_ports){
if(!nc->midi_outs.contains(mo.number) && mo.enabled){ if(!nc->selected_midi_outs.contains(mo.number) && mo.enabled){
nc->midi_outs[mo.number] = {mo.number, mo.port.port_name, false}; nc->selected_midi_outs[mo.number] = {mo.number, false, mo.port.port_name};
} }
if(nc->midi_outs.contains(mo.number) && !mo.enabled){ if(nc->selected_midi_outs.contains(mo.number) && !mo.enabled){
nc->midi_outs.erase(mo.number); nc->selected_midi_outs.erase(mo.number);
}
}
for(auto& mo : sm->midi.virtual_midi_out_ports){
if(!nc->selected_midi_outs.contains(mo.number) && mo.enabled){
nc->selected_midi_outs[mo.number] = {mo.number, false, mo.name};
}
if(nc->selected_midi_outs.contains(mo.number) && !mo.enabled){
nc->selected_midi_outs.erase(mo.number);
} }
} }
} }
@@ -139,8 +175,8 @@ namespace VISEQ::APP{
canvas->drawStart(); canvas->drawStart();
canvas->draw(); canvas->draw();
gm->drawNodes(SCREEN_MOUSE, canvas->camera);
gm->drawEdges(SCREEN_MOUSE, canvas->camera); gm->drawEdges(SCREEN_MOUSE, canvas->camera);
gm->drawNodes(SCREEN_MOUSE, canvas->camera);
sm->drawSignals(SCREEN_MOUSE, canvas->camera); sm->drawSignals(SCREEN_MOUSE, canvas->camera);
im.draw(); im.draw();
+1
View File
@@ -30,6 +30,7 @@ namespace VISEQ::APP {
UI::AppUI ui; UI::AppUI ui;
void init(); void init();
void loadTextures();
void close(); void close();
void startSignals(); void startSignals();
void loadState(); void loadState();
+45 -1
View File
@@ -12,6 +12,45 @@ inline bool ViButton(Vec2Df mp, float x, float y, float radius, Color color){
return (Vector2Distance(mp, (Vector2){x,y}) < radius && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)); return (Vector2Distance(mp, (Vector2){x,y}) < radius && IsMouseButtonPressed(MOUSE_BUTTON_LEFT));
} }
inline bool ViTexButton(Vec2Df mp, Vec2Df position, float rotation, float radius, Texture2D tex, Texture2D tex_hover, Texture2D tex_pressed, Color color){
float scale = (radius*2.0f) / (float)tex.width;
Vec2Df start_position = position - Vec2Df((tex.width*scale) / 2.0f, (tex.height*scale) / 2.0f);
Vec2Df center_pos = start_position.rotateAround(position, rotation);
bool hover = Vector2Distance(mp, position) < radius;
bool pressed = hover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
if(!hover && !pressed) DrawTexturePro(tex, Rectangle(0.0, 0.0, tex.width, tex.height), Rectangle(center_pos.x, center_pos.y, tex.width*scale, tex.height*scale), Vec2Df(0.0f,tex.height*scale/2.0f), rotation, color);
if(hover) DrawTexturePro(tex_hover, Rectangle(0.0, 0.0, tex.width, tex.height), Rectangle(center_pos.x, center_pos.y, tex.width*scale, tex.height*scale), Vec2Df(0.0f,tex.height*scale/2.0f), rotation, color);
if(pressed) DrawTexturePro(tex_pressed, Rectangle(0.0, 0.0, tex.width, tex.height), Rectangle(center_pos.x, center_pos.y, tex.width*scale, tex.height*scale), Vec2Df(0.0f,tex.height*scale/2.0f), rotation, color);
return pressed;
}
inline bool ViTexButton(Vec2Df mp, Vec2Df position, float rotation, float radius, Texture2D tex, Texture2D tex_hover, Color color){
float scale = (radius*2.0f) / (float)tex.width;
Vec2Df start_position = position - Vec2Df((tex.width*scale) / 2.0f, (tex.height*scale) / 2.0f);
Vec2Df center_pos = start_position.rotateAround(position, rotation);
bool hover = Vector2Distance(mp, position) < radius;
bool pressed = hover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
if(!hover) DrawTexturePro(tex, Rectangle(0.0, 0.0, tex.width, tex.height), Rectangle(center_pos.x, center_pos.y, tex.width*scale, tex.height*scale), Vec2Df(0.0f,tex.height*scale/2.0f), rotation, color);
if(hover) DrawTexturePro(tex_hover, Rectangle(0.0, 0.0, tex.width, tex.height), Rectangle(center_pos.x, center_pos.y, tex.width*scale, tex.height*scale), Vec2Df(0.0f,tex.height*scale/2.0f), rotation, color);
return pressed;
}
inline bool ViTexButton(Vec2Df mp, Vec2Df position, float rotation, float radius, Texture2D tex, Color color){
float scale = (radius*2.0f) / (float)tex.width;
Vec2Df start_position = position - Vec2Df((tex.width*scale) / 2.0f, (tex.height*scale) / 2.0f);
Vec2Df center_pos = start_position.rotateAround(position, rotation);
bool hover = Vector2Distance(mp, position) < radius;
bool pressed = hover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
DrawTexturePro(tex, Rectangle(0.0, 0.0, tex.width, tex.height), Rectangle(center_pos.x, center_pos.y, tex.width*scale, tex.height*scale), Vec2Df(0.0f,tex.height*scale/2.0f), rotation, color);
return pressed;
}
inline bool ViButton(Vec2Df mp, Vec2Df position, float radius, Color color){ inline bool ViButton(Vec2Df mp, Vec2Df position, float radius, Color color){
return ViButton(mp, position.x, position.y, radius, color); return ViButton(mp, position.x, position.y, radius, color);
} }
@@ -30,7 +69,12 @@ inline bool ViSegButton(Vec2Df mp, float x, float y, float start_angle, float en
inline void DrawCenteredText(std::string text, Vec2Df position, float text_size, Color color){ inline void DrawCenteredText(std::string text, Vec2Df position, float text_size, Color color){
float offset = MeasureText(text.c_str(), text_size); float offset = MeasureText(text.c_str(), text_size);
DrawText(text.c_str(), position.x-offset/2.0f, position.y-text_size/2.0f, text_size, color); //DrawText(text.c_str(), position.x-offset/2.0f, position.y-text_size/2.0f, text_size, color);
DrawTextEx(VISEQ::APP::inter, text.c_str(), Vec2Df(position.x-offset/2.0f, position.y-(float)text_size/2.0f+1), text_size, 2.0f, color);
}
inline void DrawText(std::string text, Vec2Df position, float text_size, Color color){
DrawText(text.c_str(), position.x, position.y-text_size/2.0f, text_size, color);
} }
namespace VISEQ::APP::UI{ namespace VISEQ::APP::UI{
+2 -2
View File
@@ -21,14 +21,14 @@ namespace VISEQ::APP::CANVAS {
} }
void Canvas::pickUp() { void Canvas::pickUp() {
std::cout << "canvas pickUp" << std::endl; //std::cout << "canvas pickUp" << std::endl;
BASE::Draggable::pickUp(); BASE::Draggable::pickUp();
select_start = SCREEN_MOUSE; select_start = SCREEN_MOUSE;
state->pushEvent({getPtr(), Interaction::DESELECT}); state->pushEvent({getPtr(), Interaction::DESELECT});
} }
void Canvas::putDown() { void Canvas::putDown() {
std::cout << "canvas putDown" << std::endl; //std::cout << "canvas putDown" << std::endl;
BASE::Draggable::putDown(); BASE::Draggable::putDown();
state->pushEvent({getPtr(), Interaction::SELECT}); state->pushEvent({getPtr(), Interaction::SELECT});
} }
+7
View File
@@ -13,4 +13,11 @@ namespace VISEQ::APP {
} }
} }
std::shared_ptr<Clipboard> Clipboard::get() {
if(!Clipboard::instance){
Clipboard::instance.reset(new Clipboard());
}
return Clipboard::instance;
}
} }
+3
View File
@@ -14,5 +14,8 @@ namespace VISEQ::APP {
void copyNodes(GRAPH::NODES::VEC_SPTR_Node selected_nodes); void copyNodes(GRAPH::NODES::VEC_SPTR_Node selected_nodes);
inline static std::shared_ptr<Clipboard> instance;
static std::shared_ptr<Clipboard> get();
}; };
} }
+2 -2
View File
@@ -82,14 +82,14 @@ namespace VISEQ::GRAPH::NODES {
void ConfigNode::update() { void ConfigNode::update() {
Node::update(); Node::update();
mode = state->node_mode; //mode = state->node_mode;
} }
void ConfigNode::interact(){ void ConfigNode::interact(){
float wheel = GetMouseWheelMove(); float wheel = GetMouseWheelMove();
if(KEYS_DOWN.ctrl && !KEYS_DOWN.alt){ if(KEYS_DOWN.ctrl && !KEYS_DOWN.alt){
switch(state->node_mode){ switch(mode){
case 0:{ case 0:{
midiNote.note += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; midiNote.note += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel;
break;} break;}
+90
View File
@@ -0,0 +1,90 @@
#include "connector.h"
#include "helper.h"
#include "node.h"
#include "raymath.h"
#include "state.h"
#include "button.h"
#include <execution>
#include <memory>
namespace VISEQ::GRAPH {
GraphItemType Connector::getType() {
return GraphItemType::CONNECTOR;
}
std::shared_ptr<Connector> Connector::getPtr(){
return shared_from_this();
}
bool Connector::hovering() {
return partner.expired() && CheckCollisionPointCircle(SCREEN_MOUSE, position, radius);
}
void Connector::setParent(std::shared_ptr<GraphItem> _parent){
parent = _parent;
}
void Connector::setPosition(Vec2Df pos) {
center_position = pos;
parent_position = pos;
}
void Connector::setOrbit(float r) {
orbit = r;
}
void Connector::update() {
if(hovering()) state->pushEvent({getPtr(), APP::Interaction::HOVER});
if(hovering() && clicked()) state->pushEvent({getPtr(), APP::Interaction::PICKUP});
if(pickedUp()) state->pushEvent({getPtr(), APP::Interaction::DRAG});
if(picked_up && released()) state->pushEvent({getPtr(), APP::Interaction::PUTDOWN});
if(connected) {
state->pushEvent({getPtr(), APP::Interaction::CONNECT});
connected = false;
}
if(partner.expired()) {
position = center_position.orbitAlongVector(SCREEN_MOUSE, orbit);
position_text = center_position.orbitAlongVector(SCREEN_MOUSE, orbit+10);
}
if(!partner.expired()) {
position = center_position.orbitAlongVector(partner.lock()->position, orbit);
position_text = center_position.orbitAlongVector(partner.lock()->position, orbit+10);
}
if(new_partner) {
new_partner = false;
state->pushEvent({getPtr(), APP::Interaction::CONNECT});
}
//parent_position = std::dynamic_pointer_cast<NODES::Node>(parent.lock())->position;
}
void Connector::draw() {
BASE::Connectable::draw();
float opacity = Clamp((400.0f - Clamp(position.dist(SCREEN_MOUSE), 0.0f, 400.0f)) / 400.0f, 0.0f, 1.0f);
float rotation = 0.0f;
if(partner.expired()) rotation = HELPER::GetRotation(parent_position, SCREEN_MOUSE) + 90.0f;
if(!partner.expired()) {
rotation = HELPER::GetRotation(parent_position, partner.lock()->position) + 90.0f;
opacity = 1.0f;
}
if(connecting) opacity = 1.0f;
if(partner.expired() && !connecting) ViTexButton(SCREEN_MOUSE, position, rotation, 8.0f,
TEXTURES::tex_connector, TEXTURES::tex_connector_hover, TEXTURES::tex_connector_pressed,
ColorLerp(Fade(VS_COLOR_WHITE, .0f), Fade(VS_COLOR_WHITE, 1.0f), opacity));
if(!partner.expired() || connecting) ViTexButton(SCREEN_MOUSE, position, rotation, 8.0f,
TEXTURES::tex_connector_connected, TEXTURES::tex_connector_hover,
ColorLerp(Fade(VS_COLOR_WHITE, .0f), Fade(VS_COLOR_WHITE, 1.0f), opacity));
//int partner_id = -1;
//if(!partner.expired()) partner_id = std::dynamic_pointer_cast<Connector>(partner.lock())->id;
//DrawTextPro(GetFontDefault(), std::format("{} {}", id, partner_id).c_str(), position_text, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
//DrawText(std::format("{}", id), position + Vec2Df(100.0f,100.0f), 8.0f, Color(255, 0, 0));
}
}
+15 -53
View File
@@ -3,12 +3,10 @@
#include "connectable.h" #include "connectable.h"
#include "datatypes.h" #include "datatypes.h"
#include "graph-item.h" #include "graph-item.h"
//#include "interaction-event.h"
#include "raymath.h"
#include "state.h"
#include "vmath.h" #include "vmath.h"
#include <fcntl.h> #include <fcntl.h>
#include <memory> #include <memory>
#include <raylib.h>
namespace VISEQ::GRAPH { namespace VISEQ::GRAPH {
class Connector : public BASE::Connectable, public GraphItem, public std::enable_shared_from_this<Connector> { class Connector : public BASE::Connectable, public GraphItem, public std::enable_shared_from_this<Connector> {
@@ -18,6 +16,8 @@ namespace VISEQ::GRAPH {
Connector(std::shared_ptr<GraphItem> parent, Vec2Df center_position, float orbit) : orbit(orbit) { Connector(std::shared_ptr<GraphItem> parent, Vec2Df center_position, float orbit) : orbit(orbit) {
setPosition(center_position); setPosition(center_position);
setParent(parent); setParent(parent);
_id++;
id = _id;
} }
std::weak_ptr<GraphItem> parent; std::weak_ptr<GraphItem> parent;
@@ -27,58 +27,20 @@ namespace VISEQ::GRAPH {
float radius = 8.0f; float radius = 8.0f;
float orbit = 20.0f; float orbit = 20.0f;
Vec2Df center_position; Vec2Df center_position;
Vec2Df parent_position;
Vec2Df position_text;
inline static int _id = 0;
int id = 0;
GraphItemType getType() override{ GraphItemType getType() override;
return GraphItemType::CONNECTOR;
}
std::shared_ptr<Connector> getPtr(){ std::shared_ptr<Connector> getPtr();
return shared_from_this();
}
virtual bool hovering() override { virtual bool hovering() override;
return partner.expired() && CheckCollisionPointCircle(SCREEN_MOUSE, position, radius); void setParent(std::shared_ptr<GraphItem> _parent);
} void setPosition(Vec2Df pos) override;
void setOrbit(float r);
void setParent(std::shared_ptr<GraphItem> _parent){ void update() override;
parent = _parent; void draw() override;
}
void setPosition(Vec2Df pos) override {
center_position = pos;
}
void setOrbit(float r) {
orbit = r;
}
void update() override {
if(hovering()) state->pushEvent({getPtr(), APP::Interaction::HOVER});
if(hovering() && clicked()) state->pushEvent({getPtr(), APP::Interaction::PICKUP});
if(pickedUp()) state->pushEvent({getPtr(), APP::Interaction::DRAG});
if(picked_up && released()) state->pushEvent({getPtr(), APP::Interaction::PUTDOWN});
if(connected) {
state->pushEvent({getPtr(), APP::Interaction::CONNECT});
connected = false;
}
if(partner.expired()) position = center_position.orbitAlongVector(SCREEN_MOUSE, orbit);
if(!partner.expired()) position = center_position .orbitAlongVector(partner.lock()->position, orbit);
if(new_partner) {
new_partner = false;
state->pushEvent({getPtr(), APP::Interaction::CONNECT});
}
}
void draw() override {
BASE::Connectable::draw();
float opacity = 150.0f - Clamp(position.dist(SCREEN_MOUSE), 0.0f, 150.0f);
if(hovering()){
DrawCircle(position.x, position.y, 8.0f, (Color){108, 203, 237, 255});
} else {
DrawCircle(position.x, position.y, 8.0f, (Color){108, 153, 187, (unsigned char)opacity});
}
}
}; };
} }
+31 -1
View File
@@ -15,6 +15,7 @@
#define VS_COLOR_PURPLE (Color){158, 134, 200, 255} #define VS_COLOR_PURPLE (Color){158, 134, 200, 255}
#define VS_COLOR_PINK (Color){176, 82, 121, 255} #define VS_COLOR_PINK (Color){176, 82, 121, 255}
#define VS_COLOR_BLUE (Color){108, 153, 187, 255} #define VS_COLOR_BLUE (Color){108, 153, 187, 255}
#define VS_COLOR_LIGHTBLUE (Color){143, 206, 255, 255}
#define VS_COLOR_RED (Color){195, 83, 85, 255} #define VS_COLOR_RED (Color){195, 83, 85, 255}
#define VS_COLOR_BROWN (Color){84, 75, 61, 255} #define VS_COLOR_BROWN (Color){84, 75, 61, 255}
@@ -22,13 +23,36 @@
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
using json = nlohmann::json; using json = nlohmann::json;
#include <raylib.h>
#include <cmath>
#include <math.h> #include <math.h>
#include "libremidi/libremidi.hpp" #include "libremidi/libremidi.hpp"
#define RANGE_FILTER(L) std::ranges::views::filter(L) #define RANGE_FILTER(L) std::ranges::views::filter(L)
namespace VISEQ::APP{
inline Font inter;
}
namespace VISEQ::TEXTURES {
inline Texture2D tex_connector;
inline Texture2D tex_connector_hover;
inline Texture2D tex_connector_pressed;
inline Texture2D tex_connector_connected;
inline Texture2D tex_delete;
inline Texture2D tex_split;
inline Texture2D tex_blocker_open;
inline Texture2D tex_blocker_closed;
inline Texture2D tex_delete_hover;
inline Texture2D tex_split_hover;
inline Texture2D tex_blocker_open_hover;
inline Texture2D tex_blocker_closed_hover;
inline Texture2D tex_delete_pressed;
inline Texture2D tex_split_pressed;
inline Texture2D tex_blocker_open_pressed;
inline Texture2D tex_blocker_closed_pressed;
}
namespace VISEQ::GRAPH::NODES { namespace VISEQ::GRAPH::NODES {
enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM}; enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM};
} }
@@ -89,6 +113,12 @@ namespace VISEQ::MIDI{
bool enabled; bool enabled;
}; };
struct VirtualMidiOutPort{
int number;
bool enabled;
std::string name;
};
struct MidiOut{ struct MidiOut{
libremidi::midi_out out; libremidi::midi_out out;
int number; int number;
-1
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "moveable.h" #include "moveable.h"
#include "raylib.h"
#include "selectable.h" #include "selectable.h"
#include "state.h" #include "state.h"
#include "vmath.h" #include "vmath.h"
+1 -1
View File
@@ -32,7 +32,7 @@ namespace VISEQ::GRAPH::EDGES {
float speed = 0; float speed = 0;
float bpm = 120.0f; float bpm = 120.0f;
float connector_offset = 8.0f; float connector_offset = 2.0f;
float switches_offset = 25.0f; float switches_offset = 25.0f;
virtual bool GActive(); virtual bool GActive();
+79 -54
View File
@@ -2,6 +2,7 @@
#include "config-node.h" #include "config-node.h"
#include "datatypes.h" #include "datatypes.h"
#include "helper.h"
#include "state.h" #include "state.h"
#include "vmath.h" #include "vmath.h"
#include "raylib.h" #include "raylib.h"
@@ -52,7 +53,7 @@ namespace VISEQ::GRAPH{
void GraphManager::addNode(SPTR_Node node){ void GraphManager::addNode(SPTR_Node node){
std::cout << "added node " << node->id << std::endl; std::cout << "added node " << node->id << std::endl;
nodes.insert(nodes.end(), node); nodes.insert(nodes.end(), node);
node->update(); nodes.back()->update();
} }
void GraphManager::addConnection(WPTR_Node from, WPTR_Node to){ void GraphManager::addConnection(WPTR_Node from, WPTR_Node to){
@@ -63,10 +64,19 @@ namespace VISEQ::GRAPH{
edges.back()->edgeType = et; edges.back()->edgeType = et;
edges.back()->start = from; edges.back()->start = from;
edges.back()->end = to; edges.back()->end = to;
from.lock()->update();
to.lock()->update();
from.lock()->connectors.back()->partner = to.lock()->getConnector();
to.lock()->connectors.back()->partner = from.lock()->getConnector();
edges.back()->start_conn = from.lock()->connectors.back(); edges.back()->start_conn = from.lock()->connectors.back();
edges.back()->end_conn = to.lock()->connectors.back(); edges.back()->end_conn = to.lock()->connectors.back();
from.lock()->connections.push_back(edges.back()); from.lock()->connections.push_back(edges.back());
to.lock()->connections.push_back(edges.back()); to.lock()->connections.push_back(edges.back());
} }
} }
@@ -115,24 +125,25 @@ namespace VISEQ::GRAPH{
VEC_SPTR_Node GraphManager::getCopiesOfSelectedNodes(){ VEC_SPTR_Node GraphManager::getCopiesOfSelectedNodes(){
VEC_SPTR_Node copied_nodes; VEC_SPTR_Node copied_nodes;
for(auto n : selected_nodes){ for(auto n : selected_nodes){
copied_nodes.insert(copied_nodes.end(), std::make_shared<Node>(*n)); //copied_nodes.insert(copied_nodes.end(), std::make_shared<Node>(*n));
/*if(n->getNodeType() == NodeType::MIDINODE) copied_nodes.insert(copied_nodes.end(), std::make_shared<MidiNode>(*n));*/
/*if(n->getNodeType() == NodeType::CONFIGNODE) copied_nodes.insert(copied_nodes.end(), std::make_shared<ConfigNode>(*n));*/ if(n->getNodeType() == NodeType::MIDINODE) copied_nodes.insert(copied_nodes.end(), std::dynamic_pointer_cast<MidiNode>(n));
if(n->getNodeType() == NodeType::CONFIGNODE) copied_nodes.insert(copied_nodes.end(), std::dynamic_pointer_cast<ConfigNode>(n));
copied_nodes.back()->deselect(); copied_nodes.back()->deselect();
} }
return copied_nodes; return copied_nodes;
} }
SPTR_Node GraphManager::copyNode(SPTR_Node n, Vec2Df position){ SPTR_Node GraphManager::copyNode(const SPTR_Node n, Vec2Df position){
std::cout << "copy basenode" << std::endl; std::cout << "copy basenode" << std::endl;
nodes.insert(nodes.end(), std::make_shared<Node>(*n)); if(n->getNodeType() == NodeType::MIDINODE) nodes.insert(nodes.end(), std::dynamic_pointer_cast<MidiNode>(n));
/*if(n->getNodeType() == NodeType::MIDINODE) nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));*/ if(n->getNodeType() == NodeType::CONFIGNODE) nodes.insert(nodes.end(), std::dynamic_pointer_cast<ConfigNode>(n));
/*if(n->getNodeType() == NodeType::CONFIGNODE) nodes.insert(nodes.end(), std::make_shared<ConfigNode>(*n));*/
nodes.back()->setPosition(position); nodes.back()->setPosition(position);
return nodes.back(); return nodes.back();
} }
SPTR_Node GraphManager::copyNode(std::shared_ptr<MidiNode> n, Vec2Df position){ SPTR_Node GraphManager::copyNode(const std::shared_ptr<MidiNode> n, Vec2Df position){
std::cout << "copy midinode" << std::endl; std::cout << "copy midinode" << std::endl;
nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n)); nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));
nodes.back()->clearConnectors(); nodes.back()->clearConnectors();
@@ -146,6 +157,12 @@ namespace VISEQ::GRAPH{
} }
} }
void GraphManager::cycleModeOfSelectedNodes(bool direction){
for(auto n: selected_nodes){
n->cycleMode(direction);
}
}
void GraphManager::reset(){ void GraphManager::reset(){
counter.clear(); counter.clear();
} }
@@ -190,10 +207,15 @@ namespace VISEQ::GRAPH{
return edges.back(); return edges.back();
} }
WPTR_Node GraphManager::next(WPTR_Node current, WPTR_Node last){ VEC_WPTR_Edge GraphManager::getPassableConnections(WPTR_Node node){
VEC_WPTR_Edge possible_connections = current.lock()->connections | RANGE_FILTER([current](WPTR_Edge c){ VEC_WPTR_Edge passable_connections = node.lock()->connections | RANGE_FILTER([node](WPTR_Edge c){
return (c.lock()->getEdgeType() == EdgeType::MIDIEDGE) && ((c.lock()->start.lock() == current.lock() && c.lock()->pass_forward) || (c.lock()->end.lock() == current.lock() && c.lock()->pass_backward)); return (c.lock()->getEdgeType() == EdgeType::MIDIEDGE) && ((c.lock()->start.lock() == node.lock() && c.lock()->pass_forward) || (c.lock()->end.lock() == node.lock() && c.lock()->pass_backward));
}) | std::ranges::to<VEC_WPTR_Edge>(); }) | std::ranges::to<VEC_WPTR_Edge>();
return passable_connections;
}
WPTR_Node GraphManager::next(WPTR_Node current, WPTR_Node last){
VEC_WPTR_Edge possible_connections = getPassableConnections(current);
if(possible_connections.empty()) return SPTR_Node(nullptr); if(possible_connections.empty()) return SPTR_Node(nullptr);
@@ -291,26 +313,32 @@ namespace VISEQ::GRAPH{
void GraphManager::pasteNodesAndEdges(VEC_SPTR_Node nodes, Vec2Df position){ void GraphManager::pasteNodesAndEdges(VEC_SPTR_Node nodes, Vec2Df position){
deselect();
std::cout << "nodes size " << nodes.size() << std::endl;
VEC_SPTR_Edge copy_connections; VEC_SPTR_Edge copy_connections;
for(auto c : edges){ for(auto c : edges){
if(std::ranges::contains(nodes, c->start.lock()) && std::ranges::contains(nodes, c->end.lock())) { if(std::ranges::contains(nodes, c->start.lock()) && std::ranges::contains(nodes, c->end.lock())) {
copy_connections.push_back(std::make_shared<Edge>(*c)); copy_connections.push_back(std::make_shared<Edge>(*c));
} }
} }
std::cout << copy_connections.size() << std::endl; std::cout << "copy_connections size " << copy_connections.size() << std::endl;
Vec2Df insert_pos = nodes.begin()->get()->position;
for(auto old_node : nodes){ for(auto old_node : nodes){
SPTR_Node new_node; SPTR_Node new_node;
if(old_node->getNodeType() == NodeType::MIDINODE) { if(old_node->getNodeType() == NodeType::MIDINODE) {
new_node = copyNode(std::dynamic_pointer_cast<MidiNode>(old_node), position + old_node->drag_offset); std::cout << "node type midi" << std::endl;
new_node = copyNode(std::dynamic_pointer_cast<MidiNode>(old_node), (old_node->position - insert_pos) + position);
} else { } else {
std::cout << "not node type midi" << std::endl;
new_node = copyNode(old_node, position + old_node->drag_offset); new_node = copyNode(old_node, position + old_node->drag_offset);
} }
old_node->selected = false;
new_node->copied = false; new_node->copied = false;
new_node->selected = true; new_node->selected = true;
//TODO copy connectors //TODO copy connectors
for(auto c : copy_connections){ for(auto c : copy_connections){
@@ -325,6 +353,7 @@ namespace VISEQ::GRAPH{
} }
} }
std::ranges::copy(copy_connections.begin(), copy_connections.end(), std::back_inserter(edges)); std::ranges::copy(copy_connections.begin(), copy_connections.end(), std::back_inserter(edges));
addToSelection();
} }
void GraphManager::update(){ void GraphManager::update(){
@@ -339,41 +368,41 @@ namespace VISEQ::GRAPH{
float v1_v2_distance = v1_position.dist(&v2_position); float v1_v2_distance = v1_position.dist(&v2_position);
if(v1_v2_distance < 100) c->switches_offset = v1_v2_distance/2.3f; if(v1_v2_distance < 100) c->switches_offset = v1_v2_distance/2.3f;
Vec2Df from_to_handle = c->start.lock()->position - ((c->start.lock()->position - c->end.lock()->position)).norm() * (c->start.lock()->radius + c->switches_offset); float from_radius = c->start.lock()->radius;
Vec2Df to_from_handle = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position)).norm() * (c->end.lock()->radius + c->switches_offset); float to_radius = c->end.lock()->radius;
Vec2Df middle_handle = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position))*0.4f;
Vec2Df middle_handle_2 = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position))*0.6f; Vec2Df from_to_handle = c->start.lock()->position - ((c->start.lock()->position - c->end.lock()->position)).norm() * (from_radius + 35.0f);
Vec2Df flip_handle = middle_handle + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*0.2, 0.f, 20.f) : 1.0f); Vec2Df to_from_handle = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position)).norm() * (to_radius + 35.0f);
Vec2Df flip_handle_2 = middle_handle_2 + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*-0.2, -20.f, 0.f) : 1.0f); //Vec2Df middle_handle_2 = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position)).norm()*65.0f;
//Vec2Df middle_handle = c->start.lock()->position - ((c->start.lock()->position - c->end.lock()->position)).norm()*65.0f;
Vec2Df center_handle = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position))*0.5f;
Vec2Df delete_position = center_handle + (c->start.lock()->position - c->end.lock()->position).norm().orth() * 12.0f;
Vec2Df split_position = center_handle - (c->start.lock()->position - c->end.lock()->position).norm().orth() * 12.0f;
// Dynamic opacity by distance to mouse // Dynamic opacity by distance to mouse
unsigned char opacity = 150.0f - Clamp(middle_handle.dist(mouse_pos), 0.0f, 150.0f); unsigned char opacity = 150.0f - Clamp(center_handle.dist(mouse_pos), 0.0f, 130.0f);
unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f); unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f);
unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f); unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f);
float midi_gate_v1 = 0.0f; float opacity_normalized = Clamp((float)opacity / 255.0f, .0f, 1.0f);
float midi_gate_v2 = 0.0f; //float opacity_from_normalized = Clamp((float)opacity_from / 255.0f, .0f, 1.0f);
//float opacity_to_normalized = Clamp((float)opacity_to / 255.0f, .0f, 1.0f);
if(c->start.lock()->getNodeType() == NodeType::MIDINODE){
midi_gate_v1 = Clamp((4.f / 1000.f) * std::dynamic_pointer_cast<MidiNode>(c->start.lock())->getNotes().gate, 1.f, 4.f);
}
if(c->end.lock()->getNodeType() == NodeType::MIDINODE){
midi_gate_v2 = Clamp((4.f / 1000.f) * std::dynamic_pointer_cast<MidiNode>(c->end.lock())->getNotes().gate, 1.f, 4.f);
}
// Line with small connector circles // Line with small connector circles
if(c->end.lock()->getNodeType() == NodeType::MIDINODE && c->start.lock()->getNodeType() == NodeType::MIDINODE){ if(c->end.lock()->getNodeType() == NodeType::MIDINODE && c->start.lock()->getNodeType() == NodeType::MIDINODE){
Color col = {229, 181, 103, 255}; Color col = {229, 181, 103, 255};
if(c->GActive()) col = {108, 153, 187, 255}; if(c->GActive()) col = {108, 153, 187, 255};
DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, col); DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, col);
{ if(state->draw_edge_lengths){
float d = c->start.lock()->position.dist(c->end.lock()->position); float d = c->start.lock()->position.dist(c->end.lock()->position);
std::string frac = MIDI::Fractions.at(std::clamp<int>(round(d/60) - 1, 0, 31)); std::string frac = MIDI::Fractions.at(std::clamp<int>(round(d/60) - 1, 0, 31));
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",d).c_str(), 10.0f, 2.0f); Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",d).c_str(), 10.0f, 2.0f);
Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f); Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f);
Vec2Df middle_handle = c->start.lock()->position + (c->end.lock()->position - c->start.lock()->position) * ((d - text_length.x)*0.5f)/d; Vec2Df middle_handle = c->start.lock()->position + (c->end.lock()->position - c->start.lock()->position) * ((d - text_length.x)*0.35f)/d;
Vec2Df middle_handle_frac = c->start.lock()->position + (c->end.lock()->position - c->start.lock()->position) * ((d - text_length_frac.x)*0.5f)/d; Vec2Df middle_handle_frac = c->start.lock()->position + (c->end.lock()->position - c->start.lock()->position) * ((d - text_length_frac.x)*0.35f)/d;
Vec2Df text_position = middle_handle + (c->start.lock()->position - c->end.lock()->position).norm().orth() * 12.0f; Vec2Df text_position = middle_handle + (c->start.lock()->position - c->end.lock()->position).norm().orth() * 12.0f;
Vec2Df text_position_frac = middle_handle_frac - (c->start.lock()->position - c->end.lock()->position).norm().orth() * 4.0f; Vec2Df text_position_frac = middle_handle_frac - (c->start.lock()->position - c->end.lock()->position).norm().orth() * 4.0f;
@@ -381,38 +410,34 @@ namespace VISEQ::GRAPH{
DrawTextPro(GetFontDefault(), std::format("{:.1f}",d).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); DrawTextPro(GetFontDefault(), std::format("{:.1f}",d).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
if( (int)d % 60 == 0) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); if( (int)d % 60 == 0) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
} }
if(midi_gate_v1 == 4.0f) col = VS_COLOR_RED;
DrawCircle(v1_position.x, v1_position.y, midi_gate_v1, col);
col = {229, 181, 103, 255};
if(midi_gate_v2 == 4.0f) col = VS_COLOR_RED;
DrawCircle(v2_position.x, v2_position.y, midi_gate_v2, col);
if(!c->start.lock()->picked_up && !c->end.lock()->picked_up){ if(!c->start.lock()->picked_up && !c->end.lock()->picked_up){
// On/Off switches on both sides // On/Off switches on both sides
if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->pass_forward ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->pass_forward = !c->pass_forward;
if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c->pass_backward ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c->pass_backward = !c->pass_backward;
if(!c->pass_forward){ if(ViTexButton(mouse_pos, from_to_handle, HELPER::GetRotation(from_to_handle, to_from_handle) + 90.0f, 8.0f,
Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle; c->pass_forward ? TEXTURES::tex_blocker_open : TEXTURES::tex_blocker_closed,
Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle; c->pass_forward ? TEXTURES::tex_blocker_open_hover : TEXTURES::tex_blocker_closed_hover,
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from}); c->pass_forward ? TEXTURES::tex_blocker_open_pressed : TEXTURES::tex_blocker_closed_pressed,
} ColorLerp(Fade(VS_COLOR_WHITE, .0f), Fade(VS_COLOR_WHITE, 1.0f), 1.0))) c->pass_forward = !c->pass_forward;
if(!c->pass_backward){ if(ViTexButton(mouse_pos, to_from_handle, HELPER::GetRotation(to_from_handle, from_to_handle) + 90.0f, 8.0f,
Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle; c->pass_backward ? TEXTURES::tex_blocker_open : TEXTURES::tex_blocker_closed,
Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle; c->pass_backward ? TEXTURES::tex_blocker_open_hover : TEXTURES::tex_blocker_closed_hover,
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_to}); c->pass_backward ? TEXTURES::tex_blocker_open_pressed : TEXTURES::tex_blocker_closed_pressed,
} ColorLerp(Fade(VS_COLOR_WHITE, .0f), Fade(VS_COLOR_WHITE, 1.0f), 1.0))) c->pass_backward = !c->pass_backward;
if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 125, 62, opacity} )) splitEdge(c); if(ViTexButton(mouse_pos, split_position, HELPER::GetRotation(from_to_handle, to_from_handle) + 90.0f, 8.0f,
TEXTURES::tex_split, TEXTURES::tex_split_hover, TEXTURES::tex_split_pressed, ColorLerp(Fade(VS_COLOR_WHITE, .0f), Fade(VS_COLOR_WHITE, 1.0f), opacity_normalized) )) splitEdge(c);
} }
} }
if(c->start.lock()->getNodeType() == NodeType::CONFIGNODE || c->end.lock()->getNodeType() == NodeType::CONFIGNODE){ if(c->start.lock()->getNodeType() == NodeType::CONFIGNODE || c->end.lock()->getNodeType() == NodeType::CONFIGNODE){
DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, VS_COLOR_BLUE); DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, VS_COLOR_BLUE);
} }
if(IsWindowReady()){
if(ViButton(mouse_pos, flip_handle.x, flip_handle.y, 8.0f, (Color){232, 50, 32, opacity} )) removeEdge(c); if(ViTexButton(mouse_pos, delete_position, HELPER::GetRotation(from_to_handle, to_from_handle), 8.0f,
TEXTURES::tex_delete, TEXTURES::tex_delete_hover, TEXTURES::tex_delete_pressed,
ColorLerp(Fade(VS_COLOR_WHITE, .0f), Fade(VS_COLOR_WHITE, 1.0f), opacity_normalized) )) removeEdge(c);
}
} }
} }
+2
View File
@@ -56,6 +56,7 @@ namespace VISEQ::GRAPH {
SPTR_Node copyNode(SPTR_Node n, Vec2Df position); SPTR_Node copyNode(SPTR_Node n, Vec2Df position);
SPTR_Node copyNode(std::shared_ptr<MidiNode> n, Vec2Df position); SPTR_Node copyNode(std::shared_ptr<MidiNode> n, Vec2Df position);
void setNodeMode(int mode); void setNodeMode(int mode);
void cycleModeOfSelectedNodes(bool direction);
void reset(); void reset();
WPTR_Node getNode(int i); WPTR_Node getNode(int i);
WPTR_Node getFirstNode(); WPTR_Node getFirstNode();
@@ -66,6 +67,7 @@ namespace VISEQ::GRAPH {
SPTR_Node getClosestNode(Vec2Df position); SPTR_Node getClosestNode(Vec2Df position);
VEC_WPTR_Node getNodesByID(int _id); VEC_WPTR_Node getNodesByID(int _id);
WPTR_Edge lastEdge(); WPTR_Edge lastEdge();
VEC_WPTR_Edge getPassableConnections(WPTR_Node node);
WPTR_Node next(WPTR_Node current, WPTR_Node last); WPTR_Node next(WPTR_Node current, WPTR_Node last);
void splitEdge(SPTR_Edge edge); void splitEdge(SPTR_Edge edge);
void splitEdges(); void splitEdges();
+4
View File
@@ -15,4 +15,8 @@ namespace VISEQ::HELPER{
float rotation = Vector2Angle((Vector2){1,0}, (end - start)) * RAD2DEG; float rotation = Vector2Angle((Vector2){1,0}, (end - start)) * RAD2DEG;
DrawTextPro(GetFontDefault(), text.c_str(), text_position, (Vector2){0,0}, rotation, size, 2.0f, col); DrawTextPro(GetFontDefault(), text.c_str(), text_position, (Vector2){0,0}, rotation, size, 2.0f, col);
} }
inline float GetRotation(Vec2Df start, Vec2Df end){
return Vector2Angle((Vector2){1,0}, (end - start)) * RAD2DEG;
}
} }
+1 -1
View File
@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "datatypes.h" #include "datatypes.h"
#include "raylib.h"
#include "vmath.h" #include "vmath.h"
namespace VISEQ::BASE { namespace VISEQ::BASE {
class Interactable{ class Interactable{
-1
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "interactable.h" #include "interactable.h"
#include <deque>
#include <memory> #include <memory>
namespace VISEQ::APP{ namespace VISEQ::APP{
+9 -7
View File
@@ -1,6 +1,5 @@
#include "interaction-manager.h" #include "interaction-manager.h"
#include "clipboard.h"
#include "connector.h" #include "connector.h"
#include "datatypes.h" #include "datatypes.h"
#include "node.h" #include "node.h"
@@ -14,11 +13,11 @@ namespace VISEQ::INTERACTION{
void InteractionManager::update(){ void InteractionManager::update(){
if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){ if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){
VEC_SPTR_Node selected_nodes = gm->getCopiesOfSelectedNodes(); VEC_SPTR_Node selected_nodes = gm->getCopiesOfSelectedNodes();
if(!selected_nodes.empty()) cb.copyNodes(selected_nodes); if(!selected_nodes.empty()) cb->copyNodes(selected_nodes);
} }
if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_V)){ if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_V)){
VEC_SPTR_Node paste_nodes = cb.pasteNodes(); VEC_SPTR_Node paste_nodes = cb->pasteNodes();
if(!paste_nodes.empty()) gm->pasteNodesAndEdges(paste_nodes, MOD_MOUSE); if(!paste_nodes.empty()) gm->pasteNodesAndEdges(paste_nodes, MOD_MOUSE);
} }
@@ -27,13 +26,16 @@ namespace VISEQ::INTERACTION{
} }
if(!KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) { if(!KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) {
state->node_mode = (state->node_mode + 1) % 7; gm->cycleModeOfSelectedNodes(true);
} }
if(KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) { if(KEYS_DOWN.shift && IsKeyPressed(KEY_TAB)) {
state->node_mode -= state->node_mode > 0 ? 1 : -6; gm->cycleModeOfSelectedNodes(false);
} }
if(IsKeyPressed(KEY_V)){
state->draw_edge_lengths = !state->draw_edge_lengths;
}
} }
void InteractionManager::draw(){ void InteractionManager::draw(){
@@ -150,8 +152,8 @@ namespace VISEQ::INTERACTION{
auto connector = std::dynamic_pointer_cast<Connector>(e.item); auto connector = std::dynamic_pointer_cast<Connector>(e.item);
if(found && partner != e){ if(found && partner != e){
auto connector_to = std::dynamic_pointer_cast<Connector>(partner.item); auto connector_to = std::dynamic_pointer_cast<Connector>(partner.item);
connector->partner = connector_to; //connector->partner = connector_to;
connector_to->partner = connector; //connector_to->partner = connector;
gm->addConnection(std::dynamic_pointer_cast<Node>(connector->parent.lock()), std::dynamic_pointer_cast<Node>(connector_to->parent.lock())); gm->addConnection(std::dynamic_pointer_cast<Node>(connector->parent.lock()), std::dynamic_pointer_cast<Node>(connector_to->parent.lock()));
} else if (partner != e){ } else if (partner != e){
if(KEYS_DOWN.alt){ if(KEYS_DOWN.alt){
+2 -1
View File
@@ -56,13 +56,14 @@ namespace VISEQ::INTERACTION{
std::shared_ptr<APP::CANVAS::Canvas> canvas; std::shared_ptr<APP::CANVAS::Canvas> canvas;
std::shared_ptr<GraphManager> gm; std::shared_ptr<GraphManager> gm;
std::shared_ptr<SIGNAL::SignalManager> sm; std::shared_ptr<SIGNAL::SignalManager> sm;
VISEQ::APP::Clipboard cb;
std::shared_ptr<APP::State> state = APP::State::get(); std::shared_ptr<APP::State> state = APP::State::get();
Vec2Df scale_start; Vec2Df scale_start;
std::shared_ptr<ScaleHandle> scale_handle = std::make_shared<ScaleHandle>(); std::shared_ptr<ScaleHandle> scale_handle = std::make_shared<ScaleHandle>();
std::shared_ptr<APP::Clipboard> cb = APP::Clipboard::get();
void update(); void update();
void draw(); void draw();
void removeNodes(VEC_SPTR_Node nodes); void removeNodes(VEC_SPTR_Node nodes);
+5 -1
View File
@@ -4,6 +4,7 @@
* 2024 Sebastian Kujas * 2024 Sebastian Kujas
* *
*/ */
#define _USE_MATH_DEFINES
#define RAYGUI_IMPLEMENTATION #define RAYGUI_IMPLEMENTATION
#include <raylib.h> #include <raylib.h>
@@ -51,16 +52,19 @@ int main(){
app.init(); app.init();
app.ui.init(); app.ui.init();
app.loadTextures();
app.loadState(); app.loadState();
app.startSignals(); app.startSignals();
while(!WindowShouldClose()){ while(!WindowShouldClose()){
app.update(); app.update();
app.draw(); if(IsWindowReady()) app.draw();
} }
app.close(); app.close();
app.sm->midi.update();
CloseWindow(); CloseWindow();
+187 -173
View File
@@ -3,7 +3,8 @@
#include "config-node.h" #include "config-node.h"
#include "datatypes.h" #include "datatypes.h"
#include "edge.h" #include "edge.h"
#include "node-handle.h" #include "interaction-event.h"
#include "midi.h"
#include "node.h" #include "node.h"
#include "raylib.h" #include "raylib.h"
#include "state.h" #include "state.h"
@@ -14,35 +15,10 @@
namespace VISEQ::GRAPH::NODES { namespace VISEQ::GRAPH::NODES {
void MidiNode::init(){ void MidiNode::init(){
float orbit_1 = radius + 25.0f; midiNote.note = 64;
float orbit_2 = orbit_1 + 20.0f; midiNote.channel = 1;
float orbit_3 = orbit_2 + 20.0f; midiNote.gate = 250;
float orbit_4 = orbit_3 + 20.0f; midiNote.velocity = 64;
float orbit_5 = orbit_4 + 30.0f;
midiHandles[NOTE].emplace_back(std::make_shared<NodeHandle<int>>(midiNote.note, position, VS_COLOR_GREEN, "NOTE", orbit_5, 12));
midiHandles[NOTE].emplace_back(std::make_shared<NodeHandle<int>>(midiNote.channel, position, VS_COLOR_PINK, "CHANNEL", orbit_1, 16, 1, 16, 40, 150));
midiHandles[NOTE].emplace_back(std::make_shared<NodeHandle<int>>(midiNote.gate, position, VS_COLOR_RED, "GATE", orbit_3, 30, 10, 30000, 40, 300));
midiHandles[NOTE].back()->logScale = true;
midiHandles[NOTE].emplace_back(std::make_shared<NodeHandle<int>>(midiNote.velocity, position, VS_COLOR_PURPLE, "VELOCITY", orbit_4, 32));
midiHandles[CC].emplace_back(std::make_shared<NodeHandle<int>>(midiCC.control, position, VS_COLOR_SUN, "CONTROL", orbit_3, 32));
midiHandles[CC].emplace_back(std::make_shared<NodeHandle<int>>(midiCC.channel, position, VS_COLOR_PINK, "CHANNEL", orbit_1, 1, 1, 16, 40, 150));
midiHandles[CC].emplace_back(std::make_shared<NodeHandle<int>>(midiCC.value, position, VS_COLOR_GREEN, "VALUE", orbit_4, 32));
midiHandles[PC].emplace_back(std::make_shared<NodeHandle<int>>(midiPC.program, position, VS_COLOR_SUN, "PROGRAM", orbit_3, 32));
midiHandles[PC].emplace_back(std::make_shared<NodeHandle<int>>(midiPC.channel, position, VS_COLOR_PINK, "CHANNEL", orbit_1, 1, 1, 16, 40, 150));
midiHandles[PC].emplace_back(std::make_shared<NodeHandle<int>>(midiPC.value, position, VS_COLOR_GREEN, "VALUE", orbit_4, 32));
midiHandles[PB].emplace_back(std::make_shared<NodeHandle<int>>(midiPitchBend.channel, position, VS_COLOR_PINK, "CHANNEL", orbit_1, 1, 1, 16, 40, 150));
midiHandles[PB].emplace_back(std::make_shared<NodeHandle<int>>(midiPitchBend.value, position, VS_COLOR_GREEN, "VALUE", orbit_3, 256, -8192, 8192, 40, 300));
midiHandles[AT].emplace_back(std::make_shared<NodeHandle<int>>(midiAftertouch.channel, position, VS_COLOR_PINK, "CHANNEL", orbit_1, 1, 1, 16, 40, 150));
midiHandles[AT].emplace_back(std::make_shared<NodeHandle<int>>(midiAftertouch.value, position, VS_COLOR_GREEN, "VALUE", orbit_3, 32));
midiHandles[PP].emplace_back(std::make_shared<NodeHandle<int>>(midiPolyPressure.channel, position, VS_COLOR_PINK, "CHANNEL", orbit_1, 1, 1, 16, 40, 150));
midiHandles[PP].emplace_back(std::make_shared<NodeHandle<int>>(midiPolyPressure.value, position, VS_COLOR_GREEN, "VALUE", orbit_4, 32));
midiHandles[PP].emplace_back(std::make_shared<NodeHandle<int>>(midiPolyPressure.note, position, VS_COLOR_SUN, "NOTE", orbit_5, 12));
} }
std::shared_ptr<MidiNode> MidiNode::getPtr(){ std::shared_ptr<MidiNode> MidiNode::getPtr(){
@@ -54,7 +30,8 @@ namespace VISEQ::GRAPH::NODES {
} }
void MidiNode::setMidiPort(int midi_port, bool _state){ void MidiNode::setMidiPort(int midi_port, bool _state){
midi_outs[midi_port].enabled = _state; selected_midi_outs[midi_port].enabled = _state;
std::cout << midi_port << " " << _state << std::endl;
} }
void MidiNode::trigger() { void MidiNode::trigger() {
@@ -128,40 +105,49 @@ namespace VISEQ::GRAPH::NODES {
void MidiNode::update() { void MidiNode::update() {
Node::update(); Node::update();
mode = state->node_mode;
for(auto mh : midiHandles[NOTE]){
mh->update(position);
}
for(auto mh : midiHandles[CC]){
mh->update(position);
}
for(auto mh : midiHandles[PC]){
mh->update(position);
}
for(auto mh : midiHandles[PB]){
mh->update(position);
}
for(auto mh : midiHandles[AT]){
mh->update(position);
}
for(auto mh : midiHandles[PP]){
mh->update(position);
}
} }
void MidiNode::modMidiNote(int incr){ void MidiNode::modMidiChannel(int incr){
}
void MidiNode::modMidiNoteValue(int incr){
midiNote.note += incr; midiNote.note += incr;
if(midiNote.note < 0 ) midiNote.note = VISEQ::MIDI::Notes.size()-1; if(midiNote.note < 0 ) midiNote.note = VISEQ::MIDI::Notes.size()-1;
if(midiNote.note >= (int)VISEQ::MIDI::Notes.size()) midiNote.note = 0; if(midiNote.note >= (int)VISEQ::MIDI::Notes.size()) midiNote.note = 0;
} }
void MidiNode::modMidiCC(int incr){ void MidiNode::modMidiNoteVelocity(int incr){
midiNote.velocity += incr;
if(midiNote.velocity < 0 ) midiNote.velocity = 127;
if(midiNote.velocity > 127 ) midiNote.velocity = 0;
}
void MidiNode::modMidiNoteGate(int incr){
midiNote.gate += incr;
if(midiNote.gate < 0 ) midiNote.gate = 0;
if(midiNote.gate > 20000) midiNote.gate = 20000;
}
void MidiNode::modMidiCCValue(int incr){
midiCC.value += incr;
if(midiCC.value < 0 ) midiCC.value = 127;
if(midiCC.value > 127 ) midiCC.value = 0;
}
void MidiNode::modMidiCCControl(int incr){
midiCC.control += incr; midiCC.control += incr;
if(midiCC.control < 0 ) midiCC.control = 127; if(midiCC.control < 0 ) midiCC.control = 127;
if(midiCC.control > 127 ) midiCC.control = 0; if(midiCC.control > 127 ) midiCC.control = 0;
} }
void MidiNode::modMidiPC(int incr){ void MidiNode::modMidiPCValue(int incr){
midiPC.value += incr;
if(midiPC.value < 0 ) midiPC.value = 127;
if(midiPC.value > 127 ) midiPC.value = 0;
}
void MidiNode::modMidiPCProgram(int incr){
midiPC.program += incr; midiPC.program += incr;
if(midiPC.program < 0 ) midiPC.program = 127; if(midiPC.program < 0 ) midiPC.program = 127;
if(midiPC.program > 127 ) midiPC.program = 0; if(midiPC.program > 127 ) midiPC.program = 0;
@@ -179,88 +165,73 @@ namespace VISEQ::GRAPH::NODES {
if(midiAftertouch.value > 127 ) midiAftertouch.value = 127; if(midiAftertouch.value > 127 ) midiAftertouch.value = 127;
} }
void MidiNode::modMidiPolyPressure(int incr){ void MidiNode::modMidiPolyPressureValue(int incr){
midiPolyPressure.value += incr; midiPolyPressure.value += incr;
if(midiPolyPressure.value < 0 ) midiPolyPressure.value = 0; if(midiPolyPressure.value < 0 ) midiPolyPressure.value = 0;
if(midiPolyPressure.value > 127 ) midiPolyPressure.value = 127; if(midiPolyPressure.value > 16383 ) midiPolyPressure.value = 16383;
}
void MidiNode::modMidiPolyPressureNote(int incr){
midiPolyPressure.note += incr;
if(midiPolyPressure.note < 0 ) midiPolyPressure.note = VISEQ::MIDI::Notes.size()-1;
if(midiPolyPressure.note >= (int)VISEQ::MIDI::Notes.size()) midiPolyPressure.note = 0;
} }
void MidiNode::interact(){ void MidiNode::interact(){
float wheel = GetMouseWheelMove(); float wheel = GetMouseWheelMove();
if(KEYS_DOWN.ctrl && !KEYS_DOWN.alt){ switch(mode){
switch(state->node_mode){ case NOTE:{
case 0:{ if(state->isModChain(APP::CTRL)) modMidiNoteValue(wheel);
modMidiNote(wheel); if(state->isModChain(APP::CTRL, APP::SHIFT)) modMidiNoteValue(wheel*12);
if(state->isModChain(APP::CTRL, APP::ALT)) modMidiNoteValue(wheel*12);
if(state->isModChain(APP::CTRL, APP::SHIFT, APP::ALT)) modMidiNoteValue(wheel*24);
if(state->isModChain(APP::CTRL, APP::ALT, APP::SHIFT)) modMidiNoteValue(wheel*24);
if(state->isModChain(APP::SHIFT)) modMidiNoteVelocity(wheel);
if(state->isModChain(APP::SHIFT, APP::CTRL)) modMidiNoteVelocity(wheel*16);
if(state->isModChain(APP::SHIFT, APP::ALT)) modMidiNoteVelocity(wheel*16);
if(state->isModChain(APP::SHIFT, APP::CTRL, APP::ALT)) modMidiNoteVelocity(wheel*32);
if(state->isModChain(APP::SHIFT, APP::ALT, APP::CTRL)) modMidiNoteVelocity(wheel*32);
if(state->isModChain(APP::ALT)) modMidiNoteGate(wheel*100);
if(state->isModChain(APP::ALT, APP::CTRL)) modMidiNoteGate(wheel*1000);
if(state->isModChain(APP::ALT, APP::SHIFT)) modMidiNoteGate(wheel*10);
if(state->isModChain(APP::ALT, APP::SHIFT, APP::CTRL)) modMidiNoteGate(wheel);
break;} break;}
case 1:{ case CC:{
modMidiCC(wheel); if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) modMidiCCValue(wheel);
if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && !KEYS_DOWN.alt) modMidiCCControl(wheel);
break;} break;}
case 2:{ case PC:{
modMidiPC(wheel); if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) modMidiPCValue(wheel);
break;} break;}
case 3:{ case PB:{
modMidiPitchBend(wheel); if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPitchBend(wheel*64);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPitchBend(wheel*2048);
if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPitchBend(wheel*256);
if(KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPitchBend(wheel);
break;} break;}
case 4:{ case AT:{
modMidiAftertouch(wheel); if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiAftertouch(wheel*10);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiAftertouch(wheel*100);
if(KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiAftertouch(wheel);
break;} break;}
case 5:{ case PP:{
modMidiPolyPressure(wheel); if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && !KEYS_DOWN.alt) modMidiPolyPressureNote(wheel);
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) modMidiPolyPressureNote(wheel*10);
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPolyPressureValue(wheel*64);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPolyPressureValue(wheel*2048);
if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPolyPressureValue(wheel*256);
if(KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) modMidiPolyPressureValue(wheel);
break;} break;}
}; };
} else if(KEYS_DOWN.shift && !KEYS_DOWN.alt) {
midiNote.velocity += wheel;
if(midiNote.velocity < 0 ) midiNote.velocity = 127;
if(midiNote.velocity > 127 ) midiNote.velocity = 0;
} else if(KEYS_DOWN.alt) {
switch(state->node_mode){
case 0:{
float incr = (float)wheel * (KEYS_DOWN.shift ? 100.0f : KEYS_DOWN.ctrl ? 1000.0f : 10.0f);
midiNote.gate += incr;
if(midiNote.gate < 0 ) midiNote.gate = 0;
break;}
case 1:{
midiCC.value += wheel;
if(midiCC.value < 0 ) midiCC.value = 0;
if(midiCC.value > 127 ) midiCC.value = 127;
break;}
case 2:{
midiPC.value += wheel;
if(midiPC.value < 0 ) midiPC.value = 0;
if(midiPC.value > 127 ) midiPC.value = 127;
break;}
case 3:{
float incr = (float)wheel * (KEYS_DOWN.shift ? 100.0f : KEYS_DOWN.ctrl ? 1000.0f : 10.0f);
midiPitchBend.value += incr;
if(midiPitchBend.value < 0 ) midiPitchBend.value = 0;
if(midiPitchBend.value > 16383 ) midiPitchBend.value = 16383;
break;}
case 4:{
float incr = (float)wheel * (KEYS_DOWN.shift ? 100.0f : KEYS_DOWN.ctrl ? 1000.0f : 10.0f);
midiAftertouch.value += incr;
if(midiAftertouch.value < 0 ) midiAftertouch.value = 0;
if(midiAftertouch.value > 127 ) midiAftertouch.value = 127;
break;}
case 5:{
float incr = (float)wheel * (KEYS_DOWN.shift ? 100.0f : KEYS_DOWN.ctrl ? 1000.0f : 10.0f);
midiPolyPressure.value += incr;
if(midiPolyPressure.value < 0 ) midiPolyPressure.value = 0;
if(midiPolyPressure.value > 127 ) midiPolyPressure.value = 127;
break;}
};
}
} }
void MidiNode::draw(Vec2Df mouse, Camera2D cam) { void MidiNode::draw(Vec2Df mouse, Camera2D cam) {
Node::draw(); Node::draw();
for(int i = 0; i < 6; ++i){
for(auto mh : midiHandles[(Handles)i]){
mh->lock();
}
}
if(hovering() || selected) interact(); if(hovering() || selected) interact();
last = time; last = time;
@@ -272,60 +243,127 @@ namespace VISEQ::GRAPH::NODES {
fade -= (time - last)*1000.0f; fade -= (time - last)*1000.0f;
} }
DrawRing(position, radius, radius + 4, 0, 360, 24, (Color){60, 60, 60, 255}); switch((Handles)mode){
DrawRing(position, radius, radius + 4, 0.0f - 90.0f, (360.0f/127.0f) * getNotes().velocity - 90.0f, 24, (Color){158, 134, 200, 255}); case NOTE:{
DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255}); radius = (float)midiNote.velocity * 0.2f + 15.0f;
break;}
case CC:{
radius = (float)midiCC.value * 0.2f + 15.0f;
break;}
case PC:{
radius = (float)midiPC.value * 0.2f + 15.0f;
break;}
case PB:{
radius = (float)midiPitchBend.value * 0.002f + 15.0f;
break;}
case AT:{
radius = (float)midiAftertouch.value * 0.002f + 15.0f;
break;}
case PP:{
radius = (float)midiPolyPressure.value * 0.002f + 15.0f;
break;}
}
if(!selected) DrawCircle(position.x, position.y, radius, state->settings.mode_colors[mode]);
if(selected) DrawCircle(position.x, position.y, radius, VS_COLOR_LIGHTBLUE);
float trigger_alpha = (1.f / getNotes().gate) * fade; float trigger_alpha = (1.f / getNotes().gate) * fade;
if(!picked_up && !selected && !in_selection_rect && !hovering()) DrawCircle(position.x, position.y, radius, ColorLerp(state->mode_color, VS_COLOR_RED, trigger_alpha)); if(!selected && !pickedUp() && !hovering()) DrawRing(position, radius, radius + 3, 0, 360, 24, VS_COLOR_GREY);
if(picked_up || in_selection_rect || hovering()) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); DrawRing(position, radius, radius + 3, 0, 360, 24, ColorLerp(VS_COLOR_GREY, VS_COLOR_RED, trigger_alpha));
if(selected) DrawCircle(position.x, position.y, radius, (Color){255, 153, 187, 255}); if(selected) DrawRing(position, radius, radius + 3, 0, 360, 24, VS_COLOR_RED);
if(picked_up || (in_selection_rect && MOUSE_LEFT.down) || selected) DrawRing(position, radius, radius + 3, 0, 360, 24, VS_COLOR_LIGHTBLUE);
if(hovering()) DrawRing(position, radius, radius + 3, 0, 360, 24, VS_COLOR_PINK);
DrawCircleLinesV(position, radius + 3, VS_COLOR_LIGHTGREY);
//if(hovering()) DrawCircleLinesV(position, radius + 4, VS_COLOR_PINK);
if(distributionMode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK); if(distributionMode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK);
if(distributionMode == Distribution::ROUNDROBIN) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_YELLOW); if(distributionMode == Distribution::ROUNDROBIN) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_YELLOW);
if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255});
bool modified = false;
if(selected && mode >= 0 && mode < 6){
for(auto mh : midiHandles[(Handles)mode]){
mh->unlock();
mh->draw();
std::string text = "";
if(mh->hovering() || mh->picked_up){
text = std::format("{}", mh->assignedValueRef);
if(mh->name == "NOTE") text = MIDI::Notes[mh->assignedValueRef];
if(mh->name == "GATE") text = std::format("{:.2f}", mh->assignedValueRef / 1000.0f);
if(mh->name == "VALUE" && (Handles)mode == PB) text = std::format("{}", round(((float)mh->assignedValueRef / 8192.0f) * 100));
DrawCenteredText(text, position, 12, WHITE);
modified = true;
}
}
}
if(!modified){ VMATH::Vec2D<float> desc_position = position + VMATH::Vec2D<float>(radius + 7.0f, radius + 7.0f);
switch((Handles)mode){ switch(mode){
case NOTE:{ case NOTE:{
DrawCenteredText(MIDI::Notes[getNotes().note], position, 12, WHITE); if(state->isModChainStart(APP::CTRL) || state->modifier_chain.size() == 0) DrawCenteredText(MIDI::Notes[getNotes().note], position, 14, VS_COLOR_DARKGREY);
if(state->isModChainStart(APP::SHIFT)) DrawCenteredText(std::format("{}", getNotes().velocity), position, 12, VS_COLOR_DARKGREY);
if(state->isModChain(APP::ALT)) DrawCenteredText(std::format("{:.1f}s", (float)getNotes().gate / 1000.f), position, 12, VS_COLOR_DARKGREY);
if(state->isModChainStart(APP::ALT, APP::CTRL)) DrawCenteredText(std::format("{:.2f}s", (float)getNotes().gate / 1000.f), position, 12, VS_COLOR_DARKGREY);
if(state->isModChain(APP::ALT, APP::SHIFT)) DrawCenteredText(std::format("{:.2f}s", (float)getNotes().gate / 1000.f), position, 12, VS_COLOR_DARKGREY);
if(state->isModChain(APP::ALT, APP::SHIFT, APP::CTRL)) DrawCenteredText(std::format("{:.3f}s", (float)getNotes().gate / 1000.f), position, 12, VS_COLOR_DARKGREY);
if(selected || hovering()){
if(state->isModChain(APP::CTRL)) DrawText("NOTE +1", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::CTRL, APP::SHIFT)) DrawText("NOTE +12", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::CTRL, APP::ALT)) DrawText("NOTE +12", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::CTRL, APP::SHIFT, APP::ALT)) DrawText("NOTE +24", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::CTRL, APP::ALT, APP::SHIFT)) DrawText("NOTE +24", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::SHIFT)) DrawText("VELOCITY +1", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::SHIFT, APP::CTRL)) DrawText("VELOCITY +16", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::SHIFT, APP::ALT)) DrawText("VELOCITY +16", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::SHIFT, APP::CTRL, APP::ALT)) DrawText("VELOCITY +32", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::SHIFT, APP::ALT, APP::CTRL)) DrawText("VELOCITY +32", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::ALT)) DrawText("GATE 0.1s", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChainStart(APP::ALT, APP::CTRL)) DrawText("GATE 1.0s", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::ALT, APP::SHIFT)) DrawText("GATE 0.01s", desc_position, 8, VS_COLOR_WHITE);
if(state->isModChain(APP::ALT, APP::SHIFT, APP::CTRL)) DrawText("GATE 0.001s", desc_position, 8, VS_COLOR_WHITE);
}
break;} break;}
case CC:{ case CC:{
DrawCenteredText(std::format("{}", getCC().value), position, 12, WHITE); if(!KEYS_DOWN.shift) DrawCenteredText(std::format("{}", getCC().value), position, 12, VS_COLOR_DARKGREY);
if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawCenteredText(std::format("{}", getCC().control), position, 12, VS_COLOR_WHITE);
if(selected){
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("CC", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("VALUE", desc_position, 8, VS_COLOR_WHITE);
if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("CONTROL", desc_position, 8, VS_COLOR_WHITE);
}
break;} break;}
case PC:{ case PC:{
DrawCenteredText(std::format("{}", getPC().value), position, 12, WHITE); if(!KEYS_DOWN.shift) DrawCenteredText(std::format("{}", getPC().value), position, 12, VS_COLOR_DARKGREY);
if(selected){
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("PROGRAM CHANGE", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("PROGRAM", desc_position, 8, VS_COLOR_WHITE);
}
break;} break;}
case PB:{ case PB:{
DrawCenteredText(std::format("{}", round(((float)getPitchBend().value / 8192.0f) * 100)), position, 12, WHITE); DrawCenteredText(std::format("{}", getPitchBend().value), position, 10, VS_COLOR_DARKGREY);
if(selected){
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("PITCHBEND", desc_position, 8, VS_COLOR_WHITE);
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("64", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("2048", desc_position, 8, VS_COLOR_WHITE);
if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("256", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("1", desc_position, 8, VS_COLOR_WHITE);
}
break;} break;}
case AT:{ case AT:{
DrawCenteredText(std::format("{}", getAftertouch().value), position, 12, WHITE); DrawCenteredText(std::format("{}", getAftertouch().value), position, 12, VS_COLOR_DARKGREY);
if(selected){
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("AFTERTOUCH", desc_position, 8, VS_COLOR_WHITE);
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("10", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("100", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("1", desc_position, 8, VS_COLOR_WHITE);
}
break;} break;}
case PP:{ case PP:{
DrawCenteredText(std::format("{}", getPolyPressure().value), position, 12, WHITE); if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawCenteredText(MIDI::Notes[getPolyPressure().note], position, 12, VS_COLOR_DARKGREY);
break;}
}
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawCenteredText(std::format("{}", getPolyPressure().value), position, 12, VS_COLOR_DARKGREY);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawCenteredText(std::format("{}", getPolyPressure().value), position, 12, VS_COLOR_DARKGREY);
if(KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) DrawCenteredText(std::format("{}", getPolyPressure().value), position, 12, VS_COLOR_DARKGREY);
if(selected){
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && !KEYS_DOWN.alt) DrawText("POLYPRESSURE", desc_position, 8, VS_COLOR_WHITE);
if(!KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("64", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && !KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("2048", desc_position, 8, VS_COLOR_WHITE);
if(!KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("256", desc_position, 8, VS_COLOR_WHITE);
if(KEYS_DOWN.ctrl && KEYS_DOWN.shift && KEYS_DOWN.alt) DrawText("1", desc_position, 8, VS_COLOR_WHITE);
} }
break;}
};
if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200}); if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200});
} }
@@ -334,15 +372,6 @@ namespace VISEQ::GRAPH::NODES {
std::vector<int> conns; std::vector<int> conns;
std::ranges::transform(N.connections.begin(), N.connections.end(), std::back_inserter(conns), [](VISEQ::GRAPH::EDGES::SPTR_Edge e){ return e->id;}); std::ranges::transform(N.connections.begin(), N.connections.end(), std::back_inserter(conns), [](VISEQ::GRAPH::EDGES::SPTR_Edge e){ return e->id;});
std::vector<std::vector<Vec2Df>> handles;
for(auto i : N.midiHandles){
handles.emplace_back();
for(auto n : i.second){
handles.at(i.first).push_back(n->position);
}
}
j = json{ j = json{
{"id", N.id}, {"id", N.id},
{"position", N.position}, {"position", N.position},
@@ -354,7 +383,6 @@ namespace VISEQ::GRAPH::NODES {
{"midiPitchBend", N.midiPitchBend}, {"midiPitchBend", N.midiPitchBend},
{"midiAftertouch", N.midiAftertouch}, {"midiAftertouch", N.midiAftertouch},
{"midiPolyPressure", N.midiPolyPressure}, {"midiPolyPressure", N.midiPolyPressure},
{"handles", handles},
{"connections",conns}}; {"connections",conns}};
} }
@@ -372,20 +400,6 @@ namespace VISEQ::GRAPH::NODES {
j.at("midiPitchBend").get_to(N.midiPitchBend); j.at("midiPitchBend").get_to(N.midiPitchBend);
j.at("midiAftertouch").get_to(N.midiAftertouch); j.at("midiAftertouch").get_to(N.midiAftertouch);
j.at("midiPolyPressure").get_to(N.midiPolyPressure); j.at("midiPolyPressure").get_to(N.midiPolyPressure);
std::vector<std::vector<Vec2Df>> handles;
j.at("handles").get_to(handles);
int i = 0;
for(auto n : handles){
int j = 0;
for(auto nn : n){
N.midiHandles[(Handles)i][j]->position = nn;
j++;
}
i++;
}
} }
void to_json(json& j, const std::shared_ptr<MidiNode>& N){ void to_json(json& j, const std::shared_ptr<MidiNode>& N){
+14 -8
View File
@@ -27,14 +27,12 @@ namespace VISEQ::GRAPH::NODES {
MIDI::MidiAftertouch midiAftertouch; MIDI::MidiAftertouch midiAftertouch;
MIDI::MidiPolyPressure midiPolyPressure; MIDI::MidiPolyPressure midiPolyPressure;
std::map<Handles, std::vector<std::shared_ptr<NodeHandle<int>>>> midiHandles;
public: public:
struct NodeMidiOut{ struct NodeMidiOut{
int i; int i;
std::string name;
bool enabled; bool enabled;
std::string name;
}; };
MidiNode() {init();} MidiNode() {init();}
@@ -48,10 +46,12 @@ namespace VISEQ::GRAPH::NODES {
bool send_cc = false; bool send_cc = false;
bool send_pc = false; bool send_pc = false;
bool send_pitch_bend = false; bool send_pitch_bend = false;
bool send_aftertouch = false;
bool send_polypressure = false;
int midi_out = -1; int midi_out = -1;
std::map<int, NodeMidiOut> midi_outs; std::map<int, NodeMidiOut> selected_midi_outs;
bool gui_midi_channel_edit = false; bool gui_midi_channel_edit = false;
bool gui_midi_note_edit = false; bool gui_midi_note_edit = false;
@@ -77,12 +77,18 @@ namespace VISEQ::GRAPH::NODES {
MIDI::MidiPolyPressure getPolyPressure() const ; MIDI::MidiPolyPressure getPolyPressure() const ;
std::vector<std::weak_ptr<ConfigNode>> getConnectedConfigNodes() const ; std::vector<std::weak_ptr<ConfigNode>> getConnectedConfigNodes() const ;
void update() override ; void update() override ;
void modMidiNote(int incr); void modMidiChannel(int incr);
void modMidiCC(int incr); void modMidiNoteValue(int incr);
void modMidiPC(int incr); void modMidiNoteVelocity(int incr);
void modMidiNoteGate(int incr);
void modMidiCCValue(int incr);
void modMidiCCControl(int incr);
void modMidiPCValue(int incr);
void modMidiPCProgram(int incr);
void modMidiPitchBend(int incr); void modMidiPitchBend(int incr);
void modMidiAftertouch(int incr); void modMidiAftertouch(int incr);
void modMidiPolyPressure(int incr); void modMidiPolyPressureValue(int incr);
void modMidiPolyPressureNote(int incr);
void interact(); void interact();
void draw(Vec2Df mouse, Camera2D cam) override ; void draw(Vec2Df mouse, Camera2D cam) override ;
+66 -10
View File
@@ -4,27 +4,31 @@
#include "raylib.h" #include "raylib.h"
#include <iostream> #include <iostream>
#include <libremidi/message.hpp>
#include <memory> #include <memory>
#include <sstream>
#include "datatypes.h" #include "datatypes.h"
namespace VISEQ::MIDI { namespace VISEQ::MIDI {
void Midi::init(){
auto out_conf = libremidi::midi1::out_default_configuration();
for(int i = 0; i < 5; i++){
std::ostringstream port_name;
port_name << "viseq midi out " << i;
virtual_midi_out_ports.push_back({i+2000, false, port_name.str()});
}
}
void Midi::enumerate(){ void Midi::enumerate(){
std::cout << (int)obs.get_current_api() << std::endl; std::cout << (int)obs.get_current_api() << std::endl;
int i = 0; int i = 0;
midi_out_ports.clear(); midi_out_ports.clear();
for(const libremidi::output_port& port : obs.get_output_ports()){ for(const libremidi::output_port& port : obs.get_output_ports()){
midi_out_ports.push_back({port, i, false}); midi_out_ports.push_back({port, i, false});
i++; i++;
} }
auto out_conf = libremidi::midi1::out_default_configuration();
virtual_midi_out = libremidi::midi_out(libremidi::output_configuration(), out_conf);
virtual_midi_out.open_virtual_port("viseq out");
//midi_out_ports.push_back({&virtual_midi_out, 99, false});
} }
void Midi::open_midi_out(MidiOutPort *out_port){ void Midi::open_midi_out(MidiOutPort *out_port){
@@ -42,6 +46,21 @@ namespace VISEQ::MIDI {
} }
} }
void Midi::open_midi_out(VirtualMidiOutPort *out_port){
if(!midi_outs.contains(out_port->number)){
auto out = std::make_shared<libremidi::midi_out>();
out->open_virtual_port(out_port->name);
midi_outs[out_port->number] = out;
}
}
void Midi::close_midi_out(VirtualMidiOutPort *out_port){
if(midi_outs.contains(out_port->number)){
midi_outs[out_port->number]->close_port();
midi_outs.erase(out_port->number);
}
}
void Midi::note(int midi_out, int channel, int note, int velocity, int gate){ void Midi::note(int midi_out, int channel, int note, int velocity, int gate){
if(midi_outs.contains(midi_out)){ if(midi_outs.contains(midi_out)){
if(midi_outs[midi_out]->is_port_open()){ if(midi_outs[midi_out]->is_port_open()){
@@ -49,8 +68,6 @@ namespace VISEQ::MIDI {
notes.emplace_back(midi_out, channel, note, velocity, GetTime(), gate); notes.emplace_back(midi_out, channel, note, velocity, GetTime(), gate);
} }
} }
virtual_midi_out.send_message(libremidi::channel_events::note_on(channel, note, velocity));
notes.emplace_back(99, channel, note, velocity, GetTime(), gate);
} }
void Midi::cc(int midi_out, int channel, int cc, int value){ void Midi::cc(int midi_out, int channel, int cc, int value){
@@ -61,6 +78,14 @@ namespace VISEQ::MIDI {
} }
} }
void Midi::pc(int midi_out, int channel, int value){
if(midi_outs.contains(midi_out)){
if(midi_outs[midi_out]->is_port_open()){
midi_outs[midi_out]->send_message(libremidi::channel_events::program_change(channel, value));
}
}
}
void Midi::pitch_bend(int midi_out, int channel, int pitch_value){ void Midi::pitch_bend(int midi_out, int channel, int pitch_value){
if(midi_outs.contains(midi_out)){ if(midi_outs.contains(midi_out)){
if(midi_outs[midi_out]->is_port_open()){ if(midi_outs[midi_out]->is_port_open()){
@@ -69,17 +94,48 @@ namespace VISEQ::MIDI {
} }
} }
void Midi::aftertouch(int midi_out, int channel, int aftertouch_value){
if(midi_outs.contains(midi_out)){
if(midi_outs[midi_out]->is_port_open()){
midi_outs[midi_out]->send_message(libremidi::channel_events::aftertouch(channel, aftertouch_value));
}
}
}
void Midi::polypressure(int midi_out, int channel, int note, int polypressure_value){
if(midi_outs.contains(midi_out)){
if(midi_outs[midi_out]->is_port_open()){
midi_outs[midi_out]->send_message(libremidi::channel_events::poly_pressure(channel, note, polypressure_value));
}
}
}
void Midi::all_notes_off(){
for(auto &n : notes){
if(midi_outs.contains(n.midi_out) && midi_outs[n.midi_out]->is_port_open()) midi_outs[n.midi_out]->send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity));
n.erase = true;
}
std::erase_if(notes, [](const auto& item){return item.erase;});
}
void Midi::update(){ void Midi::update(){
float time = GetTime(); float time = GetTime();
for(auto &n : notes){ for(auto &n : notes){
if(time - n.start >= (float)n.gate / 1000.0f){ if(time - n.start >= (float)n.gate / 1000.0f){
if(midi_outs.contains(n.midi_out) && midi_outs[n.midi_out]->is_port_open()) midi_outs[n.midi_out]->send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity)); if(midi_outs.contains(n.midi_out) && midi_outs[n.midi_out]->is_port_open()) midi_outs[n.midi_out]->send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity));
virtual_midi_out.send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity));
n.erase = true; n.erase = true;
} }
} }
std::erase_if(notes, [](const auto& item){return item.erase;}); std::erase_if(notes, [](const auto& item){return item.erase;});
for(auto& p : virtual_midi_out_ports){
if(p.enabled) {
open_midi_out(&p);
} else if(!p.enabled) {
close_midi_out(&p);
}
}
for(auto& p : midi_out_ports){ for(auto& p : midi_out_ports){
if(p.enabled) { if(p.enabled) {
open_midi_out(&p); open_midi_out(&p);
+10 -2
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "libremidi/libremidi.hpp" #include "libremidi/libremidi.hpp"
#include "libremidi/observer_configuration.hpp"
#include <libremidi/configurations.hpp> #include <libremidi/configurations.hpp>
#include <libremidi/defaults.hpp> #include <libremidi/defaults.hpp>
@@ -26,6 +25,7 @@ namespace VISEQ::MIDI {
public: public:
Midi() { Midi() {
init();
enumerate(); enumerate();
} }
@@ -34,19 +34,27 @@ namespace VISEQ::MIDI {
std::map<int, std::shared_ptr<libremidi::midi_out>> midi_outs; std::map<int, std::shared_ptr<libremidi::midi_out>> midi_outs;
std::vector<libremidi::input_port> midi_in_ports; std::vector<libremidi::input_port> midi_in_ports;
std::vector<MidiOutPort> midi_out_ports; std::vector<MidiOutPort> midi_out_ports;
std::vector<VirtualMidiOutPort> virtual_midi_out_ports;
libremidi::midi_out virtual_midi_out;
std::vector<NoteTimer> notes; std::vector<NoteTimer> notes;
float timer; float timer;
void init();
void enumerate(); void enumerate();
void open_midi_out(MidiOutPort *out_port); void open_midi_out(MidiOutPort *out_port);
void close_midi_out(MidiOutPort *out_port); void close_midi_out(MidiOutPort *out_port);
void open_midi_out(VirtualMidiOutPort *out_port);
void close_midi_out(VirtualMidiOutPort *out_port);
void note(int midi_out, int channel, int note, int velocity, int gate); void note(int midi_out, int channel, int note, int velocity, int gate);
void cc(int midi_out, int channel, int cc, int value); void cc(int midi_out, int channel, int cc, int value);
void pc(int midi_out, int channel, int value);
void pitch_bend(int midi_out, int channel, int pitch_value); void pitch_bend(int midi_out, int channel, int pitch_value);
void aftertouch(int midi_out, int channel, int aftertouch_value);
void polypressure(int midi_out, int channel, int note, int polypressure_value);
void all_notes_off();
void update(); void update();
}; };
+2 -2
View File
@@ -85,14 +85,14 @@ namespace VISEQ::GRAPH::NODES {
void ModNode::update() { void ModNode::update() {
Node::update(); Node::update();
mode = state->node_mode; //mode = state->node_mode;
} }
void ModNode::interact(){ void ModNode::interact(){
float wheel = GetMouseWheelMove(); float wheel = GetMouseWheelMove();
if(KEYS_DOWN.ctrl && !KEYS_DOWN.alt){ if(KEYS_DOWN.ctrl && !KEYS_DOWN.alt){
switch(state->node_mode){ switch(mode){
case 0:{ case 0:{
midiNote.note += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; midiNote.note += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel;
break;} break;}
+2 -3
View File
@@ -1,8 +1,7 @@
#pragma once #pragma once
#include "state.h" //#include "state.h"
#include "vmath.h" #include "vmath.h"
#include <memory>
namespace VISEQ::BASE { namespace VISEQ::BASE {
class Movable{ class Movable{
@@ -14,7 +13,7 @@ namespace VISEQ::BASE {
Movable(Vec2Df p, Vec2Df d, float s) : speed(s), position(p), direction(d) {} Movable(Vec2Df p, Vec2Df d, float s) : speed(s), position(p), direction(d) {}
Movable(Vec2Df p, float s) : speed(s), position(p) {} Movable(Vec2Df p, float s) : speed(s), position(p) {}
std::shared_ptr<APP::State> state = APP::State::get(); // std::shared_ptr<APP::State> state = APP::State::get();
float speed = 960.0f; float speed = 960.0f;
+18
View File
@@ -63,6 +63,16 @@ namespace VISEQ::GRAPH::NODES {
c->update(); c->update();
} }
if(free_connectors == 0) addConnector(); if(free_connectors == 0) addConnector();
in_selection_rect = CheckCollisionPointRec(position, state->selection);
}
std::weak_ptr<Connector> Node::getConnector(){
for(auto c : connectors){
if(c->partner.expired()) {
return c;
}
}
return connectors.back();
} }
void Node::draw(Vec2Df mp, Camera2D cam) {} void Node::draw(Vec2Df mp, Camera2D cam) {}
@@ -73,6 +83,14 @@ namespace VISEQ::GRAPH::NODES {
} }
} }
void Node::cycleMode(bool direction){
if(direction){
mode = (mode + 1) % 6;
} else {
mode -= mode > 0 ? 1 : -5;
}
}
void to_json(json& j, const Node& N){ void to_json(json& j, const Node& N){
if(N.getNodeType() == NodeType::MIDINODE){ if(N.getNodeType() == NodeType::MIDINODE){
j = dynamic_cast<const MidiNode&>(N); j = dynamic_cast<const MidiNode&>(N);
+2
View File
@@ -44,6 +44,7 @@ namespace VISEQ::GRAPH::NODES {
std::shared_ptr<Node> getPtr(); std::shared_ptr<Node> getPtr();
virtual bool hovering() override; virtual bool hovering() override;
void addConnector(); void addConnector();
std::weak_ptr<Connector> getConnector();
void removeConnector(std::weak_ptr<Connector> connector); void removeConnector(std::weak_ptr<Connector> connector);
virtual NodeType getNodeType() const; virtual NodeType getNodeType() const;
void deselect() override; void deselect() override;
@@ -52,6 +53,7 @@ namespace VISEQ::GRAPH::NODES {
void update() override; void update() override;
void draw(Vec2Df mp, Camera2D cam) override; void draw(Vec2Df mp, Camera2D cam) override;
void draw() override; void draw() override;
virtual void cycleMode(bool direction);
friend void to_json(json& j, const Node& N); friend void to_json(json& j, const Node& N);
friend void from_json(const json& j, Node& N); friend void from_json(const json& j, Node& N);
+1
View File
@@ -16,6 +16,7 @@ namespace VISEQ::BASE {
bool erase = false; bool erase = false;
Vec2Df selection_offset; Vec2Df selection_offset;
void update();
virtual bool clicked() override; virtual bool clicked() override;
virtual bool select() = 0; virtual bool select() = 0;
+7 -4
View File
@@ -86,26 +86,29 @@ namespace VISEQ::SIGNAL {
auto last = std::chrono::high_resolution_clock::now(); auto last = std::chrono::high_resolution_clock::now();
while(loop){ while(loop){
std::chrono::duration<double, std::micro> diff = std::chrono::high_resolution_clock::now() - last; std::chrono::duration<double, std::micro> diff = std::chrono::high_resolution_clock::now() - last;
if((int)diff.count() >= 250){ if((int)diff.count() >= 100){
mutex->lock(); mutex->lock();
if(play){ if(play){
for(auto& s : signals){ for(auto& s : signals){
s->direction = (s->next.lock()->position - s->position).norm(); s->direction = (s->next.lock()->position - s->position).norm();
s->update(diff.count()); s->update(diff.count());
if(s->position.dist(s->next.lock()->position) < 0.6f) { if(round(s->position.dist(s->next.lock()->position)) == 0) {
WPTR_Node next_node = gm->next(s->next, s->last); WPTR_Node next_node = gm->next(s->next, s->last);
s->next.lock()->trigger(); s->next.lock()->trigger();
if(next_node.lock() != s->next.lock() && !next_node.expired() && s->next.lock()->getNodeType() == NodeType::MIDINODE) { if(next_node.lock() != s->next.lock() && !next_node.expired() && s->next.lock()->getNodeType() == NodeType::MIDINODE) {
auto midinode = std::dynamic_pointer_cast<MidiNode>(s->next.lock()); auto midinode = std::dynamic_pointer_cast<MidiNode>(s->next.lock());
for(auto &m : midinode->midi_outs){ for(auto &m : midinode->selected_midi_outs){
if(m.second.enabled) { if(m.second.enabled) {
std::cout << std::chrono::high_resolution_clock::now() << " : " << diff.count() << " " << m.second.name << " " << m.second.i << " " << m.second.enabled << std::endl;
if(midinode->send_note) midi.note(m.second.i, midinode->getNotes().channel, (int)Clamp(midinode->getNotes().note + s->midi_note_offset, 0, 127), midinode->getNotes().velocity, midinode->getNotes().gate); if(midinode->send_note) midi.note(m.second.i, midinode->getNotes().channel, (int)Clamp(midinode->getNotes().note + s->midi_note_offset, 0, 127), midinode->getNotes().velocity, midinode->getNotes().gate);
if(midinode->send_cc) midi.cc(m.second.i, midinode->getCC().channel, midinode->getCC().control, (int)Clamp(midinode->getCC().value + s->midi_cc_offset, 0, 127)); if(midinode->send_cc) midi.cc(m.second.i, midinode->getCC().channel, midinode->getCC().control, (int)Clamp(midinode->getCC().value + s->midi_cc_offset, 0, 127));
if(midinode->send_pc) midi.pc(m.second.i, midinode->getPC().channel, midinode->getPC().value);
if(midinode->send_pitch_bend) midi.pitch_bend(m.second.i, midinode->getPitchBend().channel, midinode->getPitchBend().value); if(midinode->send_pitch_bend) midi.pitch_bend(m.second.i, midinode->getPitchBend().channel, midinode->getPitchBend().value);
if(midinode->send_aftertouch) midi.aftertouch(m.second.i, midinode->getAftertouch().channel, midinode->getAftertouch().value);
if(midinode->send_polypressure) midi.polypressure(m.second.i, midinode->getPolyPressure().channel, midinode->getPolyPressure().note, midinode->getPolyPressure().value);
} }
} }
if(midinode->send_note) midi.note(99, midinode->getNotes().channel, (int)Clamp(midinode->getNotes().note + s->midi_note_offset, 0, 127), midinode->getNotes().velocity, midinode->getNotes().gate);
s->last = s->next; s->last = s->next;
s->next = next_node; s->next = next_node;
} }
+50
View File
@@ -4,6 +4,7 @@
#include "raylib.h" #include "raylib.h"
#include "vmath.h" #include "vmath.h"
#include <memory> #include <memory>
#include <ostream>
namespace VISEQ::APP{ namespace VISEQ::APP{
@@ -54,6 +55,29 @@ namespace VISEQ::APP{
keys_released.shift = IsKeyReleased(KEY_LEFT_SHIFT) || IsKeyReleased(KEY_RIGHT_SHIFT); keys_released.shift = IsKeyReleased(KEY_LEFT_SHIFT) || IsKeyReleased(KEY_RIGHT_SHIFT);
keys_released.alt = IsKeyReleased(KEY_LEFT_ALT) || IsKeyReleased(KEY_RIGHT_ALT); keys_released.alt = IsKeyReleased(KEY_LEFT_ALT) || IsKeyReleased(KEY_RIGHT_ALT);
int n_modifier = keys_down.alt + keys_down.ctrl + keys_down.shift;
if(modifier_chain.size() < n_modifier){
ModifierKeyNames modKey = keys_pressed.ctrl ? CTRL : keys_pressed.shift ? SHIFT : ALT;
modifier_chain.push_back(modKey);
//std::cout << modifier_chain.size() << " " << modKey << std::endl;
for(ModifierKeyNames n : modifier_chain){
std::cout << n << " ";
}
std::cout << std::endl;
}
if(modifier_chain.size() > n_modifier){
ModifierKeyNames modKey = keys_released.ctrl ? CTRL : keys_released.shift ? SHIFT : ALT;
auto it = std::remove(modifier_chain.begin(), modifier_chain.end(), modKey);
modifier_chain.erase(it);
//std::cout << modifier_chain.size() << " " << modKey << std::endl;
for(ModifierKeyNames n : modifier_chain){
std::cout << n << " ";
}
std::cout << std::endl;
}
screen_mouse = {round(mouse_pos.x), round(mouse_pos.y)}; screen_mouse = {round(mouse_pos.x), round(mouse_pos.y)};
raw_mouse = {GetMousePosition().x, GetMousePosition().y}; raw_mouse = {GetMousePosition().x, GetMousePosition().y};
mod_mouse = {round(mouse_pos.x), round(mouse_pos.y)}; mod_mouse = {round(mouse_pos.x), round(mouse_pos.y)};
@@ -73,4 +97,30 @@ namespace VISEQ::APP{
} }
return State::instance; return State::instance;
} }
bool State::isModChainEmpty(){
return modifier_chain.size() == 0;
}
bool State::isModChainStart(ModifierKeyNames first){
if(modifier_chain.size() < 1) return false;
return std::equal(modifier_chain.begin(), modifier_chain.begin() + 1, std::vector<ModifierKeyNames>{first}.begin());
}
bool State::isModChainStart(ModifierKeyNames first, ModifierKeyNames second){
if(modifier_chain.size() < 2) return false;
return std::equal(modifier_chain.begin(), modifier_chain.begin() + 2, std::vector<ModifierKeyNames>{first, second}.begin());
}
bool State::isModChain(ModifierKeyNames first){
return modifier_chain == std::vector<ModifierKeyNames>{first};
}
bool State::isModChain(ModifierKeyNames first, ModifierKeyNames second){
return modifier_chain == std::vector<ModifierKeyNames>{first, second};
}
bool State::isModChain(ModifierKeyNames first, ModifierKeyNames second, ModifierKeyNames third){
return modifier_chain == std::vector<ModifierKeyNames>{first, second, third};
}
} }
+13
View File
@@ -4,6 +4,7 @@
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "raylib.h" #include "raylib.h"
#include "vmath.h" #include "vmath.h"
#include <deque>
#include <memory> #include <memory>
#define STATE state->istate #define STATE state->istate
@@ -48,6 +49,8 @@ namespace VISEQ::APP{
bool alt = false; bool alt = false;
}; };
enum ModifierKeyNames {CTRL, SHIFT, ALT};
class State{ class State{
public: public:
State(){} State(){}
@@ -65,6 +68,7 @@ namespace VISEQ::APP{
int node_mode = 0; int node_mode = 0;
bool context_menu = false; bool context_menu = false;
bool draw_edge_lengths = false;
bool hovering = false; bool hovering = false;
@@ -78,6 +82,8 @@ namespace VISEQ::APP{
ModifierKeys keys_pressed; ModifierKeys keys_pressed;
ModifierKeys keys_released; ModifierKeys keys_released;
std::vector<ModifierKeyNames> modifier_chain;
Rectangle selection; Rectangle selection;
Rectangle bounding_box; Rectangle bounding_box;
@@ -95,6 +101,13 @@ namespace VISEQ::APP{
static std::shared_ptr<State> get(); static std::shared_ptr<State> get();
std::deque<InteractionEvent> event_queue; std::deque<InteractionEvent> event_queue;
bool isModChainEmpty();
bool isModChainStart(ModifierKeyNames first);
bool isModChainStart(ModifierKeyNames first, ModifierKeyNames second);
bool isModChain(ModifierKeyNames first);
bool isModChain(ModifierKeyNames first, ModifierKeyNames second);
bool isModChain(ModifierKeyNames first, ModifierKeyNames second, ModifierKeyNames third);
}; };
} }
+39 -16
View File
@@ -6,13 +6,16 @@
#include "raygui/raygui.h" #include "raygui/raygui.h"
#include "datatypes.h" #include "datatypes.h"
#include "vmath.h"
#include <memory> #include <memory>
#include <ranges> #include <ranges>
#include <sstream>
namespace VISEQ::APP::UI{ namespace VISEQ::APP::UI{
void AppUI::init(){ void AppUI::init(){
GuiLoadStyleDark(); GuiLoadStyleDark();
inter = LoadFontEx("resources/fonts/Inter_28pt-Bold.ttf", 96, 0, 250);
} }
void AppUI::drawSideBar(){ void AppUI::drawSideBar(){
@@ -37,6 +40,11 @@ namespace VISEQ::APP::UI{
if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate(); if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate();
int i = 0; int i = 0;
for(auto& vo : sm->midi.virtual_midi_out_ports){
GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, vo.name.substr(0,32).c_str(), &vo.enabled);
i++;
}
i++;
for(auto& mo : sm->midi.midi_out_ports){ for(auto& mo : sm->midi.midi_out_ports){
GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, mo.port.port_name.substr(0,32).c_str(), &mo.enabled); GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, mo.port.port_name.substr(0,32).c_str(), &mo.enabled);
i++; i++;
@@ -48,6 +56,11 @@ namespace VISEQ::APP::UI{
gm->setMidiPortForAll(midis.number, true); gm->setMidiPortForAll(midis.number, true);
} }
} }
for(auto &midis : sm->midi.virtual_midi_out_ports){
if(midis.enabled){
gm->setMidiPortForAll(midis.number, true);
}
}
} }
int s_signal = s_midi + 100 + i*20; int s_signal = s_midi + 100 + i*20;
@@ -66,9 +79,11 @@ namespace VISEQ::APP::UI{
s->multiplier = state->settings.bpm / 120.0f; s->multiplier = state->settings.bpm / 120.0f;
float signal_bpm = round(state->settings.bpm * s->multiplier * (s->speed / state->settings.speed)); float signal_bpm = round(state->settings.bpm * s->multiplier * (s->speed / state->settings.speed));
if(GuiSpinner((Rectangle){70, (float)s_signal+70 + signal_configs*20, 100, 20}, "", &s_speed, 1, 16 * state->settings.grid * 4, s->ui_edit_speed)) s->ui_edit_speed = !s->ui_edit_speed; if(GuiSpinner((Rectangle){70, (float)s_signal+70 + signal_configs*20, 100, 20}, "", &s_speed, 1, 16 * state->settings.grid * 4, s->ui_edit_speed)) s->ui_edit_speed = !s->ui_edit_speed;
GuiLabel((Rectangle){175, (float)s_signal+70 + signal_configs*20, 40, 20}, std::format("{}",signal_bpm).c_str());
if(GuiButton((Rectangle){200,(float)s_signal+70 + signal_configs*20, 30, 20}, "1/2")) s_speed = state->settings.speed / 2; if(GuiButton((Rectangle){200,(float)s_signal+70 + signal_configs*20, 30, 20}, "1/2")) s_speed = state->settings.speed / 2;
//if(GuiButton((Rectangle){200,(float)s_signal+70 + signal_configs*20, 30, 20},"1/4")) s_speed = state->settings.speed / 4; //if(GuiButton((Rectangle){200,(float)s_signal+70 + signal_configs*20, 30, 20},"1/4")) s_speed = state->settings.speed / 4;
GuiLabel((Rectangle){195, (float)s_signal+70 + signal_configs*20, 30, 20}, std::format("{}",signal_bpm).c_str());
GuiToggle((Rectangle){240, (float)s_signal+70 + signal_configs*20, 20, 20},"P", &s->run); GuiToggle((Rectangle){240, (float)s_signal+70 + signal_configs*20, 20, 20},"P", &s->run);
s->speed = s_speed; s->speed = s_speed;
signal_configs++; signal_configs++;
@@ -82,19 +97,20 @@ namespace VISEQ::APP::UI{
DrawText(std::format("{}", gm->getNodesSize()).c_str(), 20, state->settings.height - 70, 15, VS_COLOR_WHITE); DrawText(std::format("{}", gm->getNodesSize()).c_str(), 20, state->settings.height - 70, 15, VS_COLOR_WHITE);
DrawFPS(20, state->settings.height - 30); DrawFPS(20, state->settings.height - 30);
std::string shorts[6] = {"NT","CC","PC","PB","AT","PP"}; // std::string shorts[6] = {"NT","CC","PC","PB","AT","PP"};
for(int i = 0; i < 6; ++i){ // for(int i = 0; i < 6; ++i){
Color col = state->settings.mode_colors[i]; // Color col = state->settings.mode_colors[i];
Vec2Df pos = {state->settings.width - (6.0f*75.0f) + i*75.0f, state->settings.height - 75.0f}; // Vec2Df pos = {state->settings.width - (6.0f*75.0f) + i*75.0f, state->settings.height - 75.0f};
DrawRing(pos, 30.0f, 34.0f, 0.0f, 360.0f, 24, state->node_mode == i ? VS_COLOR_WHITE : (Color){0,0,0,0}); // DrawRing(pos, 30.0f, 34.0f, 0.0f, 360.0f, 24, state->node_mode == i ? VS_COLOR_WHITE : (Color){0,0,0,0});
DrawCircleV(pos, 30.0f, col); // DrawCircleV(pos, 30.0f, col);
DrawCenteredText(shorts[i], pos, 20, WHITE); // DrawCenteredText(shorts[i], pos, 20, WHITE);
} // }
} }
void AppUI::DrawCenteredText(std::string text, Vec2Df position, int size, Color color){ void AppUI::DrawCenteredText(std::string text, Vec2Df position, int size, Color color){
float offset = MeasureText(text.c_str(), size); float offset = MeasureText(text.c_str(), size);
DrawText(text.c_str(), position.x-offset/2.0f, position.y-(float)size/2.0f+1, size, color ); //DrawText(text.c_str(), position.x-offset/2.0f, position.y-(float)size/2.0f+1, size, color );
DrawTextEx(inter, text.c_str(), Vec2Df(position.x-offset/2.0f, position.y-(float)size/2.0f+1), size, 2.0f, color);
} }
void AppUI::drawContextMenu(Camera2D camera){ void AppUI::drawContextMenu(Camera2D camera){
@@ -119,7 +135,7 @@ namespace VISEQ::APP::UI{
int i = 0; int i = 0;
if(n->getNodeType() == NodeType::MIDINODE){ if(n->getNodeType() == NodeType::MIDINODE){
std::shared_ptr<MidiNode> mn = std::dynamic_pointer_cast<MidiNode>(n); std::shared_ptr<MidiNode> mn = std::dynamic_pointer_cast<MidiNode>(n);
for(auto& mo : mn->midi_outs){ for(auto& mo : mn->selected_midi_outs){
GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled); GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled);
i++; i++;
} }
@@ -127,14 +143,21 @@ namespace VISEQ::APP::UI{
int y_channel = y_midi + 30 + i*20; int y_channel = y_midi + 30 + i*20;
GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &mn->send_note); GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &mn->send_note);
GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &mn->send_cc); GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &mn->send_cc);
GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH", &mn->send_pitch_bend); GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH-B", &mn->send_pitch_bend);
int y_cc_note = y_channel + 120; int y_send_bools = y_channel + 30;
switch(state->node_mode){ GuiCheckBox((Rectangle){np.x + 20, np.y + y_send_bools, 20, 20}, "PC", &mn->send_pc);
case 0:{ GuiCheckBox((Rectangle){np.x + 90, np.y + y_send_bools, 20, 20}, "AT", &mn->send_aftertouch);
GuiCheckBox((Rectangle){np.x + 160, np.y + y_send_bools, 20, 20}, "POLY-P", &mn->send_polypressure);
int y_cc_note = y_send_bools + 120;
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL"); GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL");
GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midiNote.channel); GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midiNote.channel);
/*
switch(state->node_mode){
case 0:{
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE"); GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE");
float v = mn->midiNote.note; float v = mn->midiNote.note;
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, MIDI::Notes[(int)round(v)].c_str()); GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, MIDI::Notes[(int)round(v)].c_str());
@@ -183,7 +206,7 @@ namespace VISEQ::APP::UI{
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383); GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383);
mn->midiPitchBend.value = round(v); mn->midiPitchBend.value = round(v);
break;} break;}
} }*/
} }
} }
} }
+11 -1
View File
@@ -1,7 +1,9 @@
#pragma once #pragma once
#include "raylib.h" #include "raylib.h"
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
@@ -55,6 +57,14 @@ namespace VISEQ::VMATH{
return Vec2D(-y, x); return Vec2D(-y, x);
}; };
Vec2D rotate(float deg){
return Vec2D(cos(deg*DEG2RAD) * x, sin(deg*DEG2RAD) * y);
};
Vec2D rotateAround(Vec2D<T> v, float deg){
return Vec2D(cos(deg*DEG2RAD) * (x - v.x), sin(deg*DEG2RAD) * (y-v.y)) + v;
};
Vec2D norm() { return *this / length();}; Vec2D norm() { return *this / length();};
Vec2D center(Vec2D v){ Vec2D center(Vec2D v){
@@ -164,7 +174,7 @@ namespace VISEQ::VMATH{
template<typename T> template<typename T>
Vec2D<T> polarToCartesian(T r, T q) { Vec2D<T> polarToCartesian(T r, T q) {
return Vec2D<T>{r * cos(q), r * sin(q)}; return Vec2D<T>{r * (T)cos(q), r * (T)sin(q)};
} }
} }