Monday, November 12, 2007

Java pas m'énerver ...

Quand il s'agit de manipuler un document XML, moi, mon interface préférée, c'est XPath. Pas besoin de code bien compliqué: on fait comme si tous les éléments étaient des petits fichiers dans une arborescence, et on donne un chemin pour trouver les éléments qui nous intéressent. J'avais déjà pu m'en servir avec succès en PERL, je m'attendais à quelque-chose d'ultra-simple en Java, langage de l'XML par excellence.

J'y vais donc de mon petit test débile:

import java.lang.*;
import java.util.*;
import javax.xml.xpath.*;
import org.xml.sax.InputSource;

public class XpathTest {
public static void main(String[] args) {
try {
System.err.println("creating xpath...");
XPath xpath = XPathFactory.newInstance().newXPath();
String expression = args[0];
InputSource src =
new InputSource(new java.io.FileInputStream(new java.io.File(args[1])));
System.err.println("search for "+args[0]);
String content = xpath.evaluate(expression, src);
System.out.println("here: "+content);

xpath.reset();
src = new InputSource(new java.io.FileInputStream(new java.io.File(args[1])));
Object node = xpath.evaluate(expression, src, XPathConstants.NODESET);
System.out.println("here: ("+node+")");
} catch (javax.xml.xpath.XPathExpressionException ex) {
System.err.println("oops: "+ex);
} catch (java.io.FileNotFoundException ex) {
System.err.println("no file : "+ex);
} catch (java.io.IOException ex) {
System.err.println("doh: "+ex);
}
}
}

Tout ça à l'aide de la première référence que je trouve: la doc de sun bien claire, sauf sur un point "c'est quoi cette 'nodelist' que je suis supposé recevoir mais qui m'est transmise sous la simple forme d'un 'Object' ?". Au bout de quelques minutes de tests, je me rends compte que la seule chose qui marche, c'est le chemin "/" qui reprend tout le texte du document. le reste ("/feed/entry[1]/title" ou "//author", ce genre de choses chouettes et utiles), ne donne aucun résultat. Pas une exception ou un message d'erreur. non. rien, tout simplement. que le chemin corresponde à un noeud existant dans le document ou pas, d'ailleurs.

grmbl.

Puis à force d'essayer, je finis par constater que le fameux objet que je récupère est de la classe com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList.

Et là, je dis: ça pue. pourquoi m'ont-ils renvoyé un objet interne non-documenté et (de plus) qu'est-ce que c'est que ce "sun...apache..." ou bien c'est dans le standard, ou bien ça n'y est pas, non ?


allons bon ...
Xerces does not provide an XPath implementation (it implements only support for the limited expressions allowed by XML Schema constraints). Xalan provides an XPath 1.0 implementation and from the com.sun.org.apache... package name it seems there is the Sun (derived from Xalan) implementation that is included with the JVM.ref

Tout de suite, ça m'étonne moins. Reprenons calmement avec la doc d'apache, donc.
  1. on installe le package "xalan", un traducteur XSLT qui est sensé fournir XPath pour de vrai
  2. on redéfini sa variable d'environnement CLASSPATH pour pointer sur /usr/share/java/xalan2.jar
  3. on google sur "org.apache.xpath example" et pas "xpath java example"
Voyons voir. Ouais. des tonnes de Factory et docBuilder.parse() ... 'fallait s'y attendre. Et naturellement, rien n'aide dans le code java ou dans JavaDoc à retrouver comment il serait bien possible de construire un objet de telle ou telle classe à partir d'un nom de fichier, ce qui rend toujours les tutoriels Java pénibles (très 'magie noire', si vous voyons c'que j'voulions dire).

Bref, le code le plus simple auquel j'arrive ressemble à ceci:
import org.apache.xpath.*;   // for XPathAPI, obviously!
import org.apache.xpath.objects.*; // for items, nodelists, etc. (XObject)
import org.w3c.dom.*; // for Document and friends
import java.lang.*; // for String and the like.

