Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion Groups
General
GeneralPortable MacsHardwareNetworking
Applications
Mac ApplicationsEudoraFirefox / MozillaInternet ExplorerOutlook ExpressMS OfficeEntourageExcelPowerPointWordVirtual PCMedia PlayerOther MS Products
Programming
Mac ProgrammingCodeWarriorPerl
Country Specific
Australian Mac GroupUK Mac Group

Mac Forum / Programming / Mac Programming / December 2004



Tip: Looking for answers? Try searching our database.

Old school (?) drawing philosophy

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
micjuneau@gmail.com - 11 Dec 2004 09:13 GMT
I finally have a serviceable 2d image drawing engine working under
System 1.0 through OS 9.2. I can draw arbitrary sized multi-frames
sprites, with (pre-generated) white masks, if needed, and with
auto-cleaning (saves background in temp bitmap and draws it back when
moving) during the blit process. (All in C)

However, even with smallish 16x16 pixels^2 bitmaps, I notice a faint
flicker, even if I'm looking at it. My strategy is to impose a delay in
the drawing with an IF condition on the value of TickCount() (do
drawing at every 4 ticks, for example), to blit the sprite, and deal
with movement and boundary/collisions conditions afterwards.

I've read in the THINK C reference that while I could install a VBL
task in the queue, the tasks that have to be done there must not move
memory - my sprite blitting functions use several calls of CopyBits at
their core, and that moves memory. The reference also mentions that
Ticks can be tracked and followed by a "quick" drawing to ensure smooth
animation. I'm wondering - is this done inside a VBL task, or is a
simple tracking of TickCount's return value enough? I'm doing the
latter, to little success.

My main question would be: how do you test the speed of a blitting
function in a more systematic way than to fiddle with it until you
cease to see flickering?

Right now, I reckon that my blit function does several things and may
take more than a tick to resolve (in my target machines - 68k macs):
1) IF to check if the sprite cleans after itself. If yes, A) CopyBits
the old buffer into the old location. B) Change the buffer location to
the new one. C) CopyBits the new location into the buffer. No actual
sprite is drawn yet.
2) IF to check if the sprite uses a mask - if yes, draws the white mask
(a straightforward copybits with srcBic as its transfer mode).
3) CopyBits the sprite proper into its position (srcOr = transfer
mode).
4) If there's no mask (2nd IF failed), copybits the sprite with
srcCopy.

At the worst (mask + cleaning), there are 2 IFs statement to evaluate,
3 copybits going on, one Rect assigning and 2 pairs of HLock HUnlock
that are needed around the new buffer CopyBits call.

I'm trying to figure out if this can be solved with VBL tasks, or if I
plain and simple need to optimize my BlitSprite function.
David Phillip Oster - 12 Dec 2004 05:36 GMT
> I've read in the THINK C reference that while I could install a VBL
> task in the queue, the tasks that have to be done there must not move
[quoted text clipped - 4 lines]
> simple tracking of TickCount's return value enough? I'm doing the
> latter, to little success.

You can't just wait for TickCount to change: what if the use has
multiple video cards, all set to different refresh rates? TickCount is
in no way synchronized to anything. That is what SlotVBLs are for: You
register for an interrupt that occurs when the card that controls a
specific monitor sends its vertical blanking signal.

But: not all video cards send a VBL. Some LCD displays don't need one.

Also: you can't do any drawing with Quickdraw (including CopyBits) at
VBL time, since all Quickdraw drawing calls look at the visRgn and
clipRgn of the current GrafPort, and since these are RgnHandles, which
are Handles, they are not guaranteed to be valid at interrupt time,
depending on whatever heap shuffling the memory manager happens otbe
doing.

I asked Apple: what if you create your windows in a private heap, then
switch back to the main heap for everything else, so you know the memory
manager isn't going to touch your RgnHandles. I was told that even then
quickdraw at interrupt time wasn't guaranteed to be safe. (Besides,
someone might have installed unsafe trap patches.)

> My main question would be: how do you test the speed of a blitting
> function in a more systematic way than to fiddle with it until you
> cease to see flickering?

See how long it takes to execute it 10000 times in a tight loop,
compared to executing an empty 10000 times loop?

> Right now, I reckon that my blit function does several things and may
> take more than a tick to resolve (in my target machines - 68k macs):
[quoted text clipped - 15 lines]
> I'm trying to figure out if this can be solved with VBL tasks, or if I
> plain and simple need to optimize my BlitSprite function.

Use a SlotVBL to set a bit on entry to VBL time, and have your main
thread poll for that bit and do the drawing.

None of the above applies to OS X. Under OS X, you'd just use OpenGL,
which is hardware double buffered: while the user is looking at one
frame, you are drawing the next frame to an offscreen buffer. Call
SwapBuffers() and OpenGL busy-waits until that monitor's VBL time, when
it swaps the back and fore buffers by writing to single register on the
video card, and now you have an entire frame time to draw. See:

<http://www.ati.com/developer/demos/macss2/> the animusic demo, in
particular, is simply eye-popping incredible.

