View Full Version : Drawing Lines
bozmillar
10-28-2010, 01:57 PM
background: I have the IPlugExample up and running. I'm basically using that as a template to make my own plugin.
So, I want to draw a line. Since the gui is already setup to show faders and knobs in the example, is there a reason I can't just draw a random line on top of the gui?
The only change to the IPlugExample is the following lines
//Draw a Line
IColor color(255,0,0,255);
pGraphics->DrawLine(&color,100,50,150,150,0,true);
It just draws a random line on the screen, but no line shows up. What am I missing?
sstillwell
10-28-2010, 07:59 PM
Where are you placing that statement? A random "draw line" somewhere may very well get overwritten by the plugin's UI re-drawing itself.
Scott
junioreq
10-28-2010, 08:15 PM
You have to create a custom control class to do your drawing. Just like a control gets "drawn" onto your screen, when you make your "line" control, it will do the same thing, draw a line:
http://forum.cockos.com/showthread.php?t=48251
~Rob.
Xenakios
10-28-2010, 08:45 PM
You have to create a custom control class to do your drawing. Just like a control gets "drawn" onto your screen, when you make your "line" control, it will do the same thing, draw a line:
http://forum.cockos.com/showthread.php?t=48251
~Rob.
It might not be necessary, but it isn't very obvious either if it indeed is possible at all to directly draw on the plugin GUI surface using the IGraphics instance of the plugin...
bozmillar
10-29-2010, 10:31 AM
thanks guys. Sorry, reading back at my original post I didn't really give much info. I put the draw line statement after right after all the draw background and knobs statements. I didn't make any changes to the IPlugExample except for these two lines. Here is a little more of what's around it for a little more context:
bitmap = pGraphics->LoadIBitmap(TOGGLE_ID, TOGGLE_FN, kSwitch_N);
pGraphics->AttachControl(new ISwitchControl(this, kSwitch_X, kSwitch_Y, kChannelSw, &bitmap));
// Attach a rotating knob associated with the Pan parameter.
bitmap = pGraphics->LoadIBitmap(KNOB_ID, KNOB_FN);
pGraphics->AttachControl(new IKnobRotaterControl(this, kPan_X, kPan_Y, kPan, &bitmap));
//Draw a Line
IColor color(255,0,0,255);
pGraphics->DrawLine(&color,100,50,150,150,0,true);
Sorry, I'm not seeing an option to make this a monospace font, so it's hard to read.
If I have to attache a line to a control, on a high level, what does that actually mean? the background image isn't attached to any control.
junioreq
10-29-2010, 10:37 AM
Don't have iplug open right now. But. Take an iBitmap Control. And strip out all the stuff and just leave the Draw method, is the only way i know to draw in iPlug.
Also put your code in:
[ code ] your code [/ code]
Remove the spaces..
bitmap = pGraphics->LoadIBitmap(KNOB_ID, KNOB_FN);
pGraphics->AttachControl(new IKnobRotaterControl(this, kPan_X, kPan_Y, kPan, &bitmap));
That is attaching the control, not purely drawing it.
~Rob.
bozmillar
10-29-2010, 12:20 PM
That is attaching the control, not purely drawing it.
~Rob.
ah ha. ok. so where is the actual drawing of it happening?
cerberus
10-29-2010, 03:53 PM
there is also this control (see IControl.h (line 221):
// A knob that is just a line.
class IKnobLineControl : public IKnobControl
sstillwell
10-29-2010, 04:12 PM
thanks guys. Sorry, reading back at my original post I didn't really give much info. I put the draw line statement after right after all the draw background and knobs statements. I didn't make any changes to the IPlugExample except for these two lines. Here is a little more of what's around it for a little more context:
bitmap = pGraphics->LoadIBitmap(TOGGLE_ID, TOGGLE_FN, kSwitch_N);
pGraphics->AttachControl(new ISwitchControl(this, kSwitch_X, kSwitch_Y, kChannelSw, &bitmap));
// Attach a rotating knob associated with the Pan parameter.
bitmap = pGraphics->LoadIBitmap(KNOB_ID, KNOB_FN);
pGraphics->AttachControl(new IKnobRotaterControl(this, kPan_X, kPan_Y, kPan, &bitmap));
//Draw a Line
IColor color(255,0,0,255);
pGraphics->DrawLine(&color,100,50,150,150,0,true);
Sorry, I'm not seeing an option to make this a monospace font, so it's hard to read.
If I have to attache a line to a control, on a high level, what does that actually mean? the background image isn't attached to any control.
Right...here's the thing...as has been mentioned, that's creating the control objects and attaching them to the plugin. You're then effectively throwing away the pointer to the controls because they have, up until now, done everything you wanted them to do in the background, automagically...you never NEED to reference them again.
If you want something to draw on the surface of the plugin, and REMAIN there if the plugin UI is closed/reopened, covered/exposed, etc., the drawing code has to be inside, surprise, surprise, the Draw method of something...usually one or another control that is attached to the IGraphics object so that it's on the list of controls that the IGraphics object knows it needs to manage.
If that control can derive all the information it needs to draw itself from its own internal values, then you're all set. Put what you need in that new control class (inherited from whatever type of control comes closest to your desired behavior) Draw method. Done. If the control needs additional information, you may need to pass information in from elsewhere in the plugin...at that point you may want to define additional methods on that plugin and then pass in data via parameters that are get/set during, let's say, the ProcessDoubleReplacing() method. How do you do that? You don't have any way to get to the control to invoke its methods!
You can do that by...instead of just creating a new control in a variable declared inline (placing it on the stack, I think...certainly placing it where it will go out of scope and disappear after the init finishes), attaching it and throwing it away...instead of that, create your variable as member data of your plugin class...then when you create the control, keep the pointer there. It will then be available for reference anywhere in the plugin and you can call additional custom methods to pass in more data (which in turn will help you draw whatever you need to draw...)
You DO have to beware here...the ProcessDoubleReplacing() bits of the code almost always are executing on a different thread than the UI code...it's easy to make things crash here. Pay attention to thread safety and surround critical bits with mutex locks or some other mechanism...but make that lock as short as physically possible...you're potentially killing performance by making a multithreaded application pass through a single-threaded gateway, effectively.
I hope some of this makes sense...I'm REALLY tired this evening.
Scott
bozmillar
10-29-2010, 05:17 PM
Thanks scott. Everything is starting to come together. I'm clearly missing a higher level understanding of how all this stuff works together.
Is there a manual for LICE and/or IPlug? I'm new to GUI programming, so I don't know if a lot of this stuff is IPlug specific or common knowledge to anyone who has programmed GUI's.
So, I got the line to draw by putting the DrawLine() function in my ProcessDoubleReplacing() function, but it seems to eat up a significant amount of CPU to just draw a line. At least I feel like I'm heading in the right direction though.
The last few lines of my ProcessDoubleReplacing() function:
if (GetGUI()) {
GetGUI()->SetControlFromPlug(mMeterIdx_L, peakL);
GetGUI()->SetControlFromPlug(mMeterIdx_R, peakR);
GetGUI()->DrawLine(&color,100,50,150,150,0,true);
}
The first two SetControlFromPlug() lines update the meters, the last line draws a random line across the GUI. This is done at the end of every frame. Is drawing a line just inherently more CPU intensive than drawing a bitmap, or am I just calling it too often?
junioreq
10-29-2010, 05:38 PM
Why do you want to draw this line anyway?
~Rob.
sstillwell
10-29-2010, 05:44 PM
Thanks scott. Everything is starting to come together. I'm clearly missing a higher level understanding of how all this stuff works together.
Is there a manual for LICE and/or IPlug? I'm new to GUI programming, so I don't know if a lot of this stuff is IPlug specific or common knowledge to anyone who has programmed GUI's.
So, I got the line to draw by putting the DrawLine() function in my ProcessDoubleReplacing() function, but it seems to eat up a significant amount of CPU to just draw a line. At least I feel like I'm heading in the right direction though.
The last few lines of my ProcessDoubleReplacing() function:
if (GetGUI()) {
GetGUI()->SetControlFromPlug(mMeterIdx_L, peakL);
GetGUI()->SetControlFromPlug(mMeterIdx_R, peakR);
GetGUI()->DrawLine(&color,100,50,150,150,0,true);
}
The first two SetControlFromPlug() lines update the meters, the last line draws a random line across the GUI. This is done at the end of every frame. Is drawing a line just inherently more CPU intensive than drawing a bitmap, or am I just calling it too often?
Bzzt...that's just it...DON'T DRAW FROM THE AUDIO THREAD! That way lies madness...and as you've discovered, truly sucky performance.
Capture data within the audio thread and stash it in your graphics objects or in member data of your plugin...once per block is better than once per sample. Once ever few blocks is even better if you don't require that much accuracy. If you want to make sure that something gets drawn, then the way to do it is to issue a SetDirty() to that control...that will force it to redraw the next time the drawing timer kicks off (24 times per second by default...or is it 30?)
The components WILL draw themselves automatically...you just need to make sure that A) You have the data you want to draw, and B) your draw method uses that data.
Always, ALWAYS separate processing from UI tasks...the audio processing HAS to happen as quickly as possible...nothing can be allowed to slow it down. The drawing will happen when the drawing happens.
Scott
bozmillar
11-01-2010, 10:55 AM
Bzzt...that's just it...DON'T DRAW FROM THE AUDIO THREAD! That way lies madness...and as you've discovered, truly sucky performance.
Cool. So, does that mean that the sample project that comes with IPlug is using bad form in calling SetControlFromPlug() from inside ProcessDoubleReplacing()?
The default frame rate is set to 24 fps.
So, I guess, where I'm still confused is, where in IPlugExample is the drawing actually taking place? IPlugExample.cpp only has two functions: ProcessDoubleReplacing() and the constructor.
Or are there better example projects I should be looking at? Or some documentation? It seems like my only options are trace through all the code and try to figure out what it's doing, stab in the dark until I get something right, or ask a million questions on here.
cerberus
11-01-2010, 04:24 PM
tale has provided an example synth vsti which is linked here: http://forum.cockos.com/showpost.php?p=379828&postcount=5
cc_ has provided some additions to iplug. iirc; and he furnished an example to demonstrate some of his custom controls and added functions: http://forum.cockos.com/showthread.php?t=52820
i've added 2 additonal functions to my own plug-in: OnParamChange, which runs any time a control with
a paramIdx changes value ... and OnIdle(), (for which one needs first to enable idle calls, that
is documented in the comments schwa made in IPlugBase.h and IControl.h).
i declare these as public functions in my plug-in's .h file (adjacent to ProcessDoubleReplacing).
note: it seems like audio units don't like to run OnIdle() (nor OnGUIIdle())...i'll post a
separate thread on this specific issue, (seems to affect audio units only).
junioreq
11-01-2010, 06:18 PM
Pretty sure(and I haven't looked) but the GetGUI stuff is happening per block. But really you don't even want to do it there. You want to do it in the plugin constructor, at the top there. Depends on wtf you want this line to do... really.
~Rob.
sstillwell
11-01-2010, 08:38 PM
Cool. So, does that mean that the sample project that comes with IPlug is using bad form in calling SetControlFromPlug() from inside ProcessDoubleReplacing()?
The default frame rate is set to 24 fps.
So, I guess, where I'm still confused is, where in IPlugExample is the drawing actually taking place? IPlugExample.cpp only has two functions: ProcessDoubleReplacing() and the constructor.
Or are there better example projects I should be looking at? Or some documentation? It seems like my only options are trace through all the code and try to figure out what it's doing, stab in the dark until I get something right, or ask a million questions on here.
SetValueFromPlug is not the same thing as drawing a line. SetValueFromPlug is updating the value of a parameter...which then (sometime later, in a different thread) gets shown on the screen when that parameter's control redraws itself. Setting the value and drawing the control aren't directly linked.
The reason you only see two methods is that the default IPlug methods do what they're supposed to do in this case. The only time YOU write code is when you MUST override a method to make it behave differently from default. If you didn't write a ProcessDoubleReplacing, the plugin would just pass audio with no effect...not very useful for a plugin. The constructor is there because you can't set up the controls any other way...that's where you initialize the plugin and create all the GUI elements.
The actual drawing takes place in the Draw method of each control (and the background, which is also a control). You don't see the draw methods because they're all default code...most of which is defined in IPlug itself in IControl.h/.cpp. The plugin framework sets an event timer when the plugin is initiated, and then calls all the Draw methods for any controls marked dirty FPS times per second.
You need to look in the actual IPlug libraries where all the methods of a plugin are defined (IPlugBase, IPlugVST, IPlugAU). Those show you a lot of methods you COULD define, but don't necessarily have to. Just remember that if you define (override) a method for a plugin, you have to either call the ancestor method, write code to do what it used to do, or decide that you're going to do something totally different INSTEAD of doing what it used to do.
There isn't a lot in the way of documentation...basically none. Read the code. The fact that it's all OO (Object Oriented) makes it easier, but not necessarily easy.
Welcome. You can check out any time you like, but you can never leave. :)
Scott
sstillwell
11-01-2010, 08:42 PM
Pretty sure(and I haven't looked) but the GetGUI stuff is happening per block. But really you don't even want to do it there. You want to do it in the plugin constructor, at the top there. Depends on wtf you want this line to do... really.
~Rob.
If you are drawing stuff in the constructor, it's going to be visible right up to the time that anything redraws itself...at which point your drawings get overwritten...and never have any way to redraw, since constructor actions only happen once.
Drawing in a Windows app is not a one-time thing...it happens more or less constantly. Any time something passes "over" your drawing area and then moves on, or you minimize an app and restore it, you're left with having to re-draw yourself. Drawing happens in Draw methods. Create the objects that will DO the drawing in your plugin's constructor.
Scott
junioreq
11-02-2010, 12:07 AM
Thats what i meant scott, Looking back, I was assuming that my statement about the control(object) was still around. Should have made that clear.
Don't have iplug open right now. But. Take an iBitmap Control. And strip out all the stuff and just leave the Draw method, is the only way i know to draw in iPlug.
You have to create a custom control class to do your drawing. Just like a control gets "drawn" onto your screen, when you make your "line" control, it will do the same thing, draw a line:
~Rob.
sstillwell
11-02-2010, 05:37 AM
Thats what i meant scott, Looking back, I was assuming that my statement about the control(object) was still around. Should have made that clear.
~Rob.
Right on.
Scott
bozmillar
11-02-2010, 01:30 PM
alright, so I'm getting closer. Thanks for all the help by the way.
So now it draws. I have a class called DrawLineTest that has two functions, isDirty and Draw.
isDirty always returns true and Draw draws a line. But if I cover up the line with another window, it doesn't come back until I close the plugin and open it again. I thought isDirty was supposed to tell it to redraw every frame, but it doesn't seem to be doing that, or if it is, it's not redrawing the whole thing.
Any ideas?
sstillwell
11-02-2010, 08:30 PM
alright, so I'm getting closer. Thanks for all the help by the way.
So now it draws. I have a class called DrawLineTest that has two functions, isDirty and Draw.
isDirty always returns true and Draw draws a line. But if I cover up the line with another window, it doesn't come back until I close the plugin and open it again. I thought isDirty was supposed to tell it to redraw every frame, but it doesn't seem to be doing that, or if it is, it's not redrawing the whole thing.
Any ideas?
Look at the SetDirty() and IsDirty() methods of one of the existing control classes and see what they're doing...that may tell you more than we can. IsDirty() doesn't TELL it to redraw...it tells the upstream graphics container (when asked) that it's dirty and NEEDS to be redrawn.
When you create this new control, are you attaching it to the graphics engine? (so that the graphics engine knows to manage it) Are there any other controls (like a background) that occupy the same space, but get defined after it? (which would mean that they are "above" the control in Z-order and would block your view of it)
Scott
bozmillar
11-04-2010, 09:36 AM
ok guys, I finally got it. Thanks for the help. The whole picture finally makes sense.
junioreq
11-09-2010, 10:59 PM
Getting there:
http://stash.reaper.fm/oldsb/435738/drawtest1.gif
~Rob.
BTW, what else is cool that we can draw? I really want to use some of the LICE fill stuff.. but.. doesn't seem its that easy to use it directly :(
I guess I could try to draw that ball that floats on the track there, but no clue on how to go about getting it to curve around and follow the ratio line..
cerberus
11-09-2010, 11:41 PM
that's some mighty kewl slickness there.
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.