Feature Request: Store sprites as separate files

Started by JanetC, Thu 19/10/2017 19:12:44

Previous topic - Next topic

JanetC

It's currently really hard to keep AGS projects in source control, due mainly to the enormous size that acsprset.spr can grow to in any large projects. Could the sprite image sources be kept as links to separate image files on disk, as with the sound files?

eri0o


cat

The question is: can the spr file be rebuilt from the info in the Game.afg and the sprite images in the folder?

Crimson Wizard

#3
Quote from: cat on Sun 22/10/2017 20:33:00
The question is: can the spr file be rebuilt from the info in the Game.afg and the sprite images in the folder?

TBH I do not remember about sprites which keep references to sourcefiles, but the sprites package can also contain sprites copied from clipboard, in which case they do not have any links to real sprites (and there may not be any original files on disk whatsoever).

This should be also kept in mind if this feature is implemented, because unlike AudioCache which you can safely delete if you have original audios somewhere, you won't be able to just delete all sprites from cache.
So probably there should be a special folder in your project where Editor will add sprites created by clipboard copying, or something like that.

cat

In this case I would advice against git-ignoring it. The purpose of source control is being able to restore your project to a specific historic state. But if the sprite file is not included, game data is basically broken and cannot be restored which renders source control pointless.

eri0o

git-lfs would allow to version control your source and store the large binary file, but not version your large file, because each version would require it entirely so it would quickly reduce your available storage.

Alternatively, you can use Dropbox paid account for your project since it allows versioning - if you have a spare server and don't want to spend money on Dropbox, Nextcloud provide the same functionality if you install yourself.

Snarky

... Or we could correct a very poor design decision in AGS so people don't have to hack half-functioning workarounds.

eri0o

#7
if there is support for multiple sprite files, it should be simple to break it in a new one on each import, right? I also think that, if the source links are still available it should be able to rebuild from source - which would help for reimports instead of having to load the sprite window and go on each clicking replace from source.

Crimson Wizard

#8
Quote from: eri0o on Fri 03/11/2017 10:23:40
if there is support for multiple sprite files, it should be simple to break it in a new one on each import, right?
To be precise, currently there is no support for multiple sprite files, there is support for multiple resource files (they may contain other data, like rooms etc).
Technically it is possible to implement sprite archive splitting, as well as creating new part whenever new sprites are created (if I understand your idea right?).
But the point here is to move away from having compiled data packages in the project source, making project sources more open.

Same refers to the room files, actually, currently they are kept as compiled binary blobs in the project source, making it difficult to collaborate on a same rooms (team members should take turns updating them).


Quote from: eri0o on Fri 03/11/2017 10:23:40
I also think that, if the source links are still available it should be able to rebuild from source - which would help for reimports instead of having to load the sprite window and go on each clicking replace from source.
As I noted in my post above, not all sprites keep their links. Sprites copied from clipboard and sprites imported using "tiled import" feature do not have links stored.

Crimson Wizard


JanetC

We know about Git LFS and Dropbox and use both. But it would be much nicer if the sprites were stored as individual files like the sound files are. At the moment "Unavowed" has a sprite file that is several gigabytes in size and stresses even LFS.

The other unmergeable binaries, like room files, are also a small problem too because Dave & I have to be very sure that only one of us is using them! But that's not nearly as much of a problem as the enormous sprite file.

Dave Gilbert

One alternative option, if storing the sprites as separate files isn't doable.

Can there be an option to split the sprite files into smaller chunks? Much in the same way you can split up the game's .dat file?

Crimson Wizard

Quote from: Dave Gilbert on Thu 30/11/2017 16:24:18
One alternative option, if storing the sprites as separate files isn't doable.

Can there be an option to split the sprite files into smaller chunks? Much in the same way you can split up the game's .dat file?

Storing sprites as separate files is doable of course, there should be some kind of specification (rules) made first to know how exactly we are doing that (sprite cache folder similar to audio cache, etc).
Because that will completely change the way how Editor works with sprites, we need to be very careful in planning here.

Regarding splitting sprite file, that won't necessarily be much easier, because unlike game data, which is the final output, Editor uses sprite file during its work.

Crimson Wizard

