Jump to content
IGNORED

Bus Stuffing Demos


SpiceWare

Recommended Posts

Would this true Atari interlaced mode be 480i at 30Hz or 30 FPS, but real broadcast TV is 480i 60Hz 60 FPS, or am I mixing apples and oranges?

If you make the atari output a true interlaced video by adding the extra half line to each frame (which will then be more correctly called fields, as they will be alternately offset by half scanline up or down), that would be the same as the TV analog standard definition signal, that is 525 lines interlaced at 30Hz (framerate) / 60Hz (fieldrate) , or 625 25Hz / 50Hz in Europe.

Note that "frame" here just means the totality of the visible scanlines on the screen, not a still picture like a frame in a film.

Vertical and Horizontal speed of the electron beam in a CRT are fixed (they're determined by the circuitry in the TV and are not part of the video signal), To display more frames with the same resolution you should tell the TV to increase the speed of the beam and that is not possible.

 

480i and 576i only refers to digital video (for example the mpeg2 video stored on a dvd or broadcast using the DVB-T or ATSC standards).

Edited by alex_79
Link to comment
Share on other sites

The rpg looks really cool! :)

 

Both car demo's vibrate on my CRT which I think is preventing the interlacing from working so they look like 15 hz or lower.

 

What is the technique to generate half a scanline for the offset?

 

Also curious about the warning - I thought bus stuffing was safe for the hardware.

 

 

 

Vertical and Horizontal speed of the electron beam in a CRT are fixed (they're determined by the circuitry in the TV and are not part of the video signal), To display more frames with the same resolution you should tell the TV to increase the speed of the beam and that is not possible.

 

 

I disagree, the nonstandard Atari signal is already overclocking the CRT by rendering 60 full frames per second instead of fields.

 

And it is possible to change the nonstandard signal to 30 hz, 20 hz , 15 hz, etc with no change in resolution, it's just not possible to render more than 60 hz and 60 fps.

Link to comment
Share on other sites

I guess the snow-peaked mountains need something better than programmer graphics :lol:

[...]

I've made a color change which may help:

:D

Actually, I was thinking that the RPG kernel would be well suited for a "Boulder Dash" style game, so my subconscious made me write "rocks"...

 

I like the new colors better, btw!

Link to comment
Share on other sites

:D

Actually, I was thinking that the RPG kernel would be well suited for a "Boulder Dash" style game, so my subconscious made me write "rocks"...

:lol: - I've been thinking the same. One of the iconic things about Boulder Dash is the colors change every level, but on the fly color changes for PAL and SECAM didn't pan out. I've been pondering on some ideas for that and might do some experiments this weekend.

 

 

 

I like the new colors better, btw!

Thanks!

Link to comment
Share on other sites

Not sure if I get you here. That's only a restriction for the demo and not a technical limitation, correct?

I copied function ColorConvert (and supporting functions) from Draconian. They're used for on-the-fly conversion of color values from NTSC to either PAL or SECAM:

 

const unsigned char NTSCtoPAL[16] =
{
    // SeaGtGruff's conversion values from this post at AtariAge:
    // http://www.atariage.com/forums/topic/165424-modify-colour-palette/page__p__2043124#entry2043124
    0x00, 0x20, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0,
    0xd0, 0xb0, 0x90, 0x70, 0x50, 0x30, 0x30, 0x20
};

int ColorPAL(int color)
{
    return NTSCtoPAL[color>>4] +    // chroma value
           (color & 0x0f);          // luma value
}


const unsigned char NTSCtoSECAM[16] =
{
    0x0e,   // 0 = white            e = white
    0x0c,   // 1 = yellow           c = yellow
    0x0c,   // 2 = yellowish orange c = yellow
    0x04,   // 3 = reddish orange   4 = red
    0x04,   // 4 = red              4 = red
    0x06,   // 5 = reddish purple   6 = purple
    0x06,   // 6 = purple           6 = purple
    0x06,   // 7 = bluish purple    6 = purple
    0x02,   // 8 = blue             2 = blue
    0x02,   // 9 = blue             2 = blue
    0x0a,   // a = bluish cyan      a = cyan
    0x0a,   // b = cyan             a = cyan
    0x08,   // c = green            8 = green
    0x08,   // d = green            8 = green
    0x08,   // e = olive green      8 = green
    0x0c    // f = brown            c = yellow
};

int ColorSECAM(int color)
{
    if (color < 2)
        return 0;   // return black for 0 or 1
    else
        return NTSCtoSECAM[color>>4];
}

int ColorConvert(int color)
{
    if (MM_TV_TYPE == PAL)
        return ColorPAL(color);
    else if (MM_TV_TYPE == SECAM)
        return ColorSECAM(color);
    else
        return color;
}


For Draconian that worked fine as there's probably 20-30 color conversions per frame.

 

For the tile display that function's a bit more complicated as the passed value is an unsigned short int containing both shape and color, it was also being called 1152 times per frame. That caused Vertical Blank to run long enough that the picture on my very tolerant C=1084S was rolling. The frame buffer for the tile display is 2316 bytes in size (12 * 193) so Display Data RAM gets tight very quickly after everything else comes into play so preconverting tiles isn't an option.

 

I have lots of ideas for a solution, such as using 128 bytes of RAM to hold ColorTable. Update ColorTable based on the current TV Type (and level in Boulder Dash). Then the color conversion becomes color = ColorTable[color>>1]. Should be much faster, I'm just running out of time to get everything done for the Houston Arcade Expo. PAL and SECAM is meaningless for that, so trying these ideas out is on the back burner until after the expo.

Link to comment
Share on other sites

It is a bit of a waste of ROM, but the ARM really likes 32-bit values, so you could do the conversions at compile-time and define your sprite data as:

 

data | color<<4 | PAL(color)<<8 | SECAM(color)<<16  // PAL & SECAM are C macros
The fetcher code would then be:

 

unsigned int sprite = spriteData[x++];
fetcher[data++] = sprite & 0xFF;
fetcher[color++] = (sprite >> TVshift) & 0xFF;
Or something like that :)

 

