OVERRiDE Posted March 3, 2022 Share Posted March 3, 2022 Hi all, Thanks again for giving us JagStudio to empower ourselves to start developing on the Jag. I have been playing with JagStudio this week, and I am seeing a few issues with the Sprite handling that I believe are a mix of Bugs, Hardware Nuances, Feature Requests, and finally a Lack of Understanding. But putting this out there hoping to get help in finding the solution and to correct my understanding. Scaling For what I am wanting to do, scaling will be very important. The documentation indicates when a sprite is scaled, the scale factor of 32 will produce a 1:1 result, effectively producing an unscaled image. Now I have tested displaying a 4x4 grid of 32x32 pixel sprites, 16bpp, unscaled, rendered on ton top of another 4x4 grid of 32x32 pixel sprites, 16bpp, this grid is scaled with the factor of 32. The expected result is these two grids will be seamless, and of the exact same size. However the actual result is the scaled grid is not aligned with the uncsaled grid; it seems to be offset by 1 pixel on the y axis and is an extra pixel wide on the x axis. It looks like this: And what is the unit system being used on the scale factor? It seems to really behave more like a "display size" attribute from what I have tested; using a 32x32 16bpp sprite, scale factor set to 48 for x and y, results in a sprite which aligns with an actual 48x48 16bpp sprite unscaled. And similarly, using the same base sprite but setting scale factor to 63 displays a sprite which is aligned with a 64x64 pixel sprite unscaled ( scale factor of 64 seems to reintroduce the off by 1 error I mentioned above, where 63 seems a perfect 64 pixel display ). So is this really a scaling factor, as in a multiplier? If so, how do we calculate this factor from a floating point value? Culling There seems to be a Bug with the edge_kill functionality, which seems to not be taking the scaling factor into account. In this example, a scaled sprite is being culled before it reaches the near x axis of the screen. The expected result is the sprite will be visible until the left most edge of the sprite is offscreen, however it is being culled way before that. My biggest issue with edge_kill is that it does not reactivate the sprite once it is back onscreen. I believe what I really want is edge_ignore, but in this sample level I am getting very strange results using edge_ignore; this glitch does not happen with any of the other culling modes: edge_kill: edge_ignore: Does edge ignore actually "Do Nothing" in the Raptor API? I can manage sprite culling myself, but it seems like the API is overriding my active flags. Scrolling The scrolling seems to accelerate on the y axis, specifically near the top of the screen. Here I am shifting every sprite by 2 pixels each frame on button press, however near the top of the screen sprites move further away from eachother. I have tried using the rapSpriteShift function, but also wrote my own function to do this, and they actually both produce the same resutls: Notice the uniform spacing between the blocks on the left column: Now notice the top most block on the left column is no longer uniformly spaced with the other blocks: Transparency Is it possible to control what color is used for transparency, or does it have to be black? For the assets I am working with, white is used for transparency, and could save some pre-processing if we can control this through the API Rotation Does this API expose the rotation features of the Blitter? If so, how do we set this up? I think that is it for now, thanks in advance for any assistance. I can upload the project files if anybody is willing to take a closer look. Thanks! Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 3, 2022 Share Posted March 3, 2022 Hi Lets break this down. Scaliing: Bugs in the hardware shift the image/crop the image, even at 1:1 (Usually the top line of a sprite is shifted, but the left can also be shifted) Scaling is calculated as a xxx.yyyyy where xxx is the integer scale value and yyyyy are the fractional, so 00100000 is 1:1 (complete with hardware bugs) See the h/w manual for more details on the scaling bugs. Culling: RAPTOR does not take into account any scaling values when using culling. It will cull based on the original sprite size. edge_ignore does just that, it ignores the edge check. Going out of bounds will, as per the hardware, produce odd results ile wrapping, or vertically repeating bitmaps. edge_kill will not reactivate the object, it has been 'killed' (ie, set to inactive) - you will have to set its sprite_active flag manually if using this. Scrolling: (Note, you are not actually describing scrolling here) Scaled sprites will be culled at the top border accoring to their original height, so what you are seeing is normal. Transparency: Index 0 in bitmap mode is always the trans colour, regardless of the palette used. In 16 bit modes true black $000 is transparent - there is no way in the h/w to change this. Rotation: All the blitter functions are available via the blitter calls as per the latest update. There are currently no commands built in to handle rotation, however you should be able to generate a blitter command to do this using the calls. Hope that helps! CJ 4 Quote Link to comment Share on other sites More sharing options...
OVERRiDE Posted March 6, 2022 Author Share Posted March 6, 2022 @CyranoJ thank you again for your quick reply! That does help, I've worked through some of those issues but now see another problem. What I am seeing, is that if I have more that 8 sprites in a row (line) of size 32x32 at 16bpp, there is a major artifact produced on real hardware that gets increasingly worse as more sprites are displayed in that line. Hard to explain in words so I have taken some screens of what this looks like. Up To 8 Sprites in each row (horizontal line) on-screen: Looks good! Add more sprites each line and we see artifcating introduced on each row with more than 8 sprites Add even more sprites each line and we see much worse artifacting To the point where the image is unrecognizable However these issues are not present when running under emulation, everything is surprisingly fine under VJag Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 6, 2022 Share Posted March 6, 2022 Your list is too long, thats the ObjectProcessor taking longer than a scanline to process the object list chain. You really can't build a map out of tiles in a straight list without branches (or use the tilemap features of the API) Quote Link to comment Share on other sites More sharing options...
42bs Posted March 6, 2022 Share Posted March 6, 2022 I'd recommend to use the blitter to draw the background into a single object. Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 6, 2022 Share Posted March 6, 2022 32 minutes ago, 42bs said: I'd recommend to use the blitter to draw the background into a single object. The API has a fully functional tile map engine already implemented using the object processor and branch objects. Quote Link to comment Share on other sites More sharing options...
xzpecter Posted March 6, 2022 Share Posted March 6, 2022 I have had this screen tearing too. It might sound obvious, and it is documented, but scaled sprites take twice as long to process compared to unscaled sprites. If you don't need the scaling of the OP you could use pre-scaled sprites instead to get more out of the OP. Quote Link to comment Share on other sites More sharing options...
OVERRiDE Posted March 7, 2022 Author Share Posted March 7, 2022 Thank you all for your replies! I knew the Jag was going to be the most limited system I have ever develop on, but I did not think 8 scaled sprites in a row was going to be pushing the hardware boundaries lol. "You want Scaled Sprites! Heck yeah the 64-bit Atari Jaguar can do that!!!! Oh wait, you want more than 8 on a row?.... Um, no, that is impossible!" @CyranoJ I have made solid progress on my map converter already, I would really rather avoid having to convert everything to a TileMap (for more reason than 1; Precision, Animations, Specific Collision Handling, Requires Parallel Structure In-engine, etc. ). @42bs can you elaborate on your proposal? The "background" is already a single sprite ( a large sprite lol ). Its the foreground layers that are giving problems, so I am not sure I understand your feedback. As @xzpecter mentioned, in this case it seems the bottleneck is in the scaling function; I can display as many 32x32, 24x24, or 16x16 Sprites as can fit on-screen ( and more off-screen, culled ) if we disable Scaling, and no artifacts are present on real hardware! However, this is only feasible if arbitrary resolution sprites are supported, and I seem to be hitting issues for non-divisible-by-8 sprite resolutions. For example, 16x16, 24x24,32x32 pixel sprites have no problems. But if I try a 22x22 pixel sprite, it looks like garbage data. Are arbitrary resolution sprites supported? For reference, here is a snippet of the 22x22 sprite (NOT working) and the 24x24 sprite (working) ; SPRITE_22 dc.l 1 ; (REPEAT COUNTER) ; Create this many objects of this type (or 1 for a single object) dc.l is_active ; sprite_active ; sprite active flag dc.w 22*0,0 ; sprite_x ; 16.16 x value to position at dc.w 16,0 ; sprite_y ; 16.16 y value to position at dc.w 0,0 ; sprite_xadd ; 16.16 x addition for sprite movement dc.w 0,0 ; sprite_yadd ; 16.16 y addition for sprite movement dc.l 22 ; sprite_width ; width of sprite (in pixels) dc.l 22 ; sprite_height ; height of sprite (in pixels) dc.l is_normal ; sprite_flip ; flag for mirroring data left<>right dc.l 0 ; sprite_coffx ; x offset from center for collision box center dc.l 0 ; sprite_coffy ; y offset from center for collision box center dc.l 22/2 ; sprite_hbox ; width of collision box dc.l 22/2 ; sprite_vbox ; height of collision box dc.l SPRITE_022 ; sprite_gfxbase ; start of bitmap data dc.l 16 ; (BIT DEPTH) ; bitmap depth (1/2/4/8/16/24) dc.l is_RGB ; (CRY/RGB) ; bitmap GFX type dc.l is_trans ; (TRANSPARENCY) ; bitmap TRANS flag dc.l 22*22*2 ; sprite_framesz ; size per frame in bytes of sprite data dc.l 22*2 ; sprite_bytewid ; width in bytes of one line of sprite data dc.l 0 ; sprite_animspd ; frame delay between animation changes dc.l 0 ; sprite_maxframe ; number of frames in animation chain dc.l ani_rept ; sprite_animloop ; repeat or play once dc.l edge_ignore ; sprite_wrap ; wrap on screen exit, or remove dc.l spr_inf ; sprite_timer ; frames sprite is active for (or spr_inf) dc.l spr_linear ; sprite_track ; use 16.16 xadd/yadd or point to 16.16 x/y table dc.l 0 ; sprite_tracktop ; pointer to loop point in track table (if used) dc.l spr_unscale ; sprite_scaled ; flag for scaleable object dc.l 32 ; sprite_scale_x ; x scale factor (if scaled) dc.l 32 ; sprite_scale_y ; y scale factor (if scaled) dc.l -1 ; sprite_was_hit ; initially flagged as not hit dc.l 1 ; sprite_CLUT ; no_CLUT (8/16/24 bit) or CLUT (1/2/4 bit) dc.l can_hit ; sprite_colchk ; if sprite can collide with another dc.l cd_keep ; sprite_remhit ; flag to remove (or keep) on collision dc.l single ; sprite_bboxlink ; single for normal bounding box, else pointer to table dc.l 1 ; sprite_hitpoint ; Hitpoints before death dc.l 2 ; sprite_damage ; Hitpoints deducted from target dc.l 22*2 ; sprite_gwidth ; GFX width (of data) ; SPRITE_24 dc.l 1 ; (REPEAT COUNTER) ; Create this many objects of this type (or 1 for a single object) dc.l is_active ; sprite_active ; sprite active flag dc.w 24*0,0 ; sprite_x ; 16.16 x value to position at dc.w 140,0 ; sprite_y ; 16.16 y value to position at dc.w 0,0 ; sprite_xadd ; 16.16 x addition for sprite movement dc.w 0,0 ; sprite_yadd ; 16.16 y addition for sprite movement dc.l 24 ; sprite_width ; width of sprite (in pixels) dc.l 24 ; sprite_height ; height of sprite (in pixels) dc.l is_normal ; sprite_flip ; flag for mirroring data left<>right dc.l 0 ; sprite_coffx ; x offset from center for collision box center dc.l 0 ; sprite_coffy ; y offset from center for collision box center dc.l 24/2 ; sprite_hbox ; width of collision box dc.l 24/2 ; sprite_vbox ; height of collision box dc.l SPRITE_024 ; sprite_gfxbase ; start of bitmap data dc.l 16 ; (BIT DEPTH) ; bitmap depth (1/2/4/8/16/24) dc.l is_RGB ; (CRY/RGB) ; bitmap GFX type dc.l is_trans ; (TRANSPARENCY) ; bitmap TRANS flag dc.l 24*24*2 ; sprite_framesz ; size per frame in bytes of sprite data dc.l 24*2 ; sprite_bytewid ; width in bytes of one line of sprite data dc.l 0 ; sprite_animspd ; frame delay between animation changes dc.l 0 ; sprite_maxframe ; number of frames in animation chain dc.l ani_rept ; sprite_animloop ; repeat or play once dc.l edge_ignore ; sprite_wrap ; wrap on screen exit, or remove dc.l spr_inf ; sprite_timer ; frames sprite is active for (or spr_inf) dc.l spr_linear ; sprite_track ; use 16.16 xadd/yadd or point to 16.16 x/y table dc.l 0 ; sprite_tracktop ; pointer to loop point in track table (if used) dc.l spr_unscale ; sprite_scaled ; flag for scaleable object dc.l 32 ; sprite_scale_x ; x scale factor (if scaled) dc.l 32 ; sprite_scale_y ; y scale factor (if scaled) dc.l -1 ; sprite_was_hit ; initially flagged as not hit dc.l 1 ; sprite_CLUT ; no_CLUT (8/16/24 bit) or CLUT (1/2/4 bit) dc.l can_hit ; sprite_colchk ; if sprite can collide with another dc.l cd_keep ; sprite_remhit ; flag to remove (or keep) on collision dc.l single ; sprite_bboxlink ; single for normal bounding box, else pointer to table dc.l 1 ; sprite_hitpoint ; Hitpoints before death dc.l 2 ; sprite_damage ; Hitpoints deducted from target dc.l 24*2 ; sprite_gwidth ; GFX width (of data) 1 Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 7, 2022 Share Posted March 7, 2022 Quote However, this is only feasible if arbitrary resolution sprites are supported, and I seem to be hitting issues for non-divisible-by-8 sprite resolutions. For example, 16x16, 24x24,32x32 pixel sprites have no problems. But if I try a 22x22 pixel sprite, it looks like garbage data. Are arbitrary resolution sprites supported? No, the hardware requires aligned widths for the data, you can however set them to transparent and put a 22x22 in a 24x22 box. Any height is fine. 4 Quote Link to comment Share on other sites More sharing options...
42bs Posted March 7, 2022 Share Posted March 7, 2022 The OP is _not_ a sprite engine. It was not designed for this. But rather to display (independent) objects on the screen. So don't blame it on the OP if a tile based system does no work! What I meant is to draw all static parts into a single object. So you end up with the background object, the static object and maybe score and live objects. And the rest may be the moving objects. Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 7, 2022 Share Posted March 7, 2022 20 minutes ago, 42bs said: The OP is _not_ a sprite engine. It was not designed for this. But rather to display (independent) objects on the screen. So don't blame it on the OP if a tile based system does no work! Have you seen our demo of "Jumping at Shadows' ? The object processor is just fine for this kind of work if used correctly. RAPTOR API and therefore JS work this way intentionally and yes, the object processor is actually a turbo charged sprite engine. That is what it was designed for. People can of course use the blitter or the op (as the API does) neither is wrong if it works. 1 Quote Link to comment Share on other sites More sharing options...
42bs Posted March 7, 2022 Share Posted March 7, 2022 1 hour ago, CyranoJ said: Have you seen our demo of "Jumping at Shadows' ? Just did. Nice! How many objects at the same time? 1 hour ago, CyranoJ said: That is what it was designed for. I heard/read it differently. But, hey, if you use the machine as it is designed for, you end up with Cybermorph 2 Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 7, 2022 Share Posted March 7, 2022 159 objects at the moment... you made me do math, you bad man 159 is low compared to some other games (likely Super Burnout destroys this), but then they don't have three layers of them covering the entire screen hehe. Check out FaCTs for an insanely long object list! 3 Quote Link to comment Share on other sites More sharing options...
OVERRiDE Posted March 10, 2022 Author Share Posted March 10, 2022 On 3/6/2022 at 10:00 PM, 42bs said: The OP is _not_ a sprite engine. It was not designed for this. But rather to display (independent) objects on the screen. So don't blame it on the OP if a tile based system does no work! What I meant is to draw all static parts into a single object. So you end up with the background object, the static object and maybe score and live objects. And the rest may be the moving objects. Umm... yeah... according to the docs the Object Processor is a sprite engine... and then some I guess lol. In practice what it is not is a sprite scaling engine that is able to handle sprite scaling at a decent throughput. I'd bet the Sega CD hardware is probably better than this ( I have 0 experience on that hardware, just a guess ). Literally a 8 scaled sprites in the same horizontal line will break the OP. However as @xzpecter offered, disable scaling and the throughput is much, much better. In my use cases we are talking more than 2x the throughput he referenced. Quote Link to comment Share on other sites More sharing options...
OVERRiDE Posted March 10, 2022 Author Share Posted March 10, 2022 @CyranoJ speaking of Jumping At Shadows, this is looking excellent, I will be a customer of yours once this is completed! And thanks again for the detail, good to know the pixel alignment is only strict on the X-axis, we do have some freedom on the Y-axis ( this is important for non-square sprites ). I am still seeing some issues, maybe user error but also maybe bugs with the JagStudio / Raptor API. Mostly these are related to the handling of "active" sprites. edge_kill - I believe this is a bug; using edge_kill will permanently remove a sprite from display. Even if I manually set EVERY sprite as R_is_active before each vsync. Expected result is we are able to see every "active" sprite on-screen. But the actual result is that even "active" sprites which have been culled in previous frames via edge_kill are no longer visible. vsync - If we submit an empty list ( all sprites are culled / not active ) we still see the display from the most recent frame which was not empty. Expected result is we see nothing on screen. There seems to be sprite retention of non-active sprites. Its hard to explain but is similar to the note above; sometimes a sprite which is not-active is still visible on screen I can provide whatever sources you need to reproduce these cases. Thanks again for all of your efforts! Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 10, 2022 Share Posted March 10, 2022 edge_kill is working corectly in the API, this might be a JS issue or could be your code - can we see it? vsync - this is also correct, as setlist will set the list and return, but any changes between the last writes to the objects and the previous raptor handler call won't have been processed. There is an update-offscrene-list call to fix this, so you can force a list update before making it visitble. the first object in any list has to be active, if it isn't, odd things will happen. Would need to see the code to help further. Quote Link to comment Share on other sites More sharing options...
OVERRiDE Posted March 11, 2022 Author Share Posted March 11, 2022 @CyranoJ thanks again for the reply. Here is a demo which is using edge_kill, but is setting every sprite active every frame. I would expect every on-screen sprite to be visible, however if a sprite ever gets killed it will never be visible again. You can reproduce this by using the d-pad to move the world around and see once a sprite is culled, it remains culled even though I am setting it active. Also including edge_ignore.rar which is a patch to apply to the main archive; in this build I am using edge_ignore and culling the sprites outside of Raptor ( overly aggressive to ensure its working as expected, can adjust the min and max values in spritemovements.c to set to full screen bounds ). In this build we do not get the same error that we see using edge_kill. So obviously I have a workaround, just reporting this as it does appear to be a bug in JagStudio. As far as the other issues, most likely they are due to having the first object in the list become inactive as you mentioned. What is the normal way to manage this, just adding a dummy, fully transparent sprite at the start of the list? 2D_Test_1.rar edge_ignore.rar 1 Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted March 12, 2022 Share Posted March 12, 2022 OK, spent a while looking at this, and I believe you have found an undocumented feature bug! - workaround - set the x/y co-ordinates again when re-activating the object. Before auto-object culling was introduced to remove objects from the list the engine used to set culled objects offscreen. It appears it is still doing the co-ordinate change even though the culling is working. Thank you for this! Appreciate the feedback, I will try and correct in an upcoming release. 2 Quote Link to comment Share on other sites More sharing options...
OVERRiDE Posted March 12, 2022 Author Share Posted March 12, 2022 Okay think I finally have the majority of issues worked out with the rendering, manually handling things that JagStudio has Bugs with, and working with the OP as much as possible by applying scaling and rotation to the Sprites as a part of my level conversion process. Things are working on real hardware, and is actually much smoother on real hardware compared to emulator. I've attached another build, same demo as before but a step forward with the map conversion now handling scaling and rotation. Next steps: start working on gameplay! 2D_Test_1_cave1b.rar 7 Quote Link to comment Share on other sites More sharing options...
Clint Thompson Posted October 29, 2022 Share Posted October 29, 2022 @OVERRiDE how's the game coming along? Quote Link to comment Share on other sites More sharing options...
OVERRiDE Posted November 9, 2022 Author Share Posted November 9, 2022 On 10/28/2022 at 11:25 PM, Clint Thompson said: @OVERRiDE how's the game coming along? Abandoned lol. If you can't tell, my idea was to write a Mario clone using Secret Maryo Chronicles game assets. A sort of port of that game, but essentially a rewrite for the Jag. But it turns out the OP really struggled with being used as a sprite engine, and hit massive slowdowns on even the first level of the game towards the later part where the screen is mostly full of sprites. Ive sampled many levels of the game and the majority of them just have too many sprites on screen at once for the Jag to cope with. For the record, I had my level converter pre-scaling and pre-rotating all of the sprites, and using GPU culling of off-screen sprites (via raptor) so there was no more optimization that could be done for a sprite engine that I can see. Any other path forward would be a tremendous time suck that I cant afford. My hats off to the masochistic devs here who invest their time trying to push this brutal platform. I am a software engineer by trade, but it seems you also need to be a hardware engineer to really get anything meaningful out of the Jag. For me, this was a neat exercise, but found little besides headache working on this system lol. I've tapped out and have moved on. Quote Link to comment Share on other sites More sharing options...
42bs Posted November 9, 2022 Share Posted November 9, 2022 Are you using the 68k? If so, switch over to GPU only and stop the 68k. You gain plenty of cycles. 1 Quote Link to comment Share on other sites More sharing options...
Sporadic Posted November 9, 2022 Share Posted November 9, 2022 If you're drawing tiles individually then it would be worth trying some branch objects too. Or utilise the tilemap engine in Raptor (which also uses branches). 1 Quote Link to comment Share on other sites More sharing options...
+CyranoJ Posted November 9, 2022 Share Posted November 9, 2022 You need to use the tile map functions and not try to chain 120+ sprites in a line. Raptor can easily handle this. 4 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.