#13
Alright, this is not going anywhere, and people keep getting into this problem.

So this is my work suggestion.

In Game.agf sprite reference includes following additional information:
- Rectangle, the location of the original image the sprite was "cut out".
- Transparency setting the sprite was imported with.

Game project has a new folder:
- Resources/Sprites - Editor puts automatically created sprites there that serve as actual source files.
This is images copied from clipboard mainly. But you also allowed to put your own sprites there (Editor must take precaution not to overwrite existing file when generating new one). Alternatively, call folder Resources/Sprites/Generated.
"Resources" may be replaced with "Assets" if you like that word more.

Bonus feature: contents of Resources/Sprites match the folders in the Sprite manager.

Workflow:
- Editor loads sprites by reading information from Game.agf and referenced source files.
- If sprite is imported from file, game saves reference to that file.
- If sprite is imported from clipboard, game creates a new sprite in Resources/Sprites/...
- Same if sprite is imported from GIF.
- If sprite is tile-imported, game saves reference to source file and position of every sprite in there.
- If sprite is opened for edit in the paint program, game saves the changes in Resources/Sprites/.... It creates new sprite if original sprite was outside of that folder, or changes existing one if it was originally in that folder. Alternative: save changes back in the sprite is anywhere inside project folder.


Compiled sprite file is removed from the game project. It is only created when the game is compiled.
Probably for convenience we need extra subfolder in Compiled, something like "Intermediate" or "Temp" where the intermediate result of compilation is stored.


Related questions: importing/extracting compressed sprite file from the older project.

morganw

My suggestion:
- Remove the sprite manager entirely (or reduce it to become a sprite viewer)
- Game compiler builds the sprite file (so as you describe)
- Sprites are are just read from disk and not duplicated anywhere

I'm not sure what the benefit is of maintaining copies of the sprites? If just to assign ID numbers, why not just start the filenames with a number, and read the filenames?

Crimson Wizard

#15
@morganw, you say "duplicates" and "copies" but what are these? I did not mention copies anywhere.
EDIT: Okay, I used word "copies" in:
Quote
Editor copies automatically created sprites...
I changed it to "puts", because these are not copies.

Quote from: morganw on Tue 03/07/2018 19:30:54
- Remove the sprite manager entirely (or reduce it to become a sprite viewer)
What's the difference between manager and viewer? Or rather, what will be removed from it?

morganw

I'm suggesting there be no import controls at all. If there was an internal sprite editor (some sort of mini paint program) there would be an argument for keeping sprite management, but everyone is already using external tools and is then forced to go through the import process. If people are already saving their sprites and masks to disk to do an import, they may as well just save them to the game folder:
QuoteD:\MYGAME
|   MyGame.agf
|
\---Sprites
    |   apple.png
    |   banana.png
    |   pineapple.png
    |
    \---Grapes
            green_grape.png
            red_grape.png

If storing the mapping of ID number to path in the project file, you would only have to assign numbers for any new file paths which show up. Potentially though, just reading 10_apple.png as sprite 10 means no ambiguity about the sprite number, and the project file wouldn't have to track it at all. Compared to how it works at the moment, even renaming a directory full of files is a lot easier than trying to re-arrange numbers assigned by the sprite manager.

Crimson Wizard

#17
Quote from: morganw on Tue 03/07/2018 21:21:25
I'm suggesting there be no import controls at all. <...> If people are already saving their sprites and masks to disk to do an import, they may as well just save them to the game folder.

This makes certain sense, but do you do parts import in this case at all? Right now you may have tilemaps or whole animation in a single file, with that you will have to keep 1 tile/frame per file?
I don't really know how people usually do that. Maybe they prefer to have 1 frame per file anyway?

morganw

As long as you can read the frame count of the file, I think it would be okay for a whole animation in a single file, but I think people tend to export as a sequence of images anyway. Potentially you can just have the editor assume a single image with alpha channel (where available) and just store exceptions to that, either in the project file or write it as metadata into the sprite folder (you could probably reserve a sprite number range this way too).

I think I've linked to this before in another thread:
http://thebrotherhoodgames.com/blog/2013/10/visionaire-engine-powering-stasis/

