#102233 - TJ - Tue Sep 12, 2006 2:44 am
I have recently started taking a more serious approach to DS development now that the WiFi lib is progressing, and have gotten to the point that I would like to move past the simple printf interfaces I have been using so far.
Now, keep in mind, not only am I new to DS development; but I have never programmed anything but console applications in C/C++ on the PC as well. I have always felt content with text interfaces for my PC programs. So I am not terribly well prepared for a totally graphical program, but I clearly see that I need to move on to realize my program ideas.
My first thought after looking though the examples from libnds, was to draw a full screen bitmap of my interface and then overlay text on it with the console.
But trying it, I soon found that:
1. I could never manage to print console text over a bitmap (by the way, anyone want to provide some sample code for this? I know it should be easy, but I would always get corrupted text/images when I try)
2. The console is really too limited for any serious GUI
I have pretty much resolved the fact that I will need to figure out some sort of font drawing routine, which only complicates matters for me, to be honest.
So I figured I would just ask straight out the best way to do this.
Should I have the background of the GUI drawn as a bitmap, and then overlay text/buttons as sprites; or should I use the frame buffer, and draw everything that way?
And at the same time, are there any guides or example code that really cover how to do a serious UI, and not just print "Hello World" on a black background? Or at least how to create a font routine that will let me draw decent looking text at arbitrary positions on both screens simultaneously?
#102234 - sajiimori - Tue Sep 12, 2006 2:59 am
Start with "easy", then work on "fast". Writing a GUI system that's purely for bitmap modes will be much simpler. No attribute registers or VRAM concerns -- just pixels.
Sprites and tiled backgrounds will be good optimizations later on.
I have some decent code for an SDL-based GUI system (which can easily translate to anything with a framebuffer) from a few years ago. If I had to do it over, I'd take almost the same approach, architecturally. PM me if you're interested.
#102250 - abszero - Tue Sep 12, 2006 9:08 am
I've got code that does a text/tile mode GUI on BG1 overlayed with the default console on BG0 if that's of any use. It runs both under no$GBA 2.3 and on my DS Lite as presented (though I didn't provide the graphics files so you can't compile exactly as is). Comments are sparse since most things are fairly self-documenting, but if something confuses you I'll try to clarify.
Code: |
#include <nds.h>
#include <nds/arm9/console.h> //basic print funcionality
#include <stdio.h>
#include <string.h>
#include "res/gui.palette.cpp"
#include "res/gui.tiles.cpp"
#include "res/blank.map.cpp"
// Memory bases for the tiles and maps of each layer - values mostly don't matter for this example as long as they're not overlapping
const int char_base_bg0 = 0;
const int char_base_bg1 = 1;
const int screen_base_bg0 = 31;
const int screen_base_bg1 = 20;
uint16* tile_bg0 = (uint16*)CHAR_BASE_BLOCK(char_base_bg0);
uint16* tile_bg1 = (uint16*)CHAR_BASE_BLOCK(char_base_bg1);
uint16* map_bg0 = (uint16*)SCREEN_BASE_BLOCK(screen_base_bg0);
uint16* map_bg1 = (uint16*)SCREEN_BASE_BLOCK(screen_base_bg1);
// Dummy handler (if not present, runs in emu but not hardware)
void irqVBlank() {;}
int main() {
powerON(POWER_ALL_2D);
irqInit();
irqSet(IRQ_VBLANK, irqVBlank);
irqEnable(IRQ_VBLANK);
//enable vram and map it to the right places
vramSetMainBanks( VRAM_A_MAIN_BG_0x6000000, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_LCD);
//set the video mode
videoSetMode( MODE_5_2D |
DISPLAY_BG0_ACTIVE |
DISPLAY_BG1_ACTIVE |
DISPLAY_SPR_1D );
BG0_CR = BG_COLOR_16 | BG_TILE_BASE(char_base_bg0) | BG_MAP_BASE(screen_base_bg0);
BG1_CR = BG_COLOR_256 | BG_TILE_BASE(char_base_bg1) | BG_MAP_BASE(screen_base_bg1);
BG_PALETTE[255] = RGB15(0,0,0); // font color
consoleInitDefault(map_bg0, tile_bg0, 16);
// copy the palette, tiles, and map to their respective places
dmaCopy(gui_palette, BG_PALETTE, sizeof(gui_palette));
dmaCopy(gui_tiles, tile_bg1, sizeof(gui_tiles));
dmaCopy(blank_map, map_bg1, sizeof(blank_map));
while(1) {
swiWaitForVBlank();
scanKeys();
touchPosition touch = touchReadXY();
iprintf("\x1b[0;18Hkeys: %08X\n", keysHeld());
if (touch.px || touch.py)
iprintf("\x1b[0;0H(%d,%d) ",touch.px,touch.py);
else
iprintf("\x1b[0;0H ",touch.px,touch.py);
}
return 0;
}
|
To respond to your more general question about GUI implementation, I would say that the answer depends on how what your GUI needs to do maps to the available graphics modes (unless you go with a fully bitmapped/framebuffer mode as sajiimori suggested).
For example, I'm working on the GUI of a Japanese dictionary suite at the moment. The top screen will be where search results will be displayed (so mostly japanese text display) and the bottom screen will be where the user inputs things by clicking buttons, typing on keyboards, hand writing characters, etc.
Both screens will need to support at least one layer of a bitmap-like mode I have decided; for displaying large amounts of text on the top screen and a stylus drawing pad for handwriting recognition on the bottom. At the same time, implementing the rest of the GUI in a bitmap mode seems like a bit of a hassle to me (personal preference), so instead I'm doing it with tiles (the background panels, etc) and sprites (indicators, buttons, and some special bits of text). Therefore, I ended up using MODE_5_2D since it supports both text/tile and exrot/bitmap layers like I need.
So as it stands:
Top Screen - MODE_5_2D:
BG0 (Tile): Console for Debugging
BG1 (Tile): GUI Panels
BG2 (Bitmap): Japanese Text
Bottom Screen - MODE_5_2D:
Sprites: Selected buttons, widgets, etc
BG0 (Tile): Text indicators
BG1 (Tile): GUI Panels
BG2 (Bitmap): Handwriting Display
As another quick example of basing the design around the available hardware, I'm using some sprites on the bottom screen basically to implement a very limited font. But on the text-heavy top screen, that's not really an option as I'll almost certainly have more than 128 characters to display up there and would run out of sprites. So on the top screen, text will be handled via a font routine writing to a bitmap layer instead. Etc.
#102258 - memoni - Tue Sep 12, 2006 10:40 am
The IMGUI concept is pretty fast things to get your GUI up and running in no time:
http://sol.gfxile.net/imgui/
#102259 - headspin - Tue Sep 12, 2006 10:50 am
I think quite a few people just use bitmap mode for simple gui's like game menus and just read the coords of the stylus. You can have a sprite to indicate the selection over the button, or have a hand, pen cursor sprite.
If you need dynamic text, tile mode is probably a better way and that means you can keep a background for overlaying text on buttons and such if you need dynamic text.
I'm not 100% sure, but I think 0xtob could be using bitmap mode with Nitro Tracker. While it looks like it uses tiles, the controls don't line up in 8x8 tiles, that is because he uses his own dynamic controls that are drawn himself. It would be nice to hear how he does it, but it's not difficult to draw text in bitmap mode, you just have to remember that you will need to convert your font using gfx2gba using the -c32k switch. Then you can just overlay the font to the bitmap background by ORing the font characters onto the screen remembering your dealing with 16 bit data (X1B5G5R5) without a palette.
_________________
Warhawk DS | Manic Miner: The Lost Levels | The Detective Game
#102265 - 0xtob - Tue Sep 12, 2006 12:29 pm
Yep, the GUI system I coded for NitroTracker uses framebuffer for nearly everything except the for (music and text) keyboards. I have a function that prints text with dynamic-width characters on the GUI elements. I guess it's similar to libfb by DragonMinded, but less flexible. I guess you could check libfb out, TJ.
A gui system is really simple and fun to code (if you are motivated for it, of course). You need one main class that draws the screen and handles the input (i.e. that knows which widget is where and then notifies the correct widget of a pendown/penup/penmove event) and then you can design your widget classes that can draw themselves and react to input.
I have plans on open-sourcing my GUI kit, but first I want to make it more flexible, for example by changing it to use an 8 bit paletted background (I currently use 16bit). So, it will take some time.
#102280 - GPFerror - Tue Sep 12, 2006 4:31 pm
sajiimori wrote: |
Start with "easy", then work on "fast". Writing a GUI system that's purely for bitmap modes will be much simpler. No attribute registers or VRAM concerns -- just pixels.
Sprites and tiled backgrounds will be good optimizations later on.
I have some decent code for an SDL-based GUI system (which can easily translate to anything with a framebuffer) from a few years ago. If I had to do it over, I'd take almost the same approach, architecturally. PM me if you're interested. |
Just curious if you have tried to compile it with my port of the SDL lib to the ds?
Troy(GPF)
http://gpf.dcemu.co.uk
#102297 - DekuTree64 - Tue Sep 12, 2006 6:52 pm
I've been doing the GUI for my tracker in tile mode. Basically I just draw bitmaps of all my menus, making sure the controls are aligned to 8 pixels. Then I draw any text on in the program, using a slightly modified libnds console (just added a function to set the dest screen map, and palette to use).
Making buttons visually press down only involves swapping palettes, although swapping which chars the map data points to would work just as well. Some controls use sprites too, like scrollbars.
I'll probably eventually eliminate the bitmap step and just draw the controls dynamically from 3x3 char "template" bitmaps. But while I'm still working out the menu layouts, bitmaps are easier.
As for the actual code, most of the controls handle input and drawing themselves, and have a callback pointer that they call whenever their value changes (pretty similar to C-style windows API). So basically all a menu has to do is define all the controls it wants, and have a callback function with a big switch statement to set whatever variable each control affects.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#102351 - TJ - Wed Sep 13, 2006 3:54 am
My ideas where sort of a combination of what you all said. Do a bitmap background, and handle buttons and indicators as sprites or drawn on with FB routines. Good to know I wasn't thinking in a totally wrong direction, at least.
I am going to take a look at libfb, the final result certainly looks nice; and from my brief looks over the WiFi Chat source, it doesn't look to hard to handle. Anyone have any thoughts for or against it?
I should be clear, if I wasn't initially, that I have absolutely no interest in developing games for the DS. I am only interested in doing actual applications, so with that in mind, something like libfb seems to be well suited to my needs, or at least, it does in my head.
#103727 - Patater - Sun Sep 24, 2006 5:48 am
I wrote up a graphics mode independent GUI kit in C++, designed with the DS in mind. You can check it out at http://www.patatersoft.info/guikit.html
Basically, I provide classes for the most primitive GUI widgets. You use these primitives to create your own custom widgets, simply by inheriting from them and implementing a few paint functions and input handlers.
It is very easy to make dynamic GUIs (moving buttons and scroll bars, etc) with my kit, but if all you are looking for is static, it is still a nice choice. It is easy to make a map of tiles and a collision map where upon different tile presses perform different activities for static GUIs though.
This GUI Kit together with libfb for the graphics portion is probably a fine bet.
I hope you might find this GUI kit useful. Cheers!
#103918 - El Hobito - Mon Sep 25, 2006 12:06 pm
ever considered using palib? www.palib.com this makes life much easier and will allow you to concentrate more on getting a good interface rather than messing around with code
#104178 - TJ - Tue Sep 26, 2006 11:04 pm
I had looked into PALib when it was first announced...and it just isn't something I am interested in. I want more control than it would offer me.
I have been using libFB since it was suggested here, and I am having pretty good results, though I am still in the concept phase for most of my ideas.
When I get a chance, I will take a look at your project, Patater. I haven't done any advanced GUI work yet, still just simple stuff; but I will be eventually.