Squeak DisplayScreen Bitmap Stationary?

Andreas Raab Andreas.Raab at gmx.de
Mon Aug 19 22:36:41 UTC 2002


> I think you may well find that using the SurfacePlugin can provide the
> same general support in a more principled form not to mention with
> abilities to hande pixel format conversions. I really must 
> make time to try it out myslef one day,

So you should! The sole purpose of the SurfacePlugin is to provide
generalized access for forms living "outside" Squeak.

Here's a bit of basic information (someone take this email and put it up
on the Swiki). In order to support "external" forms you have to have a
way to create them by, e.g., calling some primitive. So let's assume we
got a #primitiveCreateForm residing in MyFormPlugin. What does it have
to do?!

* Step1: Take the parameters and create the form/bitmap/image whatever
* Step2: Register the bitmap with the surface plugin
* Step3: Pass back the handle obtained by the surface plugin

The resulting handle (which will be a small integer) must be stored in
the Form's 'bits' instVar. BitBlt will recognize these registered
surfaces and allow you to draw directly onto them. So, obviously, the
only question is what you have to do in order to register the bitmap
with the surface plugin. Here's how that works:

The surface plugin expects a set of functions which will be used to
query for certain properties of the bitmap used. Currently, there are
four functions:
* getSurfaceFormat(): Which queries the surface about attributes such as
width, height, pitch, lsb vs. msb etc
* lockSurface(): Which attempts to lock a portion of the surface for
drawing operations
* unlockSurface(): Which releases a prior lock of the surface
* showSurface(): Which gets called if the surface in question represents
Display

Let's take a look at some pseudo-code (most real implementations will be
exactly as simple as the following): We first define a structure which
is used to remember the attributes of any bitmap we might be using:

typedef struct MyBitmap {
   int w, h, d;    /* width, height, and depth */
   int pitch;   /* how many bytes per scan line? */
   void *bits;  /* where are those bits? */
} MyBitmap;

[Note: If you are dealing with native bitmaps chances are good that you
don't need the above structure but can just use a handle and query some
other function for those attributes. In this case just replace the
references below with calls to those functions.]

int getSurfaceFormat(MyBitmap *myBM, int *width, int *height, int
*depth, int *isMSB) {
	/* fill in status information */
	*width = myBM->w;
	*height = myBM->h;
	*depth = myBM->d;
	*isMSB = 1; /* or zero depending on platform or choice */
	return 1; /* success - otherwise return zero */
}

[Note: BitBlt will *always* query for the actual format of the surface
and not "trust" anything stored in the form itself].

int lockSurface(MyBitmap *myBM, int *pitch, int x, int y, int w, int h)
{
	/* lock the region x,y - (x+w),(y+h)
	   the area actually used is provided so that expensive
	   operations (like a round trip to the X-Server) can
	   be avoided. See SurfacePlugin.h */
	/* for our simple example, only fill in the pitch. No locking is
required. */
	*pitch = myBM->pitch;
	return 1; /* success */
}

int unlockSurface(MyBitmap *myBM, int x, int y, int w, int h) {
	/* Unlock a previously locked portion of myBM.
	   The area describes the 'dirty region' which might
	   need to be written back/flushed whatever. */
	/* for the simple example do nothing */
	return 1;
}

int showSurface(MyBitmap *myBM, int x, int y, int w, int h) {
	/* the surface represents Display - update the portion
	   described in x,y,w,h */
	/* for our simple example we just ignore this */
	return 0; /* e.g., fail */
}

Okay, that's basically it. Now all we need is a way to actually pass
these hooks into the surface plugin upon creation. Let's define the
required structure:

sqSurfaceDispatch myBMDispatch = {
	1, /* major version */
	0, /* minor version */
	(fn_getSurfaceFormat) getSurfaceFormat,
	(fn_lockSurface) lockSurface,
	(fn_unlockSurface) unlockSurface,
	(fn_showSurface) showSurface
};

and now a primitive that creates one of our own bitmaps (will be called
with width, height, and depth):

int primitiveCreateMyBitmap(void) {
	int width, height, depth;
	int sqHandle; /* the 'bits' instVar Squeak will get */
	MyBitmap *myBM;

	/* note: should check if depth is valid */
	depth = interpreterProxy->stackIntegerValue(0);
	height = interpreterProxy->stackIntegerValue(1);
	width = interpreterProxy->stackIntegerValue(2);

	/* create my bitmap */
	myBM = calloc(1, sizeof(MyBitmap));
	myBM->w = width;
	myBM->h = height;
	myBM->d = depth;
	myBM->pitch = (w*d) + 31 / 4; /* round to bytes */
	myBM->bits = calloc(h, myBM->pitch);

	/* register my bitmap - note: should check return value */
	(*registerSurface) ((int) myBM, &myBMDispatch, &sqHandle);

	/* pop args and return created handle */
	interpreterProxy->pop(4); /* args+rcvr*/
	interpreterProxy->pushInteger(sqHandle);
}

That's basically it. Using the above you can create one of our bitmaps
and happily blt away. There's one piece missing though - that's the use
of "registerSurface" in the above. These entry points need to be looked
up dynamically and here is how this goes:

/* declare the entry points */
fn_ioRegisterSurface registerSurface = 0;
fn_ioUnregisterSurface unregisterSurface = 0;
fn_ioFindSurface findSurface = 0;

/* look up the entry points on module startup */
int initialiseModule(void) {
	registerSurface = (fn_ioRegisterSurface) 
	
interpreterProxy->ioLoadFunctionFrom("ioRegisterSurface","SurfacePlugin"
);
	unregisterSurface = (fn_ioUnregisterSurface)
	
interpreterProxy->ioLoadFunctionFrom("ioUnregisterSurface","SurfacePlugi
n");
	findSurface = (fn_ioFindSurface)
	
interpreterProxy->ioLoadFunctionFrom("ioFindSurface","SurfacePlugin");
	/* note: should return zero and FAIL module loading if any of
the above is not present */
};

Obviously, unregisterSurface() is being called for unregistering a
previously registered surface. findSurface() can be used to find out if
some surface handle is really what you *think* it is, e.g.,

int primitiveDestroyMyBitmap(void) {
	int sqHandle;
	MyBitmap *myBM;

	sqHandle = intepreterProxy->stackIntegerValue(0);
	/* see if the handle really describes a MyBitmap surface */
	if( ! (*findSurface)(sqHandle, &myBMDispatch, (int*) (&myBM)) )
{
		/* i don't know what it is but certainly no MyBitmap */
		return interpreterProxy->primitiveFail();
	}
	/* unregister and destroy */
	(*unregisterSurface)(sqHandle);
	free(myBM->bits);
	free(myBM);
}

And that's it for the basics. If the colors of the surface you're using
match those of Squeak you're done here. If they don't, you'll have to
provide sufficient information to get the color mapping right - which is
not that hard either. If you can find out the "color masks" for each of
R,G,B, and alpha you can just create a ColorMap from these masks and
everything will be hoopy. For indexed colors you'd have to query for the
RGB representation of the colors directly.

Cheers,
  - Andreas




More information about the Squeak-dev mailing list