Signature

David Phillip Oster

micjuneau@gmail.com - 17 Dec 2004 20:24 GMT
---
See how long it takes to execute it 10000 times in a tight loop,
compared to executing an empty 10000 times loop?
---

Empty 5000 times loops yields a 0 tick difference between the a
tickcount made before the loop, and one after it. I guess the compiler
knows better.
However, I've tried my Blit routine (with all the mask+cleaning
features) vs a raw one (which is essentially only a direct CopyBits
use, with the transfer mode of my choice) and the difference is
staggering.
First loop strategy: BlitSprite use, and a pointer is incremented to
point to the correct frame. Ticks = 745
Second loop strategy: DrawSprite use only (equivalent to CopyBits,
using srcCopy, the fastest mode). Ticks = 25.

I've just stumbled (an hour ago) unto a sprite graphics library that
hopefully, will be easily adaptable for b&w macs (it claims it is).
It's called SAT (sprite animation toolkit) and I just downloaded
version 2.6.0. There are many similar features, judging from its header
file. However, I can't compare it to my stuff because it's compiled as
a library and the source code isn't available. I'll take what I can
from it.
Thanks for your help on VBL tasks, you've been helpful, as always.
Reinder Verlinde - 17 Dec 2004 22:42 GMT
> Empty 5000 times loops yields a 0 tick difference between the a
> tickcount made before the loop, and one after it. I guess the compiler
> knows better.

That may be the case, but I guess that you do not realize how fast
modern processors are.

An idle loop of say four instructions times 5000 loops takes 20000
instructions. At 1 GHz, that's 2 * 10^4 / 10^9 = 2 * 10^-5 seconds.

At 10 Mhz, it would take 2 ms. A Tick is about 16 ms.

=> The compiler does not have to optimize your loop away for it to take
'zero ticks'

You should use a faster counter, such as 'MicroSeconds' for your timing,
or use many more loops.

Reinder
micjuneau@gmail.com - 18 Dec 2004 05:52 GMT
---
That may be the case, but I guess that you do not realize how fast
modern processors are.

An idle loop of say four instructions times 5000 loops takes 20000
instructions. At 1 GHz, that's 2 * 10^4 / 10^9 = 2 * 10^-5 seconds.

At 10 Mhz, it would take 2 ms. A Tick is about 16 ms.
---

Thanks for the approximative educated guesses. I just had a complete
lack of knowledge in that area before.

---
You should use a faster counter, such as 'MicroSeconds' for your
timing,
or use many more loops.
---

Here's the thing. I'm using Symantec C++ 6.0 (THINK C) and intend to
program for 68000 macs. There is no MicroSeconds in that generation of
C compiler. If you know of any other way to using timing for that
period, please tell me.
Reinder Verlinde - 18 Dec 2004 09:08 GMT
> ---
> That may be the case, but I guess that you do not realize how fast
[quoted text clipped - 18 lines]
> program for 68000 macs. There is no MicroSeconds in that generation of
> C compiler.

I think that you can get MicroSeconds there by installing QuickTime
version <whatever> or higher. So, this might be a problem with your
header files.

> If you know of any other way to using timing for that
> period, please tell me.

Use the extended Time Manager

Reinder
micjuneau@gmail.com - 29 Dec 2004 19:34 GMT
-----
I think that you can get MicroSeconds there by installing QuickTime
version <whatever> or higher. So, this might be a problem with your
header files.

> If you know of any other way to using timing for that
> period, please tell me.

Use the extended Time Manager
-----

I've gathered some notes from IM and from websites about the Time
Manager:

original  - below System 6.0.3 - gives control of milliseconds (about 1
millisecond is the best), can drift over time
revised - between System 6.0.3 and 6.0.8L - gives control of
microseconds (20 ms is the best), can drift over time
Extended - From System 7.0 and up - gives control of nanoseconds,
drifting is corrected

The differences are well explained in the graphs in this IM page:
http://developer.apple.com/documentation/mac/Processes/Processes-57.html#HEADING57-0

As for the time delays I need - as I've told earlier, 500 Blits for a
small image required 745 ticks, which comes to about 1,49 ticks per
Blit (which, I remind you, uses the full gamut I've given it -
background cleaning + mask + sprite itself).

Note again that yes, I intend to write code for Classic Macs first, and
not to mess with SlotVBL interrupts. So my screen refresh frequency is
60.15 Hz. Checking the first edition of IM, here are the time delays at
hand:
Each of the 342 horizontal scan lines take 32.68 microsecs to draw.
Each horizontal blanking (going from right edge to left edge between
each line) take 12.25 microsecs.
So the drawing process takes a total of 15367.65 microsecs = 15.37 ms.
The vertical retrace takes 1.26 ms, and the grand cycle takes 16.63 ms.

