# Curves 1.5

33 replies to this topic

### #1 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 23 November 2010 - 11:39 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:27 PM.

• 0

### #2 brod

brod

Brian RODriguez

• GMC Member
• 2021 posts
• Version:GM8

Posted 24 November 2010 - 12:24 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 - 06:51 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:12 PM

Very cool!
• 0

### #5 YellowAfterlife

YellowAfterlife

GMC Member

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

Posted 24 November 2010 - 09:35 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

### #6 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 25 November 2010 - 05:51 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:10 AM

This is awesome! Nice work
• 0

### #8 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 05 December 2010 - 02:01 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
• 305 posts

Posted 05 December 2010 - 09:49 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:17 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 Lapps

Lapps

GMC Member

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

Posted 18 December 2010 - 07:30 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:32 PM.

• 0

### #12 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 18 December 2010 - 09:09 PM

One place is enough to ask, haha.
• 0

### #13 Lapps

Lapps

GMC Member

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

Posted 19 December 2010 - 04:01 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:28 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:33 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:33 PM.

• 0

### #16 GearGOD

GearGOD

Deus Verus

• GMC Member
• 2153 posts

Posted 29 December 2010 - 08:28 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

### #17 Medved

Medved

GMC Member

• New Member
• 1 posts

Posted 29 December 2010 - 09:44 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:20 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:25 PM.

• 0

### #19 LSnK

LSnK

NaN

• GMC Member
• 1188 posts

Posted 30 December 2010 - 01:02 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
• 288 posts
• Version:GM:HTML5

Posted 30 December 2010 - 01:55 AM

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

#### 0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users