twolfson / spritesmith

Utility that takes sprites and converts them into a stylesheet and its coordinates
MIT License
916 stars 56 forks source link

Add parameter: POT and square #29

Closed FunkMonkey closed 10 years ago

FunkMonkey commented 10 years ago

In some situations you need power-of-two textures. It would be nice, if that could be added as an option, so that the resulting texture will have power-of-two width and height (thus probably wasting space).

While we are at it, the square parameter would force width and height to be the same POT value.

Thanks!

twolfson commented 10 years ago

spritesmith was not built with retina in mind. As a result, retro-fitting it in would make for a poor code base. Instead, tools should either wrap it or its dependencies. Here are some past issues on this:

twolfson/json2css#13

Ensighten/spritesmith#19

twolfson/json2css#18

FunkMonkey commented 10 years ago

I think there is a misunderstanding. I am not asking for any retina-support or scaling images.

The POT parameter would just ensure that the width and height of the resulting texture are a power of two. I basically ask for adding empty pixel columns and rows.

Example: Giving spritesmith one image with the dimensions of 40x60, the result texture would be 64x64, simply adding 24 empty pixel lines to the right and 4 empty pixel lines to the bottom. Same principle, if you already packed multiple images.

This is basically useful for making textures for OpenGL/WebGL, etc.

I just looked at the code. For this issue we simply need to adjust the width and height of the canvas in the beginning of generateCanvas in smith.js. Not sure if canvas.addImage also needs to be adjusted.

Seems like a rather small change. If I had the time, I'd do it myself.

Thanks a lot!

twolfson commented 10 years ago

Can you provide examples? I am uncertain if you mean extra padding between images or on the total image.

I am also interested in learning more about this use case. I will be Googling but I assume you have better links.

Filled edge:

Filled edge

Even padding:

Even padding

joshgoodwin commented 10 years ago

Seriously Toddy, it's a holiday.

FunkMonkey commented 10 years ago

The filled edge example looks like what I need :)

Here is some background information about POT and NPOT textures (that I just googled, but which are good explanations):

Basically there are still cases today (mipmaps, repeating textures) that require images to have power-of-two dimensions.

If you need any more information, I gladly help! :)

FunkMonkey commented 10 years ago

Oh. and maybe you should also have a look at TexturePacker and all of its options if you are interested in that topic.

twolfson commented 10 years ago

Cool, thanks for all info. That was very educational =)

At this time, I am declining adding the power of two feature to spritesmith. There are two philosphies that are relevant here:

In the case of spritesmith, its purpose is to take images and lay them out into a spritesheet via a given algorithm. spritesmith does this very well and even is cross-platform in doing so.

Reflecting upon the current option set, padding technically should be pulled out but it never was.

To come back to power of two, I believe that rather than adding another option, there should be another node module (and grunt task if that is your end goal) which takes an image, calculates the next power of two (this itself could be a node module), and fills out the edge.

Some libraries you should check out:

FunkMonkey commented 10 years ago

The argument of composability makes sense for spritesmith itself, though it sounds rather hard to hook into grunt-spritesmith without having to duplicate it.

Imagine you would put the padding into its own module, how would you go and use the existing grunt task and hook in both padding, pot and/or any other related module that works on the result of spritesmith?

twolfson commented 10 years ago

grunt is a pipelining tool, you can define tasks which are composite actions of multiple tasks. You can also define tasks to use the same config as other files.

http://gruntjs.com/creating-tasks#alias-tasks

http://gruntjs.com/configuring-tasks#templates

In your case, you would create a new grunt task (e.g. grunt-fill-edge, grunt-pot) which takes an input filepath and and output filepath. It then works its magic on the input image to create a filled out output image.

The usage would look like:

{
  sprite: {
    texture: {
      src: 'sprites/*.png',
      destImg: 'tmp/texture.png',
      destCSS: 'texture.json'
    }
  },
  'fill-edge': {
    texture: {
      src: 'tmp/texture.png',
      // Should be able to use `src: '<%= sprite.texture.destImg %>'`
      dest: 'texture.png'
    }
  }
}

grunt.registerTask('texture', ['sprite', 'fill-edge']);
FunkMonkey commented 10 years ago

Hmm. sounds quite complicated for adding a couple of empty pixel lines, as I would have to start up the whole image-manipulation-machinary again.

I guess it'll be easier for me and my use-case to simply fork your repository and add the small POT changes and then use npm shrinkwrap so that grunt-spritesmith uses my fork of spritesmith.

I'll send you a pull-request anyway - just in case you change your mind. :) Though I won't have time for this in the next weeks anyway.

thanks a lot for your explanations. :)

twolfson commented 10 years ago

If it is complicated, then that is a problem that should be fixed and not worked around. I pointed you to a few image manipulation libraries which should solve the problem easily.

In the end, composability is much healthier for the community than numerous one-offs and configurations.

email2markt commented 8 years ago

Sorry to drag up an old thread, but would a "power of two packer" algo be another approach? It would lay things out in a way that is sympathetic/suitable to systems that offer mipmapping etc. and would always return width and heights that are a power of 2.

twolfson commented 8 years ago

On a more recent issue, @marekventur noted that there was no performance benefits to power of 2 images. Maybe check out this thread?

https://github.com/twolfson/gmsmith/pull/14#issuecomment-225533738

Also, @marekventur seems to author another packing system which might better suit your needs:

https://github.com/gamevy/pixi-packer

email2markt commented 8 years ago

So power of 2 sprites help with mipmapping, so that spritesheets of varying sizes can be created on the fly for use with WebGL.

Thanks for the pixi-packer link, unfortunately like so many of the solutions out there it has external dependencies. What I like about spritesmith (combined with pixelsmith) is that it all works on all platforms and all dependencies can be installed through npm

I had hoped to tweak spritesmith to work in my circumstance without changing the core spritesmith js itself but I can't find a way right now.

twolfson commented 8 years ago

Ah, I see. I'm still quite firm on this not needing to be in spritesmith's core. However, it should be possible to get POT padding relatively easily. Here are some proposals: