Jump to content
IGNORED

[IntyBASIC] How do I upload graphic data from RAM to GRAM?


Kiwi

Recommended Posts

There's many states that this object could have that has to be modified in RAM and then upload to GRAM. Specifically this 16 MOB object could have 6 paddles at a time or 1 paddle. It can be 8 pixels wide or 1 pixel wide. Only logical thing is to modify the graphic in RAM and then upload it to specific GRAM card used for this object. Otherwise, there would be boat load of graphic data in ROM.

 

I attempted it but it only skip every other lines.

Link to comment
Share on other sites

I'll admit shooting from the hip with this answer. IntyBASIC experts will need to chime in to correct me if I'm wrong.

 

I believe IntyBASIC expects the graphic data to be packed, with even rows in bits 0-7 and odd rows in bits 8-15 of a 16 bit word. That is:

.

          15           8 7            0
         +--------------+--------------+
word 0:  |     row 1    |     row 0    |
         +--------------+--------------+
word 1:  |     row 3    |     row 2    |
         +--------------+--------------+
word 2:  |     row 5    |     row 4    |
         +--------------+--------------+
word 3:  |     row 7    |     row 6    |
         +--------------+--------------+

.

I base this on the description in the manual, which says that graphic data must come from an array in 16-bit memory:

.

  DEFINE card_num,total,label
  DEFINE card_num,total,VARPTR label(expr)
  DEFINE ALTERNATE card_num,total,label
  DEFINE ALTERNATE card_num,total,VARPTR label(expr)

    Loads graphics in GRAM "card_num" (0-63) for a total of "total" cards.
    label points to graphics. (DATA or BITMAP)

    Label can be also an 16-bits array for dynamically defined GRAM.

        DIM #graphic(4)

        DEFINE 0,1,#graphic

.

Also, the hi/lo packing pattern is common in Inty programs, since it lends itself to efficient unpacking given the CPU's instruction set. The sequence "MVI@, MVO@, SWAP, MVO@" is about 6% faster than "MVI@, MVO@, MVI@, MVO@" to copy two rows. That lets you squeeze one more card in per frame.

Edited by intvnut
  • Like 2
Link to comment
Share on other sites

Otherwise, there would be boat load of graphic data in ROM.

I just wanted to add, never be afraid of this option. A "boat load of graphics data in ROM" is what allows Christmas Carol to have such smooth and detailed animation sequences: every state and transient frame of a sprite is pre-drawn in ROM. This includes sprite cardinal orientation (i.e., facing up, down, left, and right).

 

dZ.

  • Like 4
Link to comment
Share on other sites

I just wanted to add, never be afraid of this option. A "boat load of graphics data in ROM" is what allows Christmas Carol to have such smooth and detailed animation sequences: every state and transient frame of a sprite is pre-drawn in ROM. This includes sprite cardinal orientation (i.e., facing up, down, left, and right).

 

 

Indeed. :thumbsup:

 

Space Patrol also does this to provide its smooth parallax scrolling. If you're generating a large number of related shapes, you might consider writing a script to generate the images statically, which is what I did. Even with gobs of preshifted images of all the mountains, craters, rocks, etc. I still fit into a 16Kx16 ROM.

 

One aspect where IntyBASIC works against you: It does seem to trade codesize for speed, which will push against your ability to load up the ROM with graphics. But, as dZ says, don't be afraid to start with "boatload of graphics in ROM." Only generate on the fly if you need to.

  • Like 1
Link to comment
Share on other sites

There's many states that this object could have that has to be modified in RAM and then upload to GRAM. Specifically this 16 MOB object could have 6 paddles at a time or 1 paddle. It can be 8 pixels wide or 1 pixel wide. Only logical thing is to modify the graphic in RAM and then upload it to specific GRAM card used for this object. Otherwise, there would be boat load of graphic data in ROM.

 

I attempted it but it only skip every other lines.

 

