Jump to content
IGNORED

Multicolor mode - the mode everybody wants


Asmusr
 Share

Recommended Posts

I've a small update to the stardust project (if we can call in this way). Now the image has resolution 84x48 and pressing right/left you can scroll the screen allowing a limited sort of "panning" effect of the tunnel.

This is done by updating the sole PNT (768 bytes) having, pre-loaded in advance the whole VRAM with 84x48/2 = 2016 bytes per frame (corresponding to 252 tiles per frame).

The rom (almost empty for now) has been tested and will work with bluemsx, meisei and openmsx (this latter needs you select as mapper plain 64K rom)

stardust64.rom

 

I was unable to attach an AVI file to this post, so for now the only way to see how it looks like is to run the rom in an emulator, sorry.

[edit]

Here the (crappy) video on youtube

http://youtu.be/FuOT49ONNk0

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

  • 8 years later...

Wow.  Nice! 

 

Still, I think Multicolor's biggest threat on the TI-99 is just that everything it can do, bitmap mode can do better.  Which is to say, behave like a true bitmap mode, but at higher resolution (64x192 "fat pixels", instead of 64x48). 

 

But this is a beautiful design, to show off a low res look with a palette very similar to that of the TMS9918.

Link to comment
Share on other sites

18 hours ago, SteveB said:

Is there a way of using this mode from XB? Some library to load like XB256?

Well, no library of relevant subprograms as far as I know, in the way that TML furnishes XB with bitmap mode tools, and T40XB furnishes XB with text mode tools. 

 

For what it's worth, UCSD Pascal can switch to multicolor mode on command (with use of the included SET_SCREEN routine). 

 

But once invoked, populating the screen image and pattern table as desired is left as an exercise for the user. 

 

Nonetheless, VDP reads and writes are supported by TI's UCSD Pascal implementation (i.e., without your own assembly subroutine), so this is doable, in principle, it seems to me. 

 

Though pointless for a definition of "pointless" that exceeds even conventional norms of our community. 

 

 

  • Like 1
Link to comment
Share on other sites

How could such a library work? I see two options:

 

1. Writing a library with the routines MCINIT, PUTPIXEL and GETPIXEL (, ...)

2. Writing a more complex library with a CPU-RAM buffer

 

While the first would be easier, it would not offer much advantages over the more powerful full bitmap mode.

 

In order to have a fast drawing and blitting of objects I would use a linear CPU-RAM buffer 48x64 bytes (3kb) and do the tile-magic when pushing the buffer to VDP RAM. You may now paint a scene back-to-front to enable some pseudo 3D (like Wolfenstein3D did, objects were 2d in a 3d room, like paperboard figures).

 

Your thoughts?

 

  • Like 2
Link to comment
Share on other sites

My thoughts is that multicolor made more sense in the TMS 9918, which didn't have the full-screen bitmap mode, than it did in the TMS 9918A, where the bitmap mode was supported. The did of course not want to remove it again then, or it would not have been backwards compatible.

Like pixelpedant wrote above, you can "officially" enter multicolor mode with Pascal, but that's about it.

Unofficially you can also use bitmap mode, but then you have to play some tricks with the system.

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

I don't really get it ...

 

Multicolor mode
This mode is selected by setting bit 4 of VDP register 1 as 1. Bit 3 must be 0, as well as bit 7 of register 0. VR0: 0 VR1: 0 1

In this mode, the screen is divided into 48 rows of 64 boxes. Each box is 4x4 pixel and can be independently assigned a color. The screen image table is still >300 bytes long, but each byte now represent a "character" made of 4 boxes. The boxes are arranged as:
0 1
2 3
The color of the boxes are defined in the character pattern table (!). Each entry in the table is 8 bytes long but only 2 bytes are used to define the colors of the 4 boxes that make up a character: >01 >23. To avoid wasting 6 bytes in each entries, the characters on 4 consecutive rows use the same entry, with an offset of 2 bytes:
characters on row 0, 4, 8, 12, 16 and 20 use bytes 0 and 1,
characters on row 1, 5, 9, 13, 17 and 21 used bytes 2 and 3,
characters on row 2, 6, 10, 14, 18 and 22 used bytes 4 and 5,
characters on rows 3, 7, 11, 15, 19 and 23 use bytes 6 and 7.

This reduces the size of this table to 1536 bytes (24 rows x 32 columns x 8 bytes).

 

With an image table of >300 ... how do I fill the screen with 768 different characters ... when each character is between 0 and 255 ... what do I do on position >100 ? Start with >00 and the magic happens in the hardware to recognize this as character >100 in the pattern table?

 

