I built an AROS machine out of scrap!

Got to say it’s really cool that it works with hardware 3D acceleration.

I may want to try to do something with it later on, however I’ll need to get it a case.

I have a cold, and yeah sound like crap.  I’ll add specs later as I think my fever is kicking back in.  Sigh.  But yeah basically

  • P4 board / CPU / RAM $150 HKD
  • GTX-460 card $180 HKD
  • Sound Blaster Live! $20 HKD
  • 37GB IDE disk $20 HKD
  • PS/2 Keyboard $20 HKD
  • PS/2 Mouse $10 HKD
  • 700 Watt Power Supply $150 HKD

So yeah ~550 HKD or $70 USD.  Not bad.

So a little closer look at the hardware.  I’m lucky that there is an active used hardware market here in Hong Kong, elsewhere in the world you either have HAM radio events, ‘boot sales’, garage sales, or for the truly desperate, eBay, Yahoo auctions, and AliExpress.  My go to place here is of course the Capital Computer Centre, where they at least will test stuff before selling it.  I know I’m old fashioned but I like buying in person.

 

Intel P4 Mother Board

I had originally chosen this board to mess around with Darwin.  I wanted something new enough to have a P4, but old enough to still have an older ‘parallel’ EIDE controller port. And the Intel D945GNT, board certainly was up to that task.  Like ancient Darwin, AROS works best with either parallel disks, or SATA disks in older parallel emulation.  The markings on this board are a little hard to read as the bigger numbers are the product testing/radio compliance numbers, and the model number is a bunch of possible models as I guess they like to make so many variations on a single board.

close up of the D945GNT

Here is a close up, and E210882 is *NOT* the mode number.  Nothing like confusion.

The Intel D945GNT motherboards built in NIC, the Intel PRO/100

One of the big reasons for using the Intel board, is that it has an onboard NIC, and Intel of course uses Intel NIC’s so it has the very compatible Intel PRO/100 VE Desktop Adapter.

While you can get these on PCI cards, and use other boards, I figured since I was going to buy a board anyways, and once things get this old the people selling them really don’t care who made the board, but rather that this is an old P4 board, they all sell for the same price.

Another plus about this board is that it is new enough not to have AGP, but rather the new and exciting PCI Express.  This board as the Express x16, which of course is perfect for a ‘large’ GPU.  AROS has a port of the Gallium3D nouveau driver, making this perfect for a super cheap GTX 460.

I shopped around for a while and I found this accelerator, that although has no apparent labeling at least on the flip side it has the identification.  I really don’t know what is the fastest GPU you can get for AROS, but this one seems to work just fine, and it’s what Stephen Jones is using so that is what I went with.

Inno3D GTX-460

And looking under AROS, this is how the PCI resources show up for the video card.

NVIDIA GeForce GTX 460

This was an old card, and it looked like either the OEM didn’t put any stickers on it, or someone had taken them off.  Either way I don’t care, and it doesn’t matter as it works just fine.  Sure the GTX 1080 is over five times faster, but the open Gallium driver won’t work with it as Nvidia has done their best to break open stuff, and even if it did, you can’t buy a 1080 for less than a pizza.  At least not yet.

For some reason, I had begun collecting older and cheap Sound Blaster cards when I see them.  I wasn’t going to spend more than $50 HKD ($7 USD) for them, so I don’t have an Audigy cards yet, but I did have this Live card.  At the time I didn’t think it was anything special, although the EMU10k chip is desirable, and popular for much older systems.

Sound Blaster Live!

This card is the CT0100 model.  And it works great!

CT0100

And this is how AROS sees the card

Sound Blaster Live! with EMU10k1 chip

The AROS HCL is a little confusing to me, but it all seems to work.  If it weren’t for the Stephen Jones video I wouldn’t have tried as it implies it won’t work.

I have to admit that it’s impressive.  For anyone interested you can find AROS Icarus Desktop here, and here is Stephen Jones’s video that inspired me to see this run in real life!

AmiDevCpp

Antoni sent me a link to this project, AmiDevCpp. It is a nice little wrapped up IDE for cross compiling applications for the following platforms:

  • AmigaOS (m68k)
  • AmigaOS4 (PPC)
  • MorphOS(PPC)
  • AROS (i386, ppc and x86_64).

Naturally it doesn’t work correctly on Wine.. .Oh well, but for you Windows users out there that haven’t installed Cygwin this is an easy way to cross build stuff for the ancient Amiga platform.

Apparently he was able to rebulid the infamous aclock using this cross compiler…

More fun with Janus!

Frontier Elite, on Janus

Frontier Elite, on Janus

So, I came across this great page, Frontierverse, which has download links for all the versions of Frontier Elite which were released out as shareware.  So what is cool, is that using the AROS Kickstart replacement ROM, it’ll boot up and work!

Just be sure to increase the default amount of chip memory, as it seems the AROS Kickstart ROM consumes more RAM than the Commodore ROM.  But heck the AROS ROM is opensource, and free!

Pretty cool, and more interesting than say the normal, yippie a view of the AROS cat..

 

AROS Kickstart ROM

AROS Kickstart ROM

Again very cool stuff!

And lastly, I slapped together a disk that’ll boot up aclock, although it works only with a Kickstart 2 or higher ROM.. 1.3 kinda freaks out, and I didn’t feel the need to go all over the top on this one.  Booting the aclock disk with the Aros ROM though loads up, but the clock doesn’t tick..

On OS X, I’ve been using the FS-UAE emulator to some degree of success, I’ve found it a tad cumbersome for swapping floppy disks, and I’ve had a major issue where making updates on an ADF that while they all look like the changes are reflected, going to the filesystem proved otherwise.  So I wound up having to make DMS disk images, and running some ancient MS-DOS program to convert DMS to ADF‘s.  Naturally the compression programs were in turn.. compressed.  So with enough fooling around with various archivers I found here, I was finally able to get where I needed to be.

At the same time, looking at how the AROS kickstart replacement ROM is quite capable, it may be time to revisit AROS, and I would imagine it has become far more capable than that last time I had looked at it.

Fun with Qemu & Large Disks….

I was playing around with NeXTSTEP under a snapshot of qemu and I noticed that my arrow keys were not working correctly. After a few hours of digging about I found the fix was easy enough:
-k en-us
That’s it, just append that to your boot string, and away you go! Another annoyance has been my quest to install AROS onto a P4 computer.. I picked up a new 320GB IDE disk (WD Caviar Blue) .. which the BIOS & AROS promptly refused to acknowledge corectly. Everything was going to hell until I gave up and read the manual. Once again it was simple, there is a jumper setting for ‘older’ OS’s to see only 32gb, and naturally the BIOS is now happier. If only I could say the same of AROS…

Amiga Days

Do you remember the Commodore Amiga?

I certainly do!

While I was busy fiddling with my Commodore 64, a friend of mine got an Amiga in high school. The 64 was cool, but I was simply blown away by the Amiga. To say there was a gulf between the 8 bit machine, and the quasi 32/16 bit machine would be a massive understatement. His Amiga 2000 could do all kinds of neat things, from talk, run IBM XT software at 100% speed via a “bridge board”, not to mention play super snazzy games. It took me a few years to save up to buy my very own Amiga 500, and once I was ready I didn’t have enough money for a bus ride home, so I walked the FIVE miles home toting my Amiga! I was so happy to say the least!! (At least it was summer, it was flat, and there weren’t any tropical waves/hurricanes around…)

While there are a few emulation alternatives for running the old m68000 software on all kinds of machines, I’m going to talk about AROS today.

AROS is to AmigaDOS what Wine is to Windows. Once it became clear that Commodore was going to die, and that AmigaDOS and the Amiga were lost a few brave people decided that they had to take matters into their own hands. Sadly there was lots of in fighting, a tradition of the comp.sys.amiga.advocacy news group where some people get too tied into little details and let little things (like the rise of Microsoft Windows) pass them by. At any rate, Aaron Digulla knuckled down, and start to write a bug for bug clone of AmigaDOS 3.1 in C to run on the IBM PC. The result of which is AROS. It currently will either run hosted on Linux/NetBSD or natively on the i386. There is a port to the Amd64 undergoing right now. AROS even has SDL support.

So this got me thinking..

What if I were to remove all the OpenGL calls from GLFrontier, and ran it as a strictly 2d app on AROS?

So I took the first step, and I trimmed out the OpenGL support from Tom’s fix of Frontier, so it’s completely SDL 2d friendly, and cross compiled it to AROS. I built the first pass on MinGW, and got frame rates of upwards of 1000 on Vista 64!

Now for the fun part of building an AROS version. While there is now a native GCC for AROS it cannot compile the assembly listing from GLFrontier.. I suspect it’s a heap overflow. This means you have to cross compile. I have cygwin installed in a Windows 2000 VM I use with Virtual PC 2007. I’m not sure if cygwin installs on Vista, let alone Vista 64, however I do suspect it MAY have issues… I keep my dev stuff in a VM so I can move it around without losing my settings.

I downloaded and unpacked the following files into my cygwin installation:

i386-aros-cross-gcc-3.3.1-cygwin.zip

libsdl.a

And the SDL include directory from cygwin.. I think its SDL version 1.2

I did have to find all the ‘exe’ files and make sure they were chmoded +x as the compiler would not run (chmod +x /usr/local/bin/exe /usr/local/i386-aros/bin/ /usr/local/lib/gcc-lib/i386-aros/3.3.1/*exe ). Once you are ready you should be able to build files with

i386-aros-gcc

I’m not sure how to build stripped files, but I suspect it’s out there somewhere. At any rate, I did this to compile my SDL 2d version of FrontierGL:

$ cd as68k

$ make
gcc -O2 -g -Wall -c -o output.o output.c
gcc -O2 -g -Wall -c -o output_c.o output_c.c
gcc -O2 -g -Wall -c -o output_i386.o output_i386.c
output_i386.c:981:1: warning: “_S” redefined
In file included from output_i386.c:6:
/usr/include/ctype.h:35:1: warning: this is the location of the previous definition
output_i386.c: In function x_loadea':
output_i386.c:1373: warning: 'out_reg' might be used uninitialized in this function
output_i386.c: In function
x_loadval’:
output_i386.c:1474: warning: ‘reg3’ might be used uninitialized in this function
output_i386.c:1474: warning: ‘out_reg’ might be used uninitialized in this function
gcc -O2 -g -Wall -c -o as68k.o as68k.c
as68k.c: In function `asm_pass1′:
as68k.c:663: warning: ‘size’ might be used uninitialized in this function
as68k.c:671: warning: ‘coutput_label’ might be used uninitialized in this function
gcc -O2 -g -Wall -c -o dict.o dict.c
gcc -O2 -g -Wall output.o output_c.o output_i386.o as68k.o dict.o -o as68k

$ cd ..

$ as68k/as68k.exe –output-i386 fe2.s
Pass 1
Pass 2
Done! 539337 bytes and 759 relocations.

$ i386-aros-gcc -c fe2.s.S

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c audio.c
audio.c: In function Audio_Init':
audio.c:334: warning: passing arg 5 of
SDL_LoadWAV_RW’ from incompatible pointer type

$ cd src

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c hostcall.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c input.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c keymap.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c main.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c screen.c
screen.c: In function `draw_control_panel’:
screen.c:274: warning: assignment makes integer from pointer without a cast

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c shortcut.c

$ i386-aros-gcc *.o ../fe2.s.o -lsdl -o ../frontier

$ cd ..

$ file frontier
frontier: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

$ i386-aros-size frontier
text data bss dec hex filename
2580672 2036 1422076 4004784 3d1bb0 frontier

*REMEMBER as68k has to actually run on the host machine, so it needs to be native, you cannot use a cross compiler for that. However you do cross compile it’s output.

Naturally you’ll now want to run your exe!

For testing the binaries you’ll need some kind of Aros system, I recommend WinAROS, it’s a pre-built Qemu package, so the disk will work on all kinds of platforms. You can download it here: WinAros Developer

This is a pretty snazzy setup, I recommend booting into a 32bit depth display option, however you will want to modify the default script to look like this at the last line:

qemu.exe -L . -m 256 -localtime -boot c -hda WinArosHD.img -no-kqemu -net nic -net user

The next thing you’ll want to do is enable the networking. I don’t know why it’s disabled by default, but with a few moments in the CLI, and edit you can have it running:

To get the network running you have to go into Extras:Networking/Stacks/AROSTCP/db and edit static-routes, netbd-myhost, and interfaces.

First edit interfaces and uncomment the line that has device prm-rtl8029 and change the IP to 10.0.2.15

Second edit netbd-myhost and make it look like this:
HOST 10.0.2.15 arosbox.arosnet arosbox
DOMAIN arosnet 10.0.2.
NAMESERVER 10.0.2.3

Third edit static-routes and change the address to 10.0.2.2

Last add the following line to your user-startup
Execute Extras:Networking/Stacks/AROSTCP/S/startnet.

Now reboot. Open a shell and verify that you have a connection with “ifconfig -a”
You can also try to ping a website, but you might not get any return packets because of QEMU’s built in firewall. You should at least see the ip address for the site you ping. Or ping 10.0.2.2 to make sure you network is communicating with Qemu.

Now for the final moment, put your exe on a web server, and simply use wget to get it! I’d recommend zipping up your work directory, so it includes the ‘bin’ file, and the structure that GLFrontier expects. I like the zip file format as WinAROS includes unzip.

I do the following from AROS

Wget http://192.168.1.10/front.zip
Unzip front.zip

It’s that easy! Now you can either ‘cd’ or click on your frontier, and away it should go!

The video is a bit wonky in that it seems to only work in 8 bit or 24bit depths. So far I’ve only tested this in WinArosDeveloper.

It actually works, the keyboard is buggy as hell, but you can play with the mouse. The first key code seems to work, then it gets stuck, so I recommend the ‘enter’ key so you can thrust…

I’ve published my zip up to The AROS Archives with any luck when it’s there I’ll update it with a link to it. In the mean time, I’ll provide a dump of the screen.c that I fixed to remove the OpenGL support. Naturally blogspot will screw up the formatting, however it should work…

#include
#include “main.h”
#include “../m68000.h”
#include “screen.h”

/* new stuff */
enum RENDERERS use_renderer = R_OLD;
int len_main_palette;
unsigned short MainPalette[256];
unsigned short CtrlPalette[16];
int fe2_bgcol;
int mouse_shown = 0;
unsigned long logscreen, logscreen2, physcreen, physcreen2;
unsigned long VideoBase;
unsigned char *VideoRaster;
unsigned int MainRGBPalette[256];
unsigned int CtrlRGBPalette[16];
int screen_w=320;
int screen_h=200;
BOOL bGrabMouse = FALSE;
BOOL bInFullScreen = FALSE;
SDL_Surface *sdlscrn;

static const unsigned char font_bmp[] = {
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x80,0x80,0x80,0x80,0x80,0x0,
0x80,0x0,0x0,0x2,0xa0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x50,
0xf8,0x50,0x50,0xf8,0x50,0x0,0x0,0x6,0x20,0xf0,0xa0,0xa0,0xa0,0xa0,0xf0,0x20,
0x0,0x5,0x0,0xc8,0xd8,0x30,0x60,0xd8,0x98,0x0,0x0,0x6,0xa0,0x0,0xe0,0xa0,
0xa0,0xa0,0xe0,0x0,0x0,0x4,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,
0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x0,0x3,0xc0,0x40,0x40,0x40,0x40,0x40,
0x40,0xc0,0x0,0x3,0x0,0x0,0x20,0xf8,0x50,0xf8,0x20,0x0,0x0,0x6,0x0,0x0,
0x40,0xe0,0x40,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x80,
0x0,0x2,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x0,
0x0,0x0,0x80,0x0,0x0,0x2,0x0,0x8,0x18,0x30,0x60,0xc0,0x80,0x0,0x0,0x6,
0xe0,0xa0,0xa0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x40,0xc0,0x40,0x40,0x40,0x40,
0xe0,0x0,0x0,0x4,0xe0,0x20,0x20,0xe0,0x80,0x80,0xe0,0x0,0x0,0x4,0xe0,0x20,
0x20,0xe0,0x20,0x20,0xe0,0x0,0x0,0x4,0x80,0x80,0xa0,0xa0,0xe0,0x20,0x20,0x0,
0x0,0x4,0xe0,0x80,0x80,0xe0,0x20,0x20,0xe0,0x0,0x0,0x4,0xe0,0x80,0x80,0xe0,
0xa0,0xa0,0xe0,0x0,0x0,0x4,0xe0,0x20,0x20,0x20,0x20,0x20,0x20,0x0,0x0,0x4,
0xe0,0xa0,0xa0,0xe0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0xe0,0xa0,0xa0,0xe0,0x20,0x20,
0xe0,0x0,0x0,0x4,0x0,0x0,0x0,0x80,0x0,0x80,0x0,0x0,0x0,0x2,0x0,0x0,
0x0,0x80,0x0,0x0,0x80,0x80,0x0,0x2,0xe0,0x0,0xe0,0xa0,0xa0,0xa0,0xa0,0x0,
0x0,0x4,0x0,0x0,0xe0,0x0,0xe0,0x0,0x0,0x0,0x0,0x4,0xc0,0x0,0xe0,0xa0,
0xe0,0x80,0xe0,0x0,0x0,0x4,0xe0,0x20,0x20,0xe0,0x80,0x0,0x80,0x0,0x0,0x4,
0xfe,0x82,0xba,0xa2,0xba,0x82,0xfe,0x0,0x0,0x8,0xf0,0x90,0x90,0x90,0xf0,0x90,
0x90,0x0,0x0,0x5,0xf0,0x90,0x90,0xf8,0x88,0x88,0xf8,0x0,0x0,0x6,0xe0,0x80,
0x80,0x80,0x80,0x80,0xe0,0x0,0x0,0x4,0xf8,0x48,0x48,0x48,0x48,0x48,0xf8,0x0,
0x0,0x6,0xf0,0x80,0x80,0xe0,0x80,0x80,0xf0,0x0,0x0,0x5,0xf0,0x80,0x80,0xe0,
0x80,0x80,0x80,0x0,0x0,0x4,0xf0,0x80,0x80,0x80,0xb0,0x90,0xf0,0x0,0x0,0x5,
0x90,0x90,0x90,0xf0,0x90,0x90,0x90,0x0,0x0,0x5,0xe0,0x40,0x40,0x40,0x40,0x40,
0xe0,0x0,0x0,0x4,0xf0,0x20,0x20,0x20,0x20,0x20,0xe0,0x0,0x0,0x4,0x90,0xb0,
0xe0,0xc0,0xe0,0xb0,0x90,0x0,0x0,0x5,0x80,0x80,0x80,0x80,0x80,0x80,0xe0,0x0,
0x0,0x4,0x88,0xd8,0xf8,0xa8,0x88,0x88,0x88,0x0,0x0,0x6,0x90,0xd0,0xf0,0xb0,
0x90,0x90,0x90,0x0,0x0,0x5,0xf0,0x90,0x90,0x90,0x90,0x90,0xf0,0x0,0x0,0x5,
0xf0,0x90,0x90,0xf0,0x80,0x80,0x80,0x0,0x0,0x5,0xf0,0x90,0x90,0x90,0x90,0xb0,
0xf0,0x18,0x0,0x5,0xf0,0x90,0x90,0xf0,0xe0,0xb0,0x90,0x0,0x0,0x5,0xf0,0x80,
0x80,0xf0,0x10,0x10,0xf0,0x0,0x0,0x5,0xe0,0x40,0x40,0x40,0x40,0x40,0x40,0x0,
0x0,0x3,0x90,0x90,0x90,0x90,0x90,0x90,0xf0,0x0,0x0,0x5,0x90,0x90,0x90,0xb0,
0xe0,0xc0,0x80,0x0,0x0,0x5,0x88,0x88,0x88,0xa8,0xf8,0xd8,0x88,0x0,0x0,0x6,
0x88,0xd8,0x70,0x20,0x70,0xd8,0x88,0x0,0x0,0x6,0x90,0x90,0x90,0xf0,0x20,0x20,
0x20,0x0,0x0,0x5,0xf0,0x10,0x30,0x60,0xc0,0x80,0xf0,0x0,0x0,0x5,0xa0,0x0,
0xa0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x80,0xc0,0x60,0x30,0x18,0x8,0x0,
0x0,0x6,0xe0,0xa0,0xa0,0xe0,0xa0,0xa0,0xe0,0x80,0x80,0x4,0xe0,0xa0,0xe0,0x0,
0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,0x6,
0xa0,0x0,0xe0,0x20,0xe0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x0,0xe0,0x20,0xe0,0xa0,
0xe0,0x0,0x0,0x4,0x80,0x80,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x0,
0xc0,0x80,0x80,0x80,0xc0,0x0,0x0,0x3,0x20,0x20,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,
0x0,0x4,0x0,0x0,0xe0,0xa0,0xe0,0x80,0xe0,0x0,0x0,0x4,0xc0,0x80,0x80,0xc0,
0x80,0x80,0x80,0x0,0x0,0x3,0x0,0x0,0xe0,0xa0,0xa0,0xa0,0xe0,0x20,0xe0,0x4,
0x80,0x80,0xe0,0xa0,0xa0,0xa0,0xa0,0x0,0x0,0x4,0x80,0x0,0x80,0x80,0x80,0x80,
0x80,0x0,0x0,0x2,0x40,0x0,0x40,0x40,0x40,0x40,0x40,0xc0,0x0,0x3,0x80,0x80,
0xb0,0xe0,0xe0,0xb0,0x90,0x0,0x0,0x5,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x0,
0x0,0x2,0x0,0x0,0xf8,0xa8,0xa8,0xa8,0xa8,0x0,0x0,0x6,0x0,0x0,0xe0,0xa0,
0xa0,0xa0,0xa0,0x0,0x0,0x4,0x0,0x0,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,
0x0,0x0,0xe0,0xa0,0xa0,0xa0,0xe0,0x80,0x80,0x4,0x0,0x0,0xe0,0xa0,0xa0,0xa0,
0xe0,0x20,0x30,0x4,0x0,0x0,0xc0,0x80,0x80,0x80,0x80,0x0,0x0,0x3,0x0,0x0,
0xc0,0x80,0xc0,0x40,0xc0,0x0,0x0,0x3,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0,0x0,
0x0,0x3,0x0,0x0,0xa0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x0,0xa0,0xa0,
0xe0,0xc0,0x80,0x0,0x0,0x4,0x0,0x0,0x88,0xa8,0xf8,0xd8,0x88,0x0,0x0,0x6,
0x0,0x0,0xa0,0xe0,0x40,0xe0,0xa0,0x0,0x0,0x4,0x0,0x0,0xa0,0xa0,0xa0,0xa0,
0xe0,0x20,0xe0,0x4,0x0,0x0,0xf0,0x30,0x60,0xc0,0xf0,0x0,0x0,0x5,0x81,0x8d,
0xe1,0xa0,0xa0,0xa0,0xa0,0x0,0x0,0x9,0x2,0x1a,0xc2,0x80,0xc0,0x40,0xc0,0x0,
0x0,0x8,0xfe,0xfc,0xf8,0xfc,0xfe,0xdf,0x8e,0x4,0x0,0x7,0x7f,0x3f,0x1f,0x3f,
0x7f,0xfb,0x71,0x20,0x0,0x8,0x4,0x8e,0xdf,0xfe,0xfc,0xf8,0xfc,0xfe,0x0,0x8,
0x20,0x71,0xfb,0x7f,0x3f,0x1f,0x3f,0x7f,0x0,0x7,0xff,0x81,0x81,0x81,0x81,0x81,
0x81,0xff,0x0,0x9,0x0,0x0,0xe0,0x80,0x80,0x80,0xe0,0x40,0xc0,0x4,0x60,0x0,
0xe0,0xa0,0xe0,0x80,0xe0,0x0,0x0,0x4,0xc0,0x0,0xa0,0xa0,0xa0,0xa0,0xe0,0x0,
0x0,0x4,0x40,0xa0,0x40,0x40,0x40,0x40,0x40,0x0,0x0,0x4,0x40,0xa0,0xe0,0x20,
0xe0,0xa0,0xe0,0x0,0x0,0x4,0x40,0xa0,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,
0x40,0xa0,0xe0,0xa0,0xe0,0x80,0xe0,0x0,0x0,0x4,0xe0,0x0,0xa0,0xa0,0xa0,0xa0,
0xe0,0x0,0x0,0x4,0xc0,0x0,0xe0,0x20,0xe0,0xa0,0xe0,0x0,0x0,0x4,0xe0,0xa0,
0xa0,0xa0,0xe0,0xa0,0xa0,0x0,0x0,0x4,0xc0,0xa0,0xa0,0xc0,0xa0,0xa0,0xc0,0x0,
0x0,0x4,0xe0,0x80,0x80,0x80,0x80,0x80,0xe0,0x0,0x0,0x4,0xc0,0xa0,0xa0,0xa0,
0xa0,0xa0,0xc0,0x0,0x0,0x4,0xe0,0x80,0x80,0xe0,0x80,0x80,0xe0,0x0,0x0,0x4,
0xe0,0x80,0x80,0xe0,0x80,0x80,0x80,0x0,0x0,0x4
};

static inline void read_m68k_vertex (int st_vptr, int output[3])
{
output[0] = STMemory_ReadLong (st_vptr);
output[1] = STMemory_ReadLong (st_vptr+4);
output[2] = -STMemory_ReadLong (st_vptr+8);
}

struct ZNode {
unsigned int z;
struct ZNode *less, *more;
void *data;
};

#define MAX_OBJ_DATA (2<<17)
static unsigned char obj_data_area[MAX_OBJ_DATA];
static int obj_data_pos;
#define MAX_ZNODES 1000
static struct ZNode znode_buf[MAX_ZNODES];
static int znode_buf_pos;
static struct ZNode *znode_start;
static struct ZNode *znode_cur;

enum NuPrimitive {
NU_END,
NU_TRIANGLE,
NU_QUAD,
NU_LINE,
NU_BEZIER_LINE,
NU_TEARDROP,
NU_COMPLEX_SNEXT,
NU_COMPLEX_START,
NU_COMPLEX_END,
NU_COMPLEX_INNER,
NU_COMPLEX_BEZIER,
NU_TWINKLYCIRCLE,
NU_PLANET,
NU_CIRCLE,
NU_CYLINDER,
NU_BLOB,
NU_OVALTHINGY,
NU_POINT,
NU_2DLINE,
NU_MAX
};

#define MAX_QUEUED_STRINGS 200
struct QueuedString {
int x, y, col;
unsigned char str[64];
} queued_strings[MAX_QUEUED_STRINGS];
int queued_string_pos;
static bool no_znodes_kthx;

/*********PROTOTYPES****************/
static void _BuildRGBPalette (unsigned int *rgb, unsigned short *st, int len);
static void draw_3dview (struct ZNode *node);
static int DrawChar (int col, int xoffset, char *scrline, int chr);
static void Nu_DrawPrimitive (void *data);
static inline int znode_rdlong (void **data);
static void add_node (struct ZNode **node, unsigned int zval);
static void znode_insert (struct ZNode *node, unsigned int zval);
static inline void end_node ();
static inline void znode_databegin ();
static inline void znode_wrlong (int val);

int DrawStr (int xpos, int ypos, int col, unsigned char *str, bool shadowed)
{
int x, y, chr;
char *screen;

x = xpos;
y = ypos;

if ((y > 192) || (y<0)) return x;
set_line:
screen = LOGSCREEN2;
screen += SCREENBYTES_LINE * y;

while (*str) {
chr = *(str++);

if (chr < 0x1e) {
if (chr == ‘\r’) {
y += 10;
x = xpos;
goto set_line;
}
else if (chr == 1) col = *(str++);
continue;
} else if (chr == 0x1e) {
/* read new xpos */
x = *(str++);
x *= 2;
continue;
} else if (chr < 0x20) {
/* Read new position */
x = *(str++);
x *= 2;
y = *(str++);
goto set_line;
}

//if (x > 316) continue;

if (shadowed) {
DrawChar (0, x+1, screen+SCREENBYTES_LINE, chr-0x20);
}
x = DrawChar (col, x, screen, chr-0x20);
}

return x;
printf (“DrawStr [%s]\n”,str);
return 0;
}

void Nu_PutColoredPoint()
{}

void Nu_ComplexSNext()
{}
void Nu_DrawComplexSNext()
{}

void Nu_DrawComplexStart()
{}
void Nu_DrawComplexEnd()
{}

void Nu_ComplexStartInner()
{}
void Nu_DrawComplexStartInner()
{}
void Nu_ComplexBezier()
{}
void Nu_DrawComplexBezier()
{}

void draw_control_panel()
{
unsigned int *pal;
// Lock surface if needed
if (SDL_MUSTLOCK(sdlscrn))
if (SDL_LockSurface(sdlscrn) < 0)
return;

// Declare a couple of variables
int y, x, yofs, ofs;

// Draw to screen
yofs = 0;
pal=MainRGBPalette;
for (y = 0; y < screen_h; y++)
{
if(y==168)pal=CtrlRGBPalette; //bottom has differnet palette
for (x = 0, ofs = yofs; x < screen_w; x++, ofs++)
{
//((unsigned int*)sdlscrn->pixels)[ofs] = pal[VideoRaster[ofs]];

switch (sdlscrn->format->BytesPerPixel)
{
case 1: // 8-bpp
{
Uint8 *bufp;
bufp = (Uint8 *)sdlscrn->pixels + y*sdlscrn->pitch + x;
*bufp =(Uint8*) pal[VideoRaster[ofs]];
}
break;
case 2: // 15-bpp or 16-bpp
{
Uint16 *bufp;
bufp = (Uint16 *)sdlscrn->pixels + y*sdlscrn->pitch/2 + x;
*bufp = pal[VideoRaster[ofs]];
}
break;
case 3: // 24-bpp mode, usually not used
{
Uint8 *bufp;
bufp = (Uint8 *)sdlscrn->pixels + y*sdlscrn->pitch + x * 3;
if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
{
bufp[0] = pal[VideoRaster[ofs]];
bufp[1] = pal[VideoRaster[ofs]] >> 8;
bufp[2] = pal[VideoRaster[ofs]] >> 16;
} else {
bufp[2] = pal[VideoRaster[ofs]];
bufp[1] = pal[VideoRaster[ofs]] >> 8;
bufp[0] = pal[VideoRaster[ofs]] >> 16;
}
}
break;
case 4: // 32-bpp
{
Uint32 *bufp;
bufp = (Uint32 *)sdlscrn->pixels + y*sdlscrn->pitch/4 + x;
*bufp = pal[VideoRaster[ofs]];
}
break;
}

}
//yofs += sdlscrn->pitch / 4;
yofs += sdlscrn->pitch / sdlscrn->format->BytesPerPixel;
}

// Unlock if needed
if (SDL_MUSTLOCK(sdlscrn))
SDL_UnlockSurface(sdlscrn);

// Tell SDL to update the whole screen
SDL_UpdateRect(sdlscrn, 0, 0, screen_w, screen_h);

//printf(“draw_control_panel\n”);
}

void Nu_DrawScreen()
{
_BuildRGBPalette (MainRGBPalette, MainPalette, len_main_palette);
_BuildRGBPalette (CtrlRGBPalette, CtrlPalette, 16);
//printf (“Frame: %d znodex.\n”,znode_buf_pos);
//draw_3dview (znode_start);
if (mouse_shown) {
SDL_ShowCursor (SDL_ENABLE);
mouse_shown = 0;
} else {
SDL_ShowCursor (SDL_DISABLE);
}
draw_control_panel();
//set_main_viewport();

//printf(“Nu_DrawScreen\n”);

}

void Nu_PutBezierLine()
{}
void Nu_DrawBezierLine()
{}

void Nu_3DViewInit()
{
queued_string_pos = 0;
//printf (“3dviewinit()\n”);
znode_buf_pos = 0;
//printf (“%d bytes object data\n”, obj_data_pos);
obj_data_pos = 0;

znode_start = NULL;
znode_cur = NULL;
no_znodes_kthx = FALSE;
}
void Nu_InsertZNode()
{
unsigned int zval = GetReg (4);
if (use_renderer == R_OLD) return;
if (no_znodes_kthx) return;
if (znode_start == NULL) {
add_node (&znode_start, zval);
} else {
znode_insert (znode_start, zval);
}
}

void Nu_PutCircle()
{}
void Nu_DrawCircle()
{}

void Nu_PutOval()
{}
void Nu_DrawOval()
{}

void Nu_PutCylinder()
{}
void Nu_DrawCylinder()
{}

void Nu_QueueDrawStr()
{}
void Nu_IsGLRenderer()
{
SetReg(0,0);
}

void Nu_PutPlanet()
{}
void Nu_DrawPlanet()
{}

void Nu_Put2Line()
{}
void Nu_Draw2Line()
{}

void Nu_PutQuad()
{}
void Nu_DrawQuad()
{}

void Nu_GLClearArea()
{}
void Nu_PutBlob()
{use_renderer=R_OLD;}
void Nu_DrawBlob()
{}

void Nu_Put2DLine()
{}
void Nu_Draw2DLine()
{}

void Nu_PutLine()
{}
void Nu_DrawLine()
{}

void Nu_UnInit()
{}

void Nu_PutTeardrop()
{}
void Nu_DrawTeardrop()
{}

void Nu_PutPoint()
{
printf(“Nu_PutPoint\n”);
}
void Nu_DrawPoint()
{}

void Nu_PutTwinklyCircle()
{}
void Nu_DrawTwinklyCircle()
{}

void Nu_ComplexStart()
{}

void Nu_PutTriangle()
{}
void Nu_DrawTriangle()
{}

void Nu_ComplexSBegin()
{}

void Nu_ComplexEnd()
{}

void Nu_32ViewInit()
{}

void Screen_ToggleRenderer ()
{
use_renderer = R_OLD;
}

void change_vidmode(void);

void Screen_Init(void)
{
change_vidmode();
SDL_WM_SetCaption(PROG_NAME, “Frontier”);
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
SDL_ShowCursor(SDL_ENABLE);
use_renderer=R_OLD;
printf(“Screen_Init\n”);
}

void change_vidmode (void)
{
const SDL_VideoInfo *info = NULL;
int modes;

info = SDL_GetVideoInfo ();

assert (info != NULL);

modes = SDL_SWSURFACE;// SDL_ANYFORMAT | (bInFullScreen ? SDL_FULLSCREEN : 0 );

if ((sdlscrn = SDL_SetVideoMode (screen_w, screen_h,
info->vfmt->BitsPerPixel, modes)) == 0) {
fprintf (stderr, “Video mode set failed: %s\n”, SDL_GetError ());
SDL_Quit ();
exit (-1);
}
printf(“change_vidmode %d x %d %d deep\n”,screen_w,screen_h,info->vfmt->BitsPerPixel);
}

void Screen_UnInit(void)
{}
void Screen_ToggleFullScreen()
{
}

static void _BuildRGBPalette (unsigned int *rgb, unsigned short *st, int len)
{
int i;
int st_col, r, g, b;

for (i=0; i>4;
rgb[i] = 0xff000000 | (b<<16) | (g<<8) | (r);
}
}

static int DrawChar (int col, int xoffset, char *scrline, int chr)
{
const char *font_pos;
char *pix;
int i;

font_pos = font_bmp;
font_pos += (chr&0xff)*10;
scrline += xoffset;

if (xoffset < 0) {
font_pos += 9;
return xoffset + *font_pos;
}

for (i=0; i<8; i++, font_pos++, scrline += SCREENBYTES_LINE) {
pix = scrline;
if (xoffset > 319) continue;
if (*font_pos & 0x80) *pix = col;
pix++;
if (xoffset+1 > 319) continue;
if (*font_pos & 0x40) *pix = col;
pix++;
if (xoffset+2 > 319) continue;
if (*font_pos & 0x20) *pix = col;
pix++;
if (xoffset+3 > 319) continue;
if (*font_pos & 0x10) *pix = col;
pix++;
if (xoffset+4 > 319) continue;
if (*font_pos & 0x8) *pix = col;
pix++;
if (xoffset+5 > 319) continue;
if (*font_pos & 0x4) *pix = col;
pix++;
if (xoffset+6 > 319) continue;
if (*font_pos & 0x2) *pix = col;
pix++;
if (xoffset+7 > 319) continue;
if (*font_pos & 0x1) *pix = col;
}
/* width of character */
font_pos++;
i = *font_pos;
return xoffset + i;
}
/*
* znode_start is the head of a btree of znodes, each with a linked list
* of GL display lists to draw (in list order).
*
* Draw this crap starting from biggest value znodes.
*/
static void draw_3dview (struct ZNode *node)
{
if (node == NULL) return;
if (node->more) draw_3dview (node->more);

if (use_renderer) {
printf (“Z=%d “, node->z);
Nu_DrawPrimitive (node->data);
}

if (node->less) draw_3dview (node->less);
printf(“draw_3dview\n”);
}

typedef void (*NU_DRAWFUNC) (void **);
NU_DRAWFUNC nu_drawfuncs[NU_MAX] = {
NULL,
&Nu_DrawTriangle,
&Nu_DrawQuad,
&Nu_DrawLine,
&Nu_DrawBezierLine,
&Nu_DrawTeardrop,
&Nu_DrawComplexSNext, // 6
&Nu_DrawComplexStart,
&Nu_DrawComplexEnd,
&Nu_DrawComplexStartInner, // 9
&Nu_DrawComplexBezier,
&Nu_DrawTwinklyCircle,
&Nu_DrawPlanet,
&Nu_DrawCircle,
&Nu_DrawCylinder,
&Nu_DrawBlob,
&Nu_DrawOval,
&Nu_DrawPoint,
&Nu_Draw2DLine
};

static void Nu_DrawPrimitive (void *data)
{
int fnum;

for (;;) {
fnum = znode_rdlong (&data);
//fprintf (stderr, “%d “, fnum);
if (!fnum) return;
nu_drawfuncs[fnum] (&data);
}
}

static inline int znode_rdlong (void **data)
{
int val = *((int*)(*data));
(*data) += 4;
return val;
}

static void add_node (struct ZNode **node, unsigned int zval)
{
assert (znode_buf_pos < MAX_ZNODES);
/* end previous znode display list!!!!!!! */
if (znode_cur) end_node ();

*node = znode_cur = &znode_buf[znode_buf_pos++];
znode_cur->z = zval;
znode_cur->less = NULL;
znode_cur->more = NULL;
znode_databegin ();
}

static inline void end_node ()
{
znode_wrlong (0);
}

static void znode_insert (struct ZNode *node, unsigned int zval)
{
if (zval > node->z) {
if (node->more) {
znode_insert (node->more, zval);
} else {
add_node (&node->more, zval);
}
} else {
if (node->less) {
znode_insert (node->less, zval);
} else {
add_node (&node->less, zval);
}
}
}

static inline void znode_databegin ()
{
znode_cur->data = &obj_data_area[obj_data_pos];
}

static inline void znode_wrlong (int val)
{
*((int*)(obj_data_area+obj_data_pos)) = val;
obj_data_pos+=4;
}