I just wanted to add, never be afraid of this option. A "boat load of graphics data in ROM" is what allows Christmas Carol to have such smooth and detailed animation sequences: every state and transient frame of a sprite is pre-drawn in ROM. This includes sprite cardinal orientation (i.e., facing up, down, left, and right).

 

dZ.

In IntyBASIC there are way more convenient ways and ROM space is not an issue, I agree with DZJay, there are better things to focus on that calculating GRAM cards on the fly. Between DEFINE and DEFINE ALTERNATE you can do all kinds of things quickly and most importantly focus on things that would benefit from optimisation. Especially in your example. It is one character, you can call define every frame and have 50 frames of animated, all pre slugged into the rom with Bitmap statements. I've even used some outside tools to pre-generate animation frames and BITMAP statements for me rather than coding it in game

  • Like 2
Link to comment
Share on other sites

The initial idea I had was to do apply a bitwise to each bytes to resize the paddle in an 8-bit array. Erase the paddle by putting a zero into the byte. I wasn't sure what bitwise to apply to each bytes. And the graphic has to be in pair of bitmap statements so having the graphic in a 8 byte array doesn't work so that was my first error. So changing the array to 16-bit did load the graphic properly.

 

The initial paddle graphic in ROM is,

bitmap "XXXXXXXX"
bitmap "........"
bitmap "........"
bitmap "XXXXXXXX"
bitmap "........"
bitmap "........"
bitmap "XXXXXXXX"
bitmap "........"
bitmap "........"
bitmap "XXXXXXXX"
bitmap "........"
bitmap "........"
bitmap "XXXXXXXX"
bitmap "........"
bitmap "........"
bitmap "XXXXXXXX"

I was able to remove and add paddle to the array using for statement. The advice about not being afraid to stuff the ROM with graphic made me come up with this idea. I was able to expand the bitmap statement from 16 bitmap statements to 64 bitmap statements to hold 4 different size paddle and use a pointer to load the right size.

if paddle=3 then
for x=0 to 8
#fireplat(x)=0
next x 
for x=4 to 8
#fireplat(x)=IceCatch01(x+paddlestat*
next x
wait
DEFINE 48,2,#fireplat
end if

If there's 3 paddles, then it'll run this procedure to draw the 16-bit array and then upload to GRAM card.

post-24767-0-86117400-1466024293_thumb.gif <--animated gif of me pressing the keypad to change the paddle's condition.

 

This procedure doesn't run every frame, but on call when an event happens.

  • Like 2
Link to comment
Share on other sites

I was able to remove and add paddle to the array using for statement. The advice about not being afraid to stuff the ROM with graphic made me come up with this idea. I was able to expand the bitmap statement from 16 bitmap statements to 64 bitmap statements to hold 4 different size paddle and use a pointer to load the right size.

That's pretty much what I do: My sprite animation engine takes a pointer to a sprite's animation sequence (a series of decle-packed cards that describe the animation), along with the animation rate. To make the sprite "walk" horizontally, it sets the pointer to the "horizontal" sequence. When an input event occurs and the direction changes, all I do is change the pointer to the new sequence, say "up". This works the same for all sprites (since they all move in four cardinal directions).

 

Within each animation sequence, the engine uses the rate to compute a timer for the next frame. When the next frame event occurs, the engine just switches the internal "frame pointer" to the next card in the sequence. This is what is loaded into the GRAM space allocated to the sprite. This continues regardless of the frame graphic itself (it could be the same frame repeated multiple times, or a very trivial change).

 

I know it seems rather extravagant to do the same for such a simple change as just removing one single stripe from your sprite, but trust me, it may be worth it. By using the same technique for every single case (including those where the change is so minimal), you reduce complexity in the engine by avoiding "special case" branches; which leads to less bugs and potentially faster code. But more importantly, like intvnut said, you get to put your focus on what really matters: game logic and the other fun stuff. :)

 

-dZ.

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

This particular case is interesting. If I understood correctly, you could have 4 paddle widths (2px, 4px, 6px, 8px), and 6 paddle counts (1 though 6). That's 24 distinct configurations, for a total of 384 BITMAP statements. That only costs 192 words of ROM for a simple "throw ROM at it" graphics approach.

 

For comparison, I wrote up what I think is simple IntyBASIC code to compute the paddle graphic:

.

' width is 0..3 for 2px, 4px, 6px, 8px
' count is 0..6 for number of paddles
SetPaddle:  Procedure
            For I = 0 to 7 : #padgfx(I) = 0 : Next I
            If count =  6 Then #padgfx(0) = PaddleRowLo(width)
            If count >= 5 Then #padgfx(1) = PaddleRowHi(width)
            If count >= 4 Then #padgfx(3) = PaddleRowLo(width)
            If count >= 3 Then #padgfx(4) = PaddleRowHi(width)
            If count >= 2 Then #padgfx(6) = PaddleRowLo(width)
            If count >= 1 Then #padgfx(7) = PaddleRowHi(width)
            Return
            End

PaddleRowLo: Data $0018, $003C, $007E, $00FF
PaddleRowHi: Data $1800, $3C00, $7E00, $FF00

.

This compiles to 104 words of code with IntyBASIC 1.2.5. It's not much smaller than the BITMAP statements. It also cost you more cycles and 8 words of 16-bit RAM for the #padgfx array.

 

There's possibly more compact ways to write it, but the point is, there isn't much to win getting clever here with code.

 

If you wrote this in assembly, it'd be much more compact. But, we're talking IntyBASIC here. And in any case, when talking about optimizing something, there's no substitute for measuring. :)

________________

 

EDIT: I realized after I posted that each paddle configuration takes 16 BITMAP statements, not 8. Adjusted the text above appropriately.

Edited by intvnut
  • Like 1
Link to comment
Share on other sites

I think the main part of the reason that I didn't want to copy and paste bitmap statements and draw 24 different paddle in text editor that would take too much time. So having 4 full different size paddle images and having it load all or part of it to 16-bit RAM and then use define to upload to the specific GRAM card. I think I can directly write(poke it) to the GRAM without having it load to 8 words of RAM first. Then I would have to find the specific GRAM address and try it there. I'm not really hurting for 16-bit RAM and I have about 80-90 bytes of scratch pad RAM not used. The bin size is now 35.5 Kbytes and have 3 memory segment not used yet, so I have quite a bit to go before hitting 73 Kbytes to make a 42K word cart.

Link to comment
Share on other sites

Some of us toyed with POKE-ing directly to GRAM earlier, and what the culprits are when doing that. A bit of inlined assembly code might help you with speed.

 

Here is one example - there may be others and better ones:

http://atariage.com/forums/topic/247310-baby-steps/page-3?do=findComment&comment=3415168

Edited by carlsson
Link to comment
Share on other sites

The speed statement gave me an idea how to figure out where the processing is at when it is drawing the screen. If I try to write data to GRAM, it should either give me a solid box(Screen is in drawing mode), or the GRAM picture that I loaded to(In VBlank1 mostly or unlikely in VBlank2).

 

So to experiment, I removed all the wait statement before DEFINE 48,2,#fireplat for all 6 paddles to get an idea whether the processing is still in Vblank1 or in the screen portion of the game. It did write the paddle graphic to GRAM so the processing is in Vblank1.

 

I'm current making this snow level that rev wanted in Mad Bomber.

 

post-24767-0-47904500-1466148807_thumb.gif <-animated gif

 

Still very early. It is using the controller code from Mad Bomber.

  • Like 2
Link to comment
Share on other sites

The speed statement gave me an idea how to figure out where the processing is at when it is drawing the screen. If I try to write data to GRAM, it should either give me a solid box(Screen is in drawing mode), or the GRAM picture that I loaded to(In VBlank1 mostly or unlikely in VBlank2).

 

So to experiment, I removed all the wait statement before DEFINE 48,2,#fireplat for all 6 paddles to get an idea whether the processing is still in Vblank1 or in the screen portion of the game. It did write the paddle graphic to GRAM so the processing is in Vblank1.

 

I'm current making this snow level that rev wanted in Mad Bomber.

 

attachicon.gifAvalanche.gif <-animated gif

 

Still very early. It is using the controller code from Mad Bomber.

 

By the way, GRAM is equally accessible in VBLANK #1 and #2. The difference is that you have access to the STIC registers in VBLANK #1.

 

You "snow level" looks great! About the only thing I would recommend is adding a bit of damping (just a smidge) to the paddle movements so that it makes it easier to control with precision. :)

 

-dZ.

  • Like 1
Link to comment
Share on other sites

This might be borderline thread-hijack, but an IntyBASIC lightweight like me would get a lot out of understanding how to efficiently "bankswitch" swaths of ROM in and out for games, to make use of basically unlimited storage in the JLP architecture. I have taken some deep dives into AY audio outside of this group (thanks Artrag and Óscar) and hit a case where I need to use the 16k segment once to play something but after that would rather swap it out to play something else.

 

It would not have to be a low-latency operation, I'm not counting CPU cycles, but it would be helpful for me to architecturally allocate regions of RAM for audio or extremely complex graphics and swap out their ROM location as needed.

 

All ideas appreciated. :)

Link to comment
Share on other sites

From working on 2 Megacart games for Colecovision. It's not cycle intensive. It's reads a specific address and then the signal is triggered to change to that page of ROM. I swap ROMs about 3 or 4 times a frame. Coleco's sound routine advance during NMI, so I keep the sound and music in the fixed bank, just in case NMI occur before everything finished processing in a frame. Otherwise it'll take whatever data it is pointing at on the wrong page and process it.

 

Colecovision can only read 32KB at a time. With Intellivision it can read 42K word at a time, so about 84KB of data would be the compiled .bin size, plus you can have additional RAM with this memory segment set up.

 

http://wiki.intellivision.us/index.php?title=Cart.mac

 

I'm not sure how Intellivision bank-switching works, but that's something you will have to talk to the chip makers to get the information that you need to get bank-switching working.

Link to comment
Share on other sites

This probably belongs in a different thread. On the Intellivision, you accomplish a bankswitch with a simple write. Most commonly it's two instructions: MVII/MVO; about 19 cycles. In IntyBASIC, it's a single POKE. It's cheap.

 

This is assuming Mattel-style page-flipping. That's what I've implemented in as1600, jzIntv, JLP and LTO Flash.

Edited by intvnut
Link to comment
Share on other sites

This is assuming Mattel-style page-flipping. That's what I've implemented in as1600, jzIntv, JLP and LTO Flash.

 

 

I'm curious to know, is there any other kind of page-flipping/bank-switching supported by the Intellivision hardware?

Link to comment
Share on other sites

I'm curious to know, is there any other kind of page-flipping/bank-switching supported by the Intellivision hardware?

The bankswitching implementation is down to the designer of the cart hardware. You can do it the "Mattel way" or implement your own. Your game just selects the bank to be mapped in before it uses it.

Link to comment
Share on other sites

The bankswitching implementation is down to the designer of the cart hardware. You can do it the "Mattel way" or implement your own. Your game just selects the bank to be mapped in before it uses it.

 

Ah, I get it. So it's not something built into the EXEC or the Intellivision hardware; it's part of the firmware of the cartridge and how it maps the addresses to its internal memory map.

 

Thanks. :cool:

Link to comment
Share on other sites

I'm curious to know, is there any other kind of page-flipping/bank-switching supported by the Intellivision hardware?

 

Groovy already answered your question. I will say, the other observed in the field scheme is the Intellicart/CC3 scheme. I've also implemented that in as1600, jzIntv, and LTO Flash!

 

It's more flexible than the Mattel scheme in some ways, but it's also limited to 64K words of total program size.

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...