1-800-477-2659
> Corporate Smalltalk Consulting Ltd.
> http://www.smalltalkconsulting.com
>
Andreas Raab Andreas.Raab at gmx.de
Tue Aug 20 00:36:41 CEST 2002
*Previous message: Squeak DisplayScreen Bitmap Stationary?
* Next message: R.F.Clarification:
* Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
>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","SurfacePlugin");
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
Raab, Andreas Andreas.Raab at disney.com
Sun Jul 23 21:49:01 CEST 2000
* Previous message: Squeak's Foreign Function Interface
* Next message: Virtual Morphs
* Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
> In the course of those discussions, we eventually came up with the
> Treaty of Denver and the ideas that now exist in the FXBLT code ( I
> think - I haven't had time to even properly read the code yet) and
> should allow us to arbitrarily mix big-endian, little endian,
> middle-endian (yes it exists - dear old M$ does Windows bitmapts in
> middle-endian form!) as source, destiniatio, texture, halftone,
> whatever. It also allows bitmaps to be external to the Squeak object
> memory, so that memory in accelerator cards can be used.
Yup. That's the whole point. You can basically use any OS bitmap from within
Squeak with FXBlt. What you have to do is to implement about 5 C support
functions for the OS bitmap, register the thing with the surface plugin and
then you can blt from and to as you wish. No more byte reversals ;-)
> Sometime soon, VMs can be updated to make use of this and the
> pixel-swapping code will be removed from the Acorn, Windows and Unix
> windows files.
It's really trivial to do. All that's needed is to implement a couple of
primitives that actually create the bitmap (see the B3DDisplayScreen for an
example of those).
> Oh, and in most cases, the reversing loops you mentioned spend all their
> time reading from and writing to the cpu cache, so trying to do clever
> things by readinga word and hand manipulating instead of reading each
> byte separetly has no actual benefit. Been there, wasted my
> time on that....
Ah... that actually depends. If you're doing a copying reversal you might be
right. But for an inplace reversal it *does* make a difference. Been there,
tried that ;-)
- Andreas
Check out the example in the SVN repository. How do you access that?
Example surface plugin
Andreas Raab andreas.raab at gmx.de
Wed Apr 26 21:20:51 UTC 2006
* Previous message: File and directory primitives are severely broken
* Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hi Guys -
Just FYI: I noticed that my earlier example for a surface plugin got
lost in the depths of the internet so I posted an updated version to the
SVN repository. Feel free to ignore for any regular builds; it's really
just an example of how to deal with the surface plugin etc.
Cheers,
- Andreas