Another word about procedural graphics

Not long ago I published a short review of works in the genre of procedural graphics here and, in particular, called for participation in the competition. The competition I mentioned at the festival Chaos Constructions took place – seven works up to 1kb in size were presented, about which, especially two of my own making, I want to tell you.

My first work is called Way and was written for the Sony Playstation 1 (PSX) platform in MIPS R3000 assembler.

Way by Frog (PSX, MIPS R3000)

Way by Frog (PSX, MIPS R3000)

While RISC processors are usually not the best choice for writing compact code, in the case of PSX this is compensated by the GPU's ability to draw primitives in hardware.
Basically, we just list the primitives in a special format and then send this list (display list) to the GPU, having previously set the graphics mode to 640×480.

For example, this is how the sky is described – a quadrangle with a gradient fill (Guro):

sky
    db soil, soil>>8, soil>>16, $8   ; link to next list element, size of current element
    dw $38aa5b00    ; $38 - gradated 4p poly. CCBBGGRR (C - command, b,g,r - color0) $38c4deeb 
    dw $00000000    ; y0  x0 0 0
    dw $30bb5b00    ; color 1  
    dw $0000027f    ; y1  x1 639 0
    dw $30f3dec6    ; color 2    
    dw $01300000    ;  y2  x2 0 304
    dw $30f3dec6    ; color 3 
    dw $0141027f    ; y3  x3 639 321

The horizon and other lines are deliberately not parallel to the edges of the screen to achieve a cartoonish effect.

Here source.

The work is organized in a completely similar way.Invitation to CC'2024” (928 bytes) – with some hints of Suprematism, with the letters being formed by “cutting out” some quadrangles from others (drawing them in the color of the background).

CC'2024 Invitation by Frog (PSX, MIPS R3000)

CC'2024 Invitation by Frog (PSX, MIPS R3000)

Things are a little more complicated with my other job – Face (646 bytes), written for the Vectrex platform.

Face by Frog (Vectrex, Motorola 6809)

Face by Frog (Vectrex, Motorola 6809)

The Vectrex gaming computer has a vector display – there is no raster, the beam must be controlled manually (with some reservations). I have already talked about this platform in detail, so here I will describe the essence of what is happening without going too deep.

The face consists of several elements – the eyebrow and the borders of the eye (straight lines), the pupil of the eye (curve) and the contour of the face (two curves).

With straight lines everything is simple – there is a BIOS subroutine Draw_Line_d. But with curves – it is complicated.
The essence of the approach is that we manually start the integration – the beam starts moving from top to bottom from its current position to the Y value we set. At this time, we write different values ​​to the X channel and thus make the beam move to the left (if the values ​​are negative) and to the right (if positive). After writing the next value, we either write the next one right away or do nothing for some time, allowing the beam to continue moving in the same direction. This “doing nothing” initially looked like a bunch of NOPs after each change in X, and I glued a piece of parchment with a picture to the screen and selected the values ​​in the VIDE emulator.

Vide and selection of values ​​for the picture on the parchment glued to the monitor

Vide and selection of values ​​for the picture on the parchment glued to the monitor

...
                lda     #30
                sta     <VIA_port_a        	; put X to DAC 

                nop                         ; 2 cycles for each nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop

...

With this approach, you can't fit it into 1kb, so I folded all the long sequences of nops into cycles. Moreover, the instructions themselves that prepare and implement the cycle, of course, also have a certain execution duration, which also had to be taken into account by calculating all the cycles (well, approximately):

...
                lda     #30
                sta     <VIA_port_a        	; put X to DAC 

; 10
                ldb    #2                   ; 2 cycles
d6a:            decb                        ; 2 cycles
                bpl     d6a                 ; 3 cycles
...

In general, the first thought that should arise when looking at this code is that there are a lot of repeating pieces and all the delays can be reduced to tables and taken from there. Alas, any extra clock cycle will lead to an extension of the drawn vector, so a simple solution will not work here. Theoretically, it is possible to write a code generator – i.e. so that the program recreates the necessary instruction sequences based on the data from the table. Unfortunately, the Vectrex has only 1 KB of RAM – it is probably possible to squeeze it in, but the game in this case is not worth the candle (everything fits into 1 KB anyway).

A separate problem is the presence of elements in the facial silhouette that are close to horizontal (near the lips). The fact is that the beam moves from top to bottom at a constant speed – it cannot be slowed down. The steepness of the bend is determined exclusively by the value recorded in X. But more than +/- 127 cannot be recorded there, for obvious reasons.
It would have been possible to make these two elements simply separate lines, but this would have resulted in either visible mismatches between the ends of the line and the adjacent curve, or bright spots where they join. As a result, I made a silhouette of four curves, each starting where the other ends. The fact that the integration is restarted allows the beam to move left (and right) from the very beginning of the segment, thus obtaining lines that are close to horizontal.

The pupil is just a curved piece.

The glowing objects flying from the right are rendered by calling the BIOS Dot_List routine, which draws zero-length vectors from a list of coordinates. The routine is called three times with a horizontal offset, with the brightness changing after each call (to create a motion blur effect).

The text is also output by the BIOS Print_List_hw subroutine, which, given the amount of text, is a very inefficient method. However, in this case it is justified – firstly, in order to save bytes (calling a standard procedure is shorter than writing your own), and secondly, everything together (text, straight lines, curves) fits into 30 thousand processor cycles, which is necessary to avoid flickering and other undesirable effects.

Although this work was originally conceived as procedural graphics, during the above-described entertainment, I came up with the idea that you can make the face move slightly by simply changing the values ​​​​by which the beam deviates in some places and the delays after recording these values. This is how another intro appeared Aniface (820 bytes),

Video does not convey the warmth and brightness of a vector CRT monitor (and photos only remotely). Alas, here you need a very serious video camera (you need a wide dynamic range and high light sensitivity) and a lot of time to select the shooting parameters.

Finally, I will show all the works (of other authors) submitted to this competition of the Chaos Constructions festival:

Disqualified work Rebranding by artёmka // wbcbz7 – the work was written for TIC-80, but according to the rules of the competition, works for virtual platforms are not accepted

  Rebranding by artemka // wbcbz7

Rebranding by artemka // wbcbz7

6th place – Ancient Aztec Matrix 128b by g0blinish (125 bytes) for Commodore 64 (6510 processor)

Ancient Aztec Matrix 128b by g0blinish

Ancient Aztec Matrix 128b by g0blinish

Fifth place – my already mentioned above work Way by Frog //ROi

4th place – Reptile 1k by g0blinish for ZX Spectrum (z80 processor)

Reptile 1k by g0blinish

Reptile 1k by g0blinish

Third place – my already mentioned above work Face by Frog //ROi

Second place – Teonon by dart / fnm (1022 bytes) – the only one of all written for a modern platform (PC/Windows)

Teonon by dart / fnm

Teonon by dart / fnm

The winner is the work of RTZX by RCL of Virtual Vision Group (983 bytes).

RTZX by RCL of Virtual Vision Group

RTZX by RCL of Virtual Vision Group

As the author himself writes in the explanation of the work, he has implemented an honest raytracer for the ZX Spectrum 48K (z80 processor). The input is the camera position and four primitives. The work was written under the impression raytracer implementations not in BASICwhich took 17 hours to render. The competition entry takes 43 seconds to render.

The places were determined by the audience vote – interestingly, RTZX won, as people were obviously able to appreciate the complexity of implementing a raytracer on the z80 in such a volume of code.

All works can be downloaded Here or Here.

Overall, I, as one of the organizers of Chaos Constructions, who was especially pushing for this competition, was very pleased with the works presented – all of them (including the disqualified one) were very worthy.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *