XT-Engine: small, but powerful platform game engine in asm

People are still making stuff for the Sinclair related machines. Tell us about new games and other software that runs on the Spectrum, ZX80/ZX81, Pentagon and Next.
Wall_Axe
Manic Miner
Posts: 500
Joined: Mon Nov 13, 2017 11:13 pm

Re: XT-Engine: small, but powerful platform game engine in asm

Post by Wall_Axe »

So blitting sprites directly to the screen is slow, cos it happens at the wrong time or is coming from contended memory
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

tiles, not sprites. there are several dozens of animated tiles, and yes, bliting them directly to scr$ seems to be slowed down by screen access contention a lot. there is nothing we can do here, at least using "all-purpose" engine like XTE. animating so many tiles will not be fast in any case.

but now i think that i can remove this optimisation case completely. it is mostly used to erase sprites, and not that often anyway. i need to do some tests, but i believe that speed penalty will not be big enough to warrant keeping that code.

tbh, i simply forgot about contention at all, and spent a whole day trying to understand how doing more work may be faster than doing less work. ;-)
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

so, at the end of the day, removing "direct blit optimisation" looks like a good move. the final speed is almost the same, but the code is now much smaller, cleaner, and even faster in several tight loops. traded small speedup when there are 3-6 animated tiles not overlayed with sprites for 100+ bytes of code. this is a clear win in my book.

after all, if you KNOW that you will have some animated tiles never touched by sprites, it will be way easier (and faster) to directly animate them with separate printing code. as XTE doesn't touch unchanged screen areas, your code can safely print there.

also, you can easily inject your code between "tiles are marked dirty" and "tiles are printed" engine parts, and check if some tiles are touched by any sprite (a simple bit test). so if you need to optimise tile animations, you can do it without changing XTE at all, while leaving the heavy work of sprite management and printing to XTE. and if your game is ok with what XTE can do for you out of the box, you don't have to pay a 100+ bytes penalty for the code you don't need.
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

of course, it is impossible to simply sit and write the engine. i just remembered that UrAsm contains almost fully-featured Forth implementation. it was used exclusively to build dsForth (as Forth with Z80 asm), and i turned it around: it is now possible to call Forth scripts from asm mode. that is, i have a powerful language to do various data processing. like this, for example:
Spoiler

Code: Select all

asm-org@ " starting_room" asm-set-label-data
room-clear-legend
 0 [CHAR] . room-legend  ;; empty
 1 [CHAR] # room-legend  ;; brick
 2 [CHAR] [ room-legend  ;; left ladder
 3 [CHAR] ] room-legend  ;; right ladder
 4 [CHAR] @ room-legend  ;; gold
 5 [CHAR] $ room-legend  ;; column, top-left
 6 [CHAR] % room-legend  ;; column, top-right
 7 [CHAR] & room-legend  ;; column, top-left
 8 [CHAR] * room-legend  ;; column, top-right

32 24 room-def
  .@..............................
  ................................
  ..#[]#####################[]##..
  ...[].....................[]....
  ...[].....................[]....
  ...[].....................[]..@@
  @@.[].....................[]....
  ...[].....................[]....
  ...[].....................[]..@@
  @@.[].....................[]....
  ...[]......#[]#########...[]....
  ...[].......[]............[]....
  @@.[]....@@.[]............[]....
  ...[].......[]............[]....
  ...[].......[]...........###[]##
  @@.[].......[]..............[]..
  ...[].@.....[]@@............[]..
  ...#####[]#####........@@...[]..
  ........[]..................[]..
  @@......[].............@@...[]..
  ........[].....#.#.#........[]..
  ........[]..$%.#............[]..
  .@@@@...[]..&*.#@@@@........[]..
  ################################
or this:

Code: Select all

asm-org@ " rex_spr_left_3" asm-set-label-data
24 16   \ width and height
" .#_"  \ legend: empty, set, mask and not set
sprite-automasked
  ...............#..#.....
  ...............#.#......
  ..........#..##.#.......
  ...........#..##.#.##...
  ..........#####.#..###..
  .............###....###.
  ..........###.#....#.##.
  ...........#......#.##..
  ........#.....####.#..#.
  ...........#.##...##.##.
  .........#..##..##......
  ...............##.......
  ...............##.##....
  ............#.##...##...
  .............###...##...
  ..............#...##....
both excerpts are taken directly from compilable XTE code. and this is room data parser, for example:
Spoiler

Code: Select all

CREATE (room-legend)  256 allot CREATE; (hidden)

: room-clear-legend ( -- )
  256 0 DO 255 (room-legend) I + c! LOOP
;

: room-legend ( value char -- )
  255 and (room-legend) + c!
;


: room-def ( width height -- )
  args: width height

  :width 1 < :width 32 > IF " invalid room width" asm-error ENDIF
  :height 1 < :height 24 > IF " invalid room height" asm-error ENDIF

  :height 0 DO
    read-next-line IFNOT " unexpected end of file" asm-error ENDIF
    BEGIN tib-peekch dup 0> swap BL <= and WHILE tib-getch DROP REPEAT
    :width 0 DO
      tib-getch 255 and (room-legend) + c@
      dup 255 = IF " invalid room data" asm-error ENDIF
      asm-c,
    LOOP  ;; width
  LOOP  ;; height
;
tbh, i done it mostly because i am tired of shuffling around `defb`s for sprites. i want to experiment with various things, including changing sprite origin to bottom-left instead of top-left. and with bottom origin it is easier to render sprites from the bottom too. so i need to have gfx upside down. Forth code can generate any data layout from the pseudographical description above.

i just reasiled that it starting to look suspiciously like a game authoring system i planned to create (and even wrote a prototype). new plan! ;-)

btw. if is fun that my Z80 assembler contains Forth implementation, and that Forth has Z80 assembler and disassembler written entirely in Forth. i also have Forth system for Z80, with Z80 asm and disasm too, just to complete the picture. ;-)
Wall_Axe
Manic Miner
Posts: 500
Joined: Mon Nov 13, 2017 11:13 pm

Re: XT-Engine: small, but powerful platform game engine in asm

Post by Wall_Axe »

go Forth and multiply
use the Forth
Wall_Axe
Manic Miner
Posts: 500
Joined: Mon Nov 13, 2017 11:13 pm

Re: XT-Engine: small, but powerful platform game engine in asm

Post by Wall_Axe »

So it's possible to use forth and ASM with your compiler?

Or forth is just the scripting language
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

Wall_Axe wrote: Fri Sep 29, 2023 4:15 pm So it's possible to use forth and ASM with your compiler?
that is the goal of dsForth project (which was a part of UrAsm, but now separated). it is not there yet, but i'm sporadically working on it. one of the features of dsForth is "turnkey applications": the compiler can trace your code (at a separate compiling pass), and output Z80 binary with only used Forth words (and without dictionary headers).
Wall_Axe wrote: Fri Sep 29, 2023 4:15 pm Or forth is just the scripting language
and that is how it works in UrAsm now. of course, you can use UrForth itself to write a Forth cross-compiler for Z80, and use it in your sources. UrForth is a "honest" and feature-complete Forth system, not some stripped-down version, so you can write (almost) anything with it. it is possible, for example, to create a compiler for AGD-like language, to write games in any mixture of asm and AGD-like simple lang (that's what i'll prolly implement later).

of course, UrForth is lacking any documentation yet, and it is not even ANS, so i don't expect people to really use it. at least not until i write some docs. ;-)
marenja
Microbot
Posts: 108
Joined: Sun Dec 26, 2021 4:15 pm

Re: XT-Engine: small, but powerful platform game engine in asm

Post by marenja »

ketmar wrote: Fri Sep 29, 2023 10:46 am btw. if is fun that my Z80 assembler contains Forth implementation, and that Forth has Z80 assembler and disassembler written entirely in Forth. i also have Forth system for Z80, with Z80 asm and disasm too, just to complete the picture. ;-)
Sounds very tricky. Could yout explain please ...

ketmar wrote: Fri Sep 29, 2023 10:46 am if is fun that my Z80 assembler contains Forth implementation
Is this note about PC cross-assembler ?
ketmar wrote: Fri Sep 29, 2023 10:46 amand that Forth has Z80 assembler and disassembler written entirely in Forth.
And this is about cross-assembler or better to say cross-forth too? It runs on PC and produces Z80 or Forth files for Speccy isn't it? Or it produces forth files for PC?
ketmar wrote: Fri Sep 29, 2023 10:46 am i also have Forth system for Z80, with Z80 asm and disasm too, just to complete the picture. ;-)
And this forth system runs on Speccy and produces asm/disasm for Speccy?

But can PC-forth files run on Speccy? Can it be vice versa and speccy forth run on PC ?
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

marenja wrote: Sun Oct 01, 2023 10:30 am Sounds very tricky.
that was The Plan. ;-)

cross-asm contains Forth as a macro language. which was initially added to make speccy Forth (completely separate project) building easier. everything is quite… complicated there to properly explain now. ;-) there is also third Forth system there, standalone X86. all three can share Forth sources… to some extent. actually, standalone system is an offspring of macro Forth, and macro is a distant relative of speccy Forth.

i bet it became even more unclear now. ;-)
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

XTE2 video.

i didn't ported several AI routines yet, but everything else is working. please, note that while this demo is SLIGHTLY slower than the previous one (but you won't prolly notice it without running them side-by-side), it animates 32 gold bars on each frame. if i'll turn off that animation, the speed will be roughly the same as in XTE1.

some new XTE2 features:
* sprite origin is bottom line now. it costs ~200TS per sprite, but i found it easier to work with this way. also, each sprite gfx can have separate height. you can see it in the video, where Rex is sometimes 16 pixels high, and sometimes 17 (it can be noticed by attribute change).

* sprite coords are (tile/offset) pairs now, so sprites can freely go out of the visible area (and the engine will correctly clip/drop them). animation frame is independent of sprite offset too (it wasn't the case in XTE1).

* foreground masked tiles are fully supported (look at the gold bars when a sprite moves behind them).

* the engine supports both masked and ORed sprites in the same time, so you can have some less-important sprites without masks, if you need some more free memory.

as each sprite gfx has its own height field now, it is possible to completely omit empty gfx lines at the top of the sprite, which can save some more memory. most sprites in demo had at least 1 empty line at the top (and up to 9 for some "jumping letter" frames).

engine size: ~3.5KB, with ~512 bytes for render stack (it can use less memory if you know maximum number of sprites per row, and maximum number of foreground tiles; currently XTE reserves enough memory for the worst case).

the code is not public yet, sorry.
User avatar
Cgonzalez
Drutt
Posts: 40
Joined: Thu Mar 15, 2018 10:03 pm
Location: Santiago, Chile

Re: XT-Engine: small, but powerful platform game engine in asm

Post by Cgonzalez »

Wow this looks amazing, congratulations! Do you plan to create a z88dk a interface for it?
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

Cgonzalez wrote: Thu Oct 05, 2023 2:43 pm Wow this looks amazing, congratulations! Do you plan to create a z88dk a interface for it?
thank you!

as for z88dk support… dunno. i stopped pretending that the thing is not coupled with UrAsm, it never was the case anyway. it is full of conditionals, macros, struct definitions, and even some helper Forth code, so i don't think that it can be ported to other asms.

but what could be done is using UrAsm to produce asm code for the properly configured XTE. i.e. you set engine options (it has quite a lot), and then ask UrAsm to preprocess the code for you. i have to hack UrAsm to do such export, but this is prolly the only way to "port" XTE. this way you will still need UrAsm to get something you can include in your project, but will be able to use your favorite tools afterwards.

or, you can drop all your obsolete tools, and switch to The Best And The Only: UrAsm! and use its built-in Forth to write any compiler you like. ;-) joking aside, i will prolly implement an AGD-like compiler myself.
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

btw, if you wonder why Rex is so slow… that's how fast he really is if he'll move on each frame. ;-) i set his speed to "each 2nd frame" for testing purposes.

p.s.: yeah, brought back Player Controller from XTE1. no collecting gold yet, though (that code is there, but commented out).

also, wrote simple room compressor (kind of run-length), which cut the room data size from 768 bytes to 105 bytes. rooms are compressed on the fly (with embedded Forth code). in the source, it still looks like this:
Spoiler

Code: Select all

$START_FORTH
also room

$LABEL-DATA: starting_room
clear-legend
 0 [CHAR] . set-legend  ;; empty
 1 [CHAR] # set-legend  ;; brick
 2 [CHAR] [ set-legend  ;; left ladder
 3 [CHAR] ] set-legend  ;; right ladder
 4 [CHAR] @ set-legend  ;; gold
 5 [CHAR] $ set-legend  ;; column, top-left
 6 [CHAR] % set-legend  ;; column, top-right
 7 [CHAR] & set-legend  ;; column, top-left
 8 [CHAR] * set-legend  ;; column, top-right

32 24 define
  .@..............................
  ................................
  ..#[]#####################[]##..
  ...[].....................[]....
  ...[].....................[]....
  ...[].....................[]..@@
  @@.[].....................[]....
  ...[].....................[]....
  ...[].....................[]..@@
  @@.[].....................[]....
  ...[]......#[]#########...[]....
  ...[].......[]............[]....
  @@.[]....@@.[]............[]....
  ...[].......[]............[]....
  ...[].......[]...........###[]##
  @@.[].......[]..............[]..
  ...[].@.....[]@@............[]..
  ...#####[]#####........@@...[]..
  ........[]..................[]..
  @@......[].............@@...[]..
  ........[].....#.#.#........[]..
  ........[]..$%.#............[]..
  .@@@@...[]..&*.#@@@@........[]..
  ################################

previous
$END_FORTH
yes, this is the actual source which can be built with the latest UrAsm. ;-)
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

eh, why don't post more videos? there is no autoplay, so why not. ;-)

collecting gold, counting score.

the demo is locked at 16 FPS (3 intrs). if i'll remove all gold, it is much faster, and closer to 18-22 FPS of XTE1. hey, R-TYPE is ok at 12 FPS, so 16 FPS for platformer with so much animation is nice too! ;-)

the score is printed directly to screen, and as you can see, Rex is correctly drawn there, no flickering. this is because the corresponding map tiles are marked as "reserved", and the engine never renders them. this is per-tile flag. there is the sound from the XTE1 demo too.
some tech rants, because i bored of coding ;-)
Rex physics engine in demo is somewhat complicated, because i want him to fall when his legs moved into the void, not when his entire bounding box did. so he's using special code to check for head and feet solids, which shifts bounding box according to different animation frames. this also means that if you can fall down from some place, it doesn't mean that you can jump back there without moving a little. not a bug, i like it this way. ;-)

internally, i am now initialising XTE tilemap and guardian table from separate data area (decompressing data by the way). also, it can't be seen in demo, but collecing each gold is recorded (in a separate room buffer), so on flip-screen action returning to the room again will correctly remove collected gold after decompressing. room compressor creates buffers of necessary size. player controller code stores XTE tilemap address to clear there, so after decompressing room data, the code simply zeroes all addresses stored in that buffer. on game reset, just zero all such buffers, and you're done.

guardian graphics, ai and bounding box is kept in a separate table ("Big List Of Guardian Types"), and that table is used to create XTE mobj structs. room guardian data contains intial coords, type, and speed.

this (data unpacking) is not part of XTE itself, it is up to user. i am preparing to flip-screen demo, so i generalized main driver code.

i somehow need to add a hack to render attributes to separate buffer, for nice room fadeins, as in XTE1. the problem is that it is rarely needed, and renderer calculates attr$ address directly from scr$. adding 3 nops there (to be replaced with CALL to attr addres fixer) costs 12ts! this is quite a lot, considering that it will be executed for each tile XTE need to render. ok, 10ts with "JP never taken", but still too much, especially looking at comments like "always taken, so 2ts win over JR" there. ;-)

the problem is that scr$→attr$ converter is 23ts one, without the final "or #58", so i don't even have an instruction to patch a new high byte there. maybe i should switch back to 26ts conversion with "or" then. or go a hard way, and overwrite the whole thing with JP temporarily. this is something i wanted to avoid, tbh, because the more code we're patching this way, the less maintainable XTE becomes. but i guess i cannot have my cake and eat it too… (sigh)
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ParadigmShifter »

If you align your shadow attribute buffer to 1024 bytes (actually, 512 bytes might be ok, 256 bytes definitely isn't) you can go from real attrib address to shadow attrib address with a single XOR. I use this when erasing sprites to copy the background attribs from the shadow buffer to replace the erased sprite attribs. You can use XOR 0 (ATTRIBS_MAGIC EQU 0) to have no shadow attribs and that is only 7T instead of 12 and no need for a call. I only use the shadow attrib buffer when erasing sprites not when drawing them though so drawing direct to screen doesn't cost any T states.

I do this in my code

Code: Select all

ATTRIBS_MAGIC	EQU #58^(attribs/256)

; pseudocode

; HL has attrib address
	ld a, h
	xor ATTRIBS_MAGIC 
	ld h, a ; HL now has shadow attrib address ; do it again to go from shadow -> real attrib address

	
; shadow attribs

	ALIGN 1024;256 doesn't work, 512 might, not too worried since I can fill the gap with other code & data anyway
attribs:
	; 768 bytes of attrib data
	; or you can have less if the window is less than 24 rows high. Must be 32 bytes per row though
the attrib buffer needs to be 32 bytes per row though otherwise it doesn't work (but you can store the HUD attribs in and unused columns so it doesn't really matter).

I use this to have a patterned background (attribs only) like so

Image

EDIT: May look like it's taking most of the frame when it places a piece but that's mainly updating the debug minimap which isn't going in the final code.
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

thank you for the idea!

but i think i will simply temprorarily overwrite attr$ calculation code with JP to the custom code, and then restore it back. after all, i only need it once on initial room rendering, so i can fadein the room. tbh, i could simply draw tiles with a separate routine (it is initial rendering, everything is dirty anyway), but i want a fadein for the room with all sprites too, it looks better this way. if not sprites, i could simply blit tile gfx directly to scr$ w/o attrs, and collect attrs in a separate buffer.

eh, XTE is full of self-modifying code anyway (mostly inlined variables, though), one more, one less…

as for attrib buffer, it should be 768 bytes for fullscreen fadein in any case (i want to show a fullscreen game in demo). i have enough memory for that, and actually i can use working tilemap as attr buffer, overwriting room data temporarily, and restoring it back from the compressed room later. i mean, when the engine renders a row, i can safely overwrite that row data with attr data. and after a fadein, just call "unpack_room" again. so hey, no extra buffers needed at all!

i'm so lucky that i don't have to write the code for some console with cartridges, where SMC is not the case… ;-)

p.s.: writing x86 asm code makes writing Z80 code much harder, btw. because with x86 i learned to avoid jumps if possible, and then with Z80 i often writing some convoluted and slow mess only to avoid a jump… and then i remember that there is no jump penalty there. ;-)
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ParadigmShifter »

I'm using erase lists and draw lists which is how I think you are doing it too (only draw things which move), although I am drawing direct to screen rather than a backbuffer, I did that with my first ASM attempt but found it a bit too fiddly to maintain the dirty buffer... obviously it's a good idea if you can't draw everything ahead of the raster though and you have a lot of sprites so that's probably not an option for you (currently I'm only updating 2x6 (16x48 pixels) active piece and 2x6 (16x48 pixels) preview piece - where your piece will land - the one with the dotted line around it, so I'm not drawing much).

You said you weren't using the stack to copy data from the backbuffer though - not sure if that's a good idea, I know you need to turn interrupts off (only if you can't copy the dirty areas of the backbuffer in a frame though? - if you start drawing immediately after the HALT). I'm turning interrupts off when drawing to be safe at the moment though - probably won't need to when it comes to release.

Advantages of using the stack:

You can probably reduce the dirty buffer size by 50% since you only need to store 16 bits per row instead of 32 (assuming your dirty buffer is 1 bit per character cell that needs updating)

You can copy 16 bits from the backbuffer if dirty at a time instead of 8

My dirty buffer implementation notes from memory:

I had a flag for "just redraw the whole screen" for level init and I think I had an array of dirty buffer cells which needed updating which was limited size (64 cells I think) and if the dirty buffer array overflowed it set the "just redraw everything" flag (which never happened in practice). That saved me clearing the dirty buffer each frame I think (was a long time ago and I was an ASM noob). So I didn't need to scan through the dirty buffer to see what had changed, I already knew beforehand (I think that was the fiddly bit to maintain though).

This is what I did for that project anyway (unfinished, code is 13 years old I think) :) I had to cap it at 25fps cos most of the time it ran at 50fps and that was too fast to be playable. A few levels drop to 17fps though, but I didn't get around to optimising.

https://spectrumcomputing.co.uk/entry/3 ... iner_Turbo

EDIT: In the GIF I posted above, border colours represent:

black: erasing the sprites
blue: drawing the sprites - if it ever reaches the top of the drawable area I need to start worrying about the order I draw things so I always beat the raster (have ideas on how to do that if it happens though - like having 3 draw/erase lists, 1 for each 1/3 of the screen for a start)
red: building erase lists for the next frame
cyan: the pointless (although good for debugging) collision minimap - this is just drawing the piece which is made up of block graphics like what the ROM does (but done in a sensible way unlike how the ROM draws them)
magenta: processing input and movement, update the piece position for next frame
green: building next frame draw list now I know where the piece ended up
red: that's animating the dotted lines around the preview piece
white: twiddling thumbs waiting for the VBLANK

when a piece is placed it does other stuff but that's all done within the frame anyway. It updates the collision map, redraws it (which is the slowest bit lol), and build the high water mark array which is where it should draw the preview piece next frame so it is above the collision - that's not very fast but faster than drawing the collision minimap ;)

I'm using the stack to blit everything... I have 2 separate blit and clear routines, one for if the 16x16 sprite crosses a screen 1/3 boundary, one for if it doesn't - can use a thunk though if I need to to only use 1 and self modify the code to do that if I need to save memory. EDIT: So I decide before I add it to the draw list if the tile crosses a screen 1/3 boundary, so I don't need to do anything to check for that whilst drawing it.

I align my blit/clear routines to a 256 bytes boundary so I can store the address to jump to in only 1 byte (low byte is always 0). That saves several jiffies when building the lists and processing them so it's a win-win situation. Also saves memory of course. I can fill in the unused space when I get bored coding and want to rearrange things and do spring cleaning :)

Current list item format (well it's an array just null terminated, not a list)

; clear list
; routine to jump to (1 byte) 256 byte aligned
; address to clear (2 bytes). I have a routine to clear 8x16 pixels as well for "half off top of screen". Also do that for drawing.
; attrib addr (1 byte) *Only need to store 1 byte since low byte comes from address

; draw list
; routine to jump to (1 bytes). 256 byte aligned
; tile address (2 bytes)
; address (2 bytes)
; attrib address (1 byte) *won't be used by some gfx drawing routines. *Only need to store 1 byte since low byte comes from address
; attributes (2 bytes) *won't be used by some gfx drawing routines
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

yeah, XTE is using backbuffer for one screen row, and rendering one row at a time. it also maintains "first dirty" and "last dirty" indicies for each row. the basic algo is like this:
each row has a "dirty span" (first/last), and list of sprites on this row. you need to "insert" each sprite before rendering. XTE then fills row lists, calculates gfx addresses for sprite printing, and such. each tile has flags in two high bits: "clean", "copy", "dirty", "ignore".
then for each row, renderer marks all tiles touched by sprites as "dirty". it then builds list of all tiles it need to process in dirty span (skipping "clean" and "ignore"). then it calls tile and sprite printers to fill backbuffer (only printing what was changed). and then it blits all tiles from "dirty list" from backbuffer to screen. it also turns "dirty" tiles to "copy", and "copy" to "clean". this way, when a sprite was moved, it will be automatically erased on next render (because "dirty" sprite tiles became "copy" ones).

the same row sprite lists are used for broad coldet phase (so we usually need to check only several sprites instead of all sprites in a room).

this way, one room can have up to 64 different tiles. more than enough, i believe, considering the fact that tile gfx addresses are taken from a separate table, so you can use different tables for different rooms.

of course, the engine spends some frame time preparing various lists, but then it saves a lot of time skipping things it doesn't need to touch at all. unchanged rows are rejected very early too, often before any scans (due to empty "dirty spans").

the video shows one of the worst cases for XTE: a lot of rows to process. yet it still manages to maintain 16-18 FPS. without tile animations, and with less sprites it can easily hit 30+. i think even close to 40, maybe 50 with only several sprites. it basically managed to hit 50FPS with one sprite and 32 animated gold bars. i believe that with 3-5 animated tiles, and 2-3 sprites it will be solid 50. i will definitely check it later. ;-)

sure, i could use ray chasing and various SP tricks, but the idea of XTE is that you don't need to do anything special to use it at all. it doesn't even use IY (and that's quite a limitation too, i really want IY to be free!). the idea is that XTE could be small enough to use it for 16K games, for example (unrealistic goal, but why not? ;-). and it should never ever mess with DI/EI, or require a custom IM2 handler.

tbh, i think that using PUSH/POP for data transfers won't help much. maybe it will allow slightly faster loading of tile/sprite gfx, but hardly something that will give a significant speedup. yet using the engine will become much trickier.

sure, if i'd need an engine for some particular game, i would prolly write something highly optimised for that game. because then i'll know all prerequisites: (rough) room layouts, sprite counts, number of animated tiles, etc. but XTE is designed as a "general tile engine", something like SP1/SP2, only faster and slightly better suited for writing tile-based games.

the idea is to have a game authoring system a-la AGD, only with masked sprites. because i HAET xor sprites with a passion. ;-) don't take me wrong, please, AGD is great, and it had to work on the same machine user is creating a game for, so it had to sacrifice some features. but now we can cross-compile everything, so why don't go wild?

i really hope to see various XTE2 games one day. people doing wonders with AGD, so if i'll give them the system with the easy to learn AGD-like language, the ability to use PC to write their code, and the way to easily customise the engine down to source code level, i hope that they will start using it. ;-) something that is as easy to use as AGD, but even more powerful than z88dk+Churera. at least that is The Plan.

maybe i'm slightly late to the show with XTE, but hey, it's worth trying anyway. besides, i'm having fun writing it too.

p.s.: i am planning to write a MaincMinerClone demo one day. (or even MiniJSWClone.) just to see how it would work. and include is as one of the example games in the final release, of course.
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ParadigmShifter »

Well I'm not using IX or IY either, only use those for menu code or if I run out of registers and don't want to push/pop. (Which I think I used once in current release of SJOE, ran out of registers in the binary search routine, used IXH instead of a push/pop). I do use the shadow registers a lot though (but I don't return to basic, so that doesn't matter, and only H'L' needs to be restored if you do IIRC).

DI and EI is fine even with the default interrupt (which is what I am using at the moment), as long as you work out what you need to draw the frame before you are going to draw it, and immediately start drawing following the HALT. As long as you can copy the entire backbuffer to screen in a frame you should be fine? (In TurboMM I did the copy backbuffer to screen in the interrupt routine lol, wouldn't do that now, that was a silly idea).

I think my game still fits within 16K at the moment I will assemble it to #6000 and see, will post a GIF if it works showing speed difference.

Of course I'm not aiming for low memory usage at the moment (but when I merge it back into SJOE I might do since I have ~16K of 4 letter words in a big array I need to keep around in uncontended memory so only have about 16K uncontended RAM remaining).

EDIT: Just about fits in 8K (ORG #6000) it's just a bit slower - had to not move the stack to address 0 as well of course

Image

Some stats about memory used and memory gaps (quite a few, so can fill them in to use less memory). Collision minimap uses at least 1K I think as well

Image

EDIT2: Surely you'll have hardly any memory at all if you use a backbuffer and want it to run in 16K? You only have 16K minus screen RAM (~7K) which is about 9K tops and even an 8 rows x 32 columns backbuffer without attribs is 2K, 4K for 16x32. I definitely can't afford a backbuffer for SJOE cos of the 16K word list thing which is why I decided early on to draw direct to screen. Current release of SJOE does not use stack shenanigans to draw though it just uses LDI etc.
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

ParadigmShifter wrote: Fri Oct 06, 2023 10:26 pm Well I'm not using IX or IY either, only use those for menu code or if I run out of registers and don't want to push/pop.
i am using IX heavily to address mobj (that's how "active objects" called in XTE; "map objects") structs. having IY free could help with bounding box collision checks, because currently the code there assuming the known structure layout, instead of using things like "LD A,(IX+XTE_MOBJ.bb_wdt)" and such.
ParadigmShifter wrote: Fri Oct 06, 2023 10:26 pm DI and EI is fine even with the default interrupt (which is what I am using at the moment), as long as you work out what you need to draw the frame before you are going to draw it, and immediately start drawing following the HALT.
only if you are absolutely sure that you can draw everything before the next interrupt arrives. otherwise BAD THINGS could happen with, for example, AY music player. and i bet people will want AY music in their games. ;-)
ParadigmShifter wrote: Fri Oct 06, 2023 10:26 pm As long as you can copy the entire backbuffer to screen in a frame you should be fine?
yeah, but there are no guarantees of that, it heavily depends on the amount of dirty areas.
ParadigmShifter wrote: Fri Oct 06, 2023 10:26 pm EDIT2: Surely you'll have hardly any memory at all if you use a backbuffer and want it to run in 16K?
one of the XTE features: only 288 bytes for backbuffer! ;-) i only need to buffer one row, because everything is rendered row by row. that's how i managed to have the engine occupy only ~4K. i mean, 4K is WITH ALL data structures (tilemap, backbuffer, render stack). fully featured engine in less memory than you need for backbuffer if you will double-buffer the whole screen! yay! ;-) and XTE can be configured to omit various unused things, so i think that it is possible to shrink it to about ~3KB (maybe even less). so i have about 6KB for game code and data. this is a lot, because XTE does all the heavy lifting already, and has many utility routines (keyboard/joystick reading, tilemap calculations, etc.). so 6KB is really a lot.

p.s. some stats about XTE:
MSG: render stack size is 472 bytes
MSG: render stack at #F987
(this is demo room stats)
uncompressed: 768
compressed: 136
MSG: DATA SIZE for 'xte_data_tilemap': 768 bytes
MSG: DATA SIZE for 'backbuffer': 288 bytes
MSG: DATA SIZE for row list headers: 96 bytes
MSG: wasted 20 bytes before tile gfx table
MSG: CORE ENGINE DATA SIZE: 1408 bytes
MSG: CODE SIZE for 'graphics': 4430 bytes
MSG: CODE SIZE for 'xte_rowlist_insert_mobj': 450 bytes
MSG: CODE SIZE for rowlist manager: 533 bytes
MSG: rstack tile optimisation active
MSG: CODE SIZE for 'xte_render_one_row': 330 bytes
MSG: CODE SIZE for tile bliter: 72 bytes
MSG: CODE SIZE for sprite bliter: 691 bytes
MSG: CODE SIZE for render code: 1216 bytes
MSG: XTE CODE SIZE: 2014 bytes
MSG: XTE DATA SIZE: 1408 bytes
MSG: XTE RSTACK SIZE: 472 bytes
MSG: XTE TOTAL SIZE: 3894 bytes
MSG: XTE PRNG SIZE: 28 bytes
MSG: XTE PRNG-CMWC SIZE: 42 bytes
User avatar
ParadigmShifter
Manic Miner
Posts: 671
Joined: Sat Sep 09, 2023 4:55 am

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ParadigmShifter »

Ah I see. If you only backbuffer 1 line yeah you will have to alternate between drawing to buffer and screen all the time I see, so turning off interrupts will be an issue then.

I assumed you were drawing everything to the backbuffer then doing the copy as soon as the HALT finishes, that's normally a good idea if you can spare the memory of course.
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

ParadigmShifter wrote: Sat Oct 07, 2023 4:49 am I assumed you were drawing everything to the backbuffer then doing the copy as soon as the HALT finishes, that's normally a good idea if you can spare the memory of course.
yeah. but XTE is designed to be small, and easy to use. speed comes third, and if i have to choose between using several KB of memory, of some slowdown, i'll chose a slowdown.

tbh, the only good thing in having a fullscreen backbuffer is that i can prepare everything in advance, and then blit it really fast, so yeah, it could mostly finish before the next interrupt. but here i will happily trade some occasional tearing for more free memory. i believe that this is mostly a non-issue in single-screen fast-paced game.

i may try to create XTE/FAST later, though, just to see how much speed i could squeeze out of it. waste a lot of memory, precalculate everything, maybe even jit-compile some parts, and then blit it really fast, using each trick in the book. but this is not a high priority right now. i have to finish the main thing first, write documentation, create compiler from a simplier lang to ASM, and so on.
Wall_Axe
Manic Miner
Posts: 500
Joined: Mon Nov 13, 2017 11:13 pm

Re: XT-Engine: small, but powerful platform game engine in asm

Post by Wall_Axe »

Do you have support for projectiles?
I suppose the rex aspect would indicate yes.
User avatar
ketmar
Manic Miner
Posts: 713
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: XT-Engine: small, but powerful platform game engine in asm

Post by ketmar »

Wall_Axe wrote: Sat Oct 07, 2023 3:58 pm Do you have support for projectiles?
wait a little. the answer is "yes", but wait a little for the new demo. it will show a lot of things you can do with XTE — including projectiles, huge explosions, particles, and so on.
Wall_Axe
Manic Miner
Posts: 500
Joined: Mon Nov 13, 2017 11:13 pm

Re: XT-Engine: small, but powerful platform game engine in asm

Post by Wall_Axe »

Thanks,I had wanted to make a game exactly like that.
Manic miner has its place but so does Michael bay type stuff :D
Post Reply