Chris

Edited by cd-w
Link to comment
Share on other sites

I have lots of ideas for a solution, such as using 128 bytes of RAM to hold ColorTable.

Probably I miss something, but why do you have to convert the colors on-the-fly? Why not defining the colors in the code?

 

And why would the table have to be in RAM?

Link to comment
Share on other sites

It is a bit of a waste of ROM, but the ARM really likes 32-bit values, so you could do the conversions at compile-time and define your sprite data as:

...

Or something like that :)

Yeah, I'm doing compile time now:

 

NTSC            = 0
PAL             = 1
COMPILE_VERSION = NTSC
;COMPILE_VERSION = PAL

BLACK           = $00
WHITE           = $0E
GREY            = $00

 IF COMPILE_VERSION = NTSC
 ; NTSC color values
YELLOW          = $10
ORANGE          = $20
RED_ORANGE      = $30
RED             = $40
PURPLE          = $50
VIOLET          = $60
INDIGO          = $70
BLUE            = $80
BLUE2           = $90
TURQUOISE       = $A0
CYAN            = $B0
GREEN           = $C0
YELLOW_GREEN    = $D0
OCHRE_GREEN     = $E0
OCHRE           = $F0
 ELSE
YELLOW          = $20   ; no real equivalent
ORANGE          = $20
RED_ORANGE      = $40
RED             = $60
PURPLE          = $80
VIOLET          = $A0
INDIGO          = $C0
BLUE            = $D0
BLUE2           = $B0
TURQUOISE       = $90
CYAN            = $70
GREEN           = $50
YELLOW_GREEN    = $30
OCHRE_GREEN     = $30   ; no real equivalent
OCHRE           = $20   ; no real equivalent 
 ENDIF

...


Hero_ID = (*-Tiles)/(TILE_HEIGHT*2)
    .byte %00000000, BLACK  ; 0
    .byte %00011100, RED+10 ; 1
    .byte %00011100, RED+10 ; 2
    .byte %00001000, RED+10 ; 3
    .byte %01111111, BLUE+8  ; 4
    .byte %01011101, BLUE+8  ; 5
    .byte %01011101, BLUE+8  ; 6
    .byte %01011101, RED+10  ; 7
    .byte %00010100, OCHRE+4  ; 8
    .byte %00010100, OCHRE+4  ; 9
    .byte %00010100, OCHRE+4  ;10
    .byte %00110110, OCHRE+4  ;11    
Link to comment
Share on other sites

Probably I miss something, but why do you have to convert the colors on-the-fly? Why not defining the colors in the code?

I don't have to - I'd just copied over the routines from Draconian for single-ROM-solution that would show the correct colors on all 3 TV Types.

 

And why would the table have to be in RAM?

because in a single-ROM-solution the user would be selecting NTSC, PAL or SECAM via the menu. As soon as they changed the option the color table would be recalculated for the 128 values. Another option would be 3 tables in ROM, but RAM access is 4 times faster than ROM access, so having the table in RAM would help with the performance.

 

For a game like Boulder Dash having a ColorTable in RAM makes it easy to have the colors change for the levels.

Link to comment
Share on other sites

But why not set those RAM tables up once after reset depending on switches etc for PAL/NTSC (and come on, no one needs secam :)

?

 

 

That's basically what I'm talking about doing, though setting up the RAM table would occur when the (currently non-existant, but will be similar to the one in Draconian) TV-Type menu option is changed. The existing routine was fast enough for the limited color conversions needed in Draconian, so I never looked into improving its performance. When I copied it into the RPG demo was when the need for improvement showed up.

 

I have a deadline for my presentation, for which talking about (and showing) these Bus Stuffing Demos is one of the things I plan to do. PAL/SECAM conversions are not relevant for a presentation using NTSC hardware, so optimizing those routines is currently a low priority.

Link to comment
Share on other sites

Can hit Game Reset at any time to restart the game. There's a new cave system:

post-3056-0-50317900-1477862177_thumb.png

 

Items are no longer available for purchase in the castle, instead head on over to the new country store!

post-3056-0-55817600-1477862172_thumb.png

 

rpg_20161030_NTSC.bin

rpg_20161030_PAL.bin

 

 

Also getting started on a new Bus Stuffing kernel, though not much to see on it yet:

post-3056-0-61203200-1477862395_thumb.png

  • Like 1
Link to comment
Share on other sites

I did try posting a video of RPG on Facebook, but they promptly converted it to 30 fps which ruined the demo as it utilizes 30 Hz flicker. I cancelled my YouTube account a few years ago. Maybe somebody else can make and post some videos?

 

It's not a fork of Stella, it's a not-yet-committed-change because we're not finished writing it yet. The driver will be undergoing some major changes in a few weeks or so, which will break compatibility with the current demos.

Link to comment
Share on other sites

I thought 30fps turned out ok as long as you enable phosphor in stella. While it may not be a completely accurate potrayal of what real hardware looks like I think it'd be good enough for this.

 

Regarding the previous comment about the hero moving in tile sized steps. What if you have navigable regions that use PF for the tiles instead of GRP0/1. Then GRP0/1 is available to draw the character at any position inside the navigable regions. Simply split the hero's graphic accross multiple tiles as needed. Maybe with venetian blinds for the hero sprite you could also place one or more enemies in the navigable area as well. So you essential have coarse grained background where the hero and enemies roam and fine grained graphics everywhere else.

Edited by ZackAttack
Link to comment
Share on other sites

I thought 30fps turned out ok as long as you enable phosphor in stella. While it may not be a completely accurate potrayal of what real hardware looks like I think it'd be good enough for this.

I've always filmed real hardware, not Stella. Hmm, the iPhone can record at 30fps, perhaps that would work out better - will try that tonight after work.

 

 

Regarding the previous comment about the hero moving in tile sized steps. What if you have navigable regions that use PF for the tiles instead of GRP0/1. Then GRP0/1 is available to draw the character at any position inside the navigable regions. Simply split the hero's graphic accross multiple tiles as needed. Maybe with venetian blinds for the hero sprite you could also place one or more enemies in the navigable area as well. So you essential have coarse grained background where the hero and enemies roam and fine grained graphics everywhere else.

Could do something like Cat Quest, but the purpose of the demo was to show something that couldn't be done without the use of bus stuffing. In this case Chris worked out a 96 pixel kernel with 12 colors per scanline and suggested a tile based RPG. We can draw the playfield behind the 96 pixels, but only a symmetrical one as the kernel's too busy mid-screen updating the players & colors to also update the playfield registers for the right side.

 

I probably won't spend much more time on the RPG demo as I've already started writing the kernel for the bus stuffing reboot of Draconian. I'm currently rewriting the score kernel so I can show diagnostic info.

 

