Written by me (Anixias).
function draw_circle_hollow(x, y, radius, width) { draw_circle_hollow_quality(x, y, radius, 0, width, 64); } function draw_circle_hollow_quality(x, y, radius, offset, width, quality) { draw_primitive_begin(pr_trianglelist); for(var i = offset; i < 360 + offset; i += 360 / quality) { var r = max(0, radius - width); var next_i = (i + (360 / quality)); var inner_x = x + lengthdir_x(r, i); var inner_y = y + lengthdir_y(r, i); var outer_x = x + lengthdir_x(radius, i); var outer_y = y + lengthdir_y(radius, i); var next_inner_x = x + lengthdir_x(r, next_i); var next_inner_y = y + lengthdir_y(r, next_i); var next_outer_x = x + lengthdir_x(radius, next_i); var next_outer_y = y + lengthdir_y(radius, next_i); // First triangle draw_vertex(inner_x, inner_y); // inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_inner_x, next_inner_y); // next inner // Second triangle draw_vertex(next_inner_x, next_inner_y); // next inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_outer_x, next_outer_y); // next outer } draw_primitive_end(); } function draw_healthbar_circular(x, y, radius, amount, backcol, mincol, maxcol, offset, direction, showback, showborder, width) { draw_healthbar_circular_quality(x, y, radius, amount, backcol, mincol, maxcol, offset, direction, showback, showborder, width, 64); } function draw_healthbar_circular_quality(x, y, radius, amount, backcol, mincol, maxcol, offset, direction, showback, showborder, width, quality) { if (direction < 0) offset += 180; quality = max(3, quality); // Using primitives var start_color = draw_get_color(); // Back if (showback) { // Border if (showborder) { draw_set_color(c_black); draw_circle_hollow_quality(x + 1, y , radius, offset, width, quality); draw_circle_hollow_quality(x - 1, y , radius, offset, width, quality); draw_circle_hollow_quality(x , y + 1, radius, offset, width, quality); draw_circle_hollow_quality(x , y - 1, radius, offset, width, quality); } // Back draw_set_color(backcol); draw_circle_hollow_quality(x, y, radius, offset, width, quality); } // Lerp color var r1, g1, b1; var r2, g2, b2; var r3, g3, b3; r1 = (mincol & 0x0000FF); g1 = (mincol & 0x00FF00) >> 8; b1 = (mincol & 0xFF0000) >> 16; r2 = (maxcol & 0x0000FF); g2 = (maxcol & 0x00FF00) >> 8; b2 = (maxcol & 0xFF0000) >> 16; var amt = clamp(amount / 100, 0, 1); r3 = lerp(r1, r2, amt); g3 = lerp(g1, g2, amt); b3 = lerp(b1, b2, amt); // Border if (showborder) { if (!showback) { var _x = x; var _y = y; draw_set_color(c_black); for(y = _y - 1; y <= _y + 1; y += 2) { for(x = _x - 1; x <= _x + 1; x += 2) { draw_primitive_begin(pr_trianglelist); for(var i = offset; i < 360 * amt + offset; i += 360 / quality) { var r = max(0, radius - width); var this_i = direction < 0 ? -i : i; var next_i = (i + (360 / quality)) * (direction < 0 ? -1 : 1); var inner_x = x + lengthdir_x(r, this_i); var inner_y = y + lengthdir_y(r, this_i); var outer_x = x + lengthdir_x(radius, this_i); var outer_y = y + lengthdir_y(radius, this_i); var next_inner_x = x + lengthdir_x(r, next_i); var next_inner_y = y + lengthdir_y(r, next_i); var next_outer_x = x + lengthdir_x(radius, next_i); var next_outer_y = y + lengthdir_y(radius, next_i); // First triangle draw_vertex(inner_x, inner_y); // inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_inner_x, next_inner_y); // next inner // Second triangle draw_vertex(next_inner_x, next_inner_y); // next inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_outer_x, next_outer_y); // next outer } draw_primitive_end(); } } x = _x; y = _y; } else { draw_set_color(c_black); var border_offset = 4; var progress = 0; draw_primitive_begin(pr_trianglelist); for(var i = offset; amt > 0 && i <= 360 * ceil(amt * 1000) / 1000 + offset; i += 360 / quality) { var r = max(0, radius - width); var this_i = direction < 0 ? -(i - border_offset) : i - border_offset; var next_i = (i + (360 / quality) + border_offset) * (direction < 0 ? -1 : 1); var inner_x = x + lengthdir_x(r, this_i); var inner_y = y + lengthdir_y(r, this_i); var outer_x = x + lengthdir_x(radius, this_i); var outer_y = y + lengthdir_y(radius, this_i); var next_inner_x = x + lengthdir_x(r, next_i); var next_inner_y = y + lengthdir_y(r, next_i); var next_outer_x = x + lengthdir_x(radius, next_i); var next_outer_y = y + lengthdir_y(radius, next_i); if (i + (360 / quality) > 360 * ceil(amt * 1000) / 1000 + offset) { var amt_within = (amt - progress) / (1 / quality); next_inner_x = lerp(inner_x, next_inner_x, amt_within); next_inner_y = lerp(inner_y, next_inner_y, amt_within); next_outer_x = lerp(outer_x, next_outer_x, amt_within); next_outer_y = lerp(outer_y, next_outer_y, amt_within); } // First triangle draw_vertex(inner_x, inner_y); // inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_inner_x, next_inner_y); // next inner // Second triangle draw_vertex(next_inner_x, next_inner_y); // next inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_outer_x, next_outer_y); // next outer progress += 1 / quality; } draw_primitive_end(); } } var progress = 0; draw_set_color(r3 | (g3 << 8) | (b3 << 16)); draw_primitive_begin(pr_trianglelist); for(var i = offset; amt > 0 && i <= 360 * ceil(amt * 1000) / 1000 + offset; i += 360 / quality) { var r = max(0, radius - width); var this_i = direction < 0 ? -i : i; var next_i = (i + (360 / quality)) * (direction < 0 ? -1 : 1); var inner_x = x + lengthdir_x(r, this_i); var inner_y = y + lengthdir_y(r, this_i); var outer_x = x + lengthdir_x(radius, this_i); var outer_y = y + lengthdir_y(radius, this_i); var next_inner_x = x + lengthdir_x(r, next_i); var next_inner_y = y + lengthdir_y(r, next_i); var next_outer_x = x + lengthdir_x(radius, next_i); var next_outer_y = y + lengthdir_y(radius, next_i); // If this is the last iteration before the loop stops if (i + (360 / quality) > 360 * ceil(amt * 1000) / 1000 + offset) { var amt_within = (amt - progress) / (1 / quality); next_inner_x = lerp(inner_x, next_inner_x, amt_within); next_inner_y = lerp(inner_y, next_inner_y, amt_within); next_outer_x = lerp(outer_x, next_outer_x, amt_within); next_outer_y = lerp(outer_y, next_outer_y, amt_within); } // First triangle draw_vertex(inner_x, inner_y); // inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_inner_x, next_inner_y); // next inner // Second triangle draw_vertex(next_inner_x, next_inner_y); // next inner draw_vertex(outer_x, outer_y); // outer draw_vertex(next_outer_x, next_outer_y); // next outer progress += 1 / quality; } draw_primitive_end(); draw_set_color(start_color); }
Notes
This can be easily modified to use textures, since it uses primitives to render. The border rendering is slightly wrong on the partial circle (the one that shows the amount), but it’s good enough for my purposes. You can use draw_healthbar_circular_quality
to actually render non-circular shapes (quality of 3 is a triangle, quality of 4 is either a diamond or rectangle based on the offset you provide, quality of 5 is a pentagon, quality of 6 is a hexagon, etc.).