|
|
@ -0,0 +1,180 @@ |
|
|
|
/******************************************************************************************* |
|
|
|
* |
|
|
|
* raylib [shapes] example - math sine cosine |
|
|
|
* |
|
|
|
* Port of the p5.js "sine and cosine" demo to raylib + raygui |
|
|
|
* Sources: https://p5js.org/examples/angles-and-motion-sine-cosine/ |
|
|
|
* |
|
|
|
* Demonstrates uniform circular motion and the correspondence between |
|
|
|
* the unit circle and sine / cosine graphs. Right panel contains a |
|
|
|
* play/pause toggle implemented with raygui. |
|
|
|
* |
|
|
|
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev |
|
|
|
* |
|
|
|
* Copyright (c) 2025 Olivier (@oqu) |
|
|
|
* |
|
|
|
********************************************************************************************/ |
|
|
|
|
|
|
|
#include "raylib.h" |
|
|
|
|
|
|
|
// Required for GUI controls |
|
|
|
#define RAYGUI_IMPLEMENTATION |
|
|
|
#include "raygui.h" |
|
|
|
|
|
|
|
#include <math.h> |
|
|
|
|
|
|
|
int main(void) |
|
|
|
{ |
|
|
|
// Window initialization |
|
|
|
const int screenWidth = 800; |
|
|
|
const int screenHeight = 450; |
|
|
|
|
|
|
|
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math sine cosine"); |
|
|
|
const char* playText = "Play"; |
|
|
|
const char* pauseText = "Pause"; |
|
|
|
|
|
|
|
// Scene layout (mimic p5 example positioning) |
|
|
|
const float circleX = 200.0f; |
|
|
|
const float circleY = 150.0f; |
|
|
|
const float circleRadius = 75.0f; |
|
|
|
|
|
|
|
const float graphX = 50.0f; |
|
|
|
const float graphY = 300.0f; |
|
|
|
const float graphAmplitude = 50.0f; |
|
|
|
const float graphPeriod = 300.0f; // width of the graph in pixels |
|
|
|
|
|
|
|
// Animation / UI state |
|
|
|
bool playing = true; // play / pause toggle |
|
|
|
int frameCountLocal = 0; // local frame counter (used when playing) |
|
|
|
|
|
|
|
SetTargetFPS(60); |
|
|
|
|
|
|
|
// Main loop |
|
|
|
while (!WindowShouldClose()) |
|
|
|
{ |
|
|
|
// Handle GUI and input first |
|
|
|
BeginDrawing(); |
|
|
|
|
|
|
|
ClearBackground(BLACK); |
|
|
|
|
|
|
|
// Right control panel |
|
|
|
float panelX = (float)GetScreenWidth() - 270.0f; |
|
|
|
Rectangle panel = {panelX, 10, 260, (float)GetScreenHeight() - 20}; |
|
|
|
DrawRectangleRec(panel, Fade(LIGHTGRAY, 0.6f)); |
|
|
|
DrawRectangleLinesEx(panel, 1, GRAY); |
|
|
|
|
|
|
|
int y = 20; |
|
|
|
int px = (int)panelX + 10; |
|
|
|
DrawText("Sine / Cosine Demo", px, y, 20, DARKGRAY); |
|
|
|
y += 34; |
|
|
|
|
|
|
|
// Play / Pause toggle |
|
|
|
DrawText("Animation:", px, y, 14, DARKGRAY); |
|
|
|
y += 18; |
|
|
|
GuiToggle((Rectangle){(float)px, y, 220, 30}, playing ? pauseText : playText, &playing); |
|
|
|
y += 40; |
|
|
|
|
|
|
|
// Small description |
|
|
|
DrawText("Animated demonstration of a point moving", px, y, 10, DARKGRAY); |
|
|
|
y += 14; |
|
|
|
DrawText("around the unit circle and the corresponding", px, y, 10, DARKGRAY); |
|
|
|
y += 14; |
|
|
|
DrawText("sine (red) and cosine (orange) graphs.", px, y, 10, DARKGRAY); |
|
|
|
y += 30; |
|
|
|
|
|
|
|
DrawFPS(px, GetScreenHeight() - 30); |
|
|
|
|
|
|
|
// Update frameCount if playing |
|
|
|
if (playing) |
|
|
|
frameCountLocal++; |
|
|
|
|
|
|
|
// Angle in degrees (like the p5 example) |
|
|
|
int angleDeg = frameCountLocal % 360; |
|
|
|
|
|
|
|
// Draw angle label |
|
|
|
Color labelCol = WHITE; |
|
|
|
DrawText(TextFormat("angle: %d", angleDeg), 25, 25, 20, labelCol); |
|
|
|
|
|
|
|
// --- Draw circle and diameters --- |
|
|
|
// circle outer |
|
|
|
DrawCircleLines((int)circleX, (int)circleY, circleRadius, Fade(GRAY, 0.6f)); |
|
|
|
// diameters |
|
|
|
DrawLine((int)circleX, (int)(circleY - circleRadius), (int)circleX, (int)(circleY + circleRadius), Fade(GRAY, 0.6f)); |
|
|
|
DrawLine((int)(circleX - circleRadius), (int)circleY, (int)(circleX + circleRadius), (int)circleY, Fade(GRAY, 0.6f)); |
|
|
|
|
|
|
|
// Compute moving point on circle (cos for x, sin for y). Note: cos/sin in C expect radians |
|
|
|
float angRad = angleDeg * (PI / 180.0f); |
|
|
|
float pointX = circleX + circleRadius * cosf(angRad); |
|
|
|
float pointY = circleY - circleRadius * sinf(angRad); // minus to match p5 y-axis direction |
|
|
|
|
|
|
|
// line from center to point |
|
|
|
DrawLine((int)circleX, (int)circleY, (int)pointX, (int)pointY, Fade(GRAY, 0.6f)); |
|
|
|
|
|
|
|
// moving points |
|
|
|
DrawCircleV((Vector2){pointX, pointY}, 6.0f, WHITE); |
|
|
|
DrawCircle((int)pointX, (int)circleY, 6.0f, ORANGE); |
|
|
|
DrawCircle((int)circleX, (int)pointY, 6.0f, RED); |
|
|
|
|
|
|
|
// --- Draw graph area axes --- |
|
|
|
// axes lines |
|
|
|
DrawLine((int)graphX, (int)graphY, (int)(graphX + graphPeriod), (int)graphY, Fade(GRAY, 0.6f)); |
|
|
|
DrawLine((int)graphX, (int)(graphY - graphAmplitude), (int)graphX, (int)(graphY + graphAmplitude), Fade(GRAY, 0.6f)); |
|
|
|
DrawLine((int)(graphX + graphPeriod), (int)(graphY - graphAmplitude), (int)(graphX + graphPeriod), (int)(graphY + graphAmplitude), Fade(GRAY, 0.6f)); |
|
|
|
|
|
|
|
// labels |
|
|
|
DrawText("0", (int)graphX - 6, (int)(graphY + graphAmplitude + 6), 14, Fade(GRAY, 0.9f)); |
|
|
|
DrawText("360", (int)(graphX + graphPeriod) - 12, (int)(graphY + graphAmplitude + 6), 14, Fade(GRAY, 0.9f)); |
|
|
|
DrawText("1", (int)(graphX / 2) - 6, (int)(graphY - graphAmplitude) - 6, 14, Fade(GRAY, 0.9f)); |
|
|
|
DrawText("0", (int)(graphX / 2) - 6, (int)(graphY)-6, 14, Fade(GRAY, 0.9f)); |
|
|
|
DrawText("-1", (int)(graphX / 2) - 10, (int)(graphY + graphAmplitude) - 6, 14, Fade(GRAY, 0.9f)); |
|
|
|
|
|
|
|
DrawText("cos", (int)(graphX + graphPeriod + graphX / 2) - 18, (int)(graphY - graphAmplitude) - 10, 20, ORANGE); |
|
|
|
DrawText("sin", (int)(graphX + graphPeriod + graphX / 2) - 18, (int)(graphY) - 10, 20, RED); |
|
|
|
|
|
|
|
// --- Draw cosine curve (orange) --- |
|
|
|
for (int t = 0; t <= 360; t++) |
|
|
|
{ |
|
|
|
float x = ((float)t / 360.0f) * graphPeriod + graphX; |
|
|
|
float y = graphY - graphAmplitude * cosf(t * (PI / 180.0f)); |
|
|
|
// draw small segments between consecutive points for smoother curve |
|
|
|
if (t > 0) |
|
|
|
{ |
|
|
|
int prevT = t - 1; |
|
|
|
float px = ((float)prevT / 360.0f) * graphPeriod + graphX; |
|
|
|
float py = graphY - graphAmplitude * cosf(prevT * (PI / 180.0f)); |
|
|
|
DrawLineEx((Vector2){px, py}, (Vector2){x, y}, 2.5f, ORANGE); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// --- Draw sine curve (red) --- |
|
|
|
for (int t = 0; t <= 360; t++) |
|
|
|
{ |
|
|
|
float x = ((float)t / 360.0f) * graphPeriod + graphX; |
|
|
|
float y = graphY - graphAmplitude * sinf(t * (PI / 180.0f)); |
|
|
|
if (t > 0) |
|
|
|
{ |
|
|
|
int prevT = t - 1; |
|
|
|
float px = ((float)prevT / 360.0f) * graphPeriod + graphX; |
|
|
|
float py = graphY - graphAmplitude * sinf(prevT * (PI / 180.0f)); |
|
|
|
DrawLineEx((Vector2){px, py}, (Vector2){x, y}, 2.5f, RED); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// --- Draw moving vertical line on the graph corresponding to the angle --- |
|
|
|
float lineX = ((float)angleDeg / 360.0f) * graphPeriod + graphX; |
|
|
|
DrawLine((int)lineX, (int)(graphY - graphAmplitude), (int)lineX, (int)(graphY + graphAmplitude), Fade(GRAY, 0.6f)); |
|
|
|
|
|
|
|
// moving points on graph |
|
|
|
float orangeY = graphY - graphAmplitude * cosf(angRad); |
|
|
|
float redY = graphY - graphAmplitude * sinf(angRad); |
|
|
|
|
|
|
|
DrawCircle((int)lineX, (int)orangeY, 6.0f, ORANGE); |
|
|
|
DrawCircle((int)lineX, (int)redY, 6.0f, RED); |
|
|
|
|
|
|
|
EndDrawing(); |
|
|
|
} |
|
|
|
|
|
|
|
CloseWindow(); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |