VOGONS

Common searches


First post, by Dice

User metadata
Rank Newbie
Rank
Newbie

Hello World! I'm currently working on a 3D game engine for DOS and would like to share it with all of you here

This game engine is called ICE as it stands for ISO/C Engine. It is written in C99 with bindings to my unique ISO programming language. Though the bindings are completely optional and you can just use plain C instead.

Screenshots:
NrV2MBO.png
J9VvXu9.gif

Current features:

  • SoundBlaster 16 (8 bit unsigned mono audio @ 32KHz)
  • 256 mixed samples
  • VESA mode 10Dh (320x200x15)
  • 256 32 bit texture buffer + Optional Z buffer
  • Fixed point triangle rasterization

TODO:

  • Covox Speech Thing support
  • Mouse support
  • Joystick support
  • SDL2 backend

This is being built using DJGPP so it can only run in protected mode on Pentium and later processors. Also, I have only tested this in DOSBox and haven't tried it on real hardware yet.
I also plan on implementing an SDL2 backend so games can be ported over to other platforms.

You can find the source and prebuilt binaries here: https://github.com/0x1ED1CE/ICE

I would appreciate any feedback on this!

Reply 1 of 13, by Deano

User metadata
Rank Newbie
Rank
Newbie

Your vertex interpolations looks good for 15 bit. Thats classic RGB iterations I'd expect to see.

Is your rasterization a bit off or is your cube not welded properly? The second video I can see red peeping through on the back face when it shouldn't EVEN with no back face culling. Usually this is because the rules of rasterization aren't exact. You probably also want sub pixel rasterization whilst you are there.

I'd also grab the classic rubber doc model that was a common complex object back in the mid 90s. Pretty much everybody used that when bringing up there software 3D engines back in the day.

Not sure what you mean by texture buffer tbh

Z-Buffering was rare in the DOS era, whilst I did ship a game with one in 96/97 is wasn't pleasant and I wouldn't if I had the choice. Suggest a PS1 style depth list, if that won't work then intra-object level polygon sorting if you can get away with else (else global poly sort).

Game dev since last century

Reply 2 of 13, by Dice

User metadata
Rank Newbie
Rank
Newbie
Deano wrote on 2024-01-16, 11:18:

Is your rasterization a bit off or is your cube not welded properly? The second video I can see red peeping through on the back face when it shouldn't EVEN with no back face culling. Usually this is because the rules of rasterization aren't exact. You probably also want sub pixel rasterization whilst you are there.

Actually this is just the classic texture bleed caused by UV coordinates not perfectly lining up with the texture that I used.

Deano wrote on 2024-01-16, 11:18:

I'd also grab the classic rubber doc model that was a common complex object back in the mid 90s. Pretty much everybody used that when bringing up there software 3D engines back in the day.

I was planning on demoing the Utah teapot but I haven't finished my obj loader as of yet.

Deano wrote on 2024-01-16, 11:18:

Not sure what you mean by texture buffer tbh

It just means every texture in memory is mutable. I plan to change that later on.

Deano wrote on 2024-01-16, 11:18:

Z-Buffering was rare in the DOS era, whilst I did ship a game with one in 96/97 is wasn't pleasant and I wouldn't if I had the choice. Suggest a PS1 style depth list, if that won't work then intra-object level polygon sorting if you can get away with else (else global poly sort).

Yeah Z-buffering takes quite a toll especially with having to branch per pixel. I was actually thinking of taking a page from Quake and implement span buffers. Since I'm already using scanline rasterization it shouldn't be too hard to adapt the code. Though I am still trying to figure out how I would like to handle transparency...

Reply 3 of 13, by Deano

User metadata
Rank Newbie
Rank
Newbie

BTW I'm assuming by a "3d engine for DOS", you are targeting a system for the golden age of SW rasterized PC games. If not ignore this advance, as what was good around the era a Pentium is radically different from a modern CPU.

In Z-Buffer, the branch is expensive but the real cost on real systems is the memory access. You have to read/mod/write a 16/32 bit value in the inner loop, as a < PPro CPU isn't out of order you stall. Ideally the only memory lookup in the inner loop is for a texture (1 byte) and its palette (3 byte). Palette will fit in D-Cache and swizzling the texture and per polygon mip mapping will help the texture lookup by being more cache coherent.

I did have a scan buffer rasterization system back in the day, but its relatively expensive and scales badly so unless you absolutely need perfect per pixel HSR not sure I would recommend it in general (its very good in certain situations tho).

The answer to transparency is don't be general, 50/50 mix can be done very quickly in your inner loop (most of the cost comes from the 16 bit framebuffer read) and without muls. The PS1 HW did the same thing (had a selection of 4 fixed iirc)

Game dev since last century

Reply 4 of 13, by Dice

User metadata
Rank Newbie
Rank
Newbie
Deano wrote on 2024-01-17, 07:42:

I did have a scan buffer rasterization system back in the day, but its relatively expensive and scales badly so unless you absolutely need perfect per pixel HSR not sure I would recommend it in general (its very good in certain situations tho).

Could you elaborate more on this? I'm wondering how using painter's algorithm could perform better if memory access is the issue. Since painter's algorithm doesn't actually cull anything, it just reorders the drawing sequence and that results in a lot of overdraw and therefor much more unnecessary memory writes. A span buffer in the other hand should in theory perform marginally better since it both reduces per pixel sorting down into sorting segments and also culls the final raster output.

Reply 5 of 13, by Deano

User metadata
Rank Newbie
Rank
Newbie

The cost of maintaining the scan buffer is pretty expensive and scales badly with polygon count.

If your triangle rasterization inner loop is fast, a bit of overdraw isn't that expensive. A real game of the era spends a lot of pre-processing time and game specific stuff keeping the overdraw low. Where is makes sense is if you have very complicated per-pixel asm and/oe are expecting a lot of overdraw.

Lets say each span is on average 50 pixels (about 1/6 of the 320x200 screen), if your rasterization inner loop is say 30 clocks per pixel (you can do better than this with some good asm). You scan buffer has to beat ~1500 cycles per span, otherwise you might as well eat the overdraw.

Game dev since last century

Reply 6 of 13, by Deano

User metadata
Rank Newbie
Rank
Newbie

Perhaps a better explanation is its a change from a global triangle sort (painters) to lots of local segment sorts.

You can also avoid the painters sort (or technically making it a cheap radix/insert sort) by using a order buffer like the PS1 HW did.

There is no one perfect algorithm as it largely depends on you input data, which is very game specific.

Game dev since last century

Reply 8 of 13, by Dice

User metadata
Rank Newbie
Rank
Newbie
Dice wrote on 2024-01-16, 22:22:

I was planning on demoing the Utah teapot but I haven't finished my obj loader as of yet.

I lied. Here's Hatsune Miku instead. Hehe
11obVvW.gif

There's some artifacts near the edges but I think I know what's causing it... Something to do with my fixed point calculations...

EDIT: The artifact was caused by a dumb workaround I put to avoid division by zero. I just replaced with an early discard and that appears to have fixed it.

OlQvPnX.gif

Reply 9 of 13, by Dice

User metadata
Rank Newbie
Rank
Newbie

I've been spending some time optimizing since 190 FPS seemed too low for emulation running at max speed. Turns out audio processing is pretty hefty! With audio disabled I was able to gain more than 100 FPS! Skyrocketing up to 310 FPS.

Based on https://www.dosbox.com/wiki/Performance I configured DOSBox to somewhat match the performance of a 300MHz Pentium II.

With audio enabled and set at 22KHz the engine gets a little over 60 FPS. With audio disabled it goes up to 86 FPS. Again this is all emulated so I'm not too certain how it will perform on real hardware. That's why I'm going to build my own retro setup soon. If anyone has suggestions of what parts to buy, please let me know!

Reply 11 of 13, by Dice

User metadata
Rank Newbie
Rank
Newbie

Just a quick update on this, I started working on getting 3d acceleration support.

Thanks to the team behind the Q2DOS project, I was able to obtain a version of OSMesa with 3Dfx glide support which compiles using DJGPP.

Though I am having some issues getting voodoo to initialize. Mesa detects the (emulated) card but halts at grSstWinOpen error.

dkpTgB9.gif

EDIT: I was able to successfully get voodoo working! It was a dumb error in my code.

B8pnPTF.gif

Reply 13 of 13, by Dice

User metadata
Rank Newbie
Rank
Newbie

Sorry for lack of updates. Been busy with work as well as other projects.

I've resumed working on the 3dfx support and got 3D rendering!

c5G88AO.gif

There is a very subtle lag spike and dosbox keeps spitting out an error when it happens:

LOG: 1819600626 ERROR DOSMISC:DIRCACHE: FindFirst/Next: All slots full. Resetting

Not sure what this means and if it's an issue with my code or the emulator...

EDIT: It was a dumb mistake on my end. Forgot to remove a debug print which was writing to the disk PER FRAME... >_<