# Curves 1.5

33 replies to this topic

### #1 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 23 November 2010 - 11:53 PM

Last updated: 05/Dec/2010

Changelog
1.5: Added functions which set all curve parameters in one call.

1.4: Added a simpler method for drawing multipoint 2D/3D splines which supports up to 512 points.
1.4: Added the ability to draw 3D cubic beziers.

1.3: Added 3D functions. Unfortunately I was hamstrung by a lack of arguments - 10 max, which is only 3 3D points.
1.3: Improved bezier performance has improved slightly.
1.3: Fixed bezier curves were colour/alpha interpolated backwards except for their endpoints. Whoops.

1.2: First release.

WHAT
Curves are nice. This draws curves. The tentacles in the title graphic were drawn using this extension, for example.

WHY
Curves are nice, but calculating their vertices is far too slow for GML. They're also a bit difficult to grasp for novice programmers. That sucks.

HOW
The extension performs its calculations in machine code with SSE2 instructions, using GMAPI to call GM's primitive-drawing functions. This drastically increases performance. For example, a 40-vertex spline takes 95 times longer to draw in GML than with this extension. The difference becomes even more pronounced with higher vertex counts.

DEMO
Here's a demo I created using Curves. Each tentacle is a spline.

HOW TO USE
Here is how to use the extension's functions and what kind of results you can expect from them.

Beziers

Draw a bezier curve with one control point.

draw_bezier_cubic( x1,y1, x2,y2, cx1,cy1, cx2,cy2 )
Draw a bezier curve with two control points.

Draw a bezier curve in 3D.

d3d_bezier_begin()
Start drawing a bezier curve in 3D. You can specify 3 points for a quadratic curve, or 4 points for a cubic one. Excess points are ignored. This is the only way to draw a cubic bezier curve in 3D.

d3d_curve_vertex( x,y,z )
d3d_curve_vertex2( x1,y1,z1, x2,y2,z2 )
d3d_curve_vertex3( x1,y1,z1, x2,y2,z2, x3,y3,z3 )
Set the curve points. You can specify up to three points at a time. This seems redundant, but because of the function call overhead, batching multiple points together is considerably faster than specifying them individually. The point order is the same as the normal functions - start, end, control1, control2.

d3d_bezier_end()
This actually draws the curve. You can call this multiple times to redraw it without specifying the points again. This is useful if you want to draw the same curve rotated, scaled or translated using the d3d_transform functions.

Splines

draw_spline3( x1,y1, x2,y2, x3,y3 )
draw_spline4( x1,y1, x2,y2, x3,y3, x4,y4 )
draw_spline5( x1,y1, x2,y2, x3,y3, x4,y4, x5,y5 )
draw_spline_begin()
draw_curve_vertex( x,y )
draw_curve_vertex2( x1,y1, x2,y2 )
draw_curve_vertex3( x1,y1, x2,y2, x3,y3 )
draw_curve_vertex4( x1,y1, x2,y2, x3,y3, x4,y4 )
draw_curve_vertex5( x1,y1, x2,y2, x3,y3, x4,y4, x5,y5 )
draw_spline_end()
draw_spline_ds( ds_list )

d3d_spline3( x1,y1,z1, x2,y2,z2, x3,y3,z3 )
d3d_spline_begin()
d3d_curve_vertex( x,y,z )
d3d_curve_vertex2( x1,y1,z1, x2,y2,z2 )
d3d_curve_vertex3( x1,y1,z1, x2,y2,z2, x3,y3,z3 )
d3d_spline_end()
d3d_spline_ds( ds_list )

Draw a curve which passes through all intermediary points.

The start/end/vertex functions work the same as with bezier curves, except that you can specify up to 512 points for the spline to pass through. As before, minimising function calls is good for speed, so I provided batch functions.

The DS functions allow you to pass up to 512 points in a list. The ds_list should be structured as coordinate pairs/triplets like this: [x1][y1][x2][y2] or [x1][y1][z1][x2][y2][z2] etc. These functions are a little slower than the others. Warning: if you pass a list containing a string or pass a nonexistent list, your game may hang or crash. For the sake of speed there are very few sanity checks.

Arcs

draw_arc( x,y, radius, arc, dir )
Draw an arc centred on [x,y] [arc] degrees wide, centred around angle [dir]. Interpolates colour and alpha clockwise along the curve. (This can be inverted by negating the arc value)