/** see also:
http://xml.apache.org/xalan-j/apidocs/javax/xml/parsers/DocumentBuilder.html
*/
class xpath2 {
public static void main(String args[]) {
Document doc=FileToDoc(args[0]);
String xpath = args[1];
System.out.println("\nQuerying DOM using xpath string:" + xpath);
try {
XObject o = XPathAPI.eval(doc, xpath);
System.out.println(o.getTypeString()+"> "+o);
} catch (Exception e) {
System.err.println("doh:" +e);
}
}
}
mais pour ça, il me faut écrire une horrible fonction capable de passer d'un nom de fichier à un Document, parce que visiblement, les gens qui ont écrit XPathAPI n'ont pas pensé à rendre ce cas-là simple :(
    static Document FileToDoc(String fname) {
/* well, Document is an interface and cannot be built simply */
/* -- grmbl -- */
try {
javax.xml.parsers.DocumentBuilderFactory docBuilderFactory =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
javax.xml.parsers.DocumentBuilder docBuilder =
docBuilderFactory.newDocumentBuilder();

// Parse the XML file and build the Document object in RAM
return docBuilder.parse(new java.io.File(fname));
} catch (Exception e) {
System.err.println("parse error: "+e);
return null;
}
}
Notez que si vous avez déjà un InputStream prêt sur le contenu (p.ex. une connexion réseau), inutile de passer par un fichier: docBuilder.parse(InputStream) existe également. Il y a même docBuilder.parse(URL) pour ceux qui ne sont pas occupés à faire un exercice sur l'écriture d'un client HTTP :P
(soupir)

Et pour être sûr, ils ont *aussi* rendu la réécriture de documents XML vers un fichier tordue:
 import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);


Pour la postérité, la javadoc de l'API XPath sur le projet Apache.

Jouons avec netcat ...

Les blogs sont nos amis, mais pour la plupart d'entre nous (même les programmeurs), la simple question "y a-t-il du neuf sur mon blog préféré" paraît trop complexe pour qu'on se donne la peine de la programmer. Pourtant, j'aimerais bien lancer mes étudiants sur un TP basé sur les flux RSS. Alors ?

Alors, bin souvenez-vous du post sur netcat, cet outil unix capable d'ouvrir et de manipuler des sockets en ligne de commande (je simplifie, mais bion). Avec quelques connaissances de HTTP 1.1 on va pouvoir s'amuser un peu. Tout d'abord, il nous faut l'URI d'un flux RSS, en l'occurence, le mien: http://sylvainhb.blogspot.com/feeds/posts/default

Nous avons déjà l'outil wget qui nous permet de récupérer une ressource sans passer par un navigateur, mais netcat va nous permettre de bidouiller un peu notre requête HTTP et de récupérer "en live" la réponse du serveur.

Voyons donc. La manière la plus simple pour récupérer la page avec notre flux RSS en HTTP correspond à

GET http://sylvainhb.blogspot.com/feeds/posts/default HTTP/1.1
Host: sylvainhb.blogspot.com


Auquel le serveur répondra quelque-chose comme
HTTP/1.1 200 OK
Content-Type: application/atom+xml; charset=UTF-8
Last-Modified: Mon, 12 Nov 2007 11:00:00 GMT
Cache-Control: max-age=0 private
ETag: "8ec946e4-7f26-4280-8dad-30c1e7f20e51"
Transfer-Encoding: chunked
Date: Mon, 12 Nov 2007 11:15:53 GMT
Server: GFE/1.3
Connection: Close

c04
<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'>
<id>tag:blogger.com,1999:blog-34057821</id>
<updated>2007-11-12T12:07:24.724+01:00</updated>
<title type='text'>Bilou HomeBrew's Blog</title>
...


La réponse est divisée en deux parties: des en-têtes, qui nous indiquent ce que l'on va recevoir, de quand celà date et comment gérer la suite du transfer et le contenu qui nous intéresse (le flux RSS proprement dit). Ceux qui ont fait un peu de programmation WEB auront tout de suite reconnu le "look HTML" de notre contenu. Il s'agit en fait d'un document XML, qui adopte les conventions d'HTML pour présenter n'importe quel type d'information (ici, un "flux" () qui possède ses paramètres propres (titre, dernière mise à jour ...) et une série d'entrées (), qui correspondent aux articles du blog.

Grâce à la balise , il serait possible de suivre l'évolution du blog en redemandant régulièrement le flux par HTTP et en comparant avec la dernière version reçue. Mais bon, là, mon flux pèse dans les 128K et ce serait ridicule de tout retransférer à chaque fois. Il y a évidemment moyen de faire mieux -- et à mon avis, c'est un des principaux avantages de HTTP/1.1 par rapport à sa version 1.0.

Vous avez remarqué la ligne "Last-Modified" dans les en-tête de la réponse ? Il s'agit de la dernière date de mise à jour (enfin, ce qu'en pense le serveur). Et nous pouvons demander au serveur de ne nous retransmettre le document que s'il a changé depuis cette date avec une petite variante de notre requête:

GET http://sylvainhb.blogspot.com/feeds/posts/default HTTP/1.1
Host: sylvainhb.blogspot.com
If-Modified-Since: Mon, 12 Nov 2007 11:00:00 GMT


Le serveur ne répondra maintenant par un "200 OK" que si la page a changé. Dans le cas contraire, on aura droit à un petit "304", sans contenu. Nettement plus léger, non ^_^ et plus simple que d'extraire à nouveau la balise <updated> pour comparer avec la précédente. Et tout ça avec une seule ligne de commande (à mon avis, bien plus sympa pour les tests que de lancer un "telnet" et d'essayer de taper toute sa requète avant que le serveur WEB n'estime que vous êtes trop lent):

echo "GET http://sylvainhb.blogspot.com/feeds/posts/default HTTP/1.1\nHost: sylvainhb.blogspot.com\nIf-Modified-Since: Mon, 12 Nov 2007 09:51:53 GMT\nConnection: close\n\n" | nc sylvainhb.blogspot.com 80


Petit raffinement: sous Unix, on dispose aussi d'un outil "watch" qui appelle la même commande, encore et encore. On pourra donc se faire un "surveilleur de blog ultra-geek" avec
watch 'echo "GET http://sylvainhb.blogspot.com/feeds/posts/default HTTP/1.1\nHost: sylvainhb.blogspot.com\nIf-Modified-Since: Mon, 12 Nov 2007 09:51:53 GMT\nConnection: close\n\n" | nc sylvainhb.blogspot.com 80'


Bon, okay, la date de référence pour laquelle on teste les mises à jour est toujours la même ici, ce qui rend l'exercice assez inutile. C'est que le début, d'accord, d'accord ?

(edit: amusant: non seulement cette méthode m'indique quand il y a un nouveau post, mais aussi si un post a été remanié ou s'il y a un commentaire en attente de modération ;)

Thursday, November 08, 2007

Encore Titus

De temps en temps, je passe faire un tour sur vgmaps.com, un chouette site qui répertorie les niveaux de jeux vidéos comme un "atlas". C'est du boulot, évidemment. Ayant récupéré "the Blues Brothers" sur abandonia, je me suis amusé à photographier le jeu au fur et à mesure.

the Blues Brothers, c'est le jeu où Titus Interactive prépare les ingrédients de ses futurs jeux. Des munitions (caisses à lancer sur les ennemis), pas encore tant de passages secrets, mais une série de "salles secrètes", comme les cavernes de Prehistorik (premier du nom) qu'il faudra explorer pour rassembler les objets nécessaires au concert de Jack et Elwood, mais qui peuvent aussi bien contenir des "bêtes" bonus ou un loubard.

Many games feature a way to carry items between different places, but Titus Interactive, in their nineties, brought that as the number-one mechanic of the game. The amno, for instance, are things you carry along, like crates. You can only carry one at a time, and if you get hit, you lose what you're carrying. The result is a platformer where careful progress is required, but where you also face a puzzle dimension, in the sense that you will need to pick your route to save amnos.

The whole is spiced up with some exploration, as you will need to find a special item in each level to get the "good ending" of the game. By then, I found that mix much more interesting than the usual straightforward, infinite amno, gun-oriented platformer.


Autre détail qui a son importance, si vous êtes touchés alors que vous transportez une caisse, vous la perdez, ce qui veut dire que plus loin dans le jeu, vous serez désarmé face à un autre danger. Bref, le moindre faux-pas est lourd en conséquence. Autre exemple, les designers se sont amusés à s'assurer qu'à deux ou trois endroits, vous risquiez de retomber plus en arrière dans le jeu (de préférence là où vous n'aviez pas la possibilité d'éliminer tous les ennemis).

  • niveau 1 : le magasin (guitare dans une des échoppes). On affronte des loubards, des mémés en caddie, des policiers, des serveuses furieuses et des jardiniers toqués. Une fois dans les nuage, c'est le piaf pond-vite qui nous mêne la vie dure
  • niveau 2: en construction (lunettes et chapeau que je ne parviens pas à atteindre. Peut-être faut-il un parapluie ...) Sale gosses armés de pulvérisateur d'acide et gros bras maniaques de la clé à molettes, mais gare aux mares d'acides et aux broyeurs.

