Drawing one CBitmap into another.

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Gus, I hope that someone could help me out. Maybe this is simple, but since I'm coding day-and-night for Wusikstation, my mind is a blur right now. :shock:

I'm using the VST-GUI library from steinberg.

I got two variables.

1) One is the hBackground that holds the frame background.
2) Is the hImage that holds a small image that I want to draw in an area of the hBackground.

What would be the simplest way to draw this hImage on the background or even on the hBackground variable?

I know, I could just create a new controll to do just that. BUT I also need to put a knob on top of it, so it can't be a controll. It needs to draw on the background and that's all.

Any help apreciated.

Best Regards, WilliamK

Post

You say it can't be a control, but it sounds to me like an idea place to use CViewContainer. CViewContainer allows you to put whatever background you want (which will be drawn on top of the frame background) and can contain new controls to be drawn on top.

Post

autloc wrote:You say it can't be a control, but it sounds to me like an idea place to use CViewContainer. CViewContainer allows you to put whatever background you want (which will be drawn on top of the frame background) and can contain new controls to be drawn on top.
Ahhh, indeed, I never used it. Time to check it out. :P Thanks for the tip.

Best Regards, WilliamK

Post

You might be better of subclassing CView than CViewContainer. Just override the draw() function and add a bitmap member. You can then attach these bitmaps in the same way as you attach controls to a cvierwcontainer.

Post

texture wrote:You might be better of subclassing CView than CViewContainer. Just override the draw() function and add a bitmap member. You can then attach these bitmaps in the same way as you attach controls to a cvierwcontainer.
Thanks for the tip, but this sounds complicated. Mind giving me some further information? ;-)

Also keep in mind one thing, that I didn't say. I will need to draw 3 bitmaps up to 15 positions on the screen.

Best Regards, WilliamK

Post

If you need to do something funky, then you're going to have to subclass something. If that's the case, it sounds like Texture is right -- why not just subclass CView?

Post

Thanks guys for the tips. I rested longer today and my mind is good again. :P

I found that CViewContainer does exactly what I need. :D

Code: Select all

dFXbackgrounds[x] = new CViewContainer(size, frame, AddBitmap("FX"));
The Bitmap FX has 4 images, so I just use:

Code: Select all

CPoint pPoint(0,(int)(float(AddBitmap("FX")->getHeight())/4.0f)*2.0f);
dFXbackgrounds[0]->setBackgroundOffset(pPoint);
And works out perfectly.

Before adding it to the frame, I attach the Knob/Bt/Menu that I need, and that's all.

Works perfectly for me.

Thanks again for the help!

Best Regards, WilliamK

Post

The other option would have been to use COffscreenContext's to draw directly onto a pixmap. Whilst this isn't documented properly, one of the constructors for a COffscreen context takes a third parameter that allows you to use drawing funtions on a CBitmap.
From looking at the vstgui code, it looks like this might not port to Motif though. I might have missed something tho.

Code: Select all

// declarations

// class for attaching bitmaps as views
class CBitmapView : public CView 
{
	friend class CBitmapView;

public:
	CBitmapView(CRect& rect, CBitmap &bmp) 
	: CView(rect), pbmp_(&bmp) {	
		bmp.remember();	
	}

	CBitmapView(const CBitmapView& rhs) 
	: CView(rhs.size), pbmp_(rhs.pbmp_) {
		pbmp_->remember();
	}

	CBitmapView& operator= (const CBitmapView& rhs) {
		pbmp_ = rhs.pbmp_;
		pbmp_->remember();
	}

	~CBitmapView() { 
		pbmp_->forget(); 
	}

	virtual void draw(CDrawContext *pdc) {
		CView::draw (pdc);
		pbmp_->draw(pdc, size);
	}

private:
	CBitmap *pbmp_;
};

// class for managing contexts for drawing 
// to bitmaps
class BitmapContext
{
public:
	BitmapContext(CBitmap& bmp);
	~BitmapContext();

	COffscreenContext* operator->() { return poc_; }
	COffscreenContext* operator&() { return poc_; }
	COffscreenContext& operator*() { return *poc_; }
private:
	BitmapContext(const BitmapContext&); // disable copy and assignment
	BitmapContext& operator= (const BitmapContext&);

	static int dcref_;
	static CDrawContext *pdc_;

	COffscreenContext *poc_;
	CBitmap& bmp_;
};

// implementation
#include "bitmapcontext.h"

/*--------------------------------------------------------
** Class static initialisation
*/

int BitmapContext::dcref_;
CDrawContext *BitmapContext::pdc_;

/*--------------------------------------------------------
** Ctor
*/
BitmapContext::BitmapContext(CBitmap& bmp) 
: bmp_(bmp), 
  poc_(0)
{
	if (!poc_) {
		if (dcref_ == 0) {
			pdc_ = new CDrawContext(NULL, NULL, NULL);
		}
		++dcref_;

		poc_ = new COffscreenContext(pdc_, &bmp_, true);
	}

	bmp.remember();
}

/*--------------------------------------------------------
** Dtor
*/
BitmapContext::~BitmapContext() 
{
	--dcref_;

	if (dcref_ == 0) {
		delete pdc_;
		pdc_ = 0;
	}

	bmp_.forget();
	delete poc_;
}

Example use:

Code: Select all

const int bmpw = 20;
const int bmph = 50;
const int viewx = 10;
const int viewy = 10;

CRect size;

CBitmap *pbmp = new CBitmap(*frame, bmpw, bmph);
BitmapContext bmpc(*pbmp);

size(0, 0, bmpw, bmph);

bmpc->setFillColor(kRedCColor);
bmpc->floodFill(CPoint(0, 0));
// could potentially copyFrom another context

size(viewx, viewy, viewx + bmpw, viewy + bmph);
bmpview_ = new CBitmapView(size, *pbmp);

frame->addView(bmpview_);

pbmp->forget();

Post

[quote="texture"][/quote]

A word of warning:

Be careful with using contexts. VSTGUI makes it very simple creating and using offscreen contexts whenever you want. However, it makes it also very simply to use them wrongly.

Each offscreen context allocates two very memory consuming GDI objects, a Device Context (DC) and a Compatible Bitmap (DDB). These objects are *not* created and kept in your applications heap, but in Kernel-memory.

Windows (yes, even XP) has a limit to the number of these objects it can handle in the Kernel memory.

So do not keep offscreen contexts in memory all the time. If you have a specific control that keeps an offscreen context in memory, and use 200 instances of this control on your UI, then that means your plug-in uses 200 DC's and 200 DDB's per instance of the plug-in.

Insert 3-4 instances of that plug-in and you'll see Windows XP crash and burn. Windows 98 will die young after 1-2 instances already. (Depending on the size of the physical RAM the machine got, of course.)

Advice: Only create and use offscreen contexts "on the fly" in your draw() method. Dispose the context at the end of draw().

As this is considerably slower, though, keep prepared offscreen contexts for those views that are regularly redrawn in update(), like Meters for example.

This good advice is for free. ;)

Best,
Stefan
http://www.stefan-kuhn.net
Home of Vivaldi MX and Ganymed

Post

stefankuhn wrote:A word of warning:
...
Thanks for pointing this out. But looking through the VSTGUI sources, I've noticed that CSlider seems to do exactly what you suggest not to: it creates a new offscreen context when attached() is called (i.e. it's been attached to a parent view) and only deletes it when removed() is called. Does this mean that using a lot of CSliders will cause crashes? I've never noticed anything myself :?...

Anyway, I should probably rewrite some of the controls I've written (I tend to base them on CSlider :wink:).

- Niall.

Post

stefankuhn wrote: Advice: Only create and use offscreen contexts "on the fly" in your draw() method. Dispose the context at the end of draw().
Which is exactly why I wrote the BitmapContext class in the way I did.

This class offers an exception-safe way of creating the contexts for drawing to the bitmap (or a number of bitmaps, sharing the same CDC), with self cleaning of the underlying handles when the class goes out of scope. The idea being that its existence is transitory when building your bitmaps.

The problem with the design is that it is still possible to create on object on the heap, where it should only ever be created on the stack. If someone did try to create it on the heap, then they obviously wouldn't know what the hell they were doing.

Perhaps I should have declared operator new and operator delete private to make sure.

It would still be possible to create this as part of another class though, but I still think it is a useful class.

Post

texture wrote: Which is exactly why I wrote the BitmapContext class in the way I did.
Hi texture,

I hope you didn't get my post wrong.
My advice wasn't directly referring to your code example and wasn't supposed to criticise the code design in any way. It was meant as a general advice when using bitmaps and offscreen contexts.

Best,
Stefan
http://www.stefan-kuhn.net
Home of Vivaldi MX and Ganymed

Post

Ok :)

I was just pointing out that the whole purpose of the class I'd written was to enforce the fact that the contexts should be freed correctly, and also to make the resulting code when working with offscreen contexts for drawing to bitmaps much cleaner.

If there are any problems with the class though, then I would like to know so that I can improve my code.

Post

NiallM wrote:
stefankuhn wrote:A word of warning:
...
Thanks for pointing this out. But looking through the VSTGUI sources, I've noticed that CSlider seems to do exactly what you suggest not to: it creates a new offscreen context when attached() is called (i.e. it's been attached to a parent view) and only deletes it when removed() is called. Does this mean that using a lot of CSliders will cause crashes? I've never noticed anything myself :?...

Anyway, I should probably rewrite some of the controls I've written (I tend to base them on CSlider :wink:).

- Niall.
Yup. That is exactly what can happen. Just try it in "ADelayEdit" example from the SDK. Create 200 sliders and see how many instances of the plug you can load (with all Editors open, of course).

Note, however, that there are other factors involved in the likelyhood of crashing. For example the amount of physical RAM you have (and how much the kernel is using...) and how many bitmaps your plug-in loads.

When I tested these issues, I was able to create a plug-in that crashes the Host just by loading 250 small bitmaps in one instance of a plug-in.

Next to the slider, also the CViewContainer will by default allocate an offscreen context in it's constructor for it's entire size! So, if you are using lots of considerably big view containers, with lots of sliders in them, then you're scheduled for the big bang... ;)

You should be able to override these controls and destroy the context in your own constructor (and set the member pointer to NULL). At least this works fine for the CViewContainer class.

Best,
Stefan
http://www.stefan-kuhn.net
Home of Vivaldi MX and Ganymed

Post

stefankuhn wrote: Next to the slider, also the CViewContainer will by default allocate an offscreen context in it's constructor for it's entire size! So, if you are using lots of considerably big view containers, with lots of sliders in them, then you're scheduled for the big bang... ;)
Luvverly. There's quite a few things in the VSTGUI that leave a lot to be desired.
The reference counting on the bitmaps for example could have been made entirely transparent to clients. But no - your code ends up littered with calls to 'forget()'. Its almost as bad as MFC.

Do you think Steinberg use this framework for all of their own plugins?

Post Reply

Return to “DSP and Plugin Development”