Showing posts with label widget. Show all posts
Showing posts with label widget. Show all posts

Tuesday, May 02, 2023

A bit of shadow

Once upon a tweet, was a blog post about making dsgametools widget more readable and nice to use by adding a shadow to the default font. It was the youngest of the Todo family and its sibling would often make fun of it because it had the lowest possible priority for the project.

But then, on an idle day were the coder so tired he couldn't read a screen, though he had the Todo category open on his boox. "Well, why not" he thought, and he let our little Thumby Todo post jump over a blank page of his notebook.

It started sketching one letter, with its right and bottom empty lines of pixels, and split it in 3: Darkness, where light normally never comes; Highlights, where light might strike harder. And it turns out that if Highlights were to fall and the darkness picked up its power, then the letter would look all flat. And then the color that never changes, regardless of whether Highlights or Darkness is winning.

Bon, quelque part entre 2 scorpions, j'ai eu envie de creuser un peu cette histoire d'ombre pour les caractères dans les outils DS. Le mockup donne tellement mieux que mes captures d'écran ... en plus, ça se prête à merveille à un peu de programmation sur papier. Un petit schéma d'abord... puis quelques routines comme à l'époque du cours d'algo. Et puis j'ai fini par me rendre compte que chaque fois que je passais devant cette page-là dans mon livre-ordinateur cahier-agenda, ça réchauffait un peu mon coeur de codeur de penser qu'un jour, peut-être, j'aurais le temps d'essayer ça.

Very well, thought the coder, but I do not feel like hand-painting every 128 characters of the default font. Can we find a simple set of rules that, given a regular 1-bit-per-pixel font would deduce the 2-bit-per pixel font with highlights ? Yes, of course. And that's a perfect fit for bringing back paper coding.

Well, as usual, it then took a good deal of checks and debugging to find where that code should actually be invoked, what prevents it from working and so on. 

Et puis zut. On est dans un projet perso pour le plaisir, pas dans un projet-pro pour le client, donc au diables le Canban, les priorités, les milestones et tout ça. hg branch et voyons ce que ça donne... eh bien, ça donne bien. J'adore. Juste un hic: ça verrouille presque 40 couleurs de la palette utilisée par SEDS. Ou plutôt, dès qu'on charge un .spr qui utilise plus de 216 couleurs, l'effet est ruiné par un texte qui devient illisible. Parce que oui, j'utilise les palettes étendues de la NDS pour le moteur de jeu et pour presque toute l'interface graphique sauf pour le texte et ... pour le widget "palette" :-P

But there it is. Working. And even on emulator, the feel of it is just wonderful. And all it takes is some NES-glory palette swapping, where the text is moved from the 'interactive' palette with black shadow to the 'active' palette where 'shadow' is actually white and highlight has background color, as if the text had been pushed down by one pixel. Unfortunately, there's a price to pay: instead of 4 system colors, I need 40 of them (2 x 16-color palette + 4 on the 3rd palette). And so far, in SEDS, that means we can only use 216 colors instead of 250.

edit: but there is hope: SEDS is currently *not* using the multi-palettes mode (unlike LEDS) It likely wouldn't suffer from some extra system colors if it did. Converting AnimEDS sounds less appealing, because that has all its interactive windows on the 'main' screen rather than on sub-screen like older tools ^^"

Thursday, January 28, 2021

Une histoire de police

 C'est la série de p'tits fanart pixelisés de Rephil qui m'a mis la puce à l'oreille: une police en pixels, c'est quand même bien plus lisible avec un ombrage. Surtout quand on est pas déjà en noir-sur-blanc. (ou blanc sur noir). Et vous savez quoi, il arrive à le faire même en 5x5!

I guess it is the checkerboard pattern of Rephil's  (pixel|fan)art that lead me to realise is so much more readable when you drop a shadow. (yeah, that took me 15 years). So maybe it would be worth it to do the same on the DS for my game tools, right ? And maybe I could even push it further and use 'drop shadow' to indicate that some specific text is interactive! Someday ... maybe... Clearly not a high-priority thing to do.

Alors bin avec mes caractères 8x8, sur DS, il n'y a pas de raison que je m'en prive, si ? Dans presque chaque caractère, il y a une ligne vide en bas et une colonne vide à droite pour éviter qu'ils ne se 'collent' l'un à l'autre. Et ça n'est absolument pas gênant si les pixels d'ombre se colle aux pixels blanc des caractères suivant.

Petit mockup de ce que ça donnerait... On peut même raffiner en utilisant ce truc que pour les caractères "interactifs" des widgets. On peut même utiliser une couleur supplémentaire "highlight" qui disparaîtrait quand on active le widget alors que l'ombre passerait à la couleur de texte pour donner ce petit effet interactif "le bouton s'enfonce quand je pousse dessus" qui fait toujours du bien.