I also plan to extract the music from Stay Frosty 2 and use it to write a demo testing out the Bus Stuffing music support. They have some issues we still need to resolve - the sound is noisy on real hardware, and the sound is wrong(though recognizable) in Stella. Bus' music routines are based on DPC+'s music routines, with some improvements based on things we've learned since writing the DPC+ driver:

  • Frequency data no longer takes up 1K of RAM (512 bytes if using custom C code). The frequency values are now calculated on the fly, so only 12 bytes are needed to hold the 3 frequencies currently in use.
  • Waveforms are no longer fixed at 32 bytes. You can set the size to 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 or 4096 bytes based on what you need.
  • We can get the current playback position in the waveform buffer
The waveform size and position will make it easier to play back digitized audio samples. I'll be testing those out when I reboot Frantic for bus stuffing.

 

We also have an issue with some 7800s that we hope to resolve. If we can't then bus games won't be guaranteed to work on 7800s.

Link to comment
Share on other sites

Tried recording a 30fps video. It looks a lot better than what Facebook did, but there's still a scrolling section in the image where the alternating frames do not appear to be blended together even though they look just fine on real hardware. I scaled it down from 1080p so I could upload it here (it's just under the 50 MB file size limit).

 

IMG_7735.m4v.zip

  • Like 1
Link to comment
Share on other sites

Making progress on the reboot of Draconian:

post-3056-0-75872000-1478132200_thumb.png

 

In the prior builds of Draconian the positions, sizes, and colors of the topmost objects were set using a traditional routine in Vertical Blank like this:

 

       ldx #4
PAloop:    
        lda #<DF0DATA     
        jsr PosObject
        dex
        bpl PAloop
        lda #<DF0DATA
        sta NUSIZ0        ; set player/missile 0 sizes
        lda #<DF0DATA
        sta NUSIZ1        ; set player/missile 1 sizes
        lda #<DF0DATA
        sta COLUP0        ; first sprite color
        lda #<DF0DATA
        sta COLUP1        ; first sprite color
        lda #<DF0DATA
        sta COLUPF        ; first star color
        sta WSYNC
        sta HMOVE   

One of things about that route is it takes 1 *OR* 2 scanlines per object, as objects on the right side of the screen would take longer to position, plus an additional scanline at the end for setting the sizes & colors as well as strobing HMOVE. So anywhere from 6-11 scanlines worth of 6507 processing time. As such, I had to make sure the 6507 code had 11 scanlines worth of time after the custom ARM code finished running.

 

In the new version the first five scanlines, where the players are fully on, will do that instead. So while the display area has 5 extra scanlines, the Vertical Blank routine frees up 11 for a net gain of 6 scanlines worth of processing time.

 

draconian_20161102.bin

  • Like 1
Link to comment
Share on other sites

That's basically what I'm talking about doing, though setting up the RAM table would occur when the (currently non-existant, but will be similar to the one in Draconian) TV-Type menu option is changed. The existing routine was fast enough for the limited color conversions needed in Draconian, so I never looked into improving its performance. When I copied it into the RPG demo was when the need for improvement showed up.

Turns out I was actually pre-converting a color table in Draconian. The table's in RAM:

ObjectColors:   
        .byte $28       ; 0  asteroid - orange
        .byte $88       ; 1  mine - blue
        .byte $0c       ; 2  ship - white, subtract 2 due to lumaboost
        .byte $58       ; 3  itype - pink
        .byte $ac ; $b8 ; 4  ptype - cyan
        .byte $48 ; $38 ; 5  etype - reddish orange
        .byte $18       ; 6  spy - yellow
        .byte $c8       ; 7  station -green
        .byte $c4       ; 8  condition green
        .byte $1A       ; 9  condition yellow
        .byte $44       ; 10 condition red    
        .byte $38       ; 11 itype lead - orange 
        .byte $58       ; 12 ptype lead - pink
        .byte $96 ; $88 ; 13 etype lead - blue 
        .byte $48       ; 14 radar enemy
ObjectColorSize = * - ObjectColors

and this bit of C code in the menu routines would convert them as needed:

    // Convert object colors based on MM_TV_TYPE
    // -2 so the RadarColors also get updated
    for(i=-2;i<OBJECT_COLOR_SIZE;i++)
        queue[OBJECT_COLORS + i] = ColorConvert(ddrom[OBJECT_COLORS+i]);
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...