draw_sector( x,y, radius, arc, dir )
Draw an arc with the endpoints connected to the origin. Interpolates colour and alpha outwards from the origin.

Configuration
draw_set_bezier_precision( vertices )
Number of vertices to use. 2 to 512, 28 by default. Note: even though you can go much higher, more than 64 points is usually a waste of resources given the tiny visual difference.

draw_set_bezier_primitive( primitive )
Which primitive to use when drawing beziers. pr_linestrip by default. Use the other constants to get different effects; for example pr_linelist draws dashed lines.

draw_set_bezier_color( col1, col2 )
Colour of the start and end points. Smoothly interpolated along the length of the curve. By default these are set to -1, which automatically uses the current colour as set by draw_set_color().

draw_set_bezier_alpha( alpha1, alpha2 )
Alpha of the start and end points. Works the same as the colour.

draw_set_bezier_all( vertices, primitive, col1, col2, alpha1, alpha2 )
Set everything at once. This is faster than doing it individually and usually more convenient.

Note that all these values are independent. Setting the colour or alpha doesn't affect GM's current drawing colour or the colour of any other type of curve.

draw_set_spline_precision( vertices )
draw_set_spline_primitive( primitive )
draw_set_spline_color( col1, col2 )
draw_set_spline_alpha( alpha1, alpha2 )
draw_set_spline_all( vertices, primitive, col1, col2, alpha1, alpha2 )
Same as above. Precision defaults to 40.

draw_set_arc_precision( vertices )
draw_set_arc_primitive( primitive )
draw_set_arc_color( col1, col2 )
draw_set_arc_alpha( alpha1, alpha2 )
draw_set_arc_all( vertices, primitive, col1, col2, alpha1, alpha2 )
Same as above, except arcs default to -1 precision. -1 means the number of vertices is dynamically selected according to a heuristic which takes into account the radius and arc width. It tries to provide the best performance without sacrificing visual quality. It will not exceed 64 vertices. At the moment the other functions don't have this, but I'll probably implement that in a future version.

Presets
Because it can be tiresome to specify the curve settings every single time you draw a curve, you can store them for later use. This also helps performance.

draw_define_curve_preset( vertices, primitive, col1, col2, alpha1, alpha2 )
Define a preset. Returns an index to use with the functions below. You can create up to 1024 presets. They can't be destroyed or modified afterwards; if you define more than 1024 the extension will start overwriting old ones. I'll make this more flexible in future if that proves to be a problem.

draw_set_bezier_preset( preset )
draw_set_spline_preset( preset )
draw_set_arc_preset( preset )
Set the current drawing values from a preset you've created. You can also pass -1 to reset the values to their defaults.

Performance
Here's a performance breakdown. The number next to the function signifies average execution time for the function in terms of multiples of the execution time of draw_line() using the default precision values. In other words, calling the function is equivalent in performance to calling draw_line() that many times. Lower is better. For reference, draw_line() takes 1.5 microseconds on my computer.

```Function                Relative performance

draw_bezier_cubic       3.5
draw_arc                2.5
draw_sector             2.7
draw_spline3            3.9
draw_spline4            4.1
draw_spline5            4.7
draw_spline_ds          8.1 (32 points / 64 ds_list entries)

d3d_spline3             3.4
d3d_spline_ds          15.2 (32 points / 96 ds_list entries)
```
Note: Triangular primitives are slower to draw than lines or points. The above measurements were made using pr_linestrip.

To do:
I'll add this stuff when I have some free time:
- Precision heuristics for splines and beziers. The fewer function calls the better.
- Any ideas? I've done everything I personally needed, so it's up to you guys.

Last updated: 05/Dec/2010

Edited by LSnK, 19 December 2010 - 05:41 PM.

• 2

### #2 brod

brod

Brian RODriguez

• GMC Member
• 2050 posts
• Version:GM8

Posted 24 November 2010 - 12:38 AM

This is... fantastic. There's really not much else I can say except thank you very, very much.
• 0

### #3 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 24 November 2010 - 07:05 PM

Thanks Brod, you're welcome.

Update: version 1.3
I've added a few new functions and fixed a bug with bezier curves.

draw_spline_ds( ds_list )
Draws a spline through a ds_list of points. This allows you to pass up to 512 points, but is slower than the standard functions. The more points the slower it becomes, although 32 points or less is still reasonably fast. The calculations and rendering steps involved are actually identical regardless of the number of points, the slow part is getting them out of the ds_list in the first place. Let me know if you have any ideas for handling this better.