Autre petit élément sympathique, des objets tels que les parapluies ou les balons du premier niveau, offrent un gameplay plus varié.

Blues Brothers II -- jukebox adventure: un flopBref, du bon jeu de plateau comme on aimerait en voir à nouveau. Dommage que l'opus "II" (juke box adventure) n'ait pas été une réussite... Bien sûr, les graphismes sont nettement plus beaux, mais ils ont complètement perdu le fil de l'histoire. Tout d'abord, le principe même du jeu n'a plus rien avoir. On le catégorise sur abandonia de "no-brain fun", et en effet, plus la moindre recherche. La progression dans le niveau est devenue ultra-linéaire. Finies les caisses, ici on lance des disques, et il faudra souvent en balancer plusieurs pour venir à bout d'un monstre apparemment inoffensif.

Là aussi, le bât blesse: alors que Blues 1 nous avait fait affronter des personnages parfois déjantés, mais toujours réalistes, on se retrouve ici face à des pièges à loup vivants et géants, et .. euh une sorte de tondeuse à gazon croisée avec une pelleteuse mécanique qui à visiblement des instincts de pit-bull.

Bref, les deux premiers niveaux sont beaux, mais franchement insipide une fois leur côté démo/tutoriel passé, et dès le niveau 2, les monstres sont tout simplement pénibles (mouvements trop rapides, impossibilité de les dégommer quand ils sont "au repos", bref, pas impassables, mais pénibles)

Et pour le coup de grâce, je vous laisse contempler, hébétés, nos fameux blueseurs transformés en sur-hommes après avoir mangé une part de gâteau, ce qui semblerait leur permettre de faire des sauts plus longs, et peut-être renforcerait la puissance de leur lancer de disque.

Ridicule et pas convaincant pour un sous. Bref, autant Titus Interactive nous a fait de bons jeux dans ses jeunes années, autant il semblerait qu'ils aient été contaminés par la transformation du monde du jeu vidéo en un "marché" et progressivement perdu toute notion du gameplay et de la conception des bons niveaux. Je n'oserais même pas dire qu'ils ont transformé BB en un clône de Megaman: la seule ressemblance viendrait du fait que l'on tire sur des ennemis dans un sidescroller.

Bref, concentrez-vous sur le premier volet à moins d'être un graphiste en manque d'inspiration.

Monday, November 05, 2007

Pas bien (2)

je ne dois pas blogger au lieu de préparer ma défense de thèse.
je ne dois pas blogger au lieu de préparer ma défense de thèse.
je ne dois pas blogger au lieu de préparer ma défense de thèse.
je ne dois pas blogger au lieu de préparer ma défense de thèse.
je ne dois pas blogger au lieu de préparer ma défense de thèse.
je ne dois pas blogger au lieu de préparer ma défense de thèse.
je ne dois pas blogger au lieu de préparer ma défense de thèse.
je ne dois pas blogger au lieu de préparer ma défense de thèse.

Wednesday, October 24, 2007

SEDS 32x32 needs you

Les béta-testeurs sur les forums sont assez unanimes sur un point: 16x16, pour l'édition, c'est un peu juste.

Je m'attaque donc au support de blocs plus grand (32x32 pour commencer, mais de manière à pouvoir supporter les résolutions classiques des sprites GBA/DS, à savoir 32x16/16x32 ou 16x8/8x16 également).
Ca fait pas mal de chose à réviser dans le code (d'autant que je ne peux pas garder le même type d'affichage de grille à un autre niveau de zoom: on ne verrait plus rien), mais j'ai déjà pu faire quelques essais de tracé dans la grille 32x32 ce midi.

L'ennui, c'est que le touchscreen de la DS ne permet pas un tracé suffisament précis à cette résolution. En clair, ça ira pour donner les "grandes lignes" d'un dessin, mais pas pour une édition au pixel près :(