Maintenant que je suis passé à du multi-palettes dans tous mes outils, pourquoi s'en priver ?

edit: oh bin justement, quelqu'un a mis en ligne une belle collection de polices bitmap issues de la demoscene...


Saturday, July 13, 2019

Monster selector

Okay, it's not much and it wouldn't even be posted alone despite I haven't been posting about tools development for weeks. I have now the 'selected monster' arrow showing you where on the map is the selected monster if you happen to get it off-screen.

But it is not alone. Changing that required more refactoring that I kept track of, and I'll have to break that giant "stash: okay, it works" commit into proper commits. It's not just that the code was old or buggy: my coding standards have quite evolved by working in a team where most of the code you have to deal with has been written long ago (and likely not by yourself).

It's not that much about the lack of comments. Having something like

// use sprite tile 0 for the cursor
sprites[CURSOR].attribute[2] = 0;

only works if this is the only place in your code where it can happen, and without coding habits that guide you towards

const oamno_t CURSOR_TILE=0;
sprite[CURSOR].attribute[2] = CURSOR_TILE;

you're very unlikely to get it done at a single place.

I had to fix things like that, as over time, I ended up with two widgets deciding to use sprite tile 0 for their own special purpose. I had to migrate the 'sprites granularity' into the recently-introduced "UsingSprites" class as I realised that more and more parts of the code now depended on that granularity (like whenever you're allocating sprite tiles) and top-screen and bottom-screen might not be using the same granularity...

Among the ugly things in LEDS code, I shall name a global "UI-like" object -- QuickGo -- that renders the level into a small bitmap, so that we can quickly navigate the level. That object is created in the 'MapEditWindow', but it is never inserted as a widget. It seems to be a global pointer, which is accessed through LayersWindow -- the part of the application where it actually shows up -- and even there, it doesn't directly reacts to user inputs. Instead, there is a 'QuickWidget' object that doesn't show anything on screen, but that does produce events on stylus touches that MapEditWindow will further catch and process.

Such a "code-that-works" approach that breaks almost every coding convention in the "GEDS" library is tricky to reason upon. You see QuickGo in a window, so you should be allowed to assume it is part of the UI, and used in that window. 

Tuesday, February 20, 2018

Ideas for a handwriting recognition on DS


Il y a un moment que je retourne l'idée dans ma tête : un système permettant d'écrire librement (du code, pour l'éditeur de comportements) sur DS. Le système serait basé sur une grille 3x5 visible par l'utilisateur. Parce que les claviers virtuels, c'est pénible et qu'un système qui autorise l'utilisateur à écrire n'importe où et n'importe comment, ça n'aura aucune chance de marcher avec 66MHz


That is another idea that has been laying on paper for a while. I lack text and script editors at the NDS.  I don't want to go for a virtual keyboard, because they are really too slow to work with. I can't afford a complex recognition system, and even Google's handwriting system would suck on code expressions.


But I feel like it would be easy to recognize letters when they have been written on a grid. A bit like if we were painting a low-resolution font.


Every letter drawn corresponds to a 15-bit map that can be quickly tested against a small database of features and suggest letters to pick when the decision is fuzzy.

 Additional features could be the starting and terminating coordinates, as well as the number of strokes.

Cette petite grille fait que chaque lettre tracée correspond à un code sur 16 bits unique. A partir de ce code, on pourrait rapidement identifier un groupe d'entrées dans une petite base de données qui traduit les traîts en lettre (p.ex. à partir de la position du point d'origine et du nombre de traits). Je ne veux pas me limiter aux lettres, évidemment. L'idée est de reconnaître l'ensemble des caractères ASCII pour pouvoir éditer du code n'importe où le plus facilement possible. 

I hope the result will be an interesting compromise between
- early PDA "one-weird-stroke-to-write-them- all" (Palm's Graffiti system)
- sharp Zaurus "Free-letters-one-by-one"
- OCR from scanned text.


I know segmenting is a complex task in letters recognition. With pre-drawn grids, the user is guided to start a new segment or stay in the current one. We can also tell apart uppercase and lowercase Eg. "p", punctuations, etc. locally rather having to rely on some line-level calibration. And we can naturally move to the next space for the next letter.



Avec cette grille, je m'affranchis d'un des problèmes les plus costauds de la reconnaissance de caractères (la segmentation) tout en permettant d'utiliser le plus naturellement possible l'espace disponible (sur Zaurus, on devait presque toujours revenir au même endroit pour tracer la lettre suivante ou le mot suivant). Et c'est toujours plus pratique à apprendre (encore qu'on pourrait essayer d'apprendre de nouvelles écritures à la DS) d'écrire "comme Pype/Zaurus" plutôt que "comme en Grafiti", même si grafiti avait le bon goût de ne demander qu'un trait par caractère.

Granted, the hand script writing I use when I want maximum readability already separates letters a lot and uses only one stroke for most lowercase. Because I reformatted my writing for the Zaurus already. But it's not like I had a huge user base to take into account ^^".

The granularity of the grid should help making tricky characters like braces-versus-digits-versus-C easier to deal with.

Thursday, January 11, 2018

Engine Refactory

The Big Refactory has started (I could pretend it is a new-year resolution). And it even went pretty far, like abstracting away the animated objects list so that only the code for animated objects need to know details of the animation scheduler.

I was about to try changing the VRAM allocation system so that only classes deriving from using Resources could request items, and I got stuck in the animation editor.

Unlike SEDs and -to some extent- LEDs, AniMEDs still use a lot of global variables. Things like the sprite set or the animation being editted are used almost directly in many places, instead of being captured as "structural singletons". And at some places, it also means that we were calling Ressource Manager directly at top-level code, and that contradicts what a common base class can do.

There is one other peculiar thing about the animation editor: the set of pixels used in the game isn't uploaded to the video memory. Instead, we keep it in main memory, and only some bits of it go tothe VRAM through a Sprite sheet that map some sprite memory.  These sprite sheets are linked to a specific widget, such as the timeline or the frame preview. I must not try to make them part of a "model": they truly belong to the implementation of the widgets.

And yeah, although I have a digital sketchpad and an e-boox, I still enjoy some good paper and fine (erasable) pens for such things.

Sunday, February 05, 2017

class LayersConfig

All my DS tools share the same "GUI engine", but all somehow have custom requirement on what the hardware compositing engine -- the "layers" system -- should do.

Yet, so far, they do that by peek/poke-like custom lines of code hacking into the video registers of the Nintendo DS. Because the hardware is so elegant, I had no real appeal to hide it between an abstraction layer, but now I run into issues where console can't be read anymore.

So let's try to make it more structured. Capturing all code that access the layers control register into one class would be nice. I think that class -- let it be "LayersConfig" -- could be associated with *Windows classes that define the different "modes" of the application. Switching between the drawing-on-grid and the Palette-edition of the Sprite Editor implies changing the active window. Same for swapping between files picking and map editing of LEDS or swapping between downloads and playtesting in RunME.

I think I should stop trying to optimize which character is updated on such window switches and consider that there should be a clearscreen followed by a full repaint, if that's not yet the case. That could make Window::clearscreen an interesting place to do tricks like letting only some part of the console show through, for instance.

Saturday, September 19, 2015

I need the Rainbow Road

I started working on a last level for School Rush, where you'd have to climb up for safety. It was tedious, because navigating in the level in LEDS can only be done with L+DPAD at the moment, in 64-pixel increments. Yet this time, I had to move through 1024x8 pixels of emptyness before I reach the "bottom" of the level everytime I want to migrate something from the title screen.

And then, i tried to copy the current game on my brother's DS using my not-so-smartphone, so I lost that map. Sigh. I'm not re-doing it that way. I will first bring on a new tool in the Level Editor. Something like a "Quick Navigate" option. I thought a "Rainbow Road" would work okay. level structure is depicted by two rasters (one horizontal, the other one vertical), and auto-zooming so that you a square area covered with stripes, and touching one pixel of that square brings you immediately to the corresponding area of the level.


Bon, perdre un niveau qu'on édite, ce n'est pas drôle. Devoir recommencer en faisant des centaines de fois L+bas pour retourner au fond du niveau, ça l'est encore moins. J'ai pris un peu de temps cette semaine pour réfléchir à un moyen de se déplacer rapidement d'un point à l'autre de la map pendant l'édition, en tenant compte des ressources vidéo déjà largement sollicitées sur l'écran d'édition. Je propose la RainbowRoad: un carré sur lequel sera représenté le niveau en utilisant un dégradé bleu-rouge pour l'axe horizontal et un dégradé foncé-clair pour l'axe vertical.

As far as software engineering is concerned, I face once again the need for a given event (update of level coordinates) to be produced by any of M sources and consumed by N receivers. M and N are small, and constant once the program is built. A bus pattern could work, or possibly something like an object that sends notifications when updated.

Color selection in SEDS could also benefit from this pattern.

Post-Scriptum thoughts:
  • [dont] Having QuickGo out of MapEditWindow allows to keep level edition full-screen. I have very limited options to introduce yet another window over MapEdit.
  • The drawback is that currently MapEditWindow doesn't show when you toggle to TilesetWindow.
  • [done] The transient "layer selection" overlay (available when map edition in "copy" mode) could host it as well.
  • Maybe replacing one of the rasters with a overview of how "dense" the area represented by one pixel is (with transparent-to-white) would give a good feeling of where we will go ... 

Tuesday, May 01, 2012

BoxWidget ... beyond the code.

I missed a "svn commit" this morning, so all I can do is some mock-up to think about how the "BoxWidget" will be used to define hitboxes in AnimEDS... It seems like I'd rather not jump into implementation immediately and think a little bit about the options: boxes are defined on a per-animation basis, not a per-frame basis, so maybe they could be edited on the FileWindow rather than on the AnimWindow.


Bon, bin quand on a pas synchronisé son code à la fin du week-end, on peut toujours se faire un p'tit mockup pour voir comment le nouveau widget "définir une zone rectangulaire" va pouvoir aider à la définition des zones de collision. Mock-up pas totalement convaincant, d'ailleurs. Fort confus, même si je ne vois pas bien comment faire mieux. Ça me paraissait une bonne idée, au départ, de juste "suggérer" la zone de collision en marquant ses coins, mais la plupart des problèmes de collisions rencontrés jusqu'ici provenait d'un recouvrement entre zones. Du coup, pouvoir en visualiser plusieurs d'un coup ne serait sans doute pas plus mal...

It could also be interesting to be able to visualize more than one box at a time, similarly to what happens with InspectorWidget: many "collision bugs" were due to improperly overlapping windows. That could require another form of display

Saturday, April 28, 2012

SUB or not SUB ?

When I started working on SEDS, most widget was supposed to be on a very specific screen. I now have 4 tools that share the same "GUI engine" and widget library (libgeds), and some will sometimes be on the "main" screen on the DS and sometimes on the "sub" screen. Which screen is rendered where (top/bottom) can be easily swapped by the hardware, but the video memory dedicated to one of the screen cannot. When you put colours in BG_PALETTE_SUB, only one screen can use them.

Rhaa! Je sais que j'avais trouvé un truc pour que les widgets à l'écran puissent choisir d'eux-même s'ils étaient sur l'écran principal ou l'écran secondaire, mais impossible de me souvenir d'où j'avais fait ça ... Je sors mon casque de mineur des vivres pour 3 jours ... si je ne suis pas revenu du SVN à la fin de la semaine, appelez les secours

"vr" is your vram location computed by Window, btw
Là! Ça y est! le petit curseur de SEDS dont j'avais eu besoin dans LEDS pour la sélection du tile courant et dans AnimEDS pour enregistrer une animation. Ouf.

I finally found a trick to let the widget automatically allocate the proper resources (sprites, tiles, colours) depending on which window hosts it, by delaying the allocation to "widget placement" time... well, the trick is roughly one year old, now. No wonder why I had a hard time to remember on which widget I prototyped it :P

Sinon, comment vous trouvez le premier jet du décor de fond pour la bibliothèque ?
Oh, yeah, and that's a first draft of the new intended background for the library in the school zone. Do you like it ?

Monday, December 12, 2011

wanted features

There are things I would like to improve in each of my tools. Maybe it's a good time to collect them in one place. Various features I'd like to add to LEDS depend on the ability to display the map at once. I planned a radar widget in a corner of the TilesetWindow, but that's only 64 pixels wide. If I want 1 pixel per tile, that's only 2 screens wide.

To do better, I'll need to fit at least 8x8 tiles per pixel, thus I'll need direct-color rendering to vary the "gray" level to the number of "solid" tiles in an area.

I've already some code that creates a direct-color sprite (SpriteEditor, PaletteWindow, GrayPreview), but I remember I had a hard time making it work. Reading gbatek again wouldn't hurt.


On the other hand, it would be good if I could have a "stencil" feature (as in Deluxe Paint IIe) in SEDS. I realised when packing the new version for Atnas that I had a serious bug with my previous attempt to have it running. The 'quickpal' widget could be used more appropriatedly to build that idea.

Last thing, I'd need some alternate zoom level for the animation editor. Bilou, dumblador, ... they aren't the size of that Mr. Egg. I did a try a few weeks ago, but at some point, the code that enforce that position is at a specific pixel (not a fraction) despite the zoom level wasn't planned to work at other levels. More thouhgts needed.

edit: Oh, well, and of course, there's the revised collision engine, still pending in its branch. Maybe *that* should be the immediate focus ...

edit+: My milestone for the next release of LEDS should be to ensure that it's fun for a middle-aged kid to draw his own level. That may require the ability to "freely draw" an object for which no pixel art exist yet, and to allow that object to be imported in SEDS later.

Sunday, November 27, 2011

Level Editor for DS : 0.1

Nous y voilà enfin: mon éditeur de niveaux disponible au téléchargement, avec les bugs corrigés, même si l'interface reste assez expérimentale. Avec en prime deux tilesets Creative Common pour vos petits tests: "generic.spr" par Surt (CC-BY-SA) et "frogatto-dirt.spr" (CC0) par Guido Bos. Amusez-vous bien, les tifous: la version française du tutoriel est en construction sur le fil "dev-fr". Huzzah! At last, you've got it. My long-delayed Level Editor for Nintendo DS (LEDS) is at last available for download with some sample tilesets to toy with ^_^. Thanks fly to Surt and Guido Bos for releasing their game art under creative-common license on OpenGameArt. The software is still a bit rough on the angles, so make sure you've got the tutorial page displayed on some screen when you'll use it for the first time(s)... and now ...

Go create!
Features that I still wish to see appearing in a future release (check back this post for UI mock-up):
  • [hint] provide a way to change "type of tile" when editing the meta-layer, without requiring on-map display. (we have the whole ABXY buttons disabled in that mode, right ?)
  • flipped tiles that also work in "copy" mode
  • area manipulation (overlays?)
  • map size edition (crop, extend)
  • map sketching (zoomed-out drawing)
  • map radar widget
  • multi-palette support on the BG layer (needs SEDS coordination)
  • [done] more robust monster edition mode.
  • wizard for .cmd file generation
  • use the ARGV protocol to quick-load a map from runMe *at a specific position*.

Monday, November 14, 2011

meta_buttons_shown=false

Comme je devais tester une imprimante, ce week-end, je me suis imprimé quelques fichiers sources de l'éditeur de niveau, histoire de comprendre d'où vient le comportement erratique des "meta-buttons", cette petite palette en haut à droite de l'image qui permet d'indiquer quelle portion d'un niveau est solide, où sont les pentes, etc. Pour pouvoir éditer les "arènes" d'Apple Assault, je les avais rendus "escamotables", mais c'est loin d'être un succès. Ils donnent l'impression d'être actifs ou non indépendamment du fait qu'ils soient visibles ou non. Malheureusement, le Level Editor est aussi le dernier outil qui n'a pas encore été "porté" pour la nouvelle release du devkitpro. Du boulot en perspective, comme la réactivation de la lecture des répertoires, les nouveaux mécanismes pour initialiser la console, etc.

  • loadNDS_Vram turns into runNdsFile : http://dsgametools.svn.sourceforge.net/viewvc/dsgametools/trunk/SpriteEditor/source/main.cpp?r1=617&r2=824
  • convert to the new console system : http://dsgametools.svn.sourceforge.net/viewvc/dsgametools/trunk/runMe/arm9/source/main.cpp?r1=735&r2=750
at least those two must be done and checked before I can start fixing the huge mess that appeared on the Level Editor user interface when I tried to make the "meta-buttons" a pop-up widget... Yes, LEDS is the latest of my tools that has not received a revision since I switched to "devkitpro 32" ...

edit: done... maybe ?

Friday, August 12, 2011

Stacking Troubles

Fix a bug, another appear. Does that sound any familiar ? I had to reorganise the "window" that constitute my animation editor, so that I would no longer miss some data while saving my work. Those "windows" are widgets container that you can stack over each other. When the GUI engine needs to deliver an event, it starts trying to give it to the top-level window and digs deeper until one of the window has one widget that can process e.g. the click.

The reorganisation consisted of introducing the ThumbWindow (see snapshot) below the FileWindow, so that one can control the slot where an animation should be saved while he's building new skelettons and making "save animation to slot" a natural operation when you're on the road to save to a file.

at first, it seemed to work fine, unless I realised that a single click on any of the limbs or sprite tables disabled all the actions on the "bottom screen" widget. I had overlooked the fact that two of my widgets on the bottom screen (the tables) were actually not part of the "FileWindow", but something laying on the main (application-wide) MetaWindow (in red), so that they could be shared by both file storage and animation edition activities.
Unfortunately, because MetaWindow is the lowest layer of the software, it were obscured by the screen-wide "SpriteTable" that contains all the thumbs. No way to go through. Of course, this is ridiculous: those thumbs are not on the touch screen so they shouldn't be receiving any stylus-based event ... but well, they are. For some odd (historical?-) reason, the GuiEngine ignores facts as trivial as "the top window is a DownWindow, so any UpWindow in the stack shouldn't receive GUI_CLICKED". Hopefully, it features an "active" flag that windows can set and clear to indicate their will to receive/ignore such events. It's to the application author (me ^^") to ensure Window::release() and Window::restore() update this flag accordingly to the desired effect. ... which is now done.

Now, if you don't mind, I have a staircase to polish.

Tuesday, July 19, 2011

update on BG colors.

So that's the tileset as you know it so far. Used in "greenwoods demo" and "Apple Assault". It took me a few more missed attempts while trying to blindly copy Eyecraft's colours but I finally got it working... And what made it work was to build up a mockup first (the small image nearby) with BG, FG and character tiles alltogether in such a way that contrast issues became obvious. Once in that setup, with a 32x32 area to focus on where all the important things were there, I could bring the BG colours down, almost to grey, although keeping the blues with a higher value (blues and purple = dark, cold shadows. That's how our bluesky world and cone-rod eyes work ^_^)
Ingrédients: un tileset pas bien coloré, un sprite de référence, un éditeur capable de cloner des couleurs et une pinte de bonne humeur

  1. Créer une nouvelle Sprite Page et y copier l'intégralité des tiles à recolorer
  2. Copier également les tiles qui doivent avoir un bon contraste et le sprite de référence (personnage principal du jeu).
  3. Superposer l'arrière-plan et l'avant-plan en utilisant sur-chargeant avec (B) en mode curseur plutôt qu'avec (A). Construire un mini-mockup avec les tiles ainsi obtenus.
  4. Sélectionner un des tiles d'arrière-plan, cliquer sur "SCAN"
  5. Clicker sur une zone de la palette encore vierge pour définir la destination des couleurs clonées, puis L-cliquer sur le bouton [+] du sélecteur de couleur (QuickPal). Clicker sur "SYNC" pour valider les nouvelles couleurs.
  6. Passer la grille en 32x32 et charger (R-déplacer le curseur-A) la zone entourant le personnage.
  7. Basculer en mode "édition de palette" (SELECT)
  8. Ramener les couleurs clonées vers du gris. Vérifier sur la zone de preview en gris que le contraste est suffisant.
  9. Clicker sur "okay" pour prévisualiser les modifications sur l'ensemble de la page, puis validez en cliquant sur "sure". Retourner à la grille en pressant à nouveau SELECT
  10. Si nécessaire, pressez "START" et utilisez les boutons "<<" et ">>" pour faire apparaître en vis-à-vis la page avant et après modification. Clicker sur un tile "d'avant" puis L-clicker sur un emplacement "d'après" pour effectuer le transport.

See that horizontal area between [+] and [-] under your spriting grid ? This is the QuickPal widget. when you click [SCAN], all the colours present on the grid are copied there. "cloning" the colors consist of copying those colours at an alternate location in the palette. You first pick that target location by touching the palette widget, then launch the cloning by clicking [+] while holding L shoulder button of your console. All the tiles on your working sheet (on screen) will then use the new colours. All the remaining tiles are unchanged, included the backup copy of your working sheet, meaning that you can reimport some old tiles if you need to do so.


PS: ce blog comprend maintenant exactement 600 posts (dont 55 brouillons :P)

Thursday, June 23, 2011

Creating new skelettons.

Animation skeletton, GobStructure ... I haven't found yet the term that best describe "the set of pages to be used for the limbs of a compound GameObject". And I also struggle making it part of the AnimEditor. So I took the lunch to chart the three main components involved - AnimWindow, ThumbsWindow and FileWindow - and how they use each others. I want the skeletton to be defined on the FileWindow because it's convenient to navigate through available pages there (and I have plenty of room for widgets).

Je cale un peu sur la manière d'implémenter la création de la "structure" d'un sprite composite (quelle page de sprites utiliser pour quel "membre" et combien de membres y aura-t'il en tout. Entendons-nous bien: quand je dis "je cale", ici, ça signifie que je ne parviens pas à déméler la pelotte de code sur la demie-heure de disponible entre le souper et le bibi de *deline.
Dans ces cas-là rien de tel qu'un petit temps-de-midi-uml pour cartographier les alentours, même si je n'ai pas respecté la moitié des règles de bonnes pratique que je connais ^^".

Red path: FileWindow directly save the new structure into one of the animations under the selected thumb slot. Boulder: FileWindow can't convert a skeletton into a serialised representation.
Blue path: FileWindow just notify AnimWindow of the skeletton modification. Question: what should happen with the current animation ?


Edit: à bien y réfléchir, c'est quand-même un peu ridicule de se prendre à ce point la tête pour une telle bêtise! c'est tout le temps comme ça, le développement en C++ ?

Thursday, May 26, 2011

grayscale preview : done.

Well, I guess it would be fair enough to admit that my knowledge in image processing turned out to be insufficient to provide a "magic contrast boost" slider in SEDS. Yet I regularly have contrast issues with my sprites, and I've learnt on Pixelation forums that turning your sprite into grayscale is a nice way to investigate whether a sprite is contrasted and readable enough. So the plan was

gray = red*.30+grn*.59+blu*.11
C'est la formule qui permet de passer d'une couleur RGB à un niveau de gris "équivalent". Or, passer son sprite en niveau de gris, c'est le truc ultime des gurus de Pixelation pour savoir si le contraste est suffisant ou non. A défaut d'un "boosteur de contraste" magique, c'est le moins que je puisse tenter.

Reste à le mettre en oeuvre. C'est le genre de chose qui aurait été impensable avec mes éditeurs sous DOS, n'ayant qu'une palette unique de 256 couleurs ... Mais ici, avec le soutient des "sprites DirectColor" (ou ATTR0_BMP), c'est une autre histoire ... Moyennant une consommation de mémoire vidéo un peu plus importante, je peux directement donner les composant RGB de chaque pixel individuellement et indépendamment des palettes "background" et "sprite".

Ca n'aura pas été sans mal quand même, tant le fonctionnement de ces sprites diffère de celui de mes "bons vieux sprites habituels". D'abord, exit le tiling. Le pixel (x,y) à l'intérieur du sprite est stocké dans le y*width+x ème "short", tout simplement. Vu que la dénomination officielle est "SPR_BITMAP", il fallait un peu s'y attendre, celà dit :P
Deuxio, ces sprites-là ont leur propre bits de contrôle dans REG_DISPCNT, et peuvent donc rester en "mode 2D" alors que les autres sprites sont en mode 1D. On dirait d'ailleurs que desmume a encore quelques soucis avec ça et qu'il utilise ces sprites en mode 1D quoi qu'il advienne 0_0.
Enfin, le "numéro de tile" n'est plus du tout interprété de la même manière. L'interprétation exacte est donnée sur gbatek, mais en ce qui me concerne je me suis contenté d'une heuristique du genre "tileno/2" avec un 'padding' pour aligner les données du sprites sur le bloc de 32 tiles le plus proche:

tileno=Engine::allocate(Engine::RES_SPRITETILE,32+PAD); // will use directcolor.
if (PAD && tileno&(PAD-1)) tileno=(tileno+PAD)&(~(PAD-1));
sprdata = SPRITE_GFX + tileno*32;
Engine::sprites[oam].attribute[0]=ATTR0_BMP|ATTR0_ROTSCALE_DOUBLE|OBJ_Y(0);
Engine::sprites[oam].attribute[1]=ATTR1_ROTDATA(rot)|ATTR1_SIZE_32|OBJ_X(96);
Engine::sprites[oam].attribute[2]=ATTR2_PRIORITY(1)|ATTR2_ALPHA(1)|(tileno/2);
The idea was to use "direct-color" sprites in order to have the freedom of picking RGB colors without messing up with the sprite palette (sprites are already used to render the whole palette at the bottom of the editor, so that we have enough freedom for widgets). That would only cost me some more video memory (clearly affordable in this context) ... and some discovery of these new sprites' oddities...
A separate control on 1D/2D sprites, a specific scheme for reading data out of the VRAM (lowest bits of "tileno" are now used as a horizontal shift in an otherwise bitmap area) ... And of course, no tiling of the sprite data (these are named "BITMAP" sprites. What exactly did you expect, hmm ?)

Well, that's all done, now. Just give me some more time to remove debugging statements, and I should be able to release Sprite Editor 0.4 by Monday.

Monday, April 11, 2011

RES_BGTILE_SUB

Peut mieux faire. Une soirée de débugging et une heure de chipotage par essai/erreur pour parvenir à avoir la LimbsTable sur la gauche de l'image qui fonctionne correctement, il n'y a pas vraiment de quoi être fier. D'autant qu'il ne s'agissait pas cette fois-ci de coder un nouveau widget mais bien de réutiliser quelque-chose qui avait déjà été développé pour le LevelEditor!

Not really proud of how my SpriteTable widgets completely lack ease-of-use. It took me one evening debugging and one extra hour of trial/error coding to figure out how I should instanciate the "limbs table" for the animation editor. And that's not even some new widget: merely an attempt to reuse something that was built for the Level Editor a few years ago. And the resulting initialisation code is ridiculously complex:

La difficulté d'obtenir une petite partie des tiles pour un usage dédié est anormale. Voyez plutôt:

SpriteSheet limbsheet(BG_GFX_SUB + 0x4000 +
Engine::allocate(Engine::RES_BGTILE_SUB,2*16)*32,
BG_PALETTE_SUB,0x8000/64);

Alors qu'on aurait voulu pouvoir s'en sortir en écrivant limbsheet(Engine::RES_BGTILE_SUB,32). Et celà sans prendre en compte le besoin de reprogrammer le mode vidéo de l'écran "sub" (par défaut régler pour faire des zooms comme dans le SpriteEditor) et le "calque" sur lequel seront dessinés les différents membres (par défaut affichant des caractères ASCII en 16 couleurs).

Et il est temps que ça bouge, histoire que je puisse donner vies aux "petites marionnettes numériques" imaginées par mon frère pour divertir les loulous.

edit: okay. That seems to work, now. At least, I've got limbs displayed on the left and the according spritepage shown on the right when one limb is clicked. Ready to start working on the "Frame Editor" widget. But the code is still ugly.

edit++: it looks like making it "easier to use" will be required to turn the RightTable into a TileTable as well ... and that might be required to be able to display sprites on the FrameEditor.

Monday, March 14, 2011

SpriteRam, SpriteSheet, SpritePage, SpriteSet

Ce week-end, c'était priorité au montage des étagères dans mon petit bureau de 7m³, mais j'ai quand-même pu me concentrer un peu sur les petits soucis de gestion de mémoire qui me ralentissaient dans l'écriture de mon éditeur d'animations.

Pas étonnant que 3 ans après, je m'y perde un peu ... SpriteSet est commun à tous mes projets DS: c'est en gros le support du format .spr généré par le sprite editor. Mais les données graphiques qu'il manipule se sont étoffées. Les SpritePages ont été introduites en 2007 pour permettre d'éditer plus que ce que l'écran de SEDS ne peut afficher d'un coup. Les SpriteRams, en 2008 pour compenser le fait que la mémoire vidéo de la DS est séparées en "caractères" et "sprites".

I *had* to set the priority on some furniture assembly this week-end, to make my "7m³-desktop" a place where I can actually focus on what I do. Yet, I found some time to meditate on the VRAM allocation issues that were preventing me from doing progress on the animation editor. We're talking here about a set of classes that was initially designed to manipulate a single VRAM bank directly and that started to be multi-purpose (game engine + editors), multi-sets (manipulates set of sets of sprites), and that embraces ram heterogeneity (VRAM + main RAM). No wonder I was baffled.

In the case of the animation editor, the various "limbs" may use different spritepage (at least, 16x16 limbs may not reside on the same page as the 32x32 limbs), and at least for building miniatures on the timeline widget, those pages must be accessed simulatenously although there might not be enough VRAM to hold them altogether. I added a few methods to SpriteSet to address this situation in an almost clean manner.


Pour le moteur de jeu, l'ensemble des sprites est chargé en VRAM et les SpritePages servent uniquement à la construction des animations. Pour les éditeur, par contre, le contenu graphique (et donc SpriteRam.target) est généralement présent en mémoire centrale, et la VRAM est plutôt affectée aux SpriteSheets.

Pour AnimEDS, il ne me suffit plus d'avoir une seule "page" présente et affichée: les différentes étapes d'animation vont utiliser des éléments issus de différentes pages, parfois pour les afficher séparément, parfois pour les combiner. Les cogitations du week-end ont donc suggéré d'ajouter une fonction unique SpriteSet::getdata qui partage une partie de la fonctionalité de SpriteSheet::getdata mais qui peut récupérer n'importe quelle image du fichier .spr en mémoire à partir du seul numéro de page et numéro d'image dans la page.

N.B.: ça fait beaucoup d'espace "gâché" sur la gauche. J'imagine que 16x16 serait suffisant pour choisir un composant...

Saturday, January 29, 2011

Ne vous posez pas de questions ... (ou pas)

Entre une semaine de boulot bien chargé, le lave-vaisselle en panne (mais remplacé mardi prochain) et mon AMD64 qui boude la nouvelle LTS d'ubuntu, j'avais quand-même essayé d'avancer un peu dans le code de mon futur éditeur d'animations. Malheureusement, à chaque fois, je me retrouvais dans une impasse de design logiciel, à ne pas savoir quel était le bon bout des choses. Peut-être que "ne vous posez pas de questions, codez" ne s'applique pas bien à moi. Ou alors il ne s'applique pas bien au C++. Je suis donc revenu à mes bonnes vieilles habitudes: gribouille et pseudocode, avec un soupçon de "boi-boîtes et flé-flèches" UML pour aller un cran plus loin vers du code.

Is it the view ? should it be part of the model ? or of the controller ? aM Vram Cram ... I just couldn't sort it out straight ahead. No wonder why I always preferred unix's command line to the Visual Studio. If my editor series on the NintendoDs has taught me one lesson, at least, it is that "do not wonder: code" motto works poorly when *I* apply it to C++ for user interfaces. I tried several times this week to turn the 'animeds sketches' into code, but that was just like trying to dash a boulder with my bare hands.

The good news is that the "good old approach" still work well for me. Do not wonder how to code: write it down. Clarify the problem, throw arrow at those boxes until the real questions appear, let Bouli sort out what is *really* to be solved and which are the "academic" problems that are interesting from an algorithmic point of view, but that needn't to be addessed for such small values of N :P


Je vous les uploade donc ... je sais que certains d'entre-vous aiment encore bien ces petites feuilles remplies de Bilou. Mais surtout, une fois encore, ça me permettra de venir retrouver les idées dégrossies la prochaine fois que j'aurai une petite heure en fin de soirée ou sur le temps de midi pour coder un peu ...

Spoon: What's wrong ?
LAN: I'm sorry, my responses are limited...you must ask the right questions.
Spoon: "who is responsible for the VRAM and OAM slots involved in the timeline widget ?"
LAN: That, detective, is the right question. Program terminated.


Mon leitmotiv à moi sera donc "posez-vous les bonnes questions".