# Armchair coding Stunt Car Racer

Pagina 1/4
| 2 | 3 | 4

Hatched from Poll: most challenging game that could be ported to msx in the'80, a discussion on feasibility of Stunt Car Racer for the MSX 1 that I felt I had made sufficiently technical to be off topic for 'General discussion' but on topic for 'Development':

hit9918 wrote:

"screen 2 also is a tile mode"
1 byte of nametable can fill 8x8 pixels
this could make superfast polygons
if one manages to sort out the corner cases

In the case of the 8-bit Stunt Car Racer it's actually a relatively easy problem such as I can make out. I really think all it's doing is picking the half a dozen-ish floor segments to draw, performing the actual 3d maths on their top parts, then for each from back to front performing a fill from the bottom of the screen to their upper boundary, and drawing on the appropriate lines (i.e. if that top segment is front facing, all of them; otherwise only those attached to the highest edge and possibly some down the side of the track from any highest edge that is also a side). So the sky is one colour or pattern, the floor and track are another, the top segment boundaries are added for definition.

So you could arrange it so that the filling task at each floor panel is just: between x1 and x2, fill from the bottom of the screen up to the values in the computed table h[x1...x2]. So anything between (x1+7) >> 3 and x2 >> 3 is a completely enclosed column of tiles. Compute (min(h[c1 ... c8]) + 7) >> 3 to get the first tile boundary below the lowest entry in that column. Tile fill up to there. Go tile internal only for the heights above that min, and from bottom of screen to top for anything between x1 and (x1 + 7) >> 3, and between (x2 >> 3) and x2.

Then add the lines, which will involve some sort of process for each tile touched of checking whether it is currently one of the special completely solid ones and if so then substituting another. Though I don't appear to have a good instinctive sense for whether it'd be better to have a fixed allocation from screen location to tile or whether to allocate them on demand. The latter could reduce upload costs but either bookkeeping is a hassle or you risk exhaustion given the possibility that you might claim a screen tile for new drawing, draw on it, replace it with a solid one later, then claim it again for new drawing, etc.

EDIT: as an additional observation, because you need to know only the top edge of each segment and are assuming the camera to be close to upright, a further observation is that you never need worry about full polygon clipping, only individual edge clipping. Which makes life a lot easier. When last I implemented that on a Z80 I naively went with a full multiply/divide solution but I'm sure binary search would work. Don't worry about the far clip plane and the only things to clip to are z=1, z=+x, z=-x, z=+y, z=-y, doing each line separately. So per line grab a bit mask of disobeyed constraints then AND them. If that's non-zero, throw away the line. If not then OR them. While that OR is non-zero, shift it right and for each non-zero bit perform the bisection to find the point on the line that matches the constraint. Substitute it for whichever point was in violation and continue. When done, project and draw.

hit9918 wrote:
TomH wrote:

The main problem would be squeezing two video buffers into VRAM

one can have two buffers in the charset mode mindset
render in halve a charset while showing the other halve charset
doublebuffering via the nametable

If we're embracing monochrome graphics anyway, maybe even the unofficial screen 0 with three segments mode? Definitely documented as 9938 incompatible, but more compact and the big win is that you're never more than 2/171ths of a line away from a VRAM access window. So the CPU can push as fast as it can push at any time. But the addressing turns into a hassle, you still can't have completely unique pixel images unless you restrict yourself to 192 pixels across, and if you think about it then it amounts to you having to upload 25% more data than is actually visible, as two bits out of every eight aren't visible. So pushing faster also buys you the need to push more. And at any likely frame rate, being constrained to VRAM access during only the non-pixel portion of the display quite likely isn't the bottleneck.

Aangemeld of registreer om reacties te plaatsen

The more I think about it the more I think someone should definitively give it a try! Are there any other MSX/Spectrum games with 3d polygonal graphics for comparison? I can only think of:
- Stunt car racer
- Hard drivin