SEDS has been now officially advertised on some NDS forums, and i got plenty of feedback from beta-testers. Among other things, for many guys, 16x16 canvas is just too small, so i'm now trying to have 32x32 edition to work. That makes many things in the code to be adjusted, including reviving the alternate grid display -- and those are getting in place.
The one thing that is more annoying is that 'pixels' are then only 4x4 wide if i want the full 32x32 sprite displayed -- and imho, 4x4 areas are too small to be accurately enough plotted directly with the stylus. It sounds thus that i'll keep this experiment for "rough sketches", but that we will still have to work with a higher zoom level of a sprite sub-region.

A re-réfléchir, donc...

Dans le même ordre d'idées, la palette n'est pas toujours évidente à utiliser. Dans ma manière d'utiliser l'éditeur, ce n'est pas bien grave parce que je travaille essentiellement avec les flèches (couleur suivante/couleur précédente) ou la pipette, mais je dois reconnaître que cobain a mis le doigt sur un point noir. Et déplacer la palette plus loin du bord n'a pas arrangé grand-chose: cliquer dans une case 4x4 sans en sortir, ce n'est pas une mince affaire sur le touchscreen de la DS.
Le mieux, ce serait sans doute de "doubler" la palette d'une zone agrandie des 16 couleurs autour de la dernière couleur choisie ...

Similarly, the palette isn't that easy to use accurately for people who haven't fine-calibrated their stylus input. I don't care too much myself since i'm not that much using the palette directly -- i make wide use of "next/previous color" with the Dpad and the "color picking" on the grid... The best alternative i can think of would be to offer both the full palette with 4x4 per color, and a "quick pick" area where you have access to the 16 colors around the one you just clicked, but with e.g. 8x8 region per color.

pre-release 0.1 beta-test for download here

Monday, October 22, 2007

tiles extraction ...

Un autre petit outil en Perl (basé sur la bibliothèque de manipulation d'images Imlib) qui décortique une image et identifie les tiles uniques (8x8) et le nombre de couleurs utilisées...
Il ne fallait pas grand chose pour en faire un convertisseur .gif->.spr un peu plus automatisé. Je m'y suis attelé ^_^. L'outil en question s'appelle "imlib2spr.pl" et est disponible dans le CVS du projet 'runme'.

I've been working on a new small (PERL) tool for SEDS/runme. "imlib2spr.pl" is using the "imlib" package to open your .gif, .png ... pictures and identify uniques tiles and colors so that it can then convert them into .spr files.
It also builds a map of how to reuse those tiles to get the initial image back.

Mais pourquoi chercher à transformer une image .gif en un tas de tuiles, me demanderez-vous. Okay, certaines images contiennent des zones un peu répétitives et pourront donc prendre moins de place en VRAM... et c'est tout ?

Ooh non! Notre DS est effectivement capable d'afficher directement des images 'bitmap' (c'est ce que je fais quand vous envoyez à runme un fichier .pcx), mais avec une taille maximale de 256x256 ou de 512x512, selon la configuration d'écran choisie. Impeccable tant que vous voulez une image fixe, mais imaginons que je veux faire scroller horizontalement une image de 320 pixels de large, je fais quoi ?

Je passe à 512x512 ? le bitmap fera alors 256K, presque la totalité de la mémoire vidéo!
Je tronque à 256x256 et je redessine une colonne chaque fois que je me décale d'un pixel ? Bonjour le code!

Maybe you wonder why i'm trying so hard to split a picture into small tiles while i've shown with runme that it was fully possible to display a .pcx (and thus .gif and .bmp aswell) image straight on the screen. Well, the reason is scrolling. You very well can show a 256x256 image on the DS screen (which is 256x192) and side-scroll it again and again (using the 'scrolling wrap' hardware option). That will take you 64K worth of VRAM. Now if you want instead to side-scroll a 320x200 image, you'll get into trouble unless you're agree to devote 512K of VRAM just for your background image.

On the other side, once you have 'tiled' your background, you can easily repeat it as many times as you want: it's merely a matter of a few KB, and you can easily rewrite offscreen parts of the map as the scrolling goes so that you keep showing the right stuff at the right time, with a 64:1 reduction of the stress on VRAM.
Since we are running on gaming hardware, i think we should make the best possible use of it, shouldn't we?