This means that when I'm waiting for a VBL interrupt before I start
drawing, I only have 1.26 ms at my disposal before there's a risk that
there'll be blinking (especially near the top of the screen). Barring
optimizing my blit routines in assembly (which I don't want to touch
with a ten foot pole) to lower that estimate -count of 1,5 ms or so,
I'll have to use the revised Time Manager (to get System 6
compatibility, but not prior to that) in order to draw my sprites with
a strategy. I could roughly separate it into 2 drawing passes per
screen refresh, one for the top half of the screen, and one for the
bottom half, seeing as how 2 drawings of 1.5 ms each can fit fine into
this 15.37 ms total time.

I'd use the VBL interrupt ONCE to turn on a flag, which would be a cue
to start implementing 2 revised Time Manager interrupts that would
control the start of both drawing passes.

Any comments, suggestions or error pointing you see with this strategy?
I'd rather keep the original Time Manager to ensure compatibility for
earlier-than-6.0.3 Systems. I'll give it a try first, I think. Then on
to revised if it's not satisfactory.
micjuneau@gmail.com - 29 Dec 2004 19:40 GMT
Sorry about the errors with the milliseconds (ms), and microseconds (us
- mu seconds).
original - milli
revised - micro
extended - nano
screen refresh delays - total in milli, individual lines in micro
micjuneau@gmail.com - 29 Dec 2004 19:59 GMT
Just a note on the program I had on hand at the start of this thread -
I clearly see that the flickering starts to vanish partially between
the middle of the screen and about 2/3rds of the screen down. There is
no flicker between 2/3rds and the bottom of the screen. Flickering
being an optical remanance effect, it's of course lessened if the VBL
delay is set to numbers higher than 1 (ie, drawing cued at every x
screen refresh).

However, I was deliberately not helping things by forcing a 17-pixel
wide sprite unto my code. I'll repeat other tests with widths that are
multiples of 4, if not 8.
micjuneau@gmail.com - 29 Dec 2004 21:30 GMT
Sorry for the barrage of replies, but I just made some more tests and
the results are widely different. Somehow, my last results are thrice
as long as what I get now.

Blit, 16pixel wide, 10 000 times
293 ticks = 1/60.15 * 293 = 4871.16 ms
per blit: 0.4871 ms

Blit + frame reeling, 16pixel wide, 10 000 times
297 ticks = 1/60.15 * 297 = 5087.28 ms
per frame blit: 0.5087 ms

Blit, 16pixel wide, 10 000 times
301 ticks = 1/60.15 * 301 = 5004.16 ms
per blit: 0.5004 ms

Blit + frame reeling, 17pixel wide, 10 000 times
306 ticks = 1/60.15 * 306 = 4937.66 ms
per frame blit: 0.4938 ms

This means that in the best case scenario, with careful planning in the
drawing of different regions on the screen, I can get about 28 smallish
16 pixel wide sprites on screen at any given time. Of course, the
number will end up being lower since I need to perform other tasks
(collision detection, AI, etc) and I'll probably need to use larger
sprite (but the blit time is not directly proportional to width, thank
god), but at least I'm relieved that it's not as stark as I thought.
C.R. Osterwald - 20 Dec 2004 14:53 GMT
> I've just stumbled (an hour ago) unto a sprite graphics library that
> hopefully, will be easily adaptable for b&w macs (it claims it is).
[quoted text clipped - 3 lines]
> a library and the source code isn't available. I'll take what I can
> from it.

You might want to check out SpriteWorld:

<http://www.spriteworld.org/>

The older version 2.3.1 should work fine on toaster Macs, and includes
all source code.  Pascal is also available.

--
micjuneau@gmail.com - 20 Dec 2004 16:57 GMT
I found it too, shortly after my last message. It claims it requires
68020 macs and up, but I don't know if it's a requirement to compile it
(meaning, it'd be usable only on compilers which run on these
machines), or if the target environment for the compiled applications
needs to be on 68020 macs.

I'd rather continue my work and develop all my functions myself,
perfectly tailored to my needs, but looking at the header file for the
SAT engine, I have a lot of wheels to reinvent.

Right now, I'm working on trying to use InsTime and PrimeTime to
install tasks into a queue, that will give me control over
milliseconds. I'm still trying to understand how I can avoid the
flicker that comes when the background is restored under a sprite. I
might have to devise a function that looks at which pixels must be
changed and acts only upon those.
Gregory Weston - 21 Dec 2004 01:15 GMT
> I've just stumbled (an hour ago) unto a sprite graphics library that
> hopefully, will be easily adaptable for b&w macs (it claims it is).

It is.

> It's called SAT (sprite animation toolkit) and I just downloaded
> version 2.6.0. There are many similar features, judging from its header
> file. However, I can't compare it to my stuff because it's compiled as
> a library and the source code isn't available. I'll take what I can
> from it.
> Thanks for your help on VBL tasks, you've been helpful, as always.

Mr. Ragnemalm made some fairly interesting architectural choices in that
library that aren't obvious but give some useful side-effects, as I
recall. It's been a long time since I did anything with it and that was
mostly puttering. I ended up creating my own based on SpriteWorld 1.0b4
at the time and took it in my own direction after that.

G

Signature

Change account to gw when responding by mail.

 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.