This is a crazy dream of mine. At least one other member of Planet VB is helping me make this dream a reality. I will ned to learn to code, obviously, but I have some experience with BASIC and html. I really need some skill with JAVA and C. Anyway, I figure it might be useful to share what I have on a thread.
Step 1 will be to disassemble the code for the MAC release of Spectre VR, Spectre Supreme and Spectre 1.0
Step 2 will be to reverse engineer source code for these games
Step 3 will be to create a port that offers multiplayer capibility on the VB. At this point I’m hoping to base it mostly on Spectre VR. If it becomes somehow possble to do multiplayer with more than two players, then that would be awesome.
Attached are the dumped resource forks
This is a screenshot of the mac version of the game set to black and white then tinted red with the filled polygons turned off
The second is what it might looklike with filled polys turned on.
I have then reduced the resolution to 324×224
I am no where near getting this working on a real VB. I have no idea if it can handle rendering filled polygons in 3d at 50 fps.
- This reply was modified 5 years, 8 months ago by SpectreVR.
- This reply was modified 5 years, 8 months ago by SpectreVR.
- This reply was modified 5 years, 8 months ago by SpectreVR.
Attachments:
Skip steps 1 and 2. Please. You will burn yourself out in frustration after a month.
Disassembling and making sense out of optimized, unsymbolicated assembly is not for the faint of heart and definitely not a task for a beginner. Moreover, analyzing classic Mac OS assembly in 2019 is particularly difficult because Apple has done a fine job of eliminating the requisite API documentation from the Internet. By my estimation there are maybe 30 people left in the world who can decompile classic Mac OS applications, and those folks by necessity maintain a rich working knowledge of that API and its quirks.
If your goal is to make a version of Spectre on the Virtual Boy, very little of the Mac code will help you anyway. Here are a few major points about the Mac version that will not transfer over:
– No QuickTime on the VB. Nothing even close.
– Spectre’s multiplayer is communicated using the AppleTalk protocol. Needless to say, this doesn’t exist on the VB either.
– Graphics on the Mac are predominantly done entirely in software, typically via Apple’s QuickDraw API which, as you can probably guess, also isn’t on the VB. Spectre is designed to do all of its rendering in software, for instance (QuickDraw accelerators might help, but those are rare). Mac graphics coders have the advantage of better control over the back buffers– games, if not rendering to the framebuffer directly, render to an offscreen buffer (which consumes RAM) and make a final blit to the screen. You don’t have this on the Virtual Boy– an offscreen framebuffer would consume 24K, or over 1/3 of the VB’s total working RAM. In addition, video memory on the Mac is organized in horizontal scanlines– contrast this with the Virtual Boy which uses vertical scanlines. In short, you will have to fully rewrite the renderer. The Virtual Boy sports a powerful sprite engine in the VIP that can be leveraged essentially as a GPU. Taking advantage of the greater amount of ROM over RAM to prerender the 3D graphics as sprites will provide major gains in performance.
– All Macs come equipped with some kind of DAC for playing back sampled sound. No such thing on the Virtual Boy– sampled sound can be coaxed out of the VSU, but again, you’d have to do all of that in software, spoon-feeding individual samples to the VSU at a regular rate. This costs you CPU time that could be otherwise spent rendering Spectre’s 3D world and tracking gameplay. Keep in mind that the V810 processor inside the VB is clocked at just 20 Mhz– just slightly faster than a Mac SE/30. Rewriting the sound code to take advantage of the VSU’s native capabilities will win that CPU time back. Most of Spectre’s audio is not terribly complex anyway. 😉
As far as I know, the original source code to Spectre for Mac is lost. If you have your heart set on using “original” code, your best bet is probably the iOS port, which was done using a technique that I suggest you use: a fan meticulously studied the game’s operation and created their own clone using their own engine from scratch. I’m pretty sure its source code isn’t public though, but even if it was, I still wouldn’t use it for this project.
Seriously, I want to see this project succeed, as I too am a huge fan of this game and have many fond recollections of facing off against my sister in the late 90s. But you should approach it from the perspective of what the Virtual Boy is capable of and build from there. The Mac code will just get in your way.
blitter wrote:
Disassembling and making sense out of optimized, unsymbolicated assembly is not for the faint of heart and definitely not a task for a beginner.
While it’s true that someone who is just getting into programming may not be well-equipped for the task, the process in general is not as hard as you might think. With the right resources, I’m faithful that SpectreVR (the user) can pull off this Spectre VR (the game) project.
blitter wrote:
If your goal is to make a version of Spectre on the Virtual Boy, very little of the Mac code will help you anyway. Here are a few major points about the Mac version that will not transfer over:
Only a cross-section of the game’s code is necessary for a faithful port: the fundamental game engine and general rendering logic. The nitty-gritties about how the game communicates I/O with the OS or interacts with the windowing system aren’t all that important when porting the game to any target, let alone Virtual Boy. As long as one knows what the game wants to do, the rest can be handled by a purpose-built implementation.
Also, between those Inside Macintosh books and Macintosh Programmer’s Workshop–both of which are available online–we still have access to information regarding the old system API.
Ok, so I’m at the momment working on a java program that will parse throughthe MacBinaryII executable and let me copy thiungs out of it or run it through a disassembler. I’ve already used ResEdit for some of this, but unfortunately ResEdit wont let me copy some things very easily. I also need a betterway of dumping the shap resource than copying the data from resedit by hand.
Anyway, Ithought I’d share some developments. First of all the header of a macbinary is well known and is documented here
https://files.stairways.com/other/macbinaryii-standard-info.txt
It is also known that all macintosh applications have both a data fork and a resource fork. It was important to know which comes first in the binary. This sint something that is easy to find in documentation. So, time for some exparimentation. I found I can use BinHex 5.0 in baselisk to export binaries out of baselisk. Next I created a copy of Spectre 1.0 and exported it as a binary. Then I took the same copy and opened teh readme file for Spectre Supreme. Text files are purely data and show up in resedit as having a data fork. Its impoirtant to note that you cannot add data to the fork in an ID other than 128. Believe me, I tried. Anyway, open up the data resource in the readme with resEdit’s hex editor and copy the whole thing. Now back to the Spectre 1.0 copy. Open the data fork, then open data resource 128 in the hex editor, and past it in, then save. Run BinHex 5.0 on it and save this as Spectre 1.0 copy2
Now we have two binaries that we can compare in a hex editor. I used Hex Fiend. Anyway, The data stream size is listed as being located at offset 83 and its a long word, which means it will be offset 83, 84, 85, 86 and further down it says it must be in the range of 0000 0000-$007F FFFF. As we would expect, this value changes from 0000 0000 to 0000 0463 which in decimal is 1123 and corresponds exactly to the length of the data I copied into the data fork. The data I copied begins at offset 128
This same test method can be applied to locate any resource in the binary to confirm the documentation. I also tried deleting the ALRT resource and compared the one without an ALRT to the one that had it.
So in short, there is a header which is described in the link I include here, then comes a data fork, then a resource fork. The data fork may have a map, but I cant say for sure yet. What I do know is that the resource fork does have a map. Presumably this is at the start of the resource fork.
Attachments:
Work continues on the Java tool, but in the meantime I managed to copy all the PICT resources out of the first game. There is no easy way I know of to just copy and paste the resources into new PICT files that are readable by OSX, but I can copy the file from within baselisk, and go to photoshop CS5 and create a new document which at least gets the new image to be sized correctly. Then I take a screenshot of the resource in ResEdit in baselisk, open the screenshot, then copy and past THAT into the photoshop document I just created. Alignment is of course critical. I’m confident I’m absolutely spot on with most files, but large screen filling images may be off by a pixel. The prites can be done as a series of small screen shots and then resized with an automated batch process in photoshop, so that made it all go quicker.
Attachments:
Java tool to parse the data is finished. Attached is all the resource fork data separated out into individual binary files. Resedit uses templates to be able to edit and interpret the data within a resource. The TMPL resource contains templates. OS7 doubtless has several built in. Anyway, the TMPL structure is not documented but is easy enough to understand. Just by playing around in resedit I was able to confirm that a TMPL resource consists of a byte tat defines the length of the feild name, a feild name, then 4 bytes for a data type, then the next feild name size byte follows etc. It should be very simple to exploit this to dump the shap resource in the later releases to get to the original 3d models and even reformat them into a .obj file or whatever we want.
Attachments:
Ok, so here’s some detail on the shap resource found in Spectre VR
First of all there is a res edit template (TMPL resource) called shap which defines the structure of every shap resource used by spectre VR. The data is organized in words (2 bytes). The structure is as follows according to the template.
Number of verticies: ZCNT
**V**: LSTC
X (left & right) whole: DWRD
X (left & right) fraction: HWRD
Y (altitude) whole: DWRD
Y (altitude) fraction: HWRD
Z (distance from camera) whole: DWRD
Z (distance from camera) fraction: HWRD
**V**LSTE
Number of planes: ZCNT
**P**LSTC
Verticies in this plane: ZCNT
*V*P*: LSTC
Vertex number:DWRD
*V*P*:LSTE
Plane ColorDWRD
**P**:LSTE
Number of points (Top View): ZCNT
*P*T*:LSTC
X (left & right) whole: DWRD
X (left & right) fraction: HWRD
Y (altitude) whole: DWRD
Y (altitude) fraction: HWRD
Z (distance from camera) whole: DWRD
Z (distance from camera) fraction: HWRD
*P*T*:LSTE
Number of lines (Top View):ZCNT
*L*T*:LSTC
starting point:DWRD
ending point:DWRD
*L*T*LSTE:
Plane SidesDWRD
Thats really all you need to parse the shap resource. DWRD means “Decimal Word” HWRD means “Hexadecimal word” ZCNT, LSTC, and LSTE are used to loop a list of feilds, with ZCNT indicating the number of times the list is looped. In other words, if ZCNT had a value of 2 in the number of verticies secion at the top, it would look for LSTC in the template, then repeat though everything between LSTC and LSTE 3 times.
Here’s an actual example. This is the “acid” shap. In the game its just a triangle on the gound that damages your tank when you run over it.
0002FFEE 00000000 0000FFEE 0000FFEE
00000000 00000012 00000012 00000000
0000FFF7 00000000 00020001 00020003
17750002 FFEE0000 00000000 FFEE0000
FFEE0000 00000000 00120000 00120000
00000000 FFF70000 00020001 00020002
00030003 00010000
Now lets chop it up into words
0002 FFEE 0000 0000 0000 FFEE 0000 FFEE
0000 0000 0000 0012 0000 0012 0000 0000
0000 FFF7 0000 0000 0002 0001 0002 0003
1775 0002 FFEE 0000 0000 0000 FFEE 0000
FFEE 0000 0000 0000 0012 0000 0012 0000
0000 0000 FFF7 0000 0002 0001 0002 0002
0003 0003 0001 0000
Next lets change the formatting a bit to divide up the relevent data. LSTC and LSTE data types don’t actually contain any data, so if you’re following along in the template, just use those as a reminder to go back through the template list.
0002
FFEE 0000 0000 0000 FFEE 0000
FFEE 0000 0000 0000 0012 0000
0012 0000 0000 0000 FFF7 0000
0000
0002
0001 0002 0003
1775
0002
FFEE 0000 0000 0000 FFEE 0000
FFEE 0000 0000 0000 0012 0000
0012 0000 0000 0000 FFF7 0000
0002
0001 0002
0002 0003
0003 0001
0000
That should be perfectly clear, but if it isn’t lets add some labels
Number of Verticies: 0002
//Verticies
1) Xint:FFEE Xfrac:0000 Yint:0000 Yfrac:0000 Zint:FFEE Zfrac:0000
2) Xint:FFEE Xfrac:0000 Yint:0000 Yfrac:0000 Zint:0012 Zfrac:0000
3) Xint:0012 Xfrac:0000 Yint:0000 Yfrac:0000 Zint:FFF7 Zfrac:0000
Number of Planes: 0000
Verticies in this plane: 0002
Vertex Numbers in this plane: 0001 0002 0003
Plane Color:1775
Number of points (Top View) 0002
1) Xint:FFEE Xfrac:0000 Yint:0000 Yfrac:0000 Zint:FFEE Zfrac:0000
2) Xint:FFEE Xfrac:0000 Yint:0000 Yfrac:0000 Zint:0012 Zfrac:0000
3) Xint:0012 Xfrac:0000 Yint:0000 Yfrac:0000 Zint:FFF7 Zfrac:0000
Number of Lines: 0002
1) starting point: 0001 ending point: 0002
1) starting point: 0002 ending point: 0003
1) starting point: 0003 ending point: 0001
Plane Sides: 0000
Of course all of these figures are in hexidecimal. This is what res edit shows for the same data
Number of Verticies: 0002
//Verticies
1) Xint:-18 Xfrac:$0000 Yint:0 Yfrac:$0000 Zint:-18 Zfrac:$0000
2) Xint:-18 Xfrac:$0000 Yint:0 Yfrac:$0000 Zint:18 Zfrac:$0000
3) Xint: 18 Xfrac:$0000 Yint:0 Yfrac:$0000 Zint:-9 Zfrac:$0000
Number of Planes: 0
Verticies in this plane: 2
Vertex Numbers in this plane: 1, 2, 3
Plane Color: 6005
Number of points (Top View) 2
1) Xint:-18 Xfrac:$0000 Yint:0 Yfrac:$0000 Zint:-18 Zfrac:$0000
2) Xint:-18 Xfrac:$0000 Yint:0 Yfrac:$0000 Zint:18 Zfrac:$0000
3) Xint: 18 Xfrac:$0000 Yint:0 Yfrac:$0000 Zint:-9 Zfrac:$0000
Number of Lines: 0002
1) starting point: 1 ending point: 2
1) starting point: 2 ending point: 3
1) starting point: 3 ending point: 1
Plane Sides: 0