Skip to content

Commit

Permalink
Updated circle angle coefficient and added a check to fix issues with…
Browse files Browse the repository at this point in the history
… small radius circles not having enough segments to complete the shape. Thanks GiovanniCmpaner for the report!
  • Loading branch information
grimfang4 committed Feb 5, 2022
1 parent 354dcff commit b21d5be
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 86 deletions.
48 changes: 33 additions & 15 deletions src/renderer_shapes_GL_common.inl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ See a particular renderer's *.c file for specifics. */



#define SDL_GPU_CIRCLE_SEGMENT_ANGLE_FACTOR 0.625f


#define CALCULATE_CIRCLE_DT_AND_SEGMENTS(radius) \
dt = SDL_GPU_CIRCLE_SEGMENT_ANGLE_FACTOR/sqrtf(radius); /* s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good */ \
numSegments = (int)(2*PI/dt) + 1; \
\
if(numSegments < 16) \
{ \
numSegments = 16; \
dt = 2*PI/(numSegments-1); \
}


static float SetLineThickness(GPU_Renderer* renderer, float thickness)
Expand Down Expand Up @@ -178,7 +190,7 @@ static void Arc(GPU_Renderer* renderer, GPU_Target* target, float x, float y, fl
}


dt = ((end_angle - start_angle)/360)*(1.25f/sqrtf(outer_radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
dt = ((end_angle - start_angle)/360)*(SDL_GPU_CIRCLE_SEGMENT_ANGLE_FACTOR/sqrtf(outer_radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.

numSegments = (int)((fabs(end_angle - start_angle)*PI/180)/dt);
if(numSegments == 0)
Expand Down Expand Up @@ -255,7 +267,7 @@ static void ArcFilled(GPU_Renderer* renderer, GPU_Target* target, float x, float
end_angle -= 360;
}

dt = ((end_angle - start_angle)/360)*(1.25f/sqrtf(radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
dt = ((end_angle - start_angle)/360)*(SDL_GPU_CIRCLE_SEGMENT_ANGLE_FACTOR/sqrtf(radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.

numSegments = (int)((fabs(end_angle - start_angle)*RAD_PER_DEG)/dt);
if(numSegments == 0)
Expand Down Expand Up @@ -314,8 +326,10 @@ static void Circle(GPU_Renderer* renderer, GPU_Target* target, float x, float y,
float t = thickness/2;
float inner_radius = radius - t;
float outer_radius = radius + t;
float dt = (1.25f/sqrtf(outer_radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
int numSegments = (int)(2*PI/dt)+1;
float dt;
int numSegments;

CALCULATE_CIRCLE_DT_AND_SEGMENTS(outer_radius);

float tempx;
float c = cosf(dt);
Expand Down Expand Up @@ -345,10 +359,12 @@ static void Circle(GPU_Renderer* renderer, GPU_Target* target, float x, float y,

static void CircleFilled(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float radius, SDL_Color color)
{
float dt = (1.25f/sqrtf(radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
float dt;
float dx, dy;
int numSegments = (int)(2*PI/dt)+1;
int numSegments;
int i;

CALCULATE_CIRCLE_DT_AND_SEGMENTS(radius);

float tempx;
float c = cosf(dt);
Expand Down Expand Up @@ -395,8 +411,10 @@ static void Ellipse(GPU_Renderer* renderer, GPU_Target* target, float x, float y
float outer_radius_x = rx + t;
float inner_radius_y = ry - t;
float outer_radius_y = ry + t;
float dt = (1.25f/sqrtf(outer_radius_x > outer_radius_y? outer_radius_x : outer_radius_y)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
int numSegments = (int)(2*M_PI/dt)+1;
float dt;
int numSegments;

CALCULATE_CIRCLE_DT_AND_SEGMENTS(outer_radius_x > outer_radius_y? outer_radius_x : outer_radius_y);

float tempx;
float c = cosf(dt);
Expand Down Expand Up @@ -442,8 +460,9 @@ static void EllipseFilled(GPU_Renderer* renderer, GPU_Target* target, float x, f
int i;
float rot_x = cosf(degrees*RAD_PER_DEG);
float rot_y = sinf(degrees*RAD_PER_DEG);
float dt = (1.25f/sqrtf(rx > ry? rx : ry)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
int numSegments = (int)(2*M_PI/dt)+1;
float dt;
int numSegments;
CALCULATE_CIRCLE_DT_AND_SEGMENTS(rx > ry? rx : ry);

float tempx;
float c = cosf(dt);
Expand Down Expand Up @@ -586,7 +605,7 @@ static void SectorFilled(GPU_Renderer* renderer, GPU_Target* target, float x, fl


t = start_angle;
dt = ((end_angle - start_angle)/360)*(1.25f/sqrtf(outer_radius)) * DEG_PER_RAD; // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
dt = ((end_angle - start_angle)/360)*(SDL_GPU_CIRCLE_SEGMENT_ANGLE_FACTOR/sqrtf(outer_radius)) * DEG_PER_RAD; // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.

numSegments = (int)(fabs(end_angle - start_angle)/dt);
if(numSegments == 0)
Expand Down Expand Up @@ -808,10 +827,9 @@ static void RectangleRound(GPU_Renderer* renderer, GPU_Target* target, float x1,
float t = thickness/2;
float inner_radius = radius - t;
float outer_radius = radius + t;
float dt = (1.25f/sqrtf(outer_radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
int numSegments = (int)(2*PI/dt)+1;
if(numSegments < 4)
numSegments = 4;
float dt;
int numSegments;
CALCULATE_CIRCLE_DT_AND_SEGMENTS(outer_radius);

// Make a multiple of 4 so we can have even corners
numSegments += numSegments % 4;
Expand Down
146 changes: 75 additions & 71 deletions tests/shapes/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,76 @@
#define M_PI 3.14159f
#endif

#define RANDOMIZE_SHAPE_DATA() \
for(i = 0; i < NUM_COLORS; i++) \
{ \
colors[i].r = rand() % 256; \
colors[i].g = rand() % 256; \
colors[i].b = rand() % 256; \
GET_ALPHA(colors[i]) = rand() % 256; \
} \
\
for (i = 0; i < NUM_PIXELS; i++) \
{ \
px[i] = rand() % screen->w; \
py[i] = rand() % screen->h; \
} \
\
for (i = 0; i < NUM_LINES; i++) \
{ \
lx1[i] = rand() % screen->w; \
ly1[i] = rand() % screen->h; \
lx2[i] = rand() % screen->w; \
ly2[i] = rand() % screen->h; \
} \
\
for (i = 0; i < NUM_TRIS; i++) \
{ \
tx1[i] = rand() % screen->w; \
ty1[i] = rand() % screen->h; \
tx2[i] = rand() % screen->w; \
ty2[i] = rand() % screen->h; \
tx3[i] = rand() % screen->w; \
ty3[i] = rand() % screen->h; \
} \
\
for (i = 0; i < NUM_RECTS; i++) \
{ \
rx1[i] = rand() % screen->w; \
ry1[i] = rand() % screen->h; \
rx2[i] = rand() % screen->w; \
ry2[i] = rand() % screen->h; \
rr[i] = rand() % 10 + 2; \
} \
\
for (i = 0; i < NUM_ARCS; i++) \
{ \
ax[i] = rand() % screen->w; \
ay[i] = rand() % screen->h; \
ar[i] = (rand() % screen->h) / 10.0f; \
ar2[i] = ((rand() % 101) / 100.0f) * ar[i]; \
aa1[i] = rand() % 360; \
aa2[i] = rand() % 360; \
} \
\
for (i = 0; i < NUM_POLYS; i++) \
{ \
float cx = rand() % screen->w; \
float cy = rand() % screen->h; \
float radius = 20 + rand() % (screen->w / 8); \
\
int j; \
\
pn[i] = rand() % 8 + 3; \
pv[i] = (float*)malloc(2 * pn[i] * sizeof(float)); \
\
for (j = 0; j < pn[i] * 2; j += 2) \
{ \
pv[i][j] = cx + radius * cos(2 * M_PI * (((float)j) / (pn[i] * 2))) + rand() % ((int)radius / 2); \
pv[i][j + 1] = cy + radius * sin(2 * M_PI * (((float)j) / (pn[i] * 2))) + rand() % ((int)radius / 2); \
} \
}

int main(int argc, char* argv[])
{
GPU_Target* screen;
Expand Down Expand Up @@ -79,77 +149,7 @@ int main(int argc, char* argv[])
shapeType = 0;
numShapeTypes = 18;

for(i = 0; i < NUM_COLORS; i++)
{
colors[i].r = rand()%256;
colors[i].g = rand()%256;
colors[i].b = rand()%256;
GET_ALPHA(colors[i]) = rand()%256;
}



for(i = 0; i < NUM_PIXELS; i++)
{
px[i] = rand()%screen->w;
py[i] = rand()%screen->h;
}

for(i = 0; i < NUM_LINES; i++)
{
lx1[i] = rand()%screen->w;
ly1[i] = rand()%screen->h;
lx2[i] = rand()%screen->w;
ly2[i] = rand()%screen->h;
}

for(i = 0; i < NUM_TRIS; i++)
{
tx1[i] = rand()%screen->w;
ty1[i] = rand()%screen->h;
tx2[i] = rand()%screen->w;
ty2[i] = rand()%screen->h;
tx3[i] = rand()%screen->w;
ty3[i] = rand()%screen->h;
}


for(i = 0; i < NUM_RECTS; i++)
{
rx1[i] = rand()%screen->w;
ry1[i] = rand()%screen->h;
rx2[i] = rand()%screen->w;
ry2[i] = rand()%screen->h;
rr[i] = rand()%10 + 2;
}

for(i = 0; i < NUM_ARCS; i++)
{
ax[i] = rand()%screen->w;
ay[i] = rand()%screen->h;
ar[i] = (rand()%screen->h)/10.0f;
ar2[i] = ((rand()%101)/100.0f)*ar[i];
aa1[i] = rand()%360;
aa2[i] = rand()%360;
}

for(i = 0; i < NUM_POLYS; i++)
{
float cx = rand()%screen->w;
float cy = rand()%screen->h;
float radius = 20 + rand()%(screen->w/8);

int j;

pn[i] = rand()%8 + 3;
pv[i] = (float*)malloc(2*pn[i]*sizeof(float));

for(j = 0; j < pn[i]*2; j+=2)
{
pv[i][j] = cx + radius*cos(2*M_PI*(((float)j)/(pn[i]*2))) + rand()%((int)radius/2);
pv[i][j+1] = cy + radius*sin(2*M_PI*(((float)j)/(pn[i]*2))) + rand()%((int)radius/2);
}
}
RANDOMIZE_SHAPE_DATA();

blend = 0;
thickness = 1.0f;
Expand Down Expand Up @@ -184,6 +184,10 @@ int main(int argc, char* argv[])
blend = !blend;
GPU_SetShapeBlending(blend);
}
else if(event.key.keysym.sym == SDLK_RETURN)
{
RANDOMIZE_SHAPE_DATA();
}
else if(event.key.keysym.sym == SDLK_UP || event.key.keysym.sym == SDLK_EQUALS)
{
thickness += 0.25f;
Expand Down

0 comments on commit b21d5be

Please sign in to comment.