An RPG on Uzebox

Use this forum to share and discuss Uzebox games and demos.
User avatar
Jubatian
Posts: 1561
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: An RPG on Uzebox

Post by Jubatian »

nicksen782 wrote: Sun Aug 12, 2018 5:22 pmI've got the memory swaps working. I have a question about FS_Get_Pos() and FS_Set_Pos(). Do they store the start position of the file or do they store a position within a file?
Position within a file. So if you have a filesystem structure set up to read the file, you can jump around in that file using positions obtained by these functions. This may become important in games with huge data files (several megabytes), since with FAT, you can only seek from the beginning, and forward, which is slow if you need something far inside the file (at every cluster boundary, the FAT has to be checked for the next cluster's location, so for example to position at 1Mb in a file with a typical cluster size of 4K requires 256 SD sector reads). So if you have a multi-megabyte data file, you might need this to cache positions to reduce loading times.
nicksen782 wrote: Sun Aug 12, 2018 5:22 pmWhat is t32 here? Is this the first cluster of the file? I just want to make sure since it appears that way and it is not part of sd_struct.
What it exactly is isn't that important, rather how it has to be used. Normally it is indeed a cluster, but if only the old bootloader is present, that will actually be a sector (as the fragmentation-unaware code doesn't even have the concept of clusters). You get this value by FS_Get_File_Cluster() or FS_Find, to use it as a parameter to FS_Select_Cluster to start accessing a file. Of course you can store it away during the game, but you shouldn't ever save it into a data file or EEPROM (regardless of the bootloader, the file might be elsewhere on the card next time).

So combined with the above, if you want to cache multiple files and pointer within them during a game, you stash away the cluster obtained by FS_Get_File_Cluster() or FS_Find() to allow you quickly selecting the file again any time later by FS_Select_Cluster(). If your files are large, you can use FS_Get_Pos() to extract positions other than the beginning of the file, which you can stash away for later use by FS_Set_Pos(). When using FS_Set_Pos(), the correct file has be selected with FS_Select_Cluster() first (regard them like fancy offsets into the file which have no meaning without the right file being selected, also, don't save these either to permanent storage).
nicksen782 wrote: Sun Aug 12, 2018 5:22 pmLet's say you seek to a sector (multiple of 512) and you want byte 500. You would need to get that whole sector and skip bytes until byte 500, right? It looks like the sector gets written to ->bufp. Could I just do sd_struct.bufp[500]? Again, I just want to make sure.
Yes, that's it.
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: An RPG on Uzebox

Post by nicksen782 »

Updates:

I need a memory manager with swapping abilities. Presently I am working on this and using SPIRAM as a sort of page file. I could dedicate portions of SPIRAM to use something like "slots". Perhaps a number of slots where the size is the size of vram, and maybe some other smaller slots.

Memory fragmentation comes to mind right away. But really, if your slots are of expected size then couldn't an existing one be used that is no longer in use just be overwritten?

I'm actually doing that for an unannounced game. Basically, when a new enemy sprite needs to be drawn the system just looks for the very next slot that is designated as available. All slots being the same size. That way, enemies are not locked into specific slots. Neither are the good guys either.

A 25x20 tile vram would be 500 bytes. I've been using 28x28 (784 bytes) for the game thus far. I may change this to save some more ram.

Code: Select all

// To take a snapshot of vram.
SpiRamWriteFrom(0, 0, &vram, (VRAM_TILES_V*VRAM_TILES_H) );

// To restore vram back.
SpiRamReadInto (0, 0, &vram, (VRAM_TILES_V*VRAM_TILES_H) );
You can use SetRenderingParameters, FadeOut, and FadeIn to increase performance.

QUESTION 1. If you wanted to iterate through vram you could use a for loop. But, what if you wanted to iterate through SPIRAM with a for loop? This sounds like a terrible idea from a performance prospective but it may not be so bad if you do something like a SetRenderingParameters(1, 1) first. I know that a local ram buffer is probably best. Perhaps buffer a row or a block of tiles. I was hoping to be able to queue some vram screens stored in SPIRAM. What do you think?

QUESTION 2. The variables ram_tiles and vram are set and remain set for the entire program. They cannot be resized. You can go smaller than max but you can never go over the max. What if this were not the case? What if, as needed, I could expand and contract both vram and ram_tiles? They are the largest users of ram. What if I had a small vram that gave me enough ram to do it 100% ram tile and I could load that data from SPIRAM (video?) I already know that I can use pointers to existing memory arrays (such as ram_tiles) and store normal variables there. I can also swap things in and out. What if both vram and ram_tiles could be pointers into the same large chunk of ram but at different points? And then have another variable that determines how long each of those are?

... Looking forward to seeing the completed Uzebox portable!
User avatar
Jubatian
Posts: 1561
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: An RPG on Uzebox

Post by Jubatian »

nicksen782 wrote: Wed Oct 03, 2018 3:22 pmQUESTION 1. If you wanted to iterate through vram you could use a for loop. But, what if you wanted to iterate through SPIRAM with a for loop? This sounds like a terrible idea from a performance prospective but it may not be so bad if you do something like a SetRenderingParameters(1, 1) first. I know that a local ram buffer is probably best. Perhaps buffer a row or a block of tiles. I was hoping to be able to queue some vram screens stored in SPIRAM. What do you think?
If possible (you don't want to iterate to do something for each tile, just to copy stuff between VRAM and SPI RAM), use SpiRamReadInto() and SpiRamWriteFrom() from the SPI RAM library. Those are optimized for performance. Otherwise if you want to do processing, you could interleve by using the various sequential read or write functions. I think you shouldn't do a SetRenderingParameters(1, 1), just that line 1 isn't exactly a visible line, so it may mess up the video signal. Use at least 20 for the starting line. You may see some losses of sync with this as in the current kernel the algorithm behind this function isn't very well implemented.
nicksen782 wrote: Wed Oct 03, 2018 3:22 pmQUESTION 2. The variables ram_tiles and vram are set and remain set for the entire program. They cannot be resized. You can go smaller than max but you can never go over the max. What if this were not the case? What if, as needed, I could expand and contract both vram and ram_tiles? They are the largest users of ram. What if I had a small vram that gave me enough ram to do it 100% ram tile and I could load that data from SPIRAM (video?) I already know that I can use pointers to existing memory arrays (such as ram_tiles) and store normal variables there. I can also swap things in and out. What if both vram and ram_tiles could be pointers into the same large chunk of ram but at different points? And then have another variable that determines how long each of those are?
This is the domain of my video mode designs where such are often possible. It wouldn't be easy to modify Mode 3 in such a manner that it supported such while retaining compatibility with existing games (so they could be recompiled with newer kernels if needed). So for now you are pretty much left with swapping in and out stuff.
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: An RPG on Uzebox

Post by D3thAdd3r »

Realistically, you don't want to do nasty stuff like I tried in Columns which was hard coded to individual tiles(some of that is unavoidable, the crazier you "need" to get). Because the loading and moving is by far the most expensive part, I recommend considering a sort of script thing. I found things like that to be diminishing returns on development time pretty quickly, but an RPG might be a different pay off. Find the common requirements of everything you are looking to do, and make an FSM to run sequences of commands from the SD image that can do all of it. Just my $0.02, it really depends on the particular requirements versus the time to implement it. Development time available will always end up more limited than the actual 644 possibilities!
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: An RPG on Uzebox

Post by nicksen782 »

Scripting is a great idea. Here is a question though. How would I do the actual scripting? I mean, lets say the script would run 5 functions. How do I run those functions? I could perhaps create an array of function pointers and call functions by the array index (assuming the signature is the same.)

Is there an "eval" in C like there is in Javascript? PHP has "call_user_func_array($theFunction, $theArgs);". Any ideas?

I'll be making the screen size a bit smaller to save on ram. I'll consider increasing it towards the end of the game if feasible.
User avatar
Jubatian
Posts: 1561
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: An RPG on Uzebox

Post by Jubatian »

nicksen782 wrote: Mon Oct 08, 2018 2:02 pmScripting is a great idea. Here is a question though. How would I do the actual scripting? I mean, lets say the script would run 5 functions. How do I run those functions? I could perhaps create an array of function pointers and call functions by the array index (assuming the signature is the same.)
Think of something like a BASIC interpreter. It is just code processing some kind of data, this case the data describing various operations. You will need to implement a small virtual machine to run it, for example if you want real functions in your script language, you need a concept of stack where you can push return addresses (positions in the script where execution should continue when the function returns). Flight of a Dragon's music engine is actually a three threaded scripting language with 3 levels deep stack per thread, allowing all the music occurring in the game (if you completed it, there is also an endgame tune) to consume less than 500 bytes.

Jump tables, which in C can be implemented as an array of function pointers can indeed be useful if you plan your language accordingly, having operation selector bits for example which can be translated into an index to this array.
Post Reply