Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by svenvandevelde

  1. I will contact you on discord @Wavicle.
  2. Very true however, then the figures are either very flat or very wide, unless i'm misunderstanding thefeedback. But yes, this has crossed my mind and will use these in the game. For lasers or for structures like walls with lasers etc.
  3. May it also be noted, that the sprite registers have a lot of unused areas, like register 3 and 5. There are free bits which potentially could be used by vera for further settings. @Wavicle.
  4. Thanks Ed. I read your mail with great interest. Probably yes, but not convinced. Allow me to reflect my thinking about this idea a bit further, let's talk about complexity elements, like heap manager, cpu overhead, code size and data size... Complexity factors to be taken into account: Copying the image data (in my case 1152 bytes) onto those asymetrically distributed sprites.... For a 48x48 I would paint a 32x32; 32x16; 16x32; 16x16. This combination gives the most memory efficiency. Selecting which sprite offsets to use... It matters as sprites with offsets lower in memory are painted above sprites with offsets higher in memory. So when sprites overlap each other, in my case enemies, you want to have enemies showing a consistent overlap and not one part overlapping while an other part appears behind the sprites. So the sprite offsets to be selected carefully. Maybe the offsets even have to be sorted, which also takes CPU time. Moving the sprites.... moving gets more overhead on the CPU. Imagine 16 enemies on the screen moving. Each enemy having 4 sprites. Moving for my case, means 2 things: x and y axis plus animation image updates. So that would mean 4 (sprites) times 4 (x/y) times 2 (image offset addresses) times 16 bytes to be updated every frame. It's not that the cx16 cannot pull this at 8Mhz, it can do this easily, but it adds CPU time per frame. These things can be done but it gives extra CPU overhead and extra code to manage all this. The heap manager in combination with the lru cache can help greatly with dynamically allocating those sprite image parts. However: Each image part would have a handle pointing to the place on the heap, which again consumes memory. Instead of one handle the logic now needs to reserve more handles pointing to the images per sprite. I would need to put an extra layer to manage the lru cache. Since sprites are composed out of multiple images, the elements in the lru cache should point to an array of image offset handles, and not to the handles itself ... Allocating sprites on the heap and memory checking becomes more labour intensive. A sprite with 16 animations in a 48x48 setup results in 64 images allocated on the heap, thus 64 heap manager index entries. For speed reasons the vera heap manager indexes are only one byte long. A maximum of 255 images can be stored in the heap manager because NULL value is also required. That would mean a maximum of 4 enemies (having 16 animation frames). No ... 3 enemies as the heap also manages player, bullets, particles, weapons, ground installations. Maybe even 2 enemies maximum possible. Or the heap manager should have 16 bit indexes increasing memory and decreasing speed. So it looks like the heap manager index size would become an issue. In fact, not really. In the current setup, the heap manager really helps and it is very efficient. I would say a very little CPU overhead, some code overhead and some data overhead. Regarding overhead: The vera heap manager from a code perspective is about 0x600 bytes for the core heap functions. However, the heap needs data which adds another 0x0800 bytes. The indexes are managed in banked ram. The lru cache is also an object that requires code and memory. It consumes about 0x0400 bytes of code, and the lru heap is located in main memory in address 0x0400. It consumes only 0x01FF bytes. sv.
  5. Very cool feedback, yes, probably you are right and the 8px is required as a sprite map. It would be great if the vera would allow to configure the sprite map sizes somehow with a bit map flag, just as @AndyMt already indicated. Your suggstion to blow up the 32px is a good one. Or to reduce the 64px. I think a "dynamic solution" would be the best maybe.
  6. @ZeroByte This is the lru cache in action ...
  7. I have 2 things implemented in this algorithm ... A "least recently used cache or LRU cache", that monitors which was the vera image that was least recently used. The index (handle) pointing to the images are dynamically allocated in VRAM through a heap manager. So, when the drawing engine is trying to draw an image of a sprite, it checks if this sprite image is already in the lru cache. If it is in the lru-cache, it will just re-use the image already in VRAM. If it is not in the lru cache, it will loop ... until the required image can be put into vram. How? It loops, freeing the last image in the lru cache (so the least recently used image) from vram. It deletes this entry from the lru cache and then frees the image from vram. Then it tries to best-fit the new image in vram (it checks if there is space for it). If that best-fit search fails, (due to the least recently used image freed space made available being too small), it retries freeing the least recently used image from the lru cache and freeing vram of that image. This until the image could be successfully best fitted in vram by the heap manager, and then the image is copied into the vram dynamically, and added to the lru cache as the most recently used image. Images are copied from BRAM into VRAM using indeed, some sort of a copy funciton, which i worked on very hard to get it optimal. I still need to work on this copy module. See below the lru cache core utilization logic for managing the images. vera_sprite_image_offset sprite_image_cache_vram(fe_sprite_index_t fe_sprite_index, unsigned char fe_sprite_image_index) { // check if the image in vram is in use where the fe_sprite_vram_image_index is pointing to. // if this vram_image_used is false, that means that the image in vram is not in use anymore (not displayed or destroyed). unsigned int image_index = sprite_cache.offset[fe_sprite_index] + fe_sprite_image_index; // We retrieve the image from BRAM from the sprite_control bank. // TODO: what if there are more sprite control data than that can fit into one CX16 bank? bank_push_set_bram(fe.bram_sprite_control); heap_bram_fb_handle_t handle_bram = sprite_bram_handles[image_index]; bank_pull_bram(); // We declare temporary variables for the vram memory handles. lru_cache_data_t vram_handle; vram_bank_t vram_bank; vram_offset_t vram_offset; // We check if there is a cache hit? lru_cache_index_t vram_index = lru_cache_index(&sprite_cache_vram, image_index); lru_cache_data_t lru_cache_data; vera_sprite_image_offset sprite_offset; if (vram_index != 0xFF) { // So we have a cache hit, so we can re-use the same image from the cache and we win time! vram_handle = lru_cache_get(&sprite_cache_vram, vram_index); vram_bank = vera_heap_data_get_bank(VERA_HEAP_SEGMENT_SPRITES, vram_handle); vram_offset = vera_heap_data_get_offset(VERA_HEAP_SEGMENT_SPRITES, vram_handle); sprite_offset = vera_sprite_get_image_offset(vram_bank, vram_offset); } else { // The idea of this section is to free up lru_cache and/or vram memory until there is sufficient space available. // The size requested contains the required size to be allocated on vram. vera_heap_size_int_t vram_size_required = sprite_cache.size[fe_sprite_index]; // We check if the vram heap has sufficient memory available for the size requested. // We also check if the lru cache has sufficient elements left to contain the new sprite image. bool vram_has_free = vera_heap_has_free(VERA_HEAP_SEGMENT_SPRITES, vram_size_required); bool lru_cache_not_free = lru_cache_max(&sprite_cache_vram); // Free up the lru_cache and vram memory until the requested size is available! // This ensures that vram has sufficient place to allocate the new sprite image. while(lru_cache_not_free || !vram_has_free) { // If the cache is at it's maximum, before we can add a new element, we must remove the least used image. // We search for the least used image in vram. lru_cache_key_t vram_last = lru_cache_last(&sprite_cache_vram); // We delete the least used image from the vram cache, and this function returns the stored vram handle obtained by the vram heap manager. vram_handle = lru_cache_delete(&sprite_cache_vram, vram_last); if(vram_handle==0xFFFF) { gotoxy(0,59); printf("error! vram_handle is nothing!"); } // And we free the vram heap with the vram handle that we received. // But before we can free the heap, we must first convert back from teh sprite offset to the vram address. // And then to a valid vram handle :-). vera_heap_free(VERA_HEAP_SEGMENT_SPRITES, vram_handle); vram_has_free = vera_heap_has_free(VERA_HEAP_SEGMENT_SPRITES, vram_size_required); } // Now that we are sure that there is sufficient space in vram and on the cache, we allocate a new element. // Dynamic allocation of sprites in vera vram. vram_handle = vera_heap_alloc(VERA_HEAP_SEGMENT_SPRITES, (unsigned long)sprite_cache.size[fe_sprite_index]); vram_bank = vera_heap_data_get_bank(VERA_HEAP_SEGMENT_SPRITES, vram_handle); vram_offset = vera_heap_data_get_offset(VERA_HEAP_SEGMENT_SPRITES, vram_handle); memcpy_vram_bram(vram_bank, vram_offset, heap_bram_fb_bank_get(handle_bram), (bram_ptr_t)heap_bram_fb_ptr_get(handle_bram), sprite_cache.size[fe_sprite_index]); sprite_offset = vera_sprite_get_image_offset(vram_bank, vram_offset); lru_cache_insert(&sprite_cache_vram, image_index, vram_handle); } // We return the image offset in vram of the sprite to be drawn. // This offset is used by the vera image set offset function to directly change the image displayed of the sprite! return sprite_offset; }
  8. Just tested alpha channel in 16 colors in aseprite. It looks kinda ok like this ... the palette can deal with it.
  9. Yeah, but if you think about it, not an option really. Alpha channels in a 16 color palette are hard. I mean, it woudl only make sense in 8bpp, right? And then you are full resolution of sprites with full bit depth. So a 64x64 sprite would be 4096 bytes. That is one sprite image, to be clear. So 0x1000 hex. If I want to animate 16 of those sprites, i would need 0x10000 or 65536 bytes in vram lol. That being said, alpha channels would be great to have for fire effects, like bullets, lighting, lasers etc. For thos bitmaps, which are naturally of smaller size, this would be a great feature to have. The CX16 indeed has its limitations and we live with it. It is just finding the borders of the machine and using them optimally. That is the challenge, and it has been a real journey so far for me ...
  10. One more note, since the cx16 doesn't have dma, every memory movement is down to the processor. Moving memory is fast, but moving 4096 bytes every frame is not an option (so i cannot use 64x64 in 8bpp) for animations, bottom line. Note that the video shows animations of two 64x64 sprites floating.
  11. You read my mind. This is an interesting hobby and you have understood my approach perfectly. Now ... since we are here ... Check on the video the 48x48 images. These are in vram on a 64x64 bitmap. Waste of memory? This is beyond the heap management approach :-). I have considered also the approach to draw multiple sprites and have some sort of "sprite painter" algorithm, that would paint the image to 4 or 9 sprites or so. But the issue then is the overhead of moving the sprites, on top of all the other logic. Just dunno what is the best. Also i am thinking of a heap compactor/defragmenter, and an approach to position the 64x64 bitmaps from the top of the heap to the botton, so that fragmentation only occurs in the lower parts. The issue that i have is that i paint too many image animations that cannot be fit into the vera vram at the same time. Obvious solution is to limit the amount of animation frames which i am implementing now. But if there would be a 48x48 size, then i would be able to fit almost the double of animation frames in vram. Bascially i use vram as a cache, which is dynamically updated upon demand.
  12. I have written in my original post exactly what ZeroByte has expressed, pls check the sentences below. Also i replied to the feedback of ZeroByte. What i'm trying to say, is that a 64x64 sprite size is quite large, and there is no size in between. I am not trying to request to change the machine, and it is upon much more people to judge if chaning it would be an option or not. Then why Wavicle is doing changes that are accepted by Frank? And why is Frank replying to my posts about transparency, that such would be possible to implement? Because maybe, just maybe, there is a valid reasoning that may improve the machine, and that might result in a better system overall, over time. If changing the machine is not an option, then fine, so be it. At least I've raised it and it is up for the community to consider. Latest changes by @Wavicle were accepted by Frank though. Also, Frank replied to me that alpha channels in bitmap rendering would be an option according to him also. Alpha Channel · Issue #3 · fvdhoef/vera-module (github.com)
  13. Nicely done! Great demo! However, it is not what I was looking for. I also expressed myself a bit bluntly I see upon your feedback. What I wanted to express is the vram memory consumption issue. Pls check my video if you have the time to see the challenge ... We are going waaaay beyond the scope of this post.
  14. I hope this clarifies a bit what i meant to say ... look at video around 2:30... https://screencast-o-matic.com/watch/c36ebrVtI3J
  15. As I wrote earlier: But thank you for the suggestion. Indeed, it is a good method to do and this would be a solution. However, it would make things way more complicated. I've posted a video below that shows what is in the make. This is way past a demo. It is an actual game, with lots of enemies and thus, sprites ... I want to render them as one object, but will combine the player sprite with additional modules picked up on the flight. However, for the enemies, if i need to model those also, then i am looking at a project to be release in 2 years ... Think the 48x48 is the viable option in my opinion, but only if doable technically. Actually, it would be great if vera would have some function to set the scales of sprites by the user.
  16. Do what i'm doing with vera and then you will see that it is not that simple. And 128x128 would be great, but impossible to manage at acceptable frame rates, as vera and cx16 don't have dma.
  17. I suggest to model it that the high resolution 640 width supports 16, 32, 48, 64 resolutions. And the lower resolution 320 supporting 8, 16, 32, 48? lol
  18. This idea would be a fantastic solution. Other could be that the scheme adapts based on screen width/height setting?
  19. Hi, Before you read further, please keep in mind that this post is not meant to pose any critic to Frank VdH or to the overall design of the CX16 regarding its graphics capabilities ... However, allow me to reflect the followiing ... Using vera in 640x400 graphics mode, there is a function in vera which I believe which could be further fine tuned ... It is the setting of the height and width of sprites ... Sprites can be configured as 8, 16, 32 and 64 width and height by setting the respective bits in register 7 of the sprite attributes... I find the width and height of 64 however a bit too big of a gap. Hopping from 8 to 16 is ok, from 16 to 32 is ok, but from 32 to 64 means that in terms of memory consumption there is a big increase ... Let me illustrate: 8 x 8 in 4bpp requires 32 bytes. 16 x 16 in 4bpp requires 128 bytes. 32 x 32 in 4bpp requires 512 bytes. 64 x 64 in 4bpp requires 2048. In 8 bpp that would be a whopping 4096 bytes! My question is, what if the vera would model the sprite painting with the following width registers: 16, 32, 48, 64, and discard the 8 pixel width and height setting. That would mean, that the following mode would become available: 48 x 48 in 4bpp requires 1152 bytes, in 8bpp that would be 2304 bytes. Additionally: A sprite width/height of 32 x 32 is too limiting, it does not draw sprites with sufficient size. It is a bit too small. A sprite width/height of 64 x 64 is big, which is great, but it consumes too much memory. These kind of sprites would have a more limited animation count to save memory. A sprite width/height of 48 x 48 would be a great size, as this would not consume too much memory, but would show sprites with sufficient pixel size. Please see examples below: Above is an example of a 48 x 48 sprite animation... Above is an animation of a 32 x 32 animation, great but a bit small. However, this size is perfect to flood the screen with enemies :-). But the density to show sprite animations is limited and the width/height quickly becomes obvious to the player that 32x32 is the limit as all sprites will be in this size ... Above shows 64 x 64 sprites animation, great for larger type of enemies, but consumes a lot of space. The 48 x 48 sprite size seems to be the right fit, a 64 x 64 is needed, but consumes a lot of memory. Drawing a 48 x 48 sprite animation results in a lot of vram memory being lost, due to having to draw this 48 x 48 sprite animation on 64 x 64 planes. One could argue, that yes, we can do magic and start combining sprites to make larger pictures to draw a 48x48 bitmap, like drawing 9 16x16 sprites, or 1 sprite of 32x32 + 1 sprite of 16x32 + 1 sprite of 32x16 + 1 sprite of 16x16 ... But that would make things very, very complicated, and also notice by having to draw 9 or 4 sprites instead of one, there is a performance impact. Also notice, that if I would draw a 48x48 sprite out of 9 sprites of 16x16, that would mean 72 sprites to be drawn if i want to show 8 images of 48x48 pixels! Any thoughts on this? @Wavicle?
  20. Thanks for the suggestions but looking for the real deal ...
  • Create New...

Important Information

Please review our Terms of Use