Skip to content

Commit

Permalink
[shapes] Add shapes_rectangle_advanced example implementing a `Dra…
Browse files Browse the repository at this point in the history
…wRectangleRoundedGradientH` function (#4435)

* [rshapes] Add  function

* "[shapes] rectangle advanced: fix screen width and height to fit with other examples"
  • Loading branch information
evertonse authored Oct 29, 2024
1 parent d15e583 commit ad79d4a
Show file tree
Hide file tree
Showing 7 changed files with 809 additions and 82 deletions.
3 changes: 2 additions & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,8 @@ SHAPES = \
shapes/shapes_logo_raylib_anim \
shapes/shapes_rectangle_scaling \
shapes/shapes_splines_drawing \
shapes/shapes_top_down_lights
shapes/shapes_top_down_lights \
shapes/shapes_rectangle_advanced

TEXTURES = \
textures/textures_background_scrolling \
Expand Down
3 changes: 3 additions & 0 deletions examples/Makefile.Web
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,9 @@ shapes/shapes_splines_drawing: shapes/shapes_splines_drawing.c
shapes/shapes_top_down_lights: shapes/shapes_top_down_lights.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)

shapes/shapes_rectangle_advanced: shapes/shapes_rectangle_advanced.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)


# Compile TEXTURES examples
textures/textures_background_scrolling: textures/textures_background_scrolling.c
Expand Down
163 changes: 82 additions & 81 deletions examples/README.md

Large diffs are not rendered by default.

330 changes: 330 additions & 0 deletions examples/shapes/shapes_rectangle_advanced.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
#include "raylib.h"
#include "rlgl.h"
#include <math.h>

// Draw rectangle with rounded edges and horizontal gradient, with options to choose side of roundness
// Adapted from both `DrawRectangleRounded` and `DrawRectangleGradientH`
void DrawRectangleRoundedGradientH(Rectangle rec, float roundnessLeft, float roundnessRight, int segments, Color left, Color right)
{
// Neither side is rounded
if ((roundnessLeft <= 0.0f && roundnessRight <= 0.0f) || (rec.width < 1) || (rec.height < 1 ))
{
DrawRectangleGradientEx(rec, left, left, right, right);
return;
}

if (roundnessLeft >= 1.0f) roundnessLeft = 1.0f;
if (roundnessRight >= 1.0f) roundnessRight = 1.0f;

// Calculate corner radius both from right and left
float recSize = rec.width > rec.height ? rec.height : rec.width;
float radiusLeft = (recSize*roundnessLeft)/2;
float radiusRight = (recSize*roundnessRight)/2;

if (radiusLeft <= 0.0f) radiusLeft = 0.0f;
if (radiusRight <= 0.0f) radiusRight = 0.0f;

if (radiusRight <= 0.0f && radiusLeft <= 0.0f) return;

float stepLength = 90.0f/(float)segments;

/*
Diagram Copied here for reference, original at `DrawRectangleRounded` source code
P0____________________P1
/| |\
/1| 2 |3\
P7 /__|____________________|__\ P2
| |P8 P9| |
| 8 | 9 | 4 |
| __|____________________|__ |
P6 \ |P11 P10| / P3
\7| 6 |5/
\|____________________|/
P5 P4
*/

// Coordinates of the 12 points also apdated from `DrawRectangleRounded`
const Vector2 point[12] = {
// PO, P1, P2
{(float)rec.x + radiusLeft, rec.y}, {(float)(rec.x + rec.width) - radiusRight, rec.y}, { rec.x + rec.width, (float)rec.y + radiusRight },
// P3, P4
{rec.x + rec.width, (float)(rec.y + rec.height) - radiusRight}, {(float)(rec.x + rec.width) - radiusRight, rec.y + rec.height},
// P5, P6, P7
{(float)rec.x + radiusLeft, rec.y + rec.height}, { rec.x, (float)(rec.y + rec.height) - radiusLeft}, {rec.x, (float)rec.y + radiusLeft},
// P8, P9
{(float)rec.x + radiusLeft, (float)rec.y + radiusLeft}, {(float)(rec.x + rec.width) - radiusRight, (float)rec.y + radiusRight},
// P10, P11
{(float)(rec.x + rec.width) - radiusRight, (float)(rec.y + rec.height) - radiusRight}, {(float)rec.x + radiusLeft, (float)(rec.y + rec.height) - radiusLeft}
};

const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };

#if defined(SUPPORT_QUADS_DRAW_MODE)
rlSetTexture(GetShapesTexture().id);
Rectangle shapeRect = GetShapesTextureRectangle();

rlBegin(RL_QUADS);
// Draw all the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
for (int k = 0; k < 4; ++k)
{
Color color;
float radius;
if (k == 0) color = left, radius = radiusLeft; // [1] Upper Left Corner
if (k == 1) color = right, radius = radiusRight; // [3] Upper Right Corner
if (k == 2) color = right, radius = radiusRight; // [5] Lower Right Corner
if (k == 3) color = left, radius = radiusLeft; // [7] Lower Left Corner
float angle = angles[k];
const Vector2 center = centers[k];

for (int i = 0; i < segments/2; i++)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(center.x, center.y);

rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius);

rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);

rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);

angle += (stepLength*2);
}

// End one even segments
if ( segments % 2)
{
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(center.x, center.y);

rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);

rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);

rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(center.x, center.y);
}
}

//
// Here we use the `Diagram` to guide ourselves to which point receives what color.
//
// By choosing the color correctly associated with a pointe the gradient effect
// will naturally come from OpenGL interpolation.
//

// [2] Upper Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[0].x, point[0].y);
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[8].x, point[8].y);

rlColor4ub(right.r, right.g, right.b, right.a);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[9].x, point[9].y);

rlColor4ub(right.r, right.g, right.b, right.a);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[1].x, point[1].y);

// [4] Left Rectangle
rlColor4ub(right.r, right.g, right.b, right.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[2].x, point[2].y);
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[9].x, point[9].y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[10].x, point[10].y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[3].x, point[3].y);

// [6] Bottom Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[11].x, point[11].y);
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[5].x, point[5].y);

rlColor4ub(right.r, right.g, right.b, right.a);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[4].x, point[4].y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[10].x, point[10].y);

// [8] left Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[7].x, point[7].y);
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[6].x, point[6].y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[11].x, point[11].y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[8].x, point[8].y);

// [9] Middle Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[8].x, point[8].y);
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[11].x, point[11].y);

rlColor4ub(right.r, right.g, right.b, right.a);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
rlVertex2f(point[10].x, point[10].y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(point[9].x, point[9].y);

rlEnd();
rlSetTexture(0);
#else

//
// Here we use the `Diagram` to guide ourselves to which point receives what color.
//
// By choosing the color correctly associated with a pointe the gradient effect
// will naturally come from OpenGL interpolation.
// But this time instead of Quad, we think in triangles.
//

rlBegin(RL_TRIANGLES);

// Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
for (int k = 0; k < 4; ++k)
{
Color color;
float radius;
if (k == 0) color = left, radius = radiusLeft; // [1] Upper Left Corner
if (k == 1) color = right, radius = radiusRight; // [3] Upper Right Corner
if (k == 2) color = right, radius = radiusRight; // [5] Lower Right Corner
if (k == 3) color = left, radius = radiusLeft; // [7] Lower Left Corner
float angle = angles[k];
const Vector2 center = centers[k];
for (int i = 0; i < segments; i++)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
angle += stepLength;
}
}

// [2] Upper Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlVertex2f(point[0].x, point[0].y);
rlVertex2f(point[8].x, point[8].y);
rlColor4ub(right.r, right.g, right.b, right.a);
rlVertex2f(point[9].x, point[9].y);
rlVertex2f(point[1].x, point[1].y);
rlColor4ub(left.r, left.g, left.b, left.a);
rlVertex2f(point[0].x, point[0].y);
rlColor4ub(right.r, right.g, right.b, right.a);
rlVertex2f(point[9].x, point[9].y);

// [4] Right Rectangle
rlColor4ub(right.r, right.g, right.b, right.a);
rlVertex2f(point[9].x, point[9].y);
rlVertex2f(point[10].x, point[10].y);
rlVertex2f(point[3].x, point[3].y);
rlVertex2f(point[2].x, point[2].y);
rlVertex2f(point[9].x, point[9].y);
rlVertex2f(point[3].x, point[3].y);

// [6] Bottom Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlVertex2f(point[11].x, point[11].y);
rlVertex2f(point[5].x, point[5].y);
rlColor4ub(right.r, right.g, right.b, right.a);
rlVertex2f(point[4].x, point[4].y);
rlVertex2f(point[10].x, point[10].y);
rlColor4ub(left.r, left.g, left.b, left.a);
rlVertex2f(point[11].x, point[11].y);
rlColor4ub(right.r, right.g, right.b, right.a);
rlVertex2f(point[4].x, point[4].y);

// [8] Left Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlVertex2f(point[7].x, point[7].y);
rlVertex2f(point[6].x, point[6].y);
rlVertex2f(point[11].x, point[11].y);
rlVertex2f(point[8].x, point[8].y);
rlVertex2f(point[7].x, point[7].y);
rlVertex2f(point[11].x, point[11].y);

// [9] Middle Rectangle
rlColor4ub(left.r, left.g, left.b, left.a);
rlVertex2f(point[8].x, point[8].y);
rlVertex2f(point[11].x, point[11].y);
rlColor4ub(right.r, right.g, right.b, right.a);
rlVertex2f(point[10].x, point[10].y);
rlVertex2f(point[9].x, point[9].y);
rlColor4ub(left.r, left.g, left.b, left.a);
rlVertex2f(point[8].x, point[8].y);
rlColor4ub(right.r, right.g, right.b, right.a);
rlVertex2f(point[10].x, point[10].y);
rlEnd();
#endif
}

int main(int argc, char *argv[])
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rectangle avanced");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------

// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update rectangle bounds
//----------------------------------------------------------------------------------
double width = GetScreenWidth()/2.0, height = GetScreenHeight()/6.0;
Rectangle rec = {
GetScreenWidth() / 2.0 - width/2,
GetScreenHeight() / 2.0 - (5)*(height/2),
width, height
};
//--------------------------------------------------------------------------------------

// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);

// Draw All Rectangles with different roundess for each side and different gradients
DrawRectangleRoundedGradientH(rec, 0.8, 0.8, 36, BLUE, RED);

rec.y += rec.height + 1;
DrawRectangleRoundedGradientH(rec, 0.5, 1.0, 36, RED, PINK);

rec.y += rec.height + 1;
DrawRectangleRoundedGradientH(rec, 1.0, 0.5, 36, RED, BLUE);

rec.y += rec.height + 1;
DrawRectangleRoundedGradientH(rec, 0.0, 1.0, 36, BLUE, BLACK);

rec.y += rec.height + 1;
DrawRectangleRoundedGradientH(rec, 1.0, 0.0, 36, BLUE, PINK);
EndDrawing();
//--------------------------------------------------------------------------------------
}

// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file added examples/shapes/shapes_rectangle_advanced.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ad79d4a

Please sign in to comment.