daily pastebin goal
60%
SHARE
TWEET

Untitled

a guest Jun 25th, 2018 76 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * @fileOverview
  3.  *
  4.  * Montage single sprite images from Reiner's Tileset into a single spritemap.
  5.  *
  6.  * Every Sprite has multiple images: one per animation (e.g., walk, shoot, etc).
  7.  * Each row of the spritemap corresponds to a direction (n,s,w) in alphabetical order.
  8.  * The columns are the steps of a particular animation for a direction.
  9.  *
  10.  * requires ImageMagick
  11.  */
  12.  
  13. var {list, join, write, list, isFile, isDirectory} = require('fs');
  14. var {system, command} = require('ringo/subprocess');
  15. var sys = require('system');
  16. var strings = require('ringo/utils/strings');
  17. var arrays = require('ringo/utils/arrays');
  18. var $f = require('ringo/utils/strings').format;
  19. //var {Parser} = require('ringo/args');
  20. var {get} = require('ringo/httpclient');
  21.  
  22. // "tipping over sw0011.png"
  23. // "stopped n0001.png"
  24. var FILE_REGEX = /(.*) ([^0-9]{1,2})([^\.]+)\.png/;
  25. var RAW_FILE_REGEX = /(.*) ([^0-9]{1,2})([^\.]+)\.bmp/;
  26.  
  27. /**
  28.  * Montage animations as described by output of `getAnimationInfo()` in
  29.  * directory `dir` into a single spritemap.
  30.  */
  31. function montage(dir, animations) {
  32.    for each (var animation in animations) {
  33.       if (isNaN(animation.count)) {
  34.          print ('invalid animation count ', animation.toSource());
  35.          continue;
  36.       }
  37.       var tilingArgs = ['-background', 'none',
  38.                   '-geometry', '+0+0',
  39.                   '-tile', (animation.count + 1) + 'x',
  40.                   animation.name + '.png'
  41.                   ];
  42.       var allArgs = ["montage"].concat(animation.files).concat(tilingArgs).concat({dir: dir});
  43.       system.apply(this, allArgs);
  44.    }
  45.    return;
  46. };
  47.  
  48. /**
  49.  * Returns #rgb string for top left pixel in image
  50.  */
  51. function getBackgroundColor(file) {
  52.     var args = ['convert', file, '-crop', '1x1+0+0','-unique-colors', 'txt:-'];
  53.     var output = command.apply(this, args);
  54.     var matches = output.match('(#[^ ]+)')
  55.     return matches[1];
  56. };
  57.  
  58. /**
  59.  * @returns {Object} an object describing the animations defined by the image files.
  60.  */
  61. function getAnimationInfo(dir) {
  62.    var files = list(dir);
  63.    var animations = {};
  64.    files.forEach(function(file) {
  65.       var parts = file.match(FILE_REGEX);
  66.       if (!parts) return;
  67.      
  68.       var animation = parts[1];
  69.       var direction = parts[2];
  70.       var number = parseInt(parts[3], 10);
  71.       var cani = animations[animation];
  72.       if (cani === undefined) {
  73.          cani = animations[animation] = {
  74.             name: animation,
  75.             count: number,
  76.             directions: [direction],
  77.             files: []
  78.          }
  79.       }
  80.       cani.files.push(file);
  81.       if (!arrays.contains(cani.directions, direction)) {
  82.          cani.directions.push(direction);
  83.       }
  84.       if (number > cani.count) {
  85.          cani.count = number;
  86.       }  
  87.    });
  88.    for each (var animation in animations) {
  89.       animation.files.sort();
  90.    };
  91.    return animations;
  92. };
  93.  
  94. /**
  95.  * download url to file
  96.  */
  97. function download(url, file) {
  98.    var response = get(url);
  99.    write(file, response.contentBytes, 'wb');
  100.    return;
  101. };
  102.  
  103. /**
  104.  * unpack file to dir
  105.  */
  106. function unpack(file, dir) {
  107.    command.apply(this,
  108.       ['unzip','-n', file, '-d', dir]
  109.    );
  110. };
  111.  
  112. /**
  113.  * recursively fix file encoding to utf8 in diretory
  114.  */
  115. function fixFileEncoding(dir) {
  116.    var args = ['convmv', '-r', '--notest', '-f', 'latin1', '-t', 'utf8', './', {dir: dir}];
  117.    command.apply(this, args);
  118.    return;
  119. };
  120.  
  121. /**
  122.  * convert bmp found in directory to png with background being transparent
  123.  */
  124. function toTransparentPng(dir) {
  125.    var files = list(dir);
  126.    var color = getBackgroundColor(join(dir, files[1]));
  127.    var args = ['mogrify', '-transparent', color, '-format', 'png', '*bmp', {dir: dir}];
  128.    system.apply(this, args);
  129. }
  130.  
  131. /**
  132.  * get directories below given directory or directory itself, which hold animation pictures
  133.  */
  134. function getAnimationDirectories(root) {
  135.    var directories = list(root);
  136.    var animationDirectories = [];
  137.    if (directories.length && isFile(join(root, directories[1]))) {
  138.       animationDirectories = [root];
  139.    } else {
  140.       directories.forEach(function(directory) {
  141.          if (!isDirectory(directory)) return;
  142.          
  143.          // try first file in directory
  144.          var potentialFiles = list(join(root, directory));
  145.          var isAnimation = potentialFiles.some(function(file) {
  146.             return file.match(RAW_FILE_REGEX) !== null;
  147.          });
  148.          if (isAnimation) {
  149.             animationDirectories.push(join(root, directory));
  150.          }
  151.       });
  152.    }
  153.    return animationDirectories;
  154. };
  155.  
  156. function main(args) {
  157.    /**
  158.    * Print script help
  159.    */
  160.    function help() {
  161.        print('Create a spritemap from Reiners Tileset');
  162.        print('Usage:');
  163.        print('  ringo ' + script + ' download url');
  164.        print('Options:');
  165.        print (parser.help());
  166.        return;
  167.    };
  168.  
  169.    var script = args.shift();
  170.    // option: --idle stopped  --noloop dying ...
  171.    // provide good defaults and search for them in file
  172.    // var parser = new Parser();
  173.    // parser.addOption('s', 'source', 'repository', 'Path to repository');
  174.    // var opts = parser.parse(args);
  175.  
  176.    // FIXME rename stopped and other broken?
  177.    var zipUrl = args.shift();
  178.    var zipFile = join(module.directory, zipUrl.split('/').slice(-1)[0]);
  179.    print ('downloading');
  180.    download(zipUrl, zipFile);
  181.    var zipDir = join(zipFile.split('.').slice(0,-1), '/');
  182.    print ('unpacking');
  183.    unpack(zipFile, zipDir);
  184.    fixFileEncoding(zipDir);
  185.    print ('to transparent png');
  186.    var animationDirectories = getAnimationDirectories(zipDir);
  187.    animationDirectories.forEach(function(ad) {
  188.       toTransparentPng(ad);
  189.    });
  190.    print ('composing spritemap');
  191.    animationDirectories.forEach(function(animationDirectory) {
  192.       var animations = getAnimationInfo(animationDirectory);
  193.       montage(animationDirectory, animations);
  194.    });
  195.    
  196.    // drop T_ prefix, replace %20, drop file ext
  197.    var fileName = zipFile.split('.').slice(-1)[0];
  198.    var spriteName = fileName.split('.')[0].replace('%20', '_').substr(2);
  199.    print (spriteName);
  200.    var targetDir = join(module.directory, 'animations', spriteName)
  201.    print (targetDir);
  202.    
  203.    return;
  204. };
  205.  
  206. if (require.main == module.id) {
  207.    try {
  208.       main(sys.args);
  209.    } catch (error) {
  210.       print(error);
  211.    }
  212. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top