mirror of
https://github.com/raysan5/raylib.git
synced 2026-01-10 21:48:46 +01:00
Compare commits
6 Commits
bbba3d0802
...
4caba49658
| Author | SHA1 | Date | |
|---|---|---|---|
| 4caba49658 | |||
| 86e00bde65 | |||
| 95a8977e33 | |||
| f531ee2d8f | |||
| b18f547d8f | |||
| be9a24e68c |
280
examples/shapes/shapes_rlgl_color_wheel.c
Normal file
280
examples/shapes/shapes_rlgl_color_wheel.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shapes] example - rlgl color wheel
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
|
||||
*
|
||||
* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* 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 Robin (@RobinsAviary)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include "rlgl.h"
|
||||
#include "raymath.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
#include "raygui.h"
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// The minimum/maximum points the circle can have
|
||||
const unsigned int pointsMin = 3;
|
||||
const unsigned int pointsMax = 256;
|
||||
|
||||
// The current number of points and the radius of the circle
|
||||
unsigned int triangleCount = 64;
|
||||
float pointScale = 150.0f;
|
||||
|
||||
// Slider value, literally maps to value in HSV
|
||||
float value = 1.0f;
|
||||
|
||||
// The center of the screen
|
||||
Vector2 center = { (float)screenWidth/2.0f, (float)screenHeight/2.0f };
|
||||
// The location of the color wheel
|
||||
Vector2 circlePosition = center;
|
||||
|
||||
// The currently selected color
|
||||
Color color = { 255, 255, 255, 255 };
|
||||
|
||||
// Indicates if the slider is being clicked
|
||||
bool sliderClicked = false;
|
||||
|
||||
// Indicates if the current color going to be updated, as well as the handle position
|
||||
bool settingColor = false;
|
||||
|
||||
// How the color wheel will be rendered
|
||||
unsigned int renderType = RL_TRIANGLES;
|
||||
|
||||
// Enable anti-aliasing
|
||||
SetConfigFlags(FLAG_MSAA_4X_HINT);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rlgl color wheel");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
triangleCount += (unsigned int)GetMouseWheelMove();
|
||||
triangleCount = (unsigned int)Clamp((float)triangleCount, (float)pointsMin, (float)pointsMax);
|
||||
|
||||
Rectangle sliderRectangle = { 42.0f, 16.0f + 64.0f + 45.0f, 64.0f, 16.0f };
|
||||
Vector2 mousePosition = GetMousePosition();
|
||||
|
||||
// Checks if the user is hovering over the value slider
|
||||
bool sliderHover = (mousePosition.x >= sliderRectangle.x && mousePosition.y >= sliderRectangle.y && mousePosition.x < sliderRectangle.x + sliderRectangle.width && mousePosition.y < sliderRectangle.y + sliderRectangle.height);
|
||||
|
||||
// Copy color as hex
|
||||
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
|
||||
{
|
||||
if (IsKeyPressed(KEY_C))
|
||||
{
|
||||
SetClipboardText(TextFormat("#%02X%02X%02X", color.r, color.g, color.b));
|
||||
}
|
||||
}
|
||||
|
||||
// Scale up the color wheel, adjusting the handle visually
|
||||
if (IsKeyDown(KEY_UP))
|
||||
{
|
||||
pointScale *= 1.025f;
|
||||
|
||||
if (pointScale > (float)screenHeight/2.0f)
|
||||
{
|
||||
pointScale = (float)screenHeight/2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 1.025f, 1.025f }), center);
|
||||
}
|
||||
}
|
||||
|
||||
// Scale down the wheel, adjusting the handle visually
|
||||
if (IsKeyDown(KEY_DOWN))
|
||||
{
|
||||
pointScale *= 0.975f;
|
||||
|
||||
if (pointScale < 32.0f)
|
||||
{
|
||||
pointScale = 32.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 0.975f, 0.975f }), center);
|
||||
}
|
||||
|
||||
float distance = Vector2Distance(center, circlePosition)/pointScale;
|
||||
float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f) / 2.0f);
|
||||
|
||||
if (distance > 1.0f)
|
||||
{
|
||||
circlePosition = Vector2Add((Vector2){ sinf(angle*(PI * 2.0f)) * pointScale, -cosf(angle*(PI*2.0f))*pointScale }, center);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if the user clicked on the color wheel
|
||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && Vector2Distance(GetMousePosition(), center) <= pointScale + 10.0f)
|
||||
{
|
||||
settingColor = true;
|
||||
}
|
||||
|
||||
// Update flag when mouse button is released
|
||||
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) settingColor = false;
|
||||
|
||||
// Check if the user clicked/released the slider for the color's value
|
||||
if (sliderHover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) sliderClicked = true;
|
||||
|
||||
if (sliderClicked && IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) sliderClicked = false;
|
||||
|
||||
// Update render mode accordingly
|
||||
if (IsKeyPressed(KEY_SPACE)) renderType = RL_LINES;
|
||||
|
||||
if (IsKeyReleased(KEY_SPACE)) renderType = RL_TRIANGLES;
|
||||
|
||||
// If the slider or the wheel was clicked, update the current color
|
||||
if (settingColor || sliderClicked)
|
||||
{
|
||||
if (settingColor) {
|
||||
circlePosition = GetMousePosition();
|
||||
}
|
||||
|
||||
float distance = Vector2Distance(center, circlePosition) / pointScale;
|
||||
|
||||
float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f)/2.0f);
|
||||
if (settingColor && distance > 1.0f) {
|
||||
circlePosition = Vector2Add((Vector2){ sinf(angle*(PI*2.0f))*pointScale, -cosf(angle*(PI* 2.0f))*pointScale }, center);
|
||||
}
|
||||
|
||||
float angle360 = angle*360.0f;
|
||||
|
||||
float valueActual = Clamp(distance, 0.0f, 1.0f);
|
||||
|
||||
color = ColorLerp((Color){ (int)(value*255.0f), (int)(value*255.0f), (int)(value*255.0f), 255 }, ColorFromHSV(angle360, Clamp(distance, 0.0f, 1.0f), 1.0f), valueActual);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
// Begin rendering color wheel
|
||||
rlBegin(renderType);
|
||||
for (unsigned int i = 0; i < triangleCount; i++)
|
||||
{
|
||||
float angleOffset = ((PI*2.0f)/(float)triangleCount);
|
||||
float angle = angleOffset*(float)i;
|
||||
float angleOffsetCalculated = ((float)i + 1)*angleOffset;
|
||||
Vector2 scale = (Vector2){ pointScale, pointScale };
|
||||
|
||||
Vector2 offset = Vector2Multiply((Vector2){ sinf(angle), -cosf(angle) }, scale);
|
||||
Vector2 offset2 = Vector2Multiply((Vector2){ sinf(angleOffsetCalculated), -cosf(angleOffsetCalculated) }, scale);
|
||||
|
||||
Vector2 position = Vector2Add(center, offset);
|
||||
Vector2 position2 = Vector2Add(center, offset2);
|
||||
|
||||
float angleNonRadian = (angle/(2.0f*PI))*360.0f;
|
||||
float angleNonRadianOffset = (angleOffset/(2.0f*PI))*360.0f;
|
||||
|
||||
Color currentColor = ColorFromHSV(angleNonRadian, 1.0f, 1.0f);
|
||||
Color offsetColor = ColorFromHSV(angleNonRadian + angleNonRadianOffset, 1.0f, 1.0f);
|
||||
|
||||
// Input vertices differently depending on mode
|
||||
if (renderType == RL_TRIANGLES)
|
||||
{
|
||||
// RL_TRIANGLES expects three vertices per triangle
|
||||
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
|
||||
rlVertex2f(position.x, position.y);
|
||||
rlColor4f(value, value, value, 1.0f);
|
||||
rlVertex2f(center.x, center.y);
|
||||
rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
|
||||
rlVertex2f(position2.x, position2.y);
|
||||
}
|
||||
else if (renderType == RL_LINES)
|
||||
{
|
||||
// RL_LINES expects two vertices per line
|
||||
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
|
||||
rlVertex2f(position.x, position.y);
|
||||
rlColor4ub(WHITE.r, WHITE.g, WHITE.b, WHITE.a);
|
||||
rlVertex2f(center.x, center.y);
|
||||
|
||||
rlVertex2f(center.x, center.y);
|
||||
rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
|
||||
rlVertex2f(position2.x, position2.y);
|
||||
|
||||
rlVertex2f(position2.x, position2.y);
|
||||
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
|
||||
rlVertex2f(position.x, position.y);
|
||||
}
|
||||
}
|
||||
rlEnd();
|
||||
|
||||
// Make the handle slightly more visible overtop darker colors
|
||||
Color handleColor = BLACK;
|
||||
|
||||
if (Vector2Distance(center, circlePosition)/pointScale <= 0.5f && value <= 0.5f)
|
||||
{
|
||||
handleColor = DARKGRAY;
|
||||
}
|
||||
|
||||
// Draw the color handle
|
||||
DrawCircleLinesV(circlePosition, 4.0f, handleColor);
|
||||
|
||||
// Draw the color in a preview, with a darkened outline.
|
||||
DrawRectangleV((Vector2){ 8.0f, 8.0f }, (Vector2){ 64.0f, 64.0f }, color);
|
||||
DrawRectangleLinesEx((Rectangle){ 8.0f, 8.0f, 64.0f, 64.0f }, 2.0f, ColorLerp(color, BLACK, 0.5f));
|
||||
|
||||
// Draw current color as hex and decimal
|
||||
DrawText(TextFormat("#%02X%02X%02X\n(%d, %d, %d)", color.r, color.g, color.b, color.r, color.g, color.b), 8, 8 + 64 + 8, 20, DARKGRAY);
|
||||
|
||||
// Update the visuals for the copying text
|
||||
Color copyColor = DARKGRAY;
|
||||
unsigned int offset = 0;
|
||||
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
|
||||
{
|
||||
copyColor = DARKGREEN;
|
||||
offset = 4;
|
||||
}
|
||||
|
||||
// Draw the copying text
|
||||
DrawText("press ctrl+c to copy!", 8, 425 - offset, 20, copyColor);
|
||||
|
||||
// Display the number of rendered triangles
|
||||
DrawText(TextFormat("triangle count: %d", triangleCount), 8, 395, 20, DARKGRAY);
|
||||
|
||||
// Slider to change color's value
|
||||
GuiSliderBar(sliderRectangle, "value: ", "", &value, 0.0f, 1.0f);
|
||||
|
||||
// Draw FPS next to outlined color preview
|
||||
DrawFPS(64 + 16, 8);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
examples/shapes/shapes_rlgl_color_wheel.png
Normal file
BIN
examples/shapes/shapes_rlgl_color_wheel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
@ -1749,7 +1749,12 @@ int InitPlatform(void)
|
||||
{
|
||||
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
|
||||
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
if (glfwJoystickPresent(i))
|
||||
{
|
||||
CORE.Input.Gamepad.ready[i] = true;
|
||||
CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
|
||||
strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
@ -1723,12 +1723,11 @@ void PollInputEvents(void)
|
||||
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||
strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], SDL_GameControllerNameForIndex(nextAvailableSlot), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
const char *controllerName = SDL_GameControllerNameForIndex(nextAvailableSlot);
|
||||
if (controllerName != NULL) strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], controllerName, MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
else strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
}
|
||||
} break;
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
|
||||
@ -1266,8 +1266,8 @@ int main(int argc, char *argv[])
|
||||
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
|
||||
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
|
||||
#else
|
||||
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->filter);
|
||||
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->filter));
|
||||
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name);
|
||||
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
|
||||
#endif
|
||||
|
||||
// Update generated .html metadata
|
||||
@ -1507,9 +1507,10 @@ int main(int argc, char *argv[])
|
||||
"#include <string.h>\n"
|
||||
"#include <stdlib.h>\n"
|
||||
"#include <emscripten/emscripten.h>\n\n"
|
||||
"static char logText[1024] = {0};\n"
|
||||
"static char logText[4096] = {0};\n"
|
||||
"static int logTextOffset = 0;\n\n"
|
||||
"void CustomTraceLog(int msgType, const char *text, va_list args)\n{\n"
|
||||
" if (logTextOffset < 3800)\n {\n"
|
||||
" switch (msgType)\n {\n"
|
||||
" case LOG_INFO: logTextOffset += sprintf(logText + logTextOffset, \"INFO: \"); break;\n"
|
||||
" case LOG_ERROR: logTextOffset += sprintf(logText + logTextOffset, \"ERROR: \"); break;\n"
|
||||
@ -1517,7 +1518,7 @@ int main(int argc, char *argv[])
|
||||
" case LOG_DEBUG: logTextOffset += sprintf(logText + logTextOffset, \"DEBUG: \"); break;\n"
|
||||
" default: break;\n }\n"
|
||||
" logTextOffset += vsprintf(logText + logTextOffset, text, args);\n"
|
||||
" logTextOffset += sprintf(logText + logTextOffset, \"\\n\");\n}\n\n"
|
||||
" logTextOffset += sprintf(logText + logTextOffset, \"\\n\");\n}\n}\n\n"
|
||||
"int main(int argc, char *argv[])\n{\n"
|
||||
" SetTraceLogCallback(CustomTraceLog);\n"
|
||||
" int requestedTestFrames = 0;\n"
|
||||
@ -1525,20 +1526,20 @@ int main(int argc, char *argv[])
|
||||
" if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n";
|
||||
|
||||
static const char *returnReplaceText =
|
||||
" char outputLogFile[256] = { 0 };\n"
|
||||
" TextCopy(outputLogFile, GetFileNameWithoutExt(argv[0]));\n"
|
||||
" SaveFileText(outputLogFile, logText);\n"
|
||||
" emscripten_run_script(TextFormat(\"saveFileFromMEMFSToDisk('%s','%s')\", outputLogFile, GetFileName(outputLogFile)));\n\n"
|
||||
" SaveFileText(\"outputLogFileName\", logText);\n"
|
||||
" emscripten_run_script(\"saveFileFromMEMFSToDisk('outputLogFileName','outputLogFileName')\");\n\n"
|
||||
" return 0";
|
||||
char *returnReplaceTextUpdated = TextReplace(returnReplaceText, "outputLogFileName", TextFormat("%s.log", exName));
|
||||
|
||||
char *srcTextUpdated[4] = { 0 };
|
||||
srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
|
||||
srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
|
||||
srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
|
||||
srcTextUpdated[3] = TextReplace(srcTextUpdated[2], " return 0", returnReplaceText);
|
||||
srcTextUpdated[3] = TextReplace(srcTextUpdated[2], " return 0", returnReplaceTextUpdated);
|
||||
MemFree(returnReplaceTextUpdated);
|
||||
UnloadFileText(srcText);
|
||||
|
||||
//SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[3]);
|
||||
SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[3]);
|
||||
for (int i = 0; i < 4; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; }
|
||||
|
||||
// Build example for PLATFORM_WEB
|
||||
|
||||
Reference in New Issue
Block a user