Skip to main content

News

Topic: Function to save a spriteset (for miniSphere) (Read 399 times) previous topic - next topic

  • Rhuan
  • [*][*][*][*]
Function to save a spriteset (for miniSphere)
A bit of JS I wrote as a workaround as miniSphere has no function to save a spriteset thought I'd share it in case anyone else needs to edit and save spritesets with JS and wants to work in miniSphere. I haven't made a spriteset creation function as you can just have a template spriteset you open to start with. Note this is kinda slow for large spritesets (particularly the image saving) but I couldn't think of another way to do it.

Code: [Select]
function save_sprite(sprite, filename)
{
  var file = OpenRawFile(filename,true);
  //header data - commented where not self explanatory
  file.write(CreateByteArrayFromString(".rss"));//file signiture
  Write_16Word(3, file);//rss version number - always 3
  Write_16Word(sprite.images.length, file);
  Write_16Word(sprite.images[0].width, file);
  Write_16Word(sprite.images[0].height, file);
  Write_16Word(sprite.directions.length, file);
  Write_16Word(sprite.base.x1, file);
  Write_16Word(sprite.base.y1, file);
  Write_16Word(sprite.base.x2, file);
  Write_16Word(sprite.base.y2, file);
  file.write(CreateByteArray(106));//blank space needed by format
  /*this next bit is horrid (it works but it's super slow) the format
  requires 4 bytes per colur in rgba order not aware of any other way
  to do it with sphere's available functions:( */
  var temp_s;
  var col;
  var temp_c = CreateByteArray(1);
  for(var i = 0,x=0,y=0; i < sprite.images.length; ++ i)
  {
    temp_s = sprite.images[i].createSurface();
    for(y=0;y<sprite.images[0].height;++y)
    {
      for(x=0;x<sprite.images[0].width;++x)
      {
         col = temp_s.getPixel(x,y);
         temp_c[0] = col.red & 0xff;
         file.write(temp_c);
         temp_c[0] = col.green & 0xff;
         file.write(temp_c);
         temp_c[0] = col.blue & 0xff;
         file.write(temp_c);
         temp_c[0] = col.alpha & 0xff;
         file.write(temp_c);
      }
    }
  }
  //Direction data - this is easier
  //the CreateByteArray calls are for padding the format needs
  for(i = 0; i<sprite.directions.length; ++ i)
  {
    Write_16Word(sprite.directions[i].frames.length,file);
    file.write(CreateByteArray(6));
    Write_16Word(CreateByteArrayFromString(sprite.directions[i].name).length,file);
    file.write(CreateByteArrayFromString(sprite.directions[i].name));
    for(x=0;x<sprite.directions[i].frames.length;++x)
    {
      Write_16Word(sprite.directions[i].frames[x].index,file);
      Write_16Word(sprite.directions[i].frames[x].delay,file);
      file.write(CreateByteArray(4));
    }
  }
  file.close();
}

function Write_16Word(word, file)
{
  var array_of_integer      = new Array();
  array_of_integer[0]       = (word & 0xff00) >> 8;
  array_of_integer[1]       = (word & 0x00ff);
  var byte_array_of_integer = CreateByteArray(2);
  byte_array_of_integer[0]  = array_of_integer[1];
  byte_array_of_integer[1]  = array_of_integer[0];
  file.write(byte_array_of_integer);
}

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • miniSphere Developer
Re: Function to save a spriteset (for miniSphere)
Reply #1
Nice, although you didn't have to write your own Word16, you could have used a FileWriter, e.g.:

Code: (javascript) [Select]

const FileWriter = require('struct').FileWriter;

var stream = new FileStream(filename, FileOp.Write);
var file = new FileWriter(stream);

file.writeString('.rss');
file.writeUint16(3);
file.writeUint16(sprite.images.length);
// etc.