Well, demo and code for that will follow once the 7.11.7 day is over.

Sous GBA, pas tout ces soucis: l'écran faisait 240 pixels de large et le mode bitmap 256x256 aussi, donc on avait tout loisir de redessiner des blocs dans la partie complètement masquée de l'écran, puis de scroller un peu, puis de redessiner, etc.

Eh bien, si l'on prend la peine de convertir notre bitmap en "tiles", on peut continuer ce petit jeu: une fois les tiles en mémoire, une "carte" peut très bien contenir deux fois l'image initiale sans nécessiter d'avantage de mémoire vidéo (allez, quand-même 1 ou 2K de plus, mais c'est quand même mieux que de passer de 64 à 256K, non?)

Bref, c'est Cyril qui sera content. Lui qui me proposait y'a pas 48 heures d'ajouter un mode "construisons notre map" dans SEDS ... On en est plus très loin ;)


à la base, c'était ça:
#!/usr/bin/perl
use Image::Imlib2;

$image = Image::Imlib2->load($ARGV[0]);
print STDERR "$ARGV[0]: ".$image->width."x".$image->height."\n";
while ($ty<$image->height) {
  $tx=0;
  while ($tx<$image->width) {
  foreach $y (0..7) {
    foreach $x(0..7) {
      ($r,$g,$b,$a) = $image->query_pixel($tx+$x,$ty+$y);
      $r=pack("C1",$r);
      $g=pack("C1",$g);
      $b=pack("C1",$b);
      $colors{"$r$g$b"}=$ncolors++ if !exists $colors{"$r$g$b"};
      $tile.=$colors{"$r$g$b"};
    }
  }
  $tiles{$tile}.="($tx,$ty)";
  $tx+=8;
  $tile="";
  $ntiles++;
}
$ty+=8;
print STDERR ".";
}


print scalar(keys(%tiles)) . "unique tiles (/$ntiles) detected\n";
print scalar(keys(%colors)) . "unique colors detected\n";

exit 0;
note: il nous faudra installer le package libimage-imlib2-perl pour faire fonctionner le tout.


rem: pendant ce temps-là, Globoeil nous faisait une release de son "virtual game maker DS" ...
à découvrir sur globoeil.fr/vgdms ...

Tuesday, October 16, 2007

SEDS Multipage

ah, y'a pas à dire: c'est agréable d'avoir un environnement de développement capable de mises à jour rapides ... En quelques coups de cuiller à pot, j'ai pu, hier soir, goupiller la première version de SEDS capable de gérer des fichiers .spr multipage. Enfin la possibilité de dépasser 48 sprites en un fichier (ça devenait vraiment problématique) et de réorganiser mes petits dessins par thèmes (un seul fichier pour toute la forêt, avec une page contenant les blocs de terre, une pour les arbres, une troisième pour les pommes, etc.)

Wow, needless to say, it's really a good thing to have software update to speed up application development. Just a couple of edit-compile-update loops were enough to brew the first version of SEDS that can manage multi-page .spr files (which had been tested in runme a couple of weeks ago). That means i can at last break the "48 sprites per file" limit and reorganize my own tiles theme-wise, e.g. grouping all the forest-related tiles with one page for dirt blocks, one for the tree trunk & roots, anoter one for in-progress tree tops, one for the apples, and so on.

C'est aussi un premier pas vers la possibilité de mélanger des blocs 16x16, 8x8 (pour les pieds et les mains de bilou, entre autre) et 32x32 (l'encrier).

Bon, ceci dit, pour l'instant, les réorganisations sont pénibles au possible, mais c'est juste parce qu'il me manque une interface pratique pour ce genre de tâche :P

Et il a fallu faire tout celà sans que les aventuriers qui avaient téléchargé la release d'hier ne se retrouve temporairement avec un programme inutilisable suite à un update malencontreux... ce qui n'a pas été sans mal :P

This is also the first step towards the ability of mixing 16x16, 8x8, 32x32 (and other sizes coming) resolutions in a single editor/spriteset, which will be crucial to go on working with Bilou's world. Well, right atm. "reorganization" is as tedious as moving files using MS word, but that's still better than no reorganization at all :P


Allez, ça mérite bien une "0.2"