As for implementation details, if I were to do this, I think I'd still go for Screen 2 (since we need additional tiles for the scoreboard at the bottom of the screen, etc. we would not be able to fully utilize the tile set in Screen 1 only for the game anyway). So, I think using Screen 2, using the top two banks for the game, and the bottom bank for the scoreboard could work. Then, if we want to double buffer on the VDP itself, perhaps hit9918's idea of using the first 128 patterns in each tilebank for buffer 1 and the other 128 for the buffer 2 could work. As TomH says, the graphics in Stunt Car Racer will not be complex, so it is likely that we do not need all 256 patterns to display the graphics, since there will be a lot of background!

Well there was already something done resembling Stunt Car Racer on the MSX... in Basic too

Maybe a good starting point?

I guess you'd probably need some empirical numbers on likely tile use per frame, though it strikes me that a close to optimal strategy for usage is a simple stack and a threshold. Suppose tiles 255 and 254 are your fixed full-tile pattern fills then:

1. at start of frame, seed the stack with 253 to 0 in reverse order, set the threshold to 0, draw your horizon;
2. when applying a tile fill to the display, any pattern names you replace that aren't 255 or 254 can be pushed to the top of the stack;
3. when plotting individual pixels, if the tile you want to touch already isn't 254 or 255 then just draw to it. Otherwise pull whatever is at the top of the stack, fill it with the same pattern as the tile it is replacing, then draw to it and update the pattern name table. If the new ID is greater than or equal to the threshold, increase the threshold;
4. to upload a frame, upload all the patterns from 0 to the threshold (or in reverse), then push the pattern name map.

You'll push up some tiles you don't need but you'll be pushing a contiguous block so the unrolling is easy. And they should be a relatively low proportion.

Separate observation: if you really believe that you'll stick within 128 tiles per third of the screen, then for a top-two-thirds update you're definitely not going to need to push more than 128*2*8 + 512 = 2560 bytes. With a hypothetical completely unrolled loop for an 18 cycles/byte transfer and the NTSC 69 lines of fast access available a frame, I make that three frames to push one frame. So if you were somehow producing the pixels quickly enough, you'd be able to display them at 20fps.

Since you are pretty-much definitely not going to get 20fps that means: if you restrict yourself to two thirds of the display and half the tile set, the VRAM interface is not the bottleneck. The unusual thing about the MSX isn't a problem, but rather whatever advantage you're getting from the tile fills adds up to an architectural advantage.

You know, for this one particular presentation.

Woah! that one in BASIC is good! hard to believe that one can write a BASIC program that runs that smooth!!!

So, who's going to do the first attempt?

I've written a simple 3d engine for screen 2 some years ago. The source is open, so you could use that to estimate the number of blocks being used.

@ricbit Cool!!! At work right now, so, can't check in detail, but do you have any demo/ROM of it working?

santiontanon wrote:

@ricbit Cool!!! At work right now, so, can't check in detail, but do you have any demo/ROM of it working?

Sure, here's a compiled .COM binary. It just spins a simple 3D model, you can change the model by modifying the source code. This code is kinda bad, but my suggestion is not to reuse the code, instead just plug in a representative 3D model to check how many blocks do you need to change, from frame to frame, and then use that number to properly design the best algorithm.

well.. as much as I am ashamed to admit, even if I can code in Z80 assembler, I have NO IDEA how to run a .COM file hahaha, I think it's an MSXDOS file (never owned an MSX2, so, no idea how tu run that either...). I've Googled a bit, but haven't been successful yet in running it... will try again tomorrow

Most easy way to start MSX-DOS is to use feature called "dir as disk" that can be found ie. in BlueMSX and OpenMSX. This way you don't have to learn how to put files to disk images. If you use real disk, format it first on MSX (See CALL FORMAT-command) and then use it like regular folder on PC.

To run MSX-DOS your disk needs to include files called MSXDOS.SYS and COMMAND.COM... You need to google these... then place also the .COM file to same disk and restart the emulator.

MSX-DOS should feel quite familiar if you have used MS-DOS or Windows command prompt although it is more limited. The .COM program can be started by simply writing it's name and pressing return. (No need to write extension) You can list the files on disk with command "DIR" + return. You can also exit to BASIC by writing "BASIC"+return. This already should be enough information for casual user.

And Santi, MSX-DOS runs fine on an MSX1 As long as it has 64kB RAM and a disk-drive of course.

Pagina 1/4
| 2 | 3 | 4