There is one quality in the Universe which cannot be negated.
Some refer to it as God.
Some call it Love.
We express it with 0x80.

- 1995-style multimedia experience -

VGA strongly recommended!

(TELNET version comming soon)

[A link to the past...]


A note from the



/home/śmigło .::.


DREZYNA: added support for wireframe rendering. Possible that 'old' game-oriented emulators do not support line drawing, because there weren't many titles using it (even one?). Still, I've spotted the cause of image flickering on HLE's and now it shouldn't cause epillepsy (tested with Mupen64) / EDIT: maybe it is just the Glide64 that accepts the fix; standard plugin still can't handle.


DREZYNA update.


DREZYNA: fixed lens flare effect (support for semitransparent textures).
lwo2ultra updated accordingly.


DREZYNA: cleanup. (Neverending story...)


DREZYNA: added lens flare effect (sort of...). This is Z-buffer-based and typical high-level emulators will fail to render. CEN64 recommended, as always, or some real hardware maybe.


DREZYNA: clean up.


Just two small things. First, this:

resize_Vec( self, self->max_el + 16 );

was what made my metaballs so slow. Should be rather:

resize_Vec( self, self->max_el << 1 );

See the difference: DREZYNA

Second, still learning Rust, so I've made some cleanup in lwo2ultra code.


Do you like 3D metaballs? Obviously you do! Download new DREZYNA and contemplate them. The implementation is SLOW, deliberately, to keep you safe from the modern 60 fps insanity... Far from! Moreover, some bugs were fixed and now it works without Expansion Pack. There was a small naming change in static mesh, so lwo2ultra 1.5.1 is provided as well. See you next time!


lwo2ultra 1.5.0
Program's output now contains data useful for display list relocation. On the N64, only the first 1MB of ROM is copied to RAM during boot; having more than this requires transfering stuff from ROM to RAM manually. Destination address is unknown at compile time (I use malloc), so dynamic relocation is needed. Check out latest DREZYNA; note that it requires expansion pack and may not work on Project64. Runs on CEN64 and Nemu. Still don't know how it would behave on real hardware.


lwo2ultra 1.4.0
The winter is over and some of you wake up to establish a 56k modem connection. What can be expected?
-added function for tiling large textures (the -t switch)
-fixed a bug in texture coordinate conversion
-replaced lodepng with imagefmt library (supports: BMP, JPEG, PNG, TGA)
-added option for object naming (-n)
-updated myheader.h

I've also updated DREZYNA to give an example of what that tiling feature can be used for.

Happy Easter!


DREZYNA update; features less entropic code and some basic lighting.


Dear Santa,

I'm 10 years old and interested in making games for oldschool hardware. I find lwo2ultra (...) a good aid in developing N64 programs and have a wish: to get a version that supports some reasonable texture format, like PNG.

Little Joe, America

Dear Santa Claus,

have you ever heard about lwo2ultra? Being so useful for Ninny coders, it's a shame that author forgot about converting data from Left-Handed System to RHS... (...)

Matti, 12-yo, Finland

Having received millions of letters like these from children, how could I resist? Hired some of my best staff and devoted thousands of elf-years to bring you an experimental reimplementation in Rust:


(supported by libraries: lodepng, getopts)

Merry Christmas!

BTW: This requires some not-so-old PC to run with an acceptable speed. I/O in Rust seem to be incredibly slow when taken with a naive, first-tought approach. Not being sarcastic: C version for Amiga 1200 would rather outperform this one running on a ~GHz CPU. Heh. The perceived lag doesn't seem so big for a typical N64 texture sizes, however.

Probably you don't care anyway...

Numbers show that children favor PSX over N64, actually.


DREZYNA - first release.


lwo2ultra 1.2 released.

ROM images and sources:
(Some releases require Expansion Pack; also have some issues on HLEs.)

A simple 3D engine for Nintendo 64, developed mostly with CEN64 and Project64 emulators. Didn't have an opportunity to check how it runs on real hardware, though.


sources & linux executables:

This thing converts a Lightwave object (LWO2) into a Nintendo 64 display list (F3DEX GBI).

Currently there's support for shading (per-vertex normals) and texture mapping (VMAP/VMAD chunks). Polygons in a single layer should refer to only one surface definition - if more than one surface is referenced, you get a yellow card. :) (in other words, all polygons in a layer share the same material). This will be fixed in the future (maybe).
Supported texture formats are: BMP, JPEG, PNG, TGA. Colors are counted and texture is 'downgraded' accordingly:
more than 16 colors -> RGBA 5:5:5:1 and you get a table of 16-bit texels.
no more than 16 colors -> a table of 16-bit (RGBA 5:5:5:1 for color / IA 8:8 for greyscale) values for the palette and a table of 4bit color indices packed into 8-bit values (high nibble refers to left pixel, as expected).

>Usage notes

Floating point values are converted to 16-bit integers - make sure that your input object is scaled properly (-s option).

Try to behave nicely:

lwo2ultra inputfile [-o outfile] [-s scalefactor] [-n name] [-t]

(inputfile must be first on the option list.)


Small texture memory in the RDP is a pain. To overcome this somehow, you may load parts of a large image into TMEM and render polygons in groups sharing these parts. The -t switch allows lwo2ultra to split object into such parts, each with a 'tile descriptor' giving information about which part of the image should be loaded. Note however, that the object must be properly subdivided. If you'd like to render a rectangle with a BIG 256x256 texture on it, you should subdivide it into smaller polygons (such that they are covered by - say - 32x32 texels). But you don't have to manually 'chop' the texture, create new layers and associate them with polys - as you would have to with previous versions. When subdividing, it might be a good idea to make polygons which aren't exactly covered by a largest TMEM-fittable tile. If rendering with bilinear filter, it's good to leave a bit of margin to be able to load texels surrounding right and bottom edges - this allows preventing 'seams' on polygon edges. Currently tiling gives unoptimized output - you get a new layer for EACH POLYGON.

File myheader.h provides structure declarations for use with the output code.

Output looks like this:

#include "myheader.h"

/* vertices for layer 0 */
static Vtx vts0[] = {

/* display list for layer 0 */
static Gfx drawmesh0[] = {


/* vertices for layer N */
static Vtx vtsN[] = {
/* diplay list for layer N */
static Gfx drawmeshN[] = {

/* texture 0 (RGBA 5:5:5:1) */
static u16 texture0[] = {

/* texture 1 palette */
static u16 palette1[] = {

/* texture 1 (4-bit indexes to palette, packed) */
static u8 texture1[] = {


/* texture M */
static u16 textureM[] = {

/* texture attributes */
static Texture textures[] = {
  TEXTURE_INIT(width0, height0, &texture0, NULL, format0),
  TEXTURE_INIT(width1, height1, &texture1, &palette1, format1),
  TEXTURE_INIT(widthM, heightM, &textureM, &paletteM, formatM),

/* materials */
static Material materials[] = {

/* table of layers that build a mesh. */
static Layer layers[] = {
  LAYER_INIT( MATERIALS_INDEX_0, drawmesh0, sizeof(drawmesh_0), vts0, sizeof(vts0),  RECTANGLE_INIT(0, 0, 0, 0), LAYERATTRIBUTE_NONE )
  LAYER_INIT( MATERIALS_INDEX_1, drawmesh1, sizeof(drawmesh_1), vts1, sizeof(vts1),  RECTANGLE_INIT(0, 0, 0, 0), LAYERATTRIBUTE_NONE )

StaticMesh mesh = STATICMESH_INIT( layers, NUM_LAYERS, materials, NUM_MATERIALS, textures, NUM_TEXTURES );

Hello, mr 6502

Atari executable & sources

Atari 8-bit demo made by Dely (graphics), Miker (music) and me (code). Also, there's a music player written by Fox/Taquart.
First shown at Głuchołazy 2008 demo compo.


You can write to me: l p . a i r e t n i [t a] s o l t a m

HTML 2.0 compliant :)