This commit is contained in:
Ray
2026-04-18 18:53:05 +02:00
5 changed files with 326 additions and 17 deletions

View File

@ -0,0 +1,133 @@
/*******************************************************************************************
*
* raylib [shapes] example - ellipse collision
*
* Example complexity rating: [★★☆☆] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Ziya (@Monjaris)
*
* 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 Ziya (@Monjaris)
*
********************************************************************************************/
#include "raylib.h"
#include <math.h>
// Check if point is inside ellipse
static bool CheckCollisionPointEllipse(Vector2 point, Vector2 center, float rx, float ry)
{
float dx = (point.x - center.x)/rx;
float dy = (point.y - center.y)/ry;
return (dx*dx + dy*dy) <= 1.0f;
}
// Check if two ellipses collide
// Uses radial boundary distance in the direction between centers — scales correctly with radii
static bool CheckCollisionEllipses(Vector2 c1, float rx1, float ry1, Vector2 c2, float rx2, float ry2)
{
float dx = c2.x - c1.x;
float dy = c2.y - c1.y;
float dist = sqrtf(dx*dx + dy*dy);
// Ellipses are on top of each other
if (dist == 0.0f) return true;
float theta = atan2f(dy, dx);
float cosT = cosf(theta);
float sinT = sinf(theta);
// Radial distance from center to ellipse boundary in direction theta
// r(theta) = (rx * ry) / sqrt((ry*cos)^2 + (rx*sin)^2)
float r1 = (rx1*ry1)/sqrtf((ry1*cosT)*(ry1*cosT) + (rx1*sinT)*(rx1*sinT));
float r2 = (rx2*ry2)/sqrtf((ry2*cosT)*(ry2*cosT) + (rx2*sinT)*(rx2*sinT));
return dist <= (r1 + r2);
}
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - collision ellipses");
SetTargetFPS(60);
Vector2 ellipseACenter = { (float)screenWidth/4, (float)screenHeight/2 };
float ellipseARx = 120.0f;
float ellipseARy = 70.0f;
Vector2 ellipseBCenter = { (float)screenWidth*3/4, (float)screenHeight/2 };
float ellipseBRx = 90.0f;
float ellipseBRy = 140.0f;
// 0 = controlling A, 1 = controlling B
int controlled = 0;
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_A)) controlled = 0;
if (IsKeyPressed(KEY_B)) controlled = 1;
if (controlled == 0) ellipseACenter = GetMousePosition();
else ellipseBCenter = GetMousePosition();
bool ellipsesCollide = CheckCollisionEllipses(
ellipseACenter, ellipseARx, ellipseARy,
ellipseBCenter, ellipseBRx, ellipseBRy
);
bool mouseInA = CheckCollisionPointEllipse(GetMousePosition(), ellipseACenter, ellipseARx, ellipseARy);
bool mouseInB = CheckCollisionPointEllipse(GetMousePosition(), ellipseBCenter, ellipseBRx, ellipseBRy);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
DrawEllipse((int)ellipseACenter.x, (int)ellipseACenter.y, ellipseARx, ellipseARy, ellipsesCollide ? RED : BLUE);
DrawEllipse((int)ellipseBCenter.x, (int)ellipseBCenter.y, ellipseBRx, ellipseBRy, ellipsesCollide ? RED : GREEN);
DrawEllipseLines((int)ellipseACenter.x, (int)ellipseACenter.y, ellipseARx, ellipseARy, WHITE);
DrawEllipseLines((int)ellipseBCenter.x, (int)ellipseBCenter.y, ellipseBRx, ellipseBRy, WHITE);
DrawCircleV(ellipseACenter, 4, WHITE);
DrawCircleV(ellipseBCenter, 4, WHITE);
if (ellipsesCollide) DrawText("ELLIPSES COLLIDE", screenWidth/2 - 120, 40, 28, RED);
else DrawText("NO COLLISION", screenWidth/2 - 80, 40, 28, DARKGRAY);
DrawText(controlled == 0 ? "Controlling: A" : "Controlling: B", 20, screenHeight - 40, 20, YELLOW);
if (mouseInA && controlled != 0) DrawText("Mouse inside ellipse A", 20, screenHeight - 70, 20, BLUE);
if (mouseInB && controlled != 1) DrawText("Mouse inside ellipse B", 20, screenHeight - 70, 20, GREEN);
DrawText("Press [A] or [B] to switch control", 20, 20, 20, GRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
CloseWindow();
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -26,13 +26,13 @@ REM Checks if cl is available and skips to the argument loop if it is
REM (Prevents calling vcvarsall every time you run this script)
WHERE cl >nul 2>nul
IF %ERRORLEVEL% == 0 goto READ_ARGS
REM Activate the msvc build environment if cl isn't available yet
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" (
set VC_INIT="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat"
) ELSE IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" (
set VC_INIT="C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat"
) ELSE IF EXIST "C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat" (
set VC_INIT="C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat"
for /f "tokens=*" %%i in (
'"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath 2^>nul'
) do set VS_PATH=%%i
IF defined VS_PATH (
set VC_INIT="%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat"
) ELSE (
REM Initialize your vc environment here if the defaults don't work
REM set VC_INIT="C:\your\path\here\vcvarsall.bat"
@ -167,7 +167,7 @@ IF NOT EXIST !TEMP_DIR!\ (
cd !TEMP_DIR!
REM raylib source folder
set "RAYLIB_DEFINES=/D_DEFAULT_SOURCE /DPLATFORM_DESKTOP /DGRAPHICS_API_OPENGL_33"
set RAYLIB_C_FILES="!RAYLIB_SRC!\rcore.c" "!RAYLIB_SRC!\rshapes.c" "!RAYLIB_SRC!\rtextures.c" "!RAYLIB_SRC!\rtext.c" "!RAYLIB_SRC!\rmodels.c" "!RAYLIB_SRC!\utils.c" "!RAYLIB_SRC!\raudio.c" "!RAYLIB_SRC!\rglfw.c"
set RAYLIB_C_FILES="!RAYLIB_SRC!\rcore.c" "!RAYLIB_SRC!\rshapes.c" "!RAYLIB_SRC!\rtextures.c" "!RAYLIB_SRC!\rtext.c" "!RAYLIB_SRC!\rmodels.c" "!RAYLIB_SRC!\raudio.c" "!RAYLIB_SRC!\rglfw.c"
set RAYLIB_INCLUDE_FLAGS=/I"!RAYLIB_SRC!" /I"!RAYLIB_SRC!\external\glfw\include"
IF DEFINED REALLY_QUIET (

View File

@ -275,11 +275,20 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
#GRAPHICS = GRAPHICS_API_OPENGL_SOFTWARE # Uncomment to use software rendering
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
# On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
#GRAPHICS = GRAPHICS_API_OPENGL_ES3
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_WEB_RGFW)
# On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
#GRAPHICS = GRAPHICS_API_OPENGL_ES3
ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_SOFTWARE)
$(error WEB_RGFW: Software rendering not supported!)
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
# By default use OpenGL ES 2.0 on Android
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2

View File

@ -177,6 +177,13 @@ typedef struct {
RGFW_window *window; // Native display device (physical screen connection)
RGFW_monitor *monitor;
mg_gamepads minigamepad;
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
RGFW_surface *surface;
u8 *surfacePixels;
i32 surfaceWidth;
i32 surfaceHeight;
#endif
} PlatformData;
//----------------------------------------------------------------------------------
@ -1121,7 +1128,35 @@ void DisableCursor(void)
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
RGFW_window_swapBuffers_OpenGL(platform.window);
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
{
if (platform.surface)
{
// copy rlsw pixel data to the surface framebuffer
swReadPixels(0, 0, platform.surfaceWidth, platform.surfaceHeight, SW_RGBA, SW_UNSIGNED_BYTE, platform.surfacePixels);
// Mac wants a different pixel order. I cant seem to get this to work any other way
#if defined(__APPLE__)
unsigned char temp = 0;
unsigned char *p = NULL;
for (int i = 0; i < (platform.surfaceWidth * platform.surfaceHeight); i += 1)
{
p = platform.surfacePixels + (i * 4);
temp = p[0];
p[0] = p[2];
p[2] = temp;
}
#endif
// blit surface to the window
RGFW_window_blitSurface(platform.window, platform.surface);
}
}
#else
{
RGFW_window_swapBuffers_OpenGL(platform.window);
}
#endif
}
//----------------------------------------------------------------------------------
@ -1315,6 +1350,9 @@ void PollInputEvents(void)
// Window events are also polled (Minimized, maximized, close...)
case RGFW_windowResized:
{
// set flag that the window was resized
CORE.Window.resizedLastFrame = true;
#if defined(__APPLE__)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
@ -1363,7 +1401,42 @@ void PollInputEvents(void)
CORE.Window.currentFbo.width = CORE.Window.screen.width;
CORE.Window.currentFbo.height = CORE.Window.screen.height;
#endif
CORE.Window.resizedLastFrame = true;
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
#if defined(__APPLE__)
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
SetupViewport(platform.window->w * currentMonitor->pixelRatio, platform.window->h * currentMonitor->pixelRatio);
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
#endif
platform.surfaceWidth = CORE.Window.currentFbo.width;
platform.surfaceHeight = CORE.Window.currentFbo.height;
// in software mode we dont have the viewport so we need to reverse the highdpi changes
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
Vector2 scaleDpi = GetWindowScaleDPI();
platform.surfaceWidth *= scaleDpi.x;
platform.surfaceHeight *= scaleDpi.y;
}
if (platform.surfacePixels != NULL)
{
RL_FREE(platform.surfacePixels);
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth * platform.surfaceHeight * 4);
}
if (platform.surface != NULL)
{
RGFW_surface_free(platform.surface);
platform.surface = RGFW_window_createSurface(platform.window, platform.surfacePixels, platform.surfaceWidth, platform.surfaceHeight, RGFW_formatBGRA8);
swResize(platform.surfaceWidth, platform.surfaceHeight);
}
#endif
} break;
case RGFW_windowMaximized:
{
@ -1641,6 +1714,12 @@ int InitPlatform(void)
hints->major = 4;
hints->minor = 3;
}
else if (rlGetVersion() == RL_OPENGL_SOFTWARE)
{
hints->major = 1;
hints->minor = 1;
hints->renderer = RGFW_glSoftware;
}
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) hints->samples = 4;
@ -1720,6 +1799,39 @@ int InitPlatform(void)
#endif
}
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
// apple always scales for retina
#if defined(__APPLE__)
RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window);
CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f);
CORE.Window.render.width = CORE.Window.screen.width * currentMonitor->pixelRatio;
CORE.Window.render.height = CORE.Window.screen.height * currentMonitor->pixelRatio;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
#endif
platform.surfaceWidth = CORE.Window.currentFbo.width;
platform.surfaceHeight = CORE.Window.currentFbo.height;
platform.surfacePixels = RL_MALLOC(platform.surfaceWidth * platform.surfaceHeight * 4);
if (platform.surfacePixels == NULL)
{
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize software pixel buffer");
return -1;
}
platform.surface = RGFW_window_createSurface(platform.window, platform.surfacePixels, platform.surfaceWidth, platform.surfaceHeight, RGFW_formatBGRA8);
if (platform.surface == NULL)
{
RL_FREE(platform.surfacePixels);
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize software surface");
return -1;
}
#endif
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
@ -1750,20 +1862,63 @@ int InitPlatform(void)
//----------------------------------------------------------------------------
#if defined(RGFW_WAYLAND)
if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
{
if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland, Software): Initialized successfully");
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software (fallback)): Initialized successfully");
}
else
{
if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
}
#elif defined(RGFW_X11)
#if defined(__APPLE__)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (MacOS)): Initialized successfully");
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software, (MacOS)): Initialized successfully");
}
else
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, (MacOS)): Initialized successfully");
}
#else
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software): Initialized successfully");
}
else
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
}
#endif
#elif defined (RGFW_WINDOWS)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32, Software): Initialized successfully");
}
else
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
}
#elif defined(RGFW_WASM)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs, Software): Initialized successfully");
}
else
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
}
#elif defined(RGFW_MACOS)
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
if (rlGetVersion() == RL_OPENGL_SOFTWARE)
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS, Software): Initialized successfully");
}
else
{
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
}
#endif
mg_gamepads_init(&platform.minigamepad);
@ -1776,6 +1931,18 @@ void ClosePlatform(void)
{
mg_gamepads_free(&platform.minigamepad);
RGFW_window_close(platform.window);
#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
if (platform.surfacePixels != NULL)
{
RL_FREE(platform.surfacePixels);
}
if (platform.surface != NULL)
{
RGFW_surface_free(platform.surface);
}
#endif
}
// Keycode mapping