...but have now also found where I read the direct comparison:
http://thebrotherhoodgames.com/blog/2010/12/adventure-game-engines/

Crimson Wizard

#19
Quote from: morganw on Tue 03/07/2018 22:09:26
As long as you can read the frame count of the file, I think it would be okay for a whole animation in a single file, but I think people tend to export as a sequence of images anyway. Potentially you can just have the editor assume a single image with alpha channel (where available) and just store exceptions to that, either in the project file or write it as metadata into the sprite folder (you could probably reserve a sprite number range this way too).

But if there is no sprite manager, how do you tell it about these exceptions? I think I am missing something in this plan.
Also, do you mean that file format itself stores frame count? If not, what did you mean by "read the frame count of the file"?

Could you write all this in a form of a task, with all points elaborated?

morganw

Quote from: Crimson Wizard on Tue 03/07/2018 22:16:51
But if there is no sprite manager, how do you tell it about these exceptions? I think I am missing something in this plan.
Well it would need something, but this something will not import, create or delete sprites. So if there is just a sprite viewer, it could just hand tasks off to a metadata manager, or you could be specifying any changes settings outside of the editor.

As a rough example:

  • Save a new sprite into the sprites folder
  • Editor see a new path and assigns it a number (possibly yielding to the filename or a metadata file)
  • User right clicks a sprite and choose "top left pixel as the transparency" as they don't want the default settings
  • User right clicks a sprite and manually edits the sprite number
So for these actions:

  • If the asset pipeline is consistent (i.e. you are being given or making graphics in a consistent format) it is likely you would only need to set default import settings and not make any exceptions to this
  • If you do need to change something for a particular image, this can just be stored as an exception to the default, either in the XML of the project file or in a metadata file next to the image on the disk (in the case of the extra file, you would check the image settings into version control independently of the project file)
  • If you need to make changes for multiple images, this can also be stored as an exception to the default (as above, in project file or metadata file), but referenced against a sprite folder (which is now just a folder on the disk)
  • In the case of using metadata files, you could potentially have specified the import modes and ID number reservations before the editor ever saw the images, so potentially it just needs to validate the data

Quote from: Crimson Wizard on Tue 03/07/2018 22:16:51
Also, do you mean that file format itself stores frame count? If not, what did you mean by "read the frame count of the file"?

I meant that, if you had something like a GIF file which had multiple frames, you could read the frame count from the file and allocate it the corresponding number of sprite ID numbers (instead of having to extract each frame to disk to use it).

Quote from: Crimson Wizard on Tue 03/07/2018 22:16:51
Could you write all this in a form of a task, with all points elaborated?

I will do this. I'm guessing you mean on GitHub?

Crimson Wizard

#21
Quote from: morganw on Tue 03/07/2018 23:42:45
Well it would need something, but this something will not import, create or delete sprites. So if there is just a sprite viewer, it could just hand tasks off to a metadata manager, or you could be specifying any changes settings outside of the editor.

This is like a complete overhaul to how you work with sprites in AGS. Are you sure the people will accept this?
This may be a regular workflow for professional artists, but, for example, I got used to import sprites from clipboard, that's very fast and you don't have to manage files.
And the tiled import... I was just drawing all animation sequence in 1 document, and then tile-importing them, again not thinking about cutting into files.

Perhaps there may be a way to keep these import commands? They may be simply creating new files and metadata according to the settings, work like alternate entry point into this system (main is copying file into folder).

fernewelten

Efficieny might be an issue here:

If a sprites file can have gigabytes, it will probably be comprised of thousands of separate, tiny little files. Currently, we don't notice the sprite generation because it is done piecemeal, file by file as they are imported one by one. This will change, however, when the sprite file is generated in bulk at compilation time. Thousands of tiny files will have to be opened on each compile. The time needed might be significant.

So we probably need to cache the generated sprites file. But even that is not so easy as it looks:
If the user doesn't tell AGS that some file is „imported“, then at compile time, the AGS compiler will have to peruse thousands of tiny little files in order to find out whether new ones have shown up or old ones have changed their content. So that might mean, hash file contents and store that somewhere, e.g., in a database. This might start to become messy.


Crimson Wizard

#23
Quote from: fernewelten on Tue 03/07/2018 23:59:23
If the user doesn't tell AGS that some file is „imported“, then at compile time, the AGS compiler will have to peruse thousands of tiny little files in order to find out whether new ones have shown up or old ones have changed their content. So that might mean, hash file contents and store that somewhere, e.g., in a database.

There may be slightly different approach: run a file change listener on a Sprites directory, and note files as they are added, removed or changed. Cache may be updated immediately, or at compile time using a prepared list of changes.

EDIT: oh right, the files could have been modified in between editor sessions too. So Editor would have to run full check when the project is opened.

morganw

Quote from: Crimson Wizard on Tue 03/07/2018 23:57:56
This is like a complete overhaul to how you work with sprites in AGS. Are you sure the people will accept this?
I think so, and some of what I'm suggesting is optional, but the end result is you press save in the graphics program to use or update an image. Probably best survey some people though.

Quote from: Crimson Wizard on Tue 03/07/2018 23:57:56
This may be a regular workflow for professional artists, but, for example, I got used to import sprites from clipboard, that's very fast and you don't have to manage files.
If you can press save instead of copy, it would be much the same process.

Quote from: Crimson Wizard on Tue 03/07/2018 23:57:56
And the tiled import... I was just drawing all animation sequence in 1 document, and then tile-importing them, again not thinking about cutting into files.
The metadata could define how large a tile is, and that could be referenced per image or per folder.

Quote from: Crimson Wizard on Tue 03/07/2018 23:57:56
Perhaps there may be a way to keep these import commands? They may be simply creating new files and metadata according to the settings, work like alternate entry point into this system (main is copying file into folder).
Maybe just have the option to convert an image. So for your tiled import, the image is already there and you just define the tile dimensions to reference it as multiple images. But the alternative I'm suggesting would let you specify the tile size on a sprite folder, and then all your sprite sheets which use that tile size would be automatically used as multiple sprites.

Quote from: Crimson Wizard on Wed 04/07/2018 00:05:30
There may be slightly different approach: run a file change listener on a Sprites directory, and note files as they are added, removed or changed. Cache may be updated immediately, or at compile time using a prepared list of changes.

EDIT: oh right, the files could have been modified in between editor sessions too.
Presumably though, it is possible to know the position of a particular sprite within the file, without having to read the whole thing?

Crimson Wizard

#25
I think I need to clear something up, because I forgot to explain it first.

@morganw, your idea sounds as a good "final" goal, perhaps for AGS 4(?), but I am concerned of the amount of work it will require, to develop, test and polish (and to teach users "new ways").

Frankly, my intention was to make an "intermediate" change, which would require relatively small effort, and get this into 3.4.2 update (or 3.5, whatever it be called), saving some trouble to people using source control with AGS games.

