From 6f101f40110cf1e5f49792ec2bf1ae4dfa0d3ab6 Mon Sep 17 00:00:00 2001 From: Jopestpe <47086979+Jopestpe@users.noreply.github.com> Date: Sat, 25 Oct 2025 08:38:06 -0300 Subject: [PATCH] [examples] Added: `shapes_math_sine_cosine` (#5257) * draft: [examples] Added shapes_math_sine_cosine * draft: [examples] Added screenshot shapes_math_sine_cosine * Explementary * Varying radius * adjustments * added comments and reorganized UI labels * Updated Makefile, README.md, and examples_list.txt * tabs to spaces * Fix MSVC compilation --------- Co-authored-by: Ray --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 2 +- examples/examples_list.txt | 1 + examples/shapes/shapes_math_sine_cosine.c | 176 ++++++++++++++++++++ examples/shapes/shapes_math_sine_cosine.png | Bin 0 -> 22098 bytes 6 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 examples/shapes/shapes_math_sine_cosine.c create mode 100644 examples/shapes/shapes_math_sine_cosine.png diff --git a/examples/Makefile b/examples/Makefile index ef7cb5948..9ae8bb480 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -564,6 +564,7 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_math_sine_cosine \ shapes/shapes_mouse_trail \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 5d4f3ffab..0e9b9f92f 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -564,6 +564,7 @@ SHAPES = \ shapes/shapes_lines_bezier \ shapes/shapes_logo_raylib \ shapes/shapes_logo_raylib_anim \ + shapes/shapes_math_sine_cosine \ shapes/shapes_mouse_trail \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ @@ -899,6 +900,9 @@ shapes/shapes_logo_raylib: shapes/shapes_logo_raylib.c shapes/shapes_logo_raylib_anim: shapes/shapes_logo_raylib_anim.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_math_sine_cosine: shapes/shapes_math_sine_cosine.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) diff --git a/examples/README.md b/examples/README.md index 19d110344..bbb0a0388 100644 --- a/examples/README.md +++ b/examples/README.md @@ -71,7 +71,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c | [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | | [core_text_file_loading](core/core_text_file_loading.c) | core_text_file_loading | ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) | -### category: shapes [31] +### category: shapes [32] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 71cda6c1a..4805a37ec 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -80,6 +80,7 @@ shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@ra shapes;shapes_pie_chart;★★★☆;5.5;5.6;2025;2025;"Gideon Serfontein";@GideonSerf shapes;shapes_kaleidoscope;★★☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal shapes;shapes_clock_of_clocks;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates +shapes;shapes_math_sine_cosine;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2025;2025;"Balamurugan R";@Bala050814 shapes;shapes_simple_particles;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant shapes;shapes_starfield_effect;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates diff --git a/examples/shapes/shapes_math_sine_cosine.c b/examples/shapes/shapes_math_sine_cosine.c new file mode 100644 index 000000000..f61d4f548 --- /dev/null +++ b/examples/shapes/shapes_math_sine_cosine.c @@ -0,0 +1,176 @@ +/******************************************************************************************* +* +* raylib [shapes] example - math sine cosine +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* +* Example contributed by Jopestpe (@jopestpe) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2025-2025 Jopestpe (@jopestpe) +* +********************************************************************************************/ + +#include "raylib.h" +#include +#include "raymath.h" + +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +// Wave points for sine/cosine visualization +#define WAVE_POINTS 36 + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math sine cosine"); + + Vector2 sinePoints[WAVE_POINTS]; + Vector2 cosPoints[WAVE_POINTS]; + Vector2 center = { (screenWidth/2.0f) - 30.f, screenHeight/2.0f }; + Rectangle start = { 20.f, screenHeight - 120.f , 200.0f, 100.0f}; + float radius = 130.0f; + float angle = 0.0f; + bool pause = false; + + for (int i = 0; i < WAVE_POINTS; i++) + { + float t = i/(float)(WAVE_POINTS - 1); + float currentAngle = t*360.0f*DEG2RAD; + sinePoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - sinf(currentAngle)*(start.height/2.0f) }; + cosPoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - cosf(currentAngle)*(start.height/2.0f) }; + } + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + float angleRad = angle*DEG2RAD; + float cosRad = cosf(angleRad); + float sinRad = sinf(angleRad); + + Vector2 point = { center.x + cosRad*radius, center.y - sinRad*radius }; + Vector2 limitMin = { center.x - radius, center.y - radius }; + Vector2 limitMax = { center.x + radius, center.y + radius }; + + float complementary = 90.0f - angle; + float supplementary = 180.0f - angle; + float explementary = 360.0f - angle; + + float tangent = Clamp(tanf(angleRad), -10.0f, 10.0f); + float cotangent = (fabsf(tangent) > 0.001f) ? Clamp(1.0f/tangent, -radius, radius) : 0.0f; + Vector2 tangentPoint = { center.x + radius, center.y - tangent*radius }; + Vector2 cotangentPoint = { center.x + cotangent*radius, center.y - radius }; + + angle = Wrap(angle + (!pause ? 1.0f : 0.0f), 0.0f, 360.0f); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(RAYWHITE); + + // Cotangent (orange) + DrawLineEx((Vector2){ center.x , limitMin.y }, (Vector2){ cotangentPoint.x, limitMin.y }, 2.0f, ORANGE); + DrawLineDashed(center, cotangentPoint, 10.0f, 4.0f, ORANGE); + + // Side background + DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 }); + DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 }); + + // Base circle and axes + DrawCircleLinesV(center, radius, GRAY); + DrawLineEx((Vector2){ center.x, limitMin.y }, (Vector2){ center.x, limitMax.y }, 1.0f, GRAY); + DrawLineEx((Vector2){ limitMin.x, center.y }, (Vector2){ limitMax.x, center.y }, 1.f, GRAY); + + // Wave graph axes + DrawLineEx((Vector2){ start.x , start.y }, (Vector2){ start.x , start.y + start.height }, 2.0f, GRAY); + DrawLineEx((Vector2){ start.x + start.width, start.y }, (Vector2){ start.x + start.width, start.y + start.height }, 2.0f, GRAY); + DrawLineEx((Vector2){ start.x, start.y + start.height/2 }, (Vector2){ start.x + start.width, start.y + start.height/2 }, 2.0f, GRAY); + + // Wave graph axis labels + DrawText("1", start.x - 8, start.y, 6, GRAY); + DrawText("0", start.x - 8, start.y + start.height/2 - 6, 6, GRAY); + DrawText("-1", start.x - 12, start.y + start.height - 8, 6, GRAY); + DrawText("0", start.x - 2, start.y + start.height + 4, 6, GRAY); + DrawText("360", start.x + start.width - 8, start.y + start.height + 4, 6, GRAY); + + // Sine (red - vertical) + DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ center.x, point.y }, 2.0f, RED); + DrawLineDashed((Vector2){ point.x, center.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, RED); + DrawText(TextFormat("Sine %.2f", sinRad), 640, 190, 6, RED); + DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-sinRad + 1)*start.height/2.0f) }, 4.0f, RED); + DrawSplineLinear(sinePoints, WAVE_POINTS, 1.0f, RED); + + // Cosine (blue - horizontal) + DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ point.x, center.y }, 2.0f, BLUE); + DrawLineDashed((Vector2){ center.x , point.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, BLUE); + DrawText(TextFormat("Cosine %.2f", cosRad), 640, 210, 6, BLUE); + DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-cosRad + 1)*start.height/2.0f) }, 4.0f, BLUE); + DrawSplineLinear(cosPoints, WAVE_POINTS, 1.0f, BLUE); + + // Tangent (purple) + DrawLineEx((Vector2){ limitMax.x , center.y }, (Vector2){ limitMax.x, tangentPoint.y }, 2.0f, PURPLE); + DrawLineDashed(center, tangentPoint, 10.0f, 4.0f, PURPLE); + DrawText(TextFormat("Tangent %.2f", tangent), 640, 230, 6, PURPLE); + + // Cotangent (orange) + DrawText(TextFormat("Cotangent %.2f", cotangent), 640, 250, 6, ORANGE); + + // Complementary angle (beige) + DrawCircleSectorLines(center, radius*0.6f , -angle, -90.f , 36.0f, BEIGE); + DrawText(TextFormat("Complementary %0.f°",complementary), 640, 150, 6, BEIGE); + + // Supplementary angle (darkblue) + DrawCircleSectorLines(center, radius*0.5f , -angle, -180.f , 36.0f, DARKBLUE); + DrawText(TextFormat("Supplementary %0.f°",supplementary), 640, 130, 6, DARKBLUE); + + // Explementary angle (pink) + DrawCircleSectorLines(center, radius*0.4f , -angle, -360.f , 36.0f, PINK); + DrawText(TextFormat("Explementary %0.f°",explementary), 640, 170, 6, PINK); + + // Current angle - arc (lime), radius (black), endpoint (black) + DrawCircleSectorLines(center, radius*0.7f , -angle, 0.f, 36.0f, LIME); + DrawLineEx((Vector2){ center.x , center.y }, point, 2.0f, BLACK); + DrawCircleV(point, 4.0f, BLACK); + + // Draw GUI controls + //------------------------------------------------------------------------------ + GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(GRAY)); + GuiToggle((Rectangle){ 640, 70, 120, 20}, TextFormat("Pause"), &pause); + GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(LIME)); + GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f°", angle), &angle, 0.0f, 360.f); + + // Angle values panel + GuiGroupBox((Rectangle){ 620, 110, 140, 170}, "Angle Values"); + //------------------------------------------------------------------------------ + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_math_sine_cosine.png b/examples/shapes/shapes_math_sine_cosine.png new file mode 100644 index 0000000000000000000000000000000000000000..b561f74fbbd06ab006df7e5789e79a6cba255b07 GIT binary patch literal 22098 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 PL%{ExzL{Pr&L#SP=KmFB literal 0 HcmV?d00001