The pixel-by-pixel access is indeed going to be slow, since the surface is a hardware texture and you're asking the graphics card for one pixel at a time.  But you're right that there's no other way to get at the raw image data, at least not in the format needed (even if you pull the whole thing from the graphics card, the pixels won't be in the right order and there will be unnecessary padding).  I guess I'll cave; I'll try to see how difficult it will be to support Spriteset#save() ;)
miniSphere 5.0b4 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHub
For the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enourmous man eating pigs ~Rhuan

  • Rhuan
  • [*][*][*][*]
Re: Function to save a spriteset (for miniSphere)
Reply #2
The Write_Word16 function is a cut down version of a Write integer function from a savesystem script I wrote about a decade ago, so it wasn't really anything new - that said, your struct module has some cool features which I wasn't aware of, thanks for pointing it out.

You don't need to make the function natively now though the optimisation would be appreciated, what I've got works and will work if anyone else needs it (as long as it's not performance critical, but TBH I think if anyone is saving things to disk in a performance critical piece of code they're doing it wrong from the start).

This took about a minute to save 200 images most of which were 64*64 - which isn't horrendous, if I'm having it do 500 sprite sets at once I guess it could be painful but that shouldn't really be necessary.

EDIT: New thought - considering that the whole point of surfaces (as opposed to images) is that you can edit and fiddle with them shouldn't they be stored as something other than hardware textures to give faster access? Could this be an optimisation to the engine or would it be far more pain than it's worth?
  • Last Edit: May 20, 2017, 07:27:49 pm by Rhuan

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • miniSphere Developer
Re: Function to save a spriteset (for miniSphere)
Reply #3

EDIT: New thought - considering that the whole point of surfaces (as opposed to images) is that you can edit and fiddle with them shouldn't they be stored as something other than hardware textures to give faster access? Could this be an optimisation to the engine or would it be far more pain than it's worth?


I actually tried this at one point; it ended up slowing down the majority of Sphere v1 games using surfaces.  It seems that most games (including my own...  :-[) use them as offscreen buffers more often than they do for composition, so it ends up being slower to keep them in system memory.  Incidentally, your suggestion is exactly how Surfaces work in Sphere 1.5 and things usually perform okay there; best I can tell, the default DirectDraw graphics plugins are mostly software-rendered, so software surfaces are not a bottleneck.
miniSphere 5.0b4 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHub
For the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enourmous man eating pigs ~Rhuan

  • Rhuan
  • [*][*][*][*]
Re: Function to save a spriteset (for miniSphere)
Reply #4


EDIT: New thought - considering that the whole point of surfaces (as opposed to images) is that you can edit and fiddle with them shouldn't they be stored as something other than hardware textures to give faster access? Could this be an optimisation to the engine or would it be far more pain than it's worth?


I actually tried this at one point; it ended up slowing down the majority of Sphere v1 games using surfaces.  It seems that most games (including my own...  :-[) use them as offscreen buffers more often than they do for composition, so it ends up being slower to keep them in system memory.  Incidentally, your suggestion is exactly how Surfaces work in Sphere 1.5 and things usually perform okay there; best I can tell, the default DirectDraw graphics plugins are mostly software-rendered, so software surfaces are not a bottleneck.


I had always thought that you were meant to var image = your_surface.createImage() before blit-ing it if at all possible; sounds like a lot of people didn't?

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • miniSphere Developer
Re: Function to save a spriteset (for miniSphere)
Reply #5
I think that because there's a function Surface#blit(), most people--including me--assumed they were meant to be used as offscreen buffers (I guess it didn't help that I came from a DOS Mode 13h background where offscreen compositing was common).  In fact I always remember thinking Surface#createImage() was redundant for that exact reason.  It is what it is, I guess. :P
miniSphere 5.0b4 (stable: 4.8.8) - Cell compiler - SSj debugger - thread | on GitHub
For the sake of our continued health I very much hope that Fat Cerberus does not become skilled enough at whatever arcane art it would require to cause computers to spawn enourmous man eating pigs ~Rhuan