Taking into consideration what fernewelten said above, about sprite cache may take time to compile, I've changed my original suggestion a little. So this intermediate step could look like:
- The workflow stays generally same (import commands and menus);
- Game.agf stores references to all source files, if necessary - to which part was "cut out" to make a tile;
- if sprite was imported without source file (from a clipboard) then Editor creates it on its own, giving some dummy name (like spritexxxx.bmp).
- sprite cache is preserved and updated all along with import etc commands, BUT Editor supports full recreation of sprite cache from source files (assuming they are present). To keep it up-to-date with files modified on disk it will need a way to know when sprites were changed. For simplicity it could use same technique as with AudioCache: compare file's modification time. That's far from ideal. In the worst case sprite cache could be recreated with "Rebuild all files" command. (If that's too bad, then... hash?)
- question about deleting sprite from the editor... in which case the actual source file should be deleted? For example, game could have a note saying that particular sprite is autogenerated.



From this stage, it would be possible to move further into the system you suggested.

eri0o

I think the idea of building from separate sprites directly doesn't need to eliminate cache sprite file for doing things faster, it's just that you don't need to put the cache in source control, so that when loading a project without the cache file, it would be built the first time from sources. Imagine "reimport all sprites from source" if the cache.spr is not found.

Crimson Wizard

#27
If we are going to aim for Morgan's suggestion, there are few side problems that has to be resolved along the way.
For instance, Editor is still using native drawing code for some components, like GUI and Views (maybe something else) and that code relies on runtime sprite cache. One of the preliminary steps could be reimplementing the way editor draws stuff, perhaps making it rely on its own sprite map.

(On the other hand, there was Gurok's idea to run the engine inside the editor and make it draw stuff...)

Snarky

I am all for storing sprites (and other resources) on the file system, but I just want to caution that there are definitely people who swear by tiled sprite sheets (I think ProgZmax is one of them, for example), so let's not do away with the whole import process before they've had a chance to weigh in. And no, we can't just assume that they will notice this thread.

Another thing to keep in mind when checking for changes to the sprite source files or generating the sprite cache is ensuring that sprite numbering isn't messed up.
And the system should be able to deal gracefully with changes to the resources/folder structure. So, for example, if I had a sprite folder called "Rogr walk" and I rename it to "Roger walk", it shouldn't be excessively tedious to ensure that the sprites are found and matched.

morganw

It wouldn't prevent you from using a spritesheet, you could either flag the folder for tiled import, or just flag a particular image for tiled import. Unless I'm missing something, keeping the spritesheet as a single image means you never have to re-import the whole thing if anything on the spritesheet is changed; perhaps people might be preferring spritesheets at the moment to get around workflow issues in the sprite manager. Presumably a tiled import will always give you sequential sprite IDs?

Quote from: Crimson Wizard on Wed 04/07/2018 15:14:32
One of the preliminary steps could be reimplementing the way editor draws stuff, perhaps making it rely on its own sprite map.
I guess the question is, should the editor aim to show everything on screen exactly as it is in the game, or should it just be enough to arrange everything and then run it with the debugger attached. I think at the moment it is a bit of both.

Snarky

Quote from: morganw on Wed 04/07/2018 18:09:46
It wouldn't prevent you from using a spritesheet, you could either flag the folder for tiled import, or just flag a particular image for tiled import.

If you're going to have the capability to flag a sprite for tiled import (with x and y dimensions), and set the transparent color (because that's required functionality), and view the sprites, and set the sprite number (implies reordering the sprites?), and probably the option to then delete them from within the editor, because why not... isn't that more or less everything the sprite manager does?

QuoteUnless I'm missing something, keeping the spritesheet as a single image means you never have to re-import the whole thing if anything on the spritesheet is changed

Umm... isn't it the opposite? You do have to reimport the entire thing. I assume the "re-import from source" command works correctly with tiled images, so it might just be a two-click operation if you are well organized (don't move/rename the source file).

Quoteperhaps people might be preferring spritesheets at the moment to get around workflow issues in the sprite manager.

It seems pretty much six of one, half a dozen of the other to me. In my experience tiled import is about equally quick as importing multiple files in a folder as long as you already know the tile dimensions; otherwise it's much, much slower.

QuotePresumably a tiled import will always give you sequential sprite IDs?

Should work the same as multi-import of files, I would assume? (Available sprite IDs from the lowest and up, so sequential unless you've deleted a lot of sprites recently.)

morganw

Quote from: Snarky on Wed 04/07/2018 19:04:35
If you're going to have the capability to flag a sprite for tiled import (with x and y dimensions), and set the transparent color (because that's required functionality), and view the sprites, and set the sprite number (implies reordering the sprites?), and probably the option to then delete them from within the editor, because why not... isn't that more or less everything the sprite manager does?
Yes, but those settings are applied at time of import and then everything is manually specified. Just adding a mapping between files and IDs, with the ability to rescan and remap would give similar functionality as the import, but main difference would be if you can specify default settings and then just save images to start using them.

Quote from: Snarky on Wed 04/07/2018 19:04:35
Umm... isn't it the opposite?
It doesn't look like the source file is tracked at all for a tiled import, so I can't see any benefit with regard to re-importing after an edit.

Crimson Wizard

#32
Quote from: morganw on Wed 04/07/2018 21:04:57
It doesn't look like the source file is tracked at all for a tiled import.

But this is what I am planning to fix. I guess Snarky was assuming it will work eventually even if it does not now.

morganw

