Jump to content
IGNORED

Software Sprite System


Andrew Davie

Recommended Posts

I seem to prefer doing demos than completing projects. I like pushing the envelope, not sealing it up and posting the letter.

Nonetheless, here's a thread where I hope to post some demos of my Chronocolour(TM) Software Sprite System.

I developed the basic playfield-based software sprites for my "WenHop?" project, but first as a simple test-bed sub-project where I could put some animating playfield/software sprites onscreen.  So, see the attached binary. It is probably overtime on hardware, so best to view in Stella only at this stage.

 

My immediate plans are to write a simple tool to convert from an image file to the format used for the software sprites. That should be quick and easy, but I just don't quite feel like doing that right yet. Soon.  Here's the format...

 

const unsigned char rocketShipFlame2[] = {

    1,                  // width in BYTES (=8 pix/byte) (MAX =4)
    21,                 // height in SCANLINES (pref multiples of 3 -- TRIPIXs)
    3,0,               // center point (PIXELS) from 0,0 top left

    ________
    ________
    __XXX___
    ________
    ________
    __XXX___
    ________
    ________
    ___X____
    ________
    ________
    ___X____
    ________
    ________
    ___X____
    ________
    ________
    ___X____
    ________
    ________
    ________
};

So, a basic byte array with a simple header

 

1) width in bytes (each byte being 8 PF pixels), so maximum sprite width 32 pixels

2) Height in ChronoColour(TM) scanlines. Note this should be a multiple of 3

3) pixel x,y offset of centerpoint of sprite.

4) the shape data

 

Sprites are drawn using a simple call...

 

void drawBitmap(const unsigned char *bmp, int x, int y, bool relativeToScreen

The clipping to the screen window is automatic.

The 'relativeToScreen' allows for scrolling windows into a larger playing area

 

The shape data is just a series of byte triplets (ChronoColour) for each line.  Red/Green/Blue or whatever colours you have chosen.

For shapes > 1 byte wide (i.e., >= 8 pixels) you just define the shapes side by side... for example...

 

const unsigned char flagUSAandUSSR[] = {

    2,15,0,0,

    X_______ ________
    X_______ X_______
    _XX_____ XXX_____
    X_______ X_______
    X_______ X_______
    _XX_____ XXX_____
    X_______ ________
    ________ ________
    XXX_____ XXX_____
    ________ ________
    ________ ________
    XXX_____ XXX_____
    ________ ________
    ________ ________
    ________ ________
};

 

Believe it or not, that last one looks like two flags - USA flag and USSR flag - side by side.

Low-resolution ChronoColour(TM) PF graphics are a bit of a black art...

 

103595006_ScreenShot2021-08-22at8_09_25pm.thumb.png.2d4e9f3088289e6a411b1b09d372c8c4.png

As the binary shows, the basic draw systems are functional.  This particular version is just drawing both those ships every single frame (i.e., 60Hz) but since starting work on this I have implemented a double-buffered graphics testbed. That is where we have two graphics buffers - one being displayed on the screen, and an invisible one into which we draw stuff. When drawing is finished, we swap the buffers around. That allows you to draw things over more than one frame, and get lots, lots more onto the screen.  I'll get that in soon.  I hope to release the source code and conversion tool rather soon, too.

 

So, the ships above - they are actually each more than one sprite. The Flag, for example, is a separate sprite which is drawn after the ship.  This allows parts of the sprites to be animated separately. It's an optional thing -- they are conjoined, so to speak, because they share a common origin point, so all parts of an object are drawn at the same x,y position - they just happen to have centerpoint offsets.

 

Now my immediate plans after I've written the aforementioned graphics conversion tool.. is to put in a whole bunch of animation frames, to see how animation look in ChunkyColour :P.  I'm not entirely sure it will work, but I'm keen to give it a go and see. For the first test, I'm thinking of working on some fighter sprites... and I've gone through the basics of creating a few frames from online source sprite sheets just to see how it looks "on paper"...

 

One of the neat things about the system is that it automatically creates a "mask", so that each triplet ChronoColour pixel is actually drawn over the top of any background rather than merged with it. Another way of saying this; if a ChronoColour pixel is non-zero (black), then first the background pixel is erased, so that whatever colour the new pixel is (even if one or two scanlines of that pixel are blank)... will be preserved. The upshot is that things are drawn with priority, so the last thing drawn will always be on top of earlier stuff, with no blending. This means, though, that you lose black as a valid colour. On the other hand, the system also allows you to include your own mask, so it's possible to have actually 8 colours plus transparency... at the cost of the extra data to define the mask.

 

I'd love to do a fighting game, or maybe a wrestling game with many large wrestlers going at it at once in a scrolling arena.  Something like this....

 

image.thumb.png.31ee912ba3387d5657b35784c41868a1.png

 

 

Of course on the '2600 the screen would be a small window into all that mayhem.  The frame rate may be a bit low with that much going on :) and we'd only have 7 colours + black.... but with the double-buffered draw it would not flicker.  Thinking about it, though, you only draw stuff that's visible, so it wouldn't be that slow after all.  The system already pre-culls the draw of offscreen stuff, so perhaps that many wrestlers at a relatively high frame rate might work. But first, it's going to be interesting to see how well the really low resolution works for animating people-sprites. A static image isn't going to be the greatest representation, but here's an idea of pixel chunkiness...

 

test2.png.9672a7f9320ed74ee5d86b0120c86bea.png test2.png.18a99a234accafe99b9cd3f79649f13f.png

 

The actual experience would be halfway between these two examples.  Why halfway?  It's to do with the odd triple-line colouring that ChronoColour uses, and the difficulty of showing it correctly with a simple quick-n-dirty conversion. That was a hand-converted sample.  I took the original, reduced X (only) to 30% (aliased), then downsampled the colours to the preset 8-colour palette (dithered), and then scaled up X (only) to 330%.  That's roughly what the tool would do, but with adaptive numbers.  I imagine some hand-pixel-pushing would make the frames much nicer. Another option I'm thinking about is using a sprite overlay for the head area, of much higher horizontal resolution.  For a later version, maybe, but an interesting idea.

 

Well that's it for a start. Basically a system to draw an arbitrary number of sprites into a double-buffered bitmapped buffer with inbuilt pixel shifting, masking, and clipping. In the long run I'd love to see it as a sort of template which could be used by others to write software sprite ChronoColour(TM) games.

 

If I find the motivation, I'll post more updates here... and of course hopefully a conversion tool and source code soon.

 

css20210822.bin

Edited by Andrew Davie
  • Like 3
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...