Draw a bezier curve in 3D. Unfortunately I couldn't add the cubic version due to lack of arguments.

d3d_spline3( x1,y1,z1, x2,y2,z2, x3,y3,z3 )
Draw a spline in 3D. Argument limitations also hampered me here.

d3d_spline_ds( ds_list )
3D equivalent of draw_spline_ds. Again you can use up to 512 points.

The 3D functions in action:

• 0

### #4 hanson

hanson

GMC Member

• GMC Member
• 444 posts
• Version:GM8

Posted 24 November 2010 - 07:26 PM

Very cool!
• 0

### #5 YellowAfterlife

YellowAfterlife

GMC Member

• Global Moderators
• 4157 posts
• Version:GM:Studio

Posted 24 November 2010 - 09:49 PM

Wow, magic!
I think that greatness of this extension can be describeed by the following image:

Thats provided demo, maximum detail, most speed-consuming type. Still over 60 fps

I wish I had something like this for AS3. I have a couple of projects starving without proper bezier curves.

For the 3d beziers & splines, you can make something similar to standart primitive system. Define a array to store parameters in, and when _end() is executed, loop through it and draw everything on its places.
• 0
If my posts contain broken links, try looking around my website. I gradually make blog posts for any examples I make.

### #6 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 25 November 2010 - 06:05 PM

For the 3d beziers & splines, you can make something similar to standart primitive system. Define a array to store parameters in, and when _end() is executed, loop through it and draw everything on its places.

Good idea. I've implemented this and updated the first post with the changes.
• 0

### #7 freko

freko

The Professional

• GMC Member
• 504 posts
• Version:GM8

Posted 03 December 2010 - 11:24 AM

This is awesome! Nice work
• 0
Nemesis | 3D Rts Engine
Shadow RT Engine| Freko Vehicle Engine
_____________________________________________________

Phoenix Artist blog

### #8 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 05 December 2010 - 02:15 AM

This is awesome! Nice work

Thanks.

Update: version 1.5

I find it tiresome to use the config functions all the time, so I added _all variants which set everything at once. I've also added functions that define parameter presets, allowing you to load and save curve configurations. This makes it easier to use the functions since you don't have to specify everything constantly. It's also faster.
• 0

### #9 Drara

Drara

GMC Member

• GMC Member
• 325 posts

Posted 05 December 2010 - 10:03 AM

Thats so incredible. I'm dreaming of the great effects I could make with this extension xD
I think this is even faster then particles.

Since you are already using the GMApi to get informations from the game, could you make a possibility to stop drawing automatic when a 'tentacle' leaves the visible area (for example a given view).
That could fasten a game further.

But very very good work anyway.
I'll give you much credits in my game when I'm using this.
• 0

### #10 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 05 December 2010 - 06:31 PM

Since you are already using the GMApi to get informations from the game, could you make a possibility to stop drawing automatic when a 'tentacle' leaves the visible area (for example a given view).
That could fasten a game further.

It's better to handle that with standard methods like instance deactivation.

Even if nothing is drawn the functions still take some CPU time due to overhead, which means the benefit would be pretty small. Also my code is structured in a way that makes it difficult to implement this, especially without degrading performance in the general case.

That said, when (if) I restructure things I'll give it a try.
• 0

### #11 Lewis X

Lewis X

Artist

• GMC Member
• 1050 posts
• Version:GM:Studio

Posted 18 December 2010 - 07:44 PM

Please add thickness to the drawing (with rounded edges). Then I can use this in Doodlepad... or please PM me the code (for draw_bezier_quadratic) then I can do it myself.

Edited by Sonica2, 18 December 2010 - 07:46 PM.

• 0

### #12 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 18 December 2010 - 09:23 PM

One place is enough to ask, haha.
• 0

### #13 Lewis X

Lewis X

Artist

• GMC Member
• 1050 posts
• Version:GM:Studio

Posted 19 December 2010 - 04:15 PM

Mistake, it says draw_spline_start on the topic, BUT in the EXT it's draw_spline_begin.
• 0

### #14 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 19 December 2010 - 05:42 PM

Mistake, it says draw_spline_start on the topic, BUT in the EXT it's draw_spline_begin.

Whoops. Corrected.
• 0