To track the source you will have to store the path though, as potentially the source image has changed the editor last saw it (so timestamp and hash may have changed). I think fundamentally we are both suggesting the same thing, and the mechanisms needed to reference the files would be similar. Given that an absolute path may not match on two different computers, ideally the source should be relative to the game folder, so really I think the the only difference is an implied import vs manual import, and then where the mapping is stored.

Crimson Wizard

Quote from: morganw on Wed 04/07/2018 23:02:54
To track the source you will have to store the path though, as potentially the source image has changed the editor last saw it (so timestamp and hash may have changed). I think fundamentally we are both suggesting the same thing, and the mechanisms needed to reference the files would be similar. Given that an absolute path may not match on two different computers, ideally the source should be relative to the game folder, so really I think the the only difference is an implied import vs manual import, and then where the mapping is stored.

Yes, I also do not see any difference in opinion about tracking source files. I've got an impression that the main argument here was about keeping certain import commands in the editor, but maybe Snarky meant something else.

Only to elaborate again, my intent for the moment is to implement a relatively smaller change, making sprite cache connected with source files consistently (in every possible import case). After this the editor will still rely primarily on the sprite cache when working with game, but it will be possible to fully reconstruct/update cache from the source files. If these source files are all located in the project's folder, user may put only these under source control, ignoring the cache. Probably this will require storing file hashes or timestamps in order to know when cache is out of sync.

From this point Editor may be evolved further into using files on disk directly.

eri0o

I like your idea CW :)

It's exactly what I always wanted : "no spritecache.spr found, rebuilding cache from sources in game.agf...Done!". :D

Snarky

Quote from: eri0o on Thu 05/07/2018 00:56:42
I like your idea CW :)

+1

If there's a simple change that will make it possible to store an AGS project under source control without spritecache.spr, that's an enormous improvement in itself. Then we can work out exactly how a more radical/long-term solution should work (probably the experience in itself will also teach us a lot about the issues that crop up and the features that are needed).

Crimson Wizard

#37
This may be a little early, but i finally found time to implement an experiment that recreates spritefile (acsprset.spr) from the project data + sprite sources.
This is based on 3.6.0 Beta, so keeping things minimal.

The opened ticket: https://github.com/adventuregamestudio/ags/pull/1594
The experimental build may be found here, it's based on the latest 3.6.0: https://cirrus-ci.com/task/5730993683300352

At the moment it works like this:
* Editor no longer fails opening a game with the missing acsprset.spr; instead it creates it with a single dummy 1x1 sprite at index 0 (it is necessary as a placeholder to prevent internal errors).
* A new command added, for the time being it has to be called by hand, File -> Recreate Sprite File from sources. This command completely overwrites current acsprset.spr by reimporting every sprite that has a source reference. For those which do not it either tries to get a image from existing acsprset.spr, and if there's none, then creates a dummy clear image of the same size, at least to have something.

The plan is probably to suggest user to run this command automatically upon opening the game too. But we want to test this process through first.

Theory is, this feature will allow to fully recreate acsprset.spr from sources, and thus you no longer have to keep this file under the source control, etc. This may also improve team collaboration experience.


PS. The original idea of having sprites as separate files within a project is still recorded, but suggested for "ags4", if anyone is wondering: https://github.com/adventuregamestudio/ags/issues/1281

eri0o

Hey everyone, it would be really helpful if more people could try copies of their games with this and test it out their spritecaches to see what problems could arise of this!

cat

This is fantastic news! I have to upgrade one of my games first, to try it, though. I haven't been using AGS for quite some time now.

Crimson Wizard

Updated the downloadable version, in above post, and here:
https://cirrus-ci.com/task/5730993683300352

Now there are two options, in case acsprset.spr is missing:
* editor will ask on game load, if you want to try reimporting sprites from sources; if you say "no" it will create a dummy sprite file with just a placeholder for sprite image (slot 0).
* there's an explicit command in File menu.
(and of course "reimport from source" command in the sprite manager)

eri0o

This feature is included in the latest 3.6.0 beta 3 release.

Crimson Wizard

Quote from: eri0o on Sat 16/04/2022 12:02:33
This feature is included in the latest 3.6.0 beta 3 release.

This refers to restoring acsprset.spr; storing sprites as separate files is still in plans for the future versions.

SMF spam blocked by CleanTalk