Link to comment
Share on other sites

2 hours ago, Torrax said:

You are on the right track. Just setup the Screen Image Table (SIT) with the chars 0 to 255 repeated three times.

 

Though there are certainly different ways of managing this, what you posted is what the E/A manual suggests for bitmap mode.

 

For multicolor mode, it is 4 times 0 – >1F, 4 times >20 – >3F, 4 times >40 – >5F, ..., 4 times >A0 – >BF. This puts each “character” code in a 1-character-wide-by-4-character high arrangement in the 32-character-x-24-row graphics mode or 2x8 multicolor “pixels” (MPs) in the 64-MP-x-48-row multicolor mode. Each 8-byte entry in the pattern table manages the colors of those 16 MPs (1 nybble each).

 

...lee

  • Like 2
Link to comment
Share on other sites

Motivated by this discussion, I created a really simple and stupid assembler program to test multicolour mode. Attached assembler source and cart image MULTICOLOR.bin (tested with js99er only as I'm Mac user).

While working at it, I noticed that in the table on TI tech pages there is a typo: the location of text mode and multicolour bits in VR1 is swapped. The register layout is like this:

* VR1: 7     6     5     4     3     2     1     0
* VR1: 16K   Blank Int   Text  Multi 0	   Size4 Mag 2x

Bit 7 is MSB, bit 0 LSB. Thus the sane bit order, not the TI one.

Below is a screenshot. It just draws some vertical lines, which rotate from one frame to the next and then it draws a "sprite" i.e. just a multicolour bitmap on top. The code is not optimised at all. After working on the ARM chips, the TMS9900 code really goes on pedestrian speeds :D The code contains a routine I wrote MULTICOLADDR which calculates from X and Y the address of a pair of pixels in the multicolour mode memory layout. (If you wonder inconsistent spelling, the word color comes out of my spell checker as colour).

image.thumb.png.9c528b2a9a8dd01a20c47a4bf872aef1.png

If you want to mock around with the code, use XDT99 to assemble it. I unzip the result to get multicolor.bin, the cartridge image from the zipped rpk image. 

* Assemble with: 
* 	xas99.py -L multicolor.lst -R -c multicolor.asm 
*	unzip -o multicolor.rpk 

 

MULTICOLOR.bin multicolor.asm

  • Like 4
  • Thanks 2
Link to comment
Share on other sites

56 minutes ago, speccery said:

I created a really simple and stupid assembler program to test multicolour mode

You should try to double-buffer it to remove the flicker, by writing alternate frames to different VDP addresses (>0800 and >1000), and switching to the new buffer after waiting for vsync. 

  • Like 3
Link to comment
Share on other sites

20 minutes ago, Asmusr said:

You should try to double-buffer it to remove the flicker, by writing alternate frames to different VDP addresses (>0800 and >1000), and switching to the new buffer after waiting for vsync. 

Yes I will do that. This was literally a simple quick and dirty test only. I think the rendering should be done to a system RAM buffer, and then have an optimized routine to push the data to the VDP to avoid the constant need to set the VDP write address as I do now. The RAM buffer would also be needed to draw more involved graphics, since each byte has two pixels and therefore read operations are needed on blit edges. Anyway this is a fun little exercise.

  • Like 1
Link to comment
Share on other sites

51 minutes ago, speccery said:

Yes I will do that. This was literally a simple quick and dirty test only. I think the rendering should be done to a system RAM buffer, and then have an optimized routine to push the data to the VDP to avoid the constant need to set the VDP write address as I do now. The RAM buffer would also be needed to draw more involved graphics, since each byte has two pixels and therefore read operations are needed on blit edges. Anyway this is a fun little exercise.

I agree about the RAM buffer. The question is if you should store 1 or 2 pixels per byte in the buffer?

 

With 2 pixels per byte you could transfer the buffer to VDP RAM almost one byte (2 pixels) per instruction (e.g. movb *r0+,*r15), by having one register pointing to the first row of the RAM buffer, another pointing to the next row and so on up to 8 registers. Only after transferring 8 rows would you have to update the registers. This way you should be able to transfer at least 30 frames per second, but that's just the transfer time and doesn't consider the time to update the buffer and run the game in general.

 

On the other hand, if you store 1 byte per pixel, you would first have to combine 2 pixels into a byte, which would take 3 instructions (movb, sla, socb) before sending the byte to the VDP, so approximately 4 times slower, maybe 10 FPS. But if you want to be able to draw objects to the buffer at any of the 64 horizontal positions, and in particular if you want to scroll the view by 1 horizontal pixel instead of 2, it would be a lot easier to handle if you stored one pixel per byte. 

 

I would like to see a game that scrolled a multicolor background in 8 directions (including vertical). Multicolor mode permits the use of hardware sprites, but it would also be cool to see 'sprites' drawn in multicolor mode.

 

 

  • Like 3
Link to comment
Share on other sites

I've been thinking what functions I would need / expect from a Multicolor Mode library:

 

Minimal:

  • MCINIT - Switch to Multicolor Mode and create the buffer
  • PUTPIXEL(row,col,color) - Set Pixel in (row,col) to color
  • GETPIXEL(row,col,color) - Get the color of Pixel in (row,col)
  • MCSYNC - Writes buffer to VRAM (waiting for vsynch?)
  • MCDONE  - Switch video back to standard mode 

Lines:

  • HLINE(row,col,color,len) - Draw a horizontal line
  • VLINE((row,col,color,len) - Draw a vertical line
  • LINE(row1,col1,row2,row3,color) - Draw a line between to points
  • SQUARE(row1,col1,row2,row3,color) - Draw a square 
  • BLANK(color) - fills the whole screen in one color

Shapes:

  • BLIT(row,col,address) - Draws a pattern found at address to the given point. Pattern format:
    • Byte 1: Pattern rows
    • Byte 2: Pattern columns
    • Byte 3 - (Byte1 x Byte2 +2): Pixel-Color inkl. a transparent color

Open Questions

  • Which color numbers to use (0 = transparent to >F = white? Instead of BASIC 1 - 16)
  • Would it be more practical to have an index instead of an address for the pattern to have one OBJ-file with the pattern-definitions?
  • Scrolling functions?
  • Is the redundancy LINE vs HLINE/VLINE and CLEAR vs. SQUARE a significant speedup worth the effort?
  • As with Rasmus' posting .. one or two pixel per byte in the buffer .. what's best with this kind of usage?
  • Defining a "Window" for drawing? Four additional compares, but less hassle in the main program. (added)

 

It is hard to judge if this is practical and complete without trying... what are your thoughts?

 

 

 

Edited by SteveB
added Question for drawing-window.
  • Like 4
Link to comment
Share on other sites

Here's another version about my silly multicolour test program (only tested on js99er - the single stepping disassembler behaves weirdly when debugging). This second version has two phases:

- First phase is the same slow color bar thing as the earlier one, but now with double buffering in VDP memory and code to wait for VSYNC as per guidance from @Asmusr

- Second phase is in my opinion more interesting. The code has what I call a playfield, which is 128*64 pixel bitmap on memory. From this playfield a give 64*48 pixel view is rendered to the display. The playfield window is "bounced" around and at each vertical bounce the horizontal direction is updated. Best to take a look to understand. The code does not yet know how to update the playfield from an odd pixel location, so horizontal scrolling bouncing is in steps of 2 pixels still.

image.thumb.png.6f0545c992a2a7471bdec913779a6c42.png

This code is now optimised (see below), although still running from cartridge memory. The playfield format is a linear frame buffer, with two pixels per byte, thus 4096 bytes for the whole playfield, out of which 1536 are copied to screen. @Asmusr was wondering about the best pixel format, I think the packed one is probably good, since it allows 16-bit loads from the playfield, which might be useful when adding pixel level horizontial positioning. Here is the inner loop:

Spoiler
SCANLINELP:
        LI  R10,32
; Now blast 8 lines of graphics on screen        
!       MOVB *R2+,*R0
        MOVB *R3+,*R0
        MOVB *R4+,*R0
        MOVB *R5+,*R0
        MOVB *R6+,*R0
        MOVB *R7+,*R0
        MOVB *R8+,*R0
        MOVB *R9+,*R0
        DEC R10
        JNE -!
; Now adjust the pointers for the next line, needed if pitch != 32
        MOV R1,R10      ; R10 = pitch
        SLA R10,3       ; R10 = pitch*8 (we just did 8 lines)
        AI  R10,-32     ; R10 = pitch - 32        
        A   R10,R2
        A   R10,R3
        A   R10,R4
        A   R10,R5
        A   R10,R6
        A   R10,R7
        A   R10,R8
        A   R10,R9
        AI  R11,-8
        JNE SCANLINELP

 

 

 

 

MULTICOLOR.bin multicolor.asm

  • Like 7
Link to comment
Share on other sites

  • The title was changed to Multicolor mode - the mode everybody wants

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

  • Recently Browsing   0 members

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