### #15 user_name

user_name

GMC Member

• New Member
• 80 posts

Posted 28 December 2010 - 10:47 PM

This is a great mod. Good job man! Is there any way to draw curves with a width?

Edited by user_name, 28 December 2010 - 11:47 PM.

• 0

### #16 GearGOD

GearGOD

Deus Verus

• GMC Member
• 2153 posts

Posted 29 December 2010 - 08:42 AM

Can I ask how you're handling the rounded edges and antialiasing?

I've been toying with doing similar stuff in pixel shaders, never really figured out a good way to have smooth transitions between segments.
• 0
Engineers are not programmers. Stop thinking that you can save a few bucks by writing code yourself instead of hiring a programmer. Your code sucks.

### #17 Medved

Medved

GMC Member

• New Member
• 1 posts

Posted 29 December 2010 - 09:58 AM

LSnK, Hi man from Russia - i love it )
• 0

### #18 Cameron Stevenson

Cameron Stevenson

GMC Member

• New Member
• 153 posts

Posted 29 December 2010 - 10:34 PM

By the way, This is an amazing program, to be able to get to 280FPS+ while doing all that is amazing.

I got a screenshot:

EDIT:
Okay, It does it at 60FPS also... I guess i just didn't wait long enough in slower viewing.

Edited by Cameron Stevenson, 29 December 2010 - 10:39 PM.

• 0

Current Project: Pokemon MMO
Server: 3%

Client: 2.5%

### #19 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 30 December 2010 - 01:16 AM

Thanks. And yeah, the demo randomly switches the way it draws after a while. The second type emphasises arcs and bezier curves.
• 0

### #20 ChaosMaker

ChaosMaker

GMC Member

• GMC Member
• 289 posts
• Version:GM:HTML5

Posted 30 December 2010 - 02:09 AM

WOW! Its VERY VERY NICE! EXCELLENT! Awesome *0*
you can do dynamic hair with these curves?
• 0

### #21 Topaze22

Topaze22

GMC Member

• GMC Member
• 58 posts

Posted 31 December 2010 - 09:24 AM

So beautifull !
Thanks for this amazing/original work, we love it so much, incredible performance
Thanks again !
• 0
English,spanish and French

### #22 freko

freko

The Professional

• GMC Member
• 504 posts
• Version:GM8

Posted 03 January 2011 - 01:41 PM

Just curious to know.. can it be used to make objects move along the spline and with relative rotations?
• 0
Nemesis | 3D Rts Engine
Shadow RT Engine| Freko Vehicle Engine
_____________________________________________________

Phoenix Artist blog

Potato King

• YoYo Games Staff
• 2740 posts
• Version:GM:Studio

Posted 03 January 2011 - 02:42 PM

Solid gold.
Pretty damn awe inspiring codework... FPS is through the roof.

Any GM plans beyond this?
• 0

### #24 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 03 January 2011 - 08:29 PM

Can I ask how you're handling the rounded edges and antialiasing?

I've been toying with doing similar stuff in pixel shaders, never really figured out a good way to have smooth transitions between segments.

Oops, only just noticed your post. But the extension doesn't do any of that? If you're looking at the "how to use" images I'm afraid I drew them in a paint program, haha.

Just curious to know.. can it be used to make objects move along the spline and with relative rotations?

The extension is only for drawing. GM's path functions have spline support in the form of the 'smooth' option. You can determine the direction with point_direction(xprevious,yprevious,x,y).
• 0

### #25 HaRRiKiRi

HaRRiKiRi

GMC Member

• GMC Member
• 1364 posts

Posted 06 January 2011 - 09:11 PM

I actually looked at this a long time ago, but now decided to praise you.
Really nice work. I was amazed about the example as it was so unexpectedly beautiful and fast considering GM is drawing it. Getting points on the curve is actually quite useful feature, but it possibly could be pain in the ass to find the point on a ds curve.
I was actually inspired by this to make these functions. But I would want to know how did you make the continues curve with the d3d_bezier_begin function? Does it actually draw a Bezier or some spline with Hermite (or other) interpolation? You already have a spline_begin function so I guess it really draws a Bezier, but then what order curve is it? I actually haven't tested the bezier_begin function so I should probably do that.
Anyway, really nice work.
• 0

### #26 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 18 January 2011 - 05:10 PM

But I would want to know how did you make the continues curve with the d3d_bezier_begin function? Does it actually draw a Bezier or some spline with Hermite (or other) interpolation? You already have a spline_begin function so I guess it really draws a Bezier, but then what order curve is it? I actually haven't tested the bezier_begin function so I should probably do that.
Anyway, really nice work.

Nothing that nice I'm afraid! Those functions exist only because of GM's limit of ten arguments. They only draw single quadratic/cubic beziers, selecting which to use based on the number of points given. They ignore anything higher.

And thanks.
• 0

### #27 jack1993jack

jack1993jack

GMC Member

• New Member
• 231 posts

Posted 22 January 2011 - 11:05 PM

Very nice, does this involve anti-aliasing in any way?
• 0
Testing can be used to show the presence of bugs, but never to show their absence

### #28 twiwlek

twiwlek

GMC Member

• GMC Member
• 15 posts
• Version:GM:Studio

Posted 10 July 2011 - 12:39 PM

Hello,
First I want to say great job. Its very usefull.

But also it seems to be small problem in GM8.1 under Windows 7 (under XP seems to work fine).
I start app run then exit and I got message that application crashed.

Details
```Problem signature:
Problem Event Name:	APPCRASH
Application Name:	ATT_test.exe
Application Version:	2.1.0.0
Application Timestamp:	4e15ae6c
Fault Module Version:	0.0.0.0
Fault Module Timestamp:	4cfaecfc
Exception Code:	c0000005
Exception Offset:	6fce994e
OS Version:	6.1.7600.2.0.0.256.4
Locale ID:	1045

Everything is saving before app crash so this is not critical.

Edited by twiwlek, 10 July 2011 - 12:40 PM.

• 0

### #29 HaRRiKiRi

HaRRiKiRi

GMC Member

• GMC Member
• 1364 posts

Posted 11 July 2011 - 02:57 PM

Hello,
First I want to say great job. Its very usefull.

But also it seems to be small problem in GM8.1 under Windows 7 (under XP seems to work fine).
I start app run then exit and I got message that application crashed.

Details

```Problem signature:
Problem Event Name:	APPCRASH
Application Name:	ATT_test.exe
Application Version:	2.1.0.0
Application Timestamp:	4e15ae6c
Fault Module Version:	0.0.0.0
Fault Module Timestamp:	4cfaecfc
Exception Code:	c0000005
Exception Offset:	6fce994e
OS Version:	6.1.7600.2.0.0.256.4
Locale ID:	1045

Everything is saving before app crash so this is not critical.

This uses GMApi for calling GM's built in drawing functions. GMApi is not supported in 8.1 so it crashes.
• 0

### #30 jobro

jobro

GMC Member

• GMC Member
• 1300 posts
• Version:GM:Studio

Posted 14 July 2011 - 04:03 PM

Judging from the screenshots this looks like it can be used for a lot of fun stuff! Great work. I doubt I'll have the time to play with it more seriously, but it rocks no less!
• 0

### #31 Master Xilo

Master Xilo

GMC Member

• GMC Member
• 396 posts
• Version:GM8

Posted 21 July 2011 - 03:26 PM

The demo is beautiful. Very well done!

It would be useful if you added a little help file to the extension. Or at least a link to this topic (by including an .url file (created by right clicking - create new link...) instead of a help file) (yes this works, I just tested it, you just have to manually start typing the name of the link file when including it as its not shown even with "All Files" selected).

Edited by Master Xilo, 21 July 2011 - 09:02 PM.

• 0

### #32 brod

brod

Brian RODriguez

• GMC Member
• 2050 posts
• Version:GM8

Posted 15 March 2012 - 02:14 AM

May I suggest a draw_pie function with the same parameters as draw_arc? I made one myself but I draw a lot of them quite often so I was hoping there was a similar way to make it faster as you've done with all of these.
• 0

### #33 grugin

grugin

GMC Member

• GMC Member
• 127 posts

Posted 16 March 2012 - 10:19 AM

a new GMApi is available to gamemaker 8.1. There is a chance to see your great extension ported over gm8.1 ??? Thanks in advance.
• 0

### #34 Monstr Gaming

Monstr Gaming

GMC Member

• GMC Member
• 431 posts
• Version:GM:Studio

Posted 21 April 2012 - 11:38 AM

This isn't working for me.

It technically works but will not create any curves/splines/whatever like in the screenshots
any suggestions?
• 0