#121319 - tepples - Sun Mar 11, 2007 2:59 pm
I'm tired of remaking Tetris, and I want to try making something that uses a dialogue engine. (poslundc, are you still planning on releasing PFont?) But I'm not a trained typographer, so please test my font demo to make sure it's readable.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#121325 - sgeos - Sun Mar 11, 2007 4:30 pm
Do you have a screenshot of the font?
EDIT: Why not use one of the bdf fonts on the net?
EDIT: FWIW, I think a version of posprintf that can handle arbitrary wide character encoding formats and redefine escape/formatting characters would be fantastic. Doing this myself is low on my priority list right now, but it would be nice.
-Brendan
#121333 - tepples - Sun Mar 11, 2007 6:16 pm
Do bdf/pcf fonts support anti-aliasing?
See VBA screenshot.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#121336 - sgeos - Sun Mar 11, 2007 6:30 pm
tepples wrote: |
Do bdf/pcf fonts support anti-aliasing? |
bdf is a 1 bit bitmapped font format. Anti-aliasing is a software feature. This question is like asking if plates support washing. Yes, plates can be washed, but they don't provide any built in facilities for it. (Yes, bdf fonts can be anti-aliased, but they don't provide any built in facilities for it.)
Poor man's anti-aliasing:
Shift bitmap up one pixel, blit in midtone. Shift right and blit. Shift down and blit. Shift left and blit. (Midtone outline.) Do not shift, blit in normal color. You can preprocess/optimize as much of this as you want to. (Masks and multiplies are an optimization.)
I say midtone because you may be using a dark font, or a light font. You may even want to use black and white. I actually like white text with a black outline.
The lower case "t" needs to be fixed. The quick brown fox sentence in both upper and lower case would be fantastic. (Ignore mixed case.)
-Brendan
#121338 - Fatnickc - Sun Mar 11, 2007 6:55 pm
I just tried it on my GBA, and have to agree with sgeos about the lower case t, as it is much more similar to the Japanese 'te' hiragana than the English 't'!
#121339 - Sausage Boy - Sun Mar 11, 2007 6:58 pm
I agree with sgeos, the lower case t is, while kinda cool, very confusing to read. I also personally prefer a straight ', but that's a matter of taste I suppose. The rest of the characters look absolutely wonderful.
_________________
"no offense, but this is the gayest game ever"
#121342 - tepples - Sun Mar 11, 2007 7:35 pm
sgeos wrote: |
tepples wrote: | Do bdf/pcf fonts support anti-aliasing? |
bdf is a 1 bit bitmapped font format. Anti-aliasing is a software feature. |
In the case of bitmaps, it's also a feature of the data set. Sure, downsampling a 1-bit bitmap font into an alphascale font works, but if the 1-bit font isn't hinted, the result won't be the clearest.
Quote: |
This question is like asking if plates support washing. |
Depends. A lot of families choose plates based on how well they stand up to a dishwasher. Likewise, I would choose fonts based on how well they stand up to downsampling.
Quote: |
The lower case "t" needs to be fixed. The quick brown fox sentence in both upper and lower case would be fantastic. (Ignore mixed case.) |
The t-shape in question is called the half-uncial t or insular t. It appears that this t-shape confuses more people than necessary, so I replaced it with the more familiar gothic t. (See history of t, and compare hiragana て (te).)
I have uploaded version 2 of gba and png.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#121345 - sgeos - Sun Mar 11, 2007 8:16 pm
tepples wrote: |
Quote: | This question is like asking if plates support washing. |
Depends. A lot of families choose plates based on how well they stand up to a dishwasher. Likewise, I would choose fonts based on how well they stand up to downsampling. |
Fair enough.
Quote: |
The t-shape in question is called the half-uncial t or insular t. It appears that this t-shape confuses more people than necessary, so I replaced it with the more familiar gothic t. |
Good plan. Normal fonts (ie, not your title screen art) want to be easy to read, not creative.
Quote: |
I have uploaded version 2 of gba and png. |
Looks good, but I can't really comment on the lower ascii values without seeing them in action.
-Brendan
#122031 - Ant6n - Fri Mar 16, 2007 4:35 pm
what kind of requirements would a simple text output library have, anyway?
i.e. what do people want?
#122032 - sgeos - Fri Mar 16, 2007 4:46 pm
Ant6n wrote: |
what kind of requirements would a simple text output library have, anyway?
i.e. what do people want? |
Simple? ASCII.
Nice features- can handle things like unicode, shift JIS, etc. Non-fixed width fonts are nice. Automatic line breaks are nice for English and similar languages.
-Brendan
#122062 - Ant6n - Fri Mar 16, 2007 8:25 pm
so that would mean that one should be able to load a font in some simple format. the font should specify the characters (i.e. as bitmaps), together with their width (assuming they are variable width) and bpp, and which ones are special characters like '\n' or ' '.
Would people use fonts of heights different than 8? or 16, or 32?
I was thinking that one could represent text boxes in single or multiple 4 bit sprites, Because most of the time, in games, text is displayed not on the whole screen. and if one does want full screen, then using a bg should do the job.
#122063 - sgeos - Fri Mar 16, 2007 8:54 pm
Ant6n wrote: |
so that would mean that one should be able to load a font in some simple format. |
Correct.
Ant6n wrote: |
the font should specify the characters (i.e. as bitmaps), together with their width (assuming they are variable width) and bpp, |
Font: font height, font bitmap height, bpp, special character code points.
Per Glyph: bitmap, width.
Ant6n wrote: |
and which ones are special characters like '\n' or ' '. |
You will need some way to hook code points to special characters. Newline, formfeed, etc.
You might consider taking a user defined code point to font index funtion. It could return negative values to indicate newline and friends. (Naturally, they should be hidden behind macros like LIBPREFIX_NEWLINE.)
Ant6n wrote: |
Would people use fonts of heights different than 8? or 16, or 32? |
Yes. If I were you, I would have 2 values- bitmap height (8, 16, 32) and font height. Bitmap height affects VRAM usage. Glyphs should be positioned in the upper lefthand corner of the bitmap. The next line starts (font_height + v_spacing) pixels down. The next character starts (glyph_width + h_spacing) to the right.
Quote: |
I was thinking that one could represent text boxes in single or multiple 4 bit sprites, |
4 bit sprites? Sprites are a fantastic way to display text. They make character positioning easy.
Quote: |
Because most of the time, in games, text is displayed not on the whole screen. and if one does want full screen, then using a bg should do the job. |
You could recycle sprites.
Version 3 or so should probably support antialiasing and/or font outlines. I would write the initial library with this in mind.
Version 5 or so might want to support dropping user defined sprites in the middle of the text.
"Look for a person that looks like (face icon).
He will give you (lamp icon)."
A user defined function could be responsible for reporting these items (return LIBPREFIX_ICON(3)). The user would have to figure out how to encode everything to make it work happily with the library.
-Brendan
#122064 - tepples - Fri Mar 16, 2007 9:07 pm
Ant6n wrote: |
so that would mean that one should be able to load a font in some simple format. the font should specify the characters (i.e. as bitmaps), together with their width (assuming they are variable width) and bpp, and which ones are special characters like '\n' or ' '.
Would people use fonts of heights different than 8? or 16, or 32? |
Yes.
Quote: |
I was thinking that one could represent text boxes in single or multiple 4 bit sprites, Because most of the time, in games, text is displayed not on the whole screen. |
I made a text engine that used this method. Fonts not a power of 2 pixels in size were padded out.
Quote: |
and if one does want full screen, then using a bg should do the job. |
My text engine uses a background, as a lot of the time, there will be a character name, four lines of dialogue, and up to four responses. Currently, the default font in my engine has a total height of 12 pixels: 2 for diacritics, 2 for ascenders, 6 for x-height, and 2 for descenders. Then it's set on 14 pixel line height, which is easy because it uses column-major tile ordering, where each 8-pixel-wide column of tiles is a contiguous pixel map.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#122073 - Ant6n - Fri Mar 16, 2007 9:46 pm
How would one like to control text output (where its written). I.e. is it more useful to have something like
outputtext(surface,line,column,text)
or
printtext(surface,text)
in the latter case there would be a notion of a text cursur sitting somewhere - but then what exactly happens if the cursor reaches the end of the screen?
how would one overwritte just a little segment? In the former case, it wouldnt be possible to use nonfixed width.
#122092 - sgeos - Fri Mar 16, 2007 11:32 pm
Basically everyone is using proportional fonts these days. Even translated ROMs use proportional font systems. I can't really see fixed width being all that useful for anyone who want to make production quality software.
I can see a few ways of doing things.
Text scrolls off the end of the screen unless the data contains newlines:
Code: |
setCursor(x, y); // (x, y + vofs) after newline
print(string); |
Text autowraps. User newlines might be needed to make things look prettier. Data will scroll off of the end of the screen if it is too long.
Code: |
setCursor(x, y, w); // as above with autowrap
print(string); |
Text autowraps and requires automatic keypress to advance.
Code: |
setCursor(x, y, w, h); // as above with autowrap
print(string); |
Game related control codes include "wait for user input" and "delay output". Delay may or may not want to be fancy. One control code is probably enough if the delay time can be changed using a library function. Delay can be used to do things like this:
Code: |
Was that a joke?
[delay].[delay].[delay].
[delay]Oh, now I get it. |
Formfeed clears the screen. It is very useful.
Code: |
Only you can prevent forest fires.
[userinput][formfeed]...wait...
[userinput][formfeed]So can I![newline]
Everyone can prevent forest fires! |
Formfeed probably wants to automatically call userinput. I can't see using it without user input, but I can see requiring user input without clearing the screen:
Code: |
One[userinput], two[userinput], three[userinput]...[userinput][newline]
I don't see four orbs. What are you trying to pull? |
EDIT: I would not have the library directly poll for user input. The user program is perfectly capable of figuring out what user input is. It can then call some sort of a gotUserInput() function. I would probably include an isTextOnScreen() query function.
-Brendan
#122104 - Ant6n - Sat Mar 17, 2007 1:26 am
so you say it would make sense to create a bunch of control characters.
But how can a cursor be set in a variable width context?
and what happens if the cursor goes off the screen at the bottom?
#122107 - Lick - Sat Mar 17, 2007 1:37 am
The cursor can have a pixel position. [cursor.x += character.width;]
If the text goes off the screen, don't draw it.
_________________
http://licklick.wordpress.com
#122109 - sgeos - Sat Mar 17, 2007 1:39 am
Ant6n wrote: |
so you say it would make sense to create a bunch of control characters. |
Of course. The display needs to handle display characters. The user's text system will handle tags.
Code: |
It is <dayofweek> today.[newline]
I like <dayofweek>s.[delay] Do you like <dayofweek>s? |
Ant6n wrote: |
But how can a cursor be set in a variable width context? |
It operates on pixels, not cells. Width, height, vspacing and hspacing are all calculated in pixels.
Ant6n wrote: |
and what happens if the cursor goes off the screen at the bottom? |
If you don't implent a vertical display region, undefined bahavior happens. The system just tries to write off the bottom of the screen. Nothing much happens if you drop sprites off the bottom of the screen. At any rate, it is a bug and will need to be fixed before the program "ships".
-Brendan
#122120 - Ant6n - Sat Mar 17, 2007 2:37 am
and how would text be deleted?
the most general way to implement control characters if the engine lets you define control characters for '\n' and ' ', and others with a callback function, with different returns, i.e. string (insert date) or void (delay)
#122141 - sgeos - Sat Mar 17, 2007 9:02 am
Ant6n wrote: |
and how would text be deleted? |
Clearbuffer? Formfeed? I can't envision a scenario when half the text on the screen gets deleted. I think a complete redraw would be OK.
I can see scrolling text, however- either rowlocked or free scrolling. This should be supported.
Quote: |
the most general way to implement control characters if the engine lets you define control characters for '\n' and ' ', |
Space is not really a control code. It is a glyph with an empty bitmap and a narrow width. Or are you talking about a line breakable space?
Quote: |
and others with a callback function, with different returns, i.e. string (insert date) |
You know, string is cute. If the engine has a string insertion buffer and string control code, it would be very easy for the user callback function to implement things like date:
Code: |
return_t myCallback(param_t pId)
{
// pointer to library string buffer
char *buffer = libGetBuffer();
switch (pId)
{
case MY_DATE:
// this would work for ascii
sprintf(buffer, "%d-%d-%d", year, month, day);
return LIB_CODE_STRING;
break;
case MY_PLAYER_NAME:
// this would work for ascii
sprintf(buffer, "%s", myGetString(MY_PLAYER_NAME));
return LIB_CODE_STRING;
break;
...
default:
return pId:
break;
}
} |
I would not support any hard coded string insertion tags. You don't know what the user will need, any they may be using something like a parial, packed unicode font.
Control codes so far: newline, tab, formfeed, delay, userinput, string. Bell? Being able to change the bell sound and have it play whenever it hits the bell would cute. Bell probably wants a callback function, because you don't know what the user sound system looks like.
EDIT: If you want to able to handle left to right, right to left, vertical text, etc, you'll need to keep track of the cursor base, line offset and character offsets. After each line:
Code: |
line++;
xCursor = xCursorBase + line * xLineOffset;
yCursor = yCursorBase + line * yLineOffset; |
After each character:
Code: |
xCursor += glyph.xOffset;
yCursor += glyph.yOffset; |
Clearly one of the values should always be zero. By using different values, LTR, RTL, UTD, DTU fonts can be made.
-Brendan
#122146 - DekuTree64 - Sat Mar 17, 2007 9:49 am
sgeos wrote: |
I can't envision a scenario when half the text on the screen gets deleted. I think a complete redraw would be OK. |
Not in a conversation text box, but text systems are also heavily used in menus, and you do need to be able to update small areas like your remaining money for a shop, any text being entered by the user, etc.
One useful feature I have in my text render function is a "clear width" parameter. Basically it draws the string, and then clears any space after it, up to the clear width. With that, you generally don't have to explicitly clear anything. Just redraw the string and it will take care of the leftover garbage if the old string was longer.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#122147 - Ant6n - Sat Mar 17, 2007 9:59 am
i guess using some buffer is more useful than string return.
does vertical text have variable width, height?
so far:
text is written in text boxes. text boxes either live in bg or on sprites. in order to write text one has to specify a font. a 'font' specifies
-font name (?)
-the writing direction (or xOffset,yOffset - width and height are reversed in the following if writing direction vertical?)
-the height of the characters
-whether its fixed width
-the width of characters
-the height offsets
-the palette for character bitmpas? (16 colors?)
-the interval of allowed character indizes
-the list of characters (maybe in implementation an array of offsets)
a 'character' with a given index specifies
- the associated bitmap
- bpp, index (or should this be global?)
- the width
- whether its a control character, specified together with options (or specifying that the options should be read like arguments following the control character in the text), which there could be the following
-- word separater (i.e. space - simply to know where to break text for newline) - specifying when it gets printed
-- new line
-- 'delay' - with specified 'n' vblanks (?)
-- scroll a character height (immediately/slow)
-- delete screen ('form feed'?)
-- callback/callback with string return to print
-- simply functions of the text engine itself?
-- tab -- why?
-- userinput -- on gba? how?
its probably useful to have callbacks sit in some array, which has to get initialized during runtime. also, it would probably make sense to try to make callbacks safe so that the callback function itself can access the text engine (no?). would it be useful to be able to useful multiple fonts at once?
functions
initialize (options - autowrap..)
create, delete text box
set/move/get cursor position - in pixels
set/move cursor position - in line,column
print (returns width printed)
clear (either a width in pixels, or some string)
scroll (wole line, pixels, instant, slow)
clear text box
move text box
hide/show box
set palette (?)
set callback
would one want to draw anything besides text?
what about text color?
would it make sense on such a limited system as the gba to assume that every possible font has a character set with 8 bit indizes?
i guess that if the texbox lives in the same space as some other graphics (i.e. a sprite that specifies the background of an 'ok' dialog), then it should be possible to speciy a transparent background color blit.
...gee, who would've thought something like this could be so complicated.. i smell feep
#122161 - sgeos - Sat Mar 17, 2007 2:34 pm
I would try to keep the library itself as simple as possible, while leaving plug(s) so it can easily be extended by the user. There are things your library should do and things it should not do.
Making messages is basically a four step process:
Data creation (user hanldes this; text and fonts)
Data conversion (user handles this; text and fonts, so they work with your library)
Custom extensions (user handles this; helps the library do fancy game specific things)
Putting glyphs on the screen (your library does this)
Anything else (not really related =)
You should not directly handle anything that doesn't involve putting glyphs on the screen. A little about each step:
Data creation. The programmer defines what the system will support, and then the person who writes the script writes it at a very high level, probably using tags for special display features. You may end up with thousands of messages that look something like this:
Code: |
MES_ID_HERE:
// Register Input
// r0 - NPC ID
// r1 - number of items to be given
// r2 - type of item to be given
// r3 - sound effect linked to getting item
//
[meta][face(r0)][name(r0)][voice(r0)][/meta]
[red][playername][/red]![sound(DRAMATIC)][delay] [icon(HEART)][delay] I'm [name(r0)]![playerinput][newline]
[red]I[/red] really,[delay] REALLY,[delay] want to go with [red]you[/red]. [icon(HEART)][userinput][newline]
You have [big]no idea[/big] how much this means to me. [icon(HAPPYFACE)][delay][newline]
[bold]If you let my go with you,[/bold] [italic]I'll give you [green][caps][count(r1)][x_items(r2)][/caps][/green]![/italic][sound(r3)][userinput]
|
Not all of the tags directly print something. The metadata is not printed directly. [count()] sets an internal variable that [x_items()] uses. [caps] causes the callback to always return upper case glyph entries. [bold] and [italic] change the font, etc.
Data conversion. The messages and font(s) are precompiled. The font is converted into a format your library is happy with. All of the tags and tag functions are converted into code points. Magic cookies may be inserted. (A [voice] tag may automatically be inserted before every line, [bigline] may be inserted before lines that contain big text.) The output is going to be a bunch of bytes if the user wants to do anything fancy.
I think a single callback function should be able to handle user extensions if the library has hooks to things like moveCursor(). Normal glyphs return a font index. Control codes do something (change the font, color, etc) and the return NODISPLAY. If the user want to implement caps, sound effects, register based input, etc, that is completely up to them. Your library doesn't worry about it.
Your library only really worries about moving a cursor around and dropping glyphs on the screen. It library should provide facilities for things like changing the font color, but in general it should be as simple as possible.
Ant6n wrote: |
i guess using some buffer is more useful than string return. |
I think you use both:
Code: |
return_t callback(param_t pId)
{
if ( IS_ITEM(pId) )
{
libSetSubstringBuffer( getItemName(pId) );
return LIB_PRINT_SUBSTRING;
}
// ...
}
void libCaller(param_t *pString)
{
int i;
for (i = 0; LIB_NULL != (index = callback(pString[i])); i++)
{
switch (index)
{
case LIB_PRINT_STRING:
printSubstring();
break;
default:
printGlyph(index);
break;
}
}
} |
Quote: |
does vertical text have variable width, height? |
The font and each glyph should have some way to track both width and height. A proportional vertial font will have a fixed width, but variable height.
Quote: |
text is written in text boxes. text boxes either live in bg or on sprites. in order to write text one has to specify a font. |
Sounds good.
Quote: |
a 'font' specifies
-font name (?) |
Why? A pointer to the header and glyph data should suffice. The user can set up an id easily enough.
Code: |
#define MY_FONT &something
#define MY_FONT_BOLD &something_else |
Quote: |
-the writing direction (or xOffset,yOffset - width and height are reversed in the following if writing direction vertical?) |
The way I see it, width, height, offsets, etc define the writing direction.
Code: |
Left to Right, Up to Down Proportional (English)
New Line X Offset: 0
New Line Y Offset: 16
New Glyph X Offset: PROPORTIONAL
New Glyph Y Offset: 0
Right to Left, Up to Down Fixed (Hebrew)
New Line X Offset: 0
New Line Y Offset: 16
New Glyph X Offset: -14
New Glyph Y Offset: 0
Up to Down, Right to Left Fixed (Japanese)
New Line X Offset: -16
New Line Y Offset: 0
New Glyph X Offset: 0
New Glyph Y Offset: 16
Diagonal (Alien)
New Line X Offset: -18
New Line Y Offset: -14
New Glyph X Offset: -16
New Glyph Y Offset: 4
Random (Alien)
New Line X Offset: 0
New Line Y Offset: 0
New Glyph X Offset: PROPORTIONAL
New Glyph Y Offset: PROPORTIONAL |
Quote: |
-the height of the characters
-whether its fixed width |
The height of the characters is really the newline y offset. English uses a y offset, but when vertial writing is used, and x offset will be used instead. In theory, an alien script might use a diagonal offset. (See above.)
Quote: |
-the width of characters
-the height offsets |
See above.
Quote: |
-the palette for character bitmpas? (16 colors?) |
Antialiased fonts will use a bunch of colors. I might support both normal glyphs and full color icons.
Quote: |
-the interval of allowed character indizes |
The user callback function can handle this.
Code: |
// returns font index or special library code
return_t asciiCallback(param_t pId)
{
if ((0x20 <= pId) && (pId <= 0x7E))
return pId - 0x20;
switch (pId)
{
// control codes
}
// if all else fails
assert(0);
return LIB_UNDISPLAYABLE:
} |
Quote: |
-the list of characters (maybe in implementation an array of offsets) |
This data should be a simple array. The user is responsible for making sure that the font works with your system.
Code: |
index = callback(text[i]); // you don't know or care what the encoding format is
glyphData_t glyphData[index]; // bitmap data
int glyphSize; // maybe???
glyphOffset_t glyphWidth[index]; // proportional
glyphOffset_t glyphHeight[index]; // proportional |
Code: |
a 'character' with a given index specifies
- the associated bitmap |
Definitely.
Code: |
- bpp, index (or should this be global?) |
If I want a fairly complete Chinese font, I'm looking at ~5000 characters. If I want a Chinese font with all the glyphs nobody uses, I'm looking at ~50,000 characters. Minimizing the number of tables and glyph specific data is very important. The index should be implicit. Bpp should be global. If you want to support full color icons in addition to fixed bpp glyphs, that would be really cool. I do not want to store bpp for each of 50,000 characters (the bpp will be 1, btw =).
This is the new glyph x offset. If the font has a fixed width, use that value (even 0, in the case of vertical fonts). Don't forget height. Vertical writing systems will use this. (0 for horizontal writing systems.) You should store a pointer to proportional width/height tables.
Code: |
#define PROPORTIONAL -1
if (font.newglyph.x == PROPORTIONAL)
cursorXoffset = font.newglyph.proportional.x[index];
else
cursorXoffset = font.newglyph.x;
// same for y |
Quote: |
- whether its a control character, specified together with options (or specifying that the options should be read like arguments following the control character in the text) |
I would not store this information with each character. In the fanciest Chinese system I can imagine, there will be ~50,000 glyphs and ~250 control codes. I don't want an extra 50k of null data in the ROM. I'm perfectly capable of figuring out which of the 65536 code points are control codes by looking at the encoding point. My callback can give that information to you.
Quote: |
which there could be the following
-- word separater (i.e. space - simply to know where to break text for newline) - specifying when it gets printed |
This is kind of neat. I think some languages can break more or less anywhere and others can not. A canBreak(bool pState) function that can be called by the library user might be friendlier toward large fonts.
Certainly.
Quote: |
-- 'delay' - with specified 'n' vblanks (?) |
I think one delay control coupled with a setDelay(int pVblanks) function should suffice. If the user wants multiple delays, they could do something like this:
Code: |
return_t callback(param_t pId)
{
switch (pId)
{
case MY_LONG_DELAY:
libSetDelay(LONG_DELAY);
return LIB_CONTROL_DELAY;
break;
case MY_DELAY:
libSetDelay(DELAY);
return LIB_CONTROL_DELAY;
break;
case MY_SHORT_DELAY:
libSetDelay(SHORT_DELAY);
return LIB_CONTROL_DELAY;
break;
// ...
}
} |
Quote: |
-- scroll a character height (immediately/slow) |
Scroll the text box?
Quote: |
-- delete screen ('form feed'?) |
Form feed is a way of telling the printer, "spit this sheet of paper out and give me a new one". You could call it pagebreak if you want to.
Quote: |
-- callback/callback with string return to print
-- simply functions of the text engine itself? |
If possible, your library should communicate with one callback function. The callback function can use engine functions to do fancy things, but I would actually avoid separate callbacks. Text insertion (player name, item name, etc) can be accomplished by setting the engine substring buffer and then telling the engine to print that buffer.
Because it is easy. Why not?
Quote: |
-- userinput -- on gba? how? |
Don't. This is beyond the scope of your library. If I really want to collect input, I'll print a message like this:
Code: |
A B C D E F G H I J K L
M N O P Q R S T U V W X
Y X 1 2 3 4 5 6 7 8 9 0
a b c d e f g h i j k l
m n o p q r s t u v w x
y z . , ' - & @ # _ DEL NEX |
And move my own cursor around. You only have to worry about putting that text on the screen.
Quote: |
its probably useful to have callbacks sit in some array, which has to get initialized during runtime. |
Sure, but how many do you need? User encoding to glyph index callback. Maybe a bitmap loader? I can't think of anything else. The user encoding function can handle things like bells.
Quote: |
also, it would probably make sense to try to make callbacks safe |
Well, the user is responsible for making a callback function that works. Your library should document what it is supposed to do and then assume that the function works.
Quote: |
so that the callback function itself can access the text engine (no?). |
Yes. This way the user could have game specific embedded compiled text tags. They are extremely powerful.
Quote: |
would it be useful to be able to useful multiple fonts at once? |
Yes and no. You should be able to switch the glyphset (and other font data) in the callback, but there should only be one active font at once. By switching glyphsets, you can implement bold/italic fonts. A bold control code sets the bold font, and a normal control code restores the normal font. The engine loads bitmaps from the active font. When fonts are switched, the engine should expect them to be more or less compatible (same size, writing direction, etc). If the user must, they can move the cursor around to do strange things. (The reason why I mentioned a magic cookie on a line with big text.)
Quote: |
functions
initialize (options - autowrap..)
create, delete text box
set/move/get cursor position - in pixels
set/move cursor position - in line,column
print (returns width printed)
clear (either a width in pixels, or some string)
scroll (wole line, pixels, instant, slow)
clear text box
move text box
hide/show box
set callback |
These look good.
Quote: |
what about text color? |
This is always fun. I can see three ways of doing this: multiple palettes (wasteful), offset within palette (complicated), or both at once (more complicated, but really nifty).
Or a pixel offset. Add that offset to nonzero pixels. I may want to pack 3 antialiased font colors into one palette. Palette and pixel offset could be used to fit 6 colors in palette entries.
Quote: |
would one want to draw anything besides text? |
Full color icons maybe? If I choose to use a washing machine font (they exist), your engine should not care. It should print the unwashable symbol. =) I suppose the callback could load a substring with multiple glyphs if it wanted to print really long characters. Again, the library should just do the work and not care about it.
Quote: |
would it make sense on such a limited system as the gba to assume that every possible font has a character set with 8 bit indizes? |
No. Please hide this behind a typedef. Japanese and Chinese will use at least 16 bits. I can't come up with a 32 bit scenario right now, but I suspect it exists.
Code: |
typedef u8 libchar_t; |
Quote: |
i guess that if the texbox lives in the same space as some other graphics (i.e. a sprite that specifies the background of an 'ok' dialog), then it should be possible to speciy a transparent background color blit. |
This is a good idea.
Quote: |
...gee, who would've thought something like this could be so complicated.. |
Making anything robust is complicated. I know that Square Enix has special message programmers. Other large studios probably do as well.
Feature creep? The first version should be fairly simple. Font colors, icons, etc should not be included, but you should keep them in mind. (Unless you can't wait to get multicolored text working, in that case go for it.)
-Brendan
#122168 - tepples - Sat Mar 17, 2007 3:39 pm
sgeos wrote: |
Bell? Being able to change the bell sound and have it play whenever it hits the bell would cute. Bell probably wants a callback function, because you don't know what the user sound system looks like. |
If you define "bell", you're going to have to define "simoleon", "zenny", "gil", "rupee", "zorkmid", and every other game currency.
Quote: |
EDIT: If you want to able to handle left to right, right to left, vertical text, etc, you'll need to keep track of the cursor base, line offset and character offsets. After each line:
Code: | line++;
xCursor = xCursorBase + line * xLineOffset;
yCursor = yCursorBase + line * yLineOffset; |
After each character:
Code: | xCursor += glyph.xOffset;
yCursor += glyph.yOffset; |
Clearly one of the values should always be zero. By using different values, LTR, RTL, UTD, DTU fonts can be made. |
What about those scripts that mix orientations, such as Hebrew, which is right-to-left for everything but numbers? And then you get into how much space each glyph takes, especially when using small text at 1 or 2 bpp.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#122174 - sgeos - Sat Mar 17, 2007 4:22 pm
tepples wrote: |
sgeos wrote: | Bell? Being able to change the bell sound and have it play whenever it hits the bell would cute. Bell probably wants a callback function, because you don't know what the user sound system looks like. |
If you define "bell", you're going to have to define "simoleon", "zenny", "gil", "rupee", "zorkmid", and every other game currency. |
I'm talking about ASCII value 0x07. Zenny 銭 is a real currency that is no longer in use. So is Bita 鐚 (iron coins), by the way, but I don't think a game has used it yet.
Quote: |
Quote: | EDIT: If you want to able to handle left to right, right to left, vertical text, etc, you'll need to keep track of the cursor base, line offset and character offsets. After each line:
Code: | line++;
xCursor = xCursorBase + line * xLineOffset;
yCursor = yCursorBase + line * yLineOffset; |
After each character:
Code: | xCursor += glyph.xOffset;
yCursor += glyph.yOffset; |
Clearly one of the values should always be zero. By using different values, LTR, RTL, UTD, DTU fonts can be made. |
What about those scripts that mix orientations, such as Hebrew, which is right-to-left for everything but numbers? |
If you must switch directions mid stream, you'll probably need some sort of non-newline carriage return to move to the beginning of the line based on the new directional rules. Japanese never (really) changes directions mid stream, but it can flow from either LTRUTD or UTDRTL. Somehow I imagine a game would just pick one and run with it. Being able to switch at runtime would be neat (a few code points use differnt glyphs depending on the directional flow of the text).
Evidently, the order of numbers doesn't matter in Hebrew. It looks like perl should be able to pack whatever the translator hands the team. Printing dynamic values would be a learning experience. Making something like this work in Hebrew does scare me a little: "You got [gold(r0)] gold!" I'm sure it's not actually all that bad. Has anyone done Hebrew localization work?
Quote: |
And then you get into how much space each glyph takes, especially when using small text at 1 or 2 bpp. |
Each glyph should live in a fixed size box. The width and height should be 8, 16 or 32 dot. (64 seems like much on the GBA.) From there it is just a matter of decoding the data.
This will give you the size of each glyph in ROM:
Code: |
#define BITS_PER_BYTE 8
int bytesPerGlyph(int pW, int pH, int pBpp)
{
return (pW * pH * pBpp) / BITS_PER_BYTE;
} |
An 8 by 8 font at 1 bpp will take 8 bytes per character.
-Brendan
#122182 - Ant6n - Sat Mar 17, 2007 7:10 pm
The idea with an array of offsets is that its possible to have characters of different size live in the same array. One wastes some space on the initial list but gets some from not having padding bits in the 'glyphs' (my English is sorta rusty with all these texting terms). I guess in most real cases (of 1,2 bpp fonts) the padding way saves space.
I guess one could change the writing direction, and associate it with a text box. if one ones to write
one would change the direction with some control character. If one wants to write <2007 etirw llits i tub sdrawkcab si txet ym> then either encode 2007 backwards or find out how wide 2007 is, skip that amount, change writing direction write 2007, change writing directin, skip that amount etc.
I dont think it is useful for all characters to have callback, that might take quite some time (no?).
I dont like the idea of having a callback on every character to see whether its a control character, i think that should be encoded with each character. And since width,height has to be specified with each character anyway, there might be some bits leftover for control information
#122204 - HyperHacker - Sat Mar 17, 2007 9:15 pm
I'd say for Bell, just execute a callback and let it do all the sound stuff. Don't bother with another code to choose which sound to play; the callback should be able to decide. However, if you're not going for ASCII compliance, the next byte could be a parameter passed to the callback.
_________________
I'm a PSP hacker now, but I still <3 DS.
#122212 - sgeos - Sat Mar 17, 2007 9:34 pm
Ant6n wrote: |
The idea with an array of offsets is that its possible to have characters of different size live in the same array. One wastes some space on the initial list but gets some from not having padding bits in the 'glyphs' (my English is sorta rusty with all these texting terms). I guess in most real cases (of 1,2 bpp fonts) the padding way saves space. |
I guess I don't know enough about it. How does it work? I do know that a 60564 code point unicode font will be huge even at 1bpp; I don't want to make it bigger. (Not that anyone needs the whole thing.)
Ant6n wrote: |
I guess one could change the writing direction, and associate it with a text box. if one ones to write
one would change the direction with some control character. |
My question is, a system control character or a user control character? This will not be a common feature. The engine should expose this functionality so that the user can pull something like this off, but I don't think that the system needs to support this kind of control directly because very few people will need something like this. FWIW, I think spiral text would be funny, but it has little practical application.
Code: |
I am slowly going crazy... One
,
.. Crazy going slowly am I..
. . t
h ...erht ,rouf ,evif ,xiS w
c o
tiws ,xis ,evif ,ruof ,eerht , |
Code: |
If one wants to write <2007 etirw llits i tub sdrawkcab si txet ym> then either encode 2007 backwards |
The Hebrew translators will be working with Hebrew encoding tools. They can encode constants properly. Hebrew numbers don't work like English (so far as I can tell), so dynamic text will have to be reprogrammed anyway. There is definitely a solution, and around the time you decide to pay $4000 for a Hebrew translation I bet that solution will be fairly simple to find. =)
Quote: |
or find out how wide 2007 is, skip that amount, change writing direction write 2007, change writing directin, skip that amount etc. |
At which point you are looking at something like this. I don't know how to easily calculate WIDTH if the font is proportional; not in any pretty sort of way, that is.
Code: |
[mirror]<my text is backwards but i still write [skip(WIDTH)][/mirror]2007[mirror][skip(WIDTH)]> |
Code: |
I dont think it is useful for all characters to have callback, |
You could assume that there is a contiguous mapping of encoding values to font indices, and you could assume that control codes come either before or after that section. The user would have to tell you where the break is. The problem is that if the text uses something like native shift JIS encoding, valid character codes are not contiguous and you need a callback. (Of course, text preprocessing can fix this.) IIRC, shift JIS is a "superset" ASCII. You will get a displayable glyph every other character, because the first is only half of the character code. Unless it is ASCII, in which case it is the complete character code.
Code: |
that might take quite some time (no?). |
This is a premature optimization. I think that the flexibility gained outweighs any potential performance penalties that may not exist. If a game is doing a lot, it will only display simple messages. If a game has complex messages, it won't do much else while those messages are being displayed.
Using a callback for all characters, the user can implement case locking, glyph morphing and other fancy things. The fantastic part of all of this, is that your engine will not have to worry about any of that. It can just print the control codes it gets. A simple callback function would look like this:
Code: |
return_t callback(param_t pId)
{
// if this is a normal character...
if ((MIN_PRINTABLE) && (pId <= MAX_PRINTABLE))
{
// glyph morphing here, if any
// return the font index
return pId - MIN_PRINTABLE;
}
// else, it is something special
switch (pId)
{
// handle control codes
// user can create special control codes with library hooks
}
// if we got this far, something went wrong
assert(0);
// don't display anything
return UNDISPLAYABLE:
} |
Adding caselocks would make the "normal character" portion more complex. Native SJIS would be ugly- pId would have to mangled to work with the font, but it could be done.
Quote: |
I dont like the idea of having a callback on every character to see whether its a control character, |
You are doing more than finding out if it is a control character. You are asking the user what the current code value really is. What goes in as "a", may come out as "A" or "?" if the user wants a filter like that.
Also, how would you handle user defined control codes?
Quote: |
i think that should be encoded with each character. |
Control codes don't generally have displayable glyphs associated with them. Displayable characters generally don't need control information, although I could see adding something like "line breakable" to them.
Quote: |
And since width,height has to be specified with each character anyway, there might be some bits leftover for control information |
Any reasonable font will only have either a proportional width or a proportional height, but not both. If font bitmaps can be up to 32 pixels wide, it is reasonable for proportional width to range from 0 to 32 plus a bit, or 0 to 63 at the most. This leaves 2 control bits per glyph entry, if the font is proportional.
-Brendan
#122218 - Ant6n - Sat Mar 17, 2007 10:11 pm
so basicly you are proposing to separate the index of glyphs and character indizes.
#122222 - sgeos - Sat Mar 17, 2007 10:54 pm
Ant6n wrote: |
so basicly you are proposing to separate the index of glyphs and character indizes. |
Yes. The glyph data (font) is stored in a normal array. The encoding format used may not directly map to the font (SJIS is a horrible ugly encoding format, but it is fairly compact and standard in Japan). The user callback turns the character index into a glyph index (trivial for anything like ASCII). It also returns system control codes (because you don't know anything about the encoding format and you don't want to) and handles user extensions by catching user control codes and calling library functions (this is really powerful; you can't directly support everything anyone would want to do, but you can make it easy for them to add support).
As I said, preprocessing can but used to eliminate direct mapping issues. This would actually make SJIS take up more space, because single byte charactars would have to be stored as 16 bit indices. This is not really a big deal. There are other advantages to a callback filter.
-Brendan
#122247 - Ant6n - Sun Mar 18, 2007 2:20 am
so everything done by a callback then. that callback can return a glyph index (which gets printed), and/or some standard control (which there very few, i.e. newline etc), or a string in the buffer. the callback should be able to ask for the next bytes in the string (i.e. if using some font with 16 bit characters etc).
so glyphs are bmps of static size.
one way to implement widths, heights is to have an array for them and specifiy where it is in an offset, somethin glike this
struct font{
..stuff
u32 widths_offset;
u32 widths_length;
..
}
so after widths_offset bytes from the 'font' structure there is an array of widths-length that specifies the width for each character. analogously can height or other information be stored.
#122266 - Ant6n - Sun Mar 18, 2007 6:55 am
But what would be the best way to hook the textboxes into hardware?
one way would be to assume that sprite text boxes are made of 32x32 or 64x64 sprites, so when creating a text box a list of pointers to memory have to be supplied along with it. these will be drawn into. I guess these could be directly in vram. for bg i guess the thing could be very similar, when specifying a text box one specifies a bg and a rectangle in the bg map.
when printing data could be copied in some buffer and copied into vram during vblank. make sense, no?
#122297 - sgeos - Sun Mar 18, 2007 2:52 pm
Ant6n wrote: |
so everything done by a callback then. that callback can return a glyph index (which gets printed), and/or some standard control (which there very few, i.e. newline etc), |
There should be an UNDISPLAYABLE control code, so that the user can tell the system "I did something with this, but you don't need to worry about it."
Ant6n wrote: |
or a string in the buffer. |
Right. The user fills the substring buffer (or sets a substring pointer, maybe this would be better?) and then returns a PRINT_SUBSTRING control code. Whether the system prints the substring with a recursive call or not is up to you, but that should be documented.
Ant6n wrote: |
the callback should be able to ask for the next bytes in the string (i.e. if using some font with 16 bit characters etc). |
A peek() function might be neat, but in general I think that the callback should cache a value and then wait until it is called again. I suppose the callback could call getNextCharacter(), which would return the next character and advance the stream. This is probably better. It would simplify escape characters, for the people who want to use them.
The system should operate on a typedefed character type. Some people might want to natively work with wide characters instead of multibyte characters. They should be able to do that by changing one line in the library header.
Code: |
// change unsigned char to wchar_t if you want to use wide characters with wprintf and friends
// change unsigned char to u16 or u32 for custom wide character support
typedef unsigned char libChar_t; |
Has anyone used the wprintf() family of functions on the GBA or DS? I can't find any documentation on wiprintf(). I don't think it exists, but it may have a different name.
Ant6n wrote: |
so glyphs are bmps of static size.
one way to implement widths, heights is to have an array for them and specifiy where it is in an offset, somethin glike this
struct font{
..stuff
u32 widths_offset;
u32 widths_length;
..
}
so after widths_offset bytes from the 'font' structure there is an array of widths-length that specifies the width for each character. analogously can height or other information be stored. |
Why not do something like this? It take up more or less the same amount of space and it is more organized.
Code: |
#define PROPORTIONAL -1
const glyphData_t gFontGlyph[] =
{
// 20,000 lines of font data
};
const widthData_t gFontWidth[] =
{
// 500 lines of width data
};
// height is fixed, so there is no proportional height data
const fontData_t gFontData =
{
gFontGlyph, // Glyph Data
0, // Newline X Offset
16, // Newline Y Offset
PROPORTIONAL, // Newchar X Offset
0, // Newchar Y Offset
gFontWidth, // Proportional Width
NULL, // Proportional Height
// anything else, bpp, etc
}; |
Quote: |
But what would be the best way to hook the textboxes into hardware? |
The windows that the text is drawn over? Without knowing what the user wants, it is hard to handle this problem. My advice is, don't do this directly. Your library should just worry about where glyphs end up on the screen (you will need to keep track of the size of the display area). Either let the user handle this directly (without involving your library at all), or use openTextBox() closeTextBox() callbacks and let the user handle the implemention. There are many things the user might want to do:
Code: |
Spirtes Only
OBJ0 - Text, Window, UI
BG-0 - Effects
OBJ1 - Effects
BG-1 - BG Overlay
OBJ2 - Game Objects
BG-2 - BG Underlay
OBJ3 - (unused)
BG-4 - BG Underlay
BDRP - (unused)
Sprite Text, BG Window
OBJ0 - Text, UI
BG-0 - Window, UI
OBJ1 - Effects
BG-1 - Effects
OBJ2 - Game Objects
BG-2 - BG Overlay
OBJ3 - Game Objects
BG-4 - BG Underlay
BDRP - (unused)
BG Only
OBJ0 - Cursors, UI
BG-0 - Text, Window
OBJ1 - Effects
BG-1 - Effects
OBJ2 - Game Objects
BG-2 - BG Overlay
OBJ3 - Game Objects
BG-4 - BG Underlay
BDRP - (unused)
Text Only, Sprites
OBJ0 - Text, UI
BG-0 - Effects
OBJ1 - Effects
BG-1 - BG Overlay
OBJ2 - Game Objects
BG-2 - BG Underlay
OBJ3 - (unused)
BG-4 - BG Underlay
BDRP - Solid Color Text Backdrop
Text Only, BG
OBJ0 - Cursors, UI
BG-0 - Text
OBJ1 - Effects
BG-1 - Effects
OBJ2 - Game Objects
BG-2 - BG Overlay
OBJ3 - Game Objects
BG-4 - BG Underlay
BDRP - Solid Color Text Backdrop |
Quote: |
one way would be to assume that sprite text boxes are made of 32x32 or 64x64 sprites, so when creating a text box a list of pointers to memory have to be supplied along with it. |
Sounds complicated.
Quote: |
these will be drawn into. I guess these could be directly in vram. |
I could see passing a pointer to a section of VRAM. If the amount needed is document, this would probably be the simplest approach.
Quote: |
for bg i guess the thing could be very similar, when specifying a text box one specifies a bg and a rectangle in the bg map. |
You need to know what cells to write in the BG and/or which tiles to update. Treating a bunch of tiles as a bitmap is the most powerful way to use a BG. Part of the BG is formatted to use tiles like this:
Code: |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
...
70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F |
Then you just need to update the tiles. Proportional fonts can be written to BGs using this technique. You need to know how big the text area (width, height) is, and what tile index it starts at. If you go this route, you may want to include a function that initialized a square of tiles.
Sprites are generally happy floating above everything else.
If you want to be able to handle simple windows, they usually consist on 8 border parts and an internal section.
Code: |
/- -- -\
|. .. .|
|. .. .|
|. .. .|
|. .. .|
\- -- -/ |
The corners and sides may or may not be rotated. When everything is put together it looks like this:
Code: |
/--------------------------\
|..........................|
|..HHEELLOO..WWOORRLLDD!!..|
|..HHEELLOO..WWOORRLLDD!!..|
|..........................|
\--------------------------/ |
It seems like you might need to able to specify transparent/non-transparent background colors for loaded glyphs.
Quote: |
when printing data could be copied in some buffer and copied into vram during vblank. make sense, no? |
This is a good idea. The user could call syncText() or somesuch function some time during vblank.
-Brendan
#122301 - tepples - Sun Mar 18, 2007 3:26 pm
sgeos wrote: |
The system should operate on a typedefed character type. Some people might want to natively work with wide characters instead of multibyte characters. They should be able to do that by changing one line in the library header.
Code: | // change unsigned char to wchar_t if you want to use wide characters with wprintf and friends
// change unsigned char to u16 or u32 for custom wide character support
typedef unsigned char libChar_t; |
Has anyone used the wprintf() family of functions on the GBA or DS? I can't find any documentation on wiprintf(). I don't think it exists, but it may have a different name. |
I'm not sure that newlib has an integer version of the wide character functions. The thinking is that if your machine has enough RAM to hold the glyphs for a multi-byte character set, then it probably also has an FPU.
Quote: |
Quote: | these will be drawn into. I guess these could be directly in vram. |
I could see passing a pointer to a section of VRAM. If the amount needed is document, this would probably be the simplest approach. |
Or pass a pointer to a struct containing VRAM base address, width, and height.
Quote: |
Quote: | for bg i guess the thing could be very similar, when specifying a text box one specifies a bg and a rectangle in the bg map. |
You need to know what cells to write in the BG and/or which tiles to update. Treating a bunch of tiles as a bitmap is the most powerful way to use a BG. Part of the BG is formatted to use tiles like this:
Code: | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
...
70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F |
Then you just need to update the tiles. Proportional fonts can be written to BGs using this technique. You need to know how big the text area (width, height) is, and what tile index it starts at. If you go this route, you may want to include a function that initialized a square of tiles. |
If you are using a background map, then the following layout seen in the demo "fr018" is even easier because it treats each column of tiles as a linear bitmap so that going from row 7 to 8 doesn't need any special handling.
Code: |
00 08 10 18 20 28 30 38 40 48 50 58 60 68 ... B0 B8
01 09 11 19 21 29 31 39 41 49 51 59 61 69 ... B1 B9
...
07 0F 17 1F 27 2F 37 3F 47 4F 57 5F 67 6F ... B7 BF |
Quote: |
If you want to be able to handle simple windows, they usually consist on 8 border parts and an internal section.
Code: | /- -- -\
|. .. .|
|. .. .|
|. .. .|
|. .. .|
\- -- -/ |
|
Or the border can be fancier (although still rectangular) in the case of, say, the fluffy rectangles used for dialogue windows in Animal Crossing.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#122308 - sgeos - Sun Mar 18, 2007 5:05 pm
tepples wrote: |
I'm not sure that newlib has an integer version of the wide character functions. The thinking is that if your machine has enough RAM to hold the glyphs for a multi-byte character set, then it probably also has an FPU. |
This is why assumptions are bad. An FPU has nothing to do with ROM size. Once you hit 257 glyphs, you need a non-single byte encoding scheme. The gakushu kanji 学習漢字, kana, romaji and punctuation should come out to around 1200 ~ 1300 characters. At 1 bpp, there is more than enough space for such a font (150k).
tepples wrote: |
Quote: | Quote: | these will be drawn into. I guess these could be directly in vram. |
I could see passing a pointer to a section of VRAM. If the amount needed is document, this would probably be the simplest approach. |
Or pass a pointer to a struct containing VRAM base address, width, and height. |
This is better.
tepples wrote: |
If you are using a background map, then the following layout seen in the demo "fr018" is even easier because it treats each column of tiles as a linear bitmap so that going from row 7 to 8 doesn't need any special handling.
Code: | 00 08 10 18 20 28 30 38 40 48 50 58 60 68 ... B0 B8
01 09 11 19 21 29 31 39 41 49 51 59 61 69 ... B1 B9
...
07 0F 17 1F 27 2F 37 3F 47 4F 57 5F 67 6F ... B7 BF |
|
This is really neat.
tepples wrote: |
Quote: | If you want to be able to handle simple windows, they usually consist on 8 border parts and an internal section.
Code: | /- -- -\
|. .. .|
|. .. .|
|. .. .|
|. .. .|
\- -- -/ |
|
Or the border can be fancier (although still rectangular) in the case of, say, the fluffy rectangles used for dialogue windows in Animal Crossing. |
All sorts of things get used- nothing but half fade out, solid boxes, simple borders, fancy borders, gradient windows, bitmapped windows...
-Brendan
#122322 - Ant6n - Sun Mar 18, 2007 6:27 pm
my idea of having some function -getnextchar- that can be called by the callback is that if the font uses 16 bit characters, the user can always combine the argument of the callback (the current byte) and getnextchar to a u16, or u32.
Peek seems like a cool idea, it only needs to return a pointer to the next byt in the string.
the idea of using a big struct that declares offsets and array sizes for some of its members is that the data can easily be stored in some continuous fashion, i.e. a file. It also means there is only one big structure (of unkown length, but oh well) despite there being many dynamic members.
Quote: |
Or pass a pointer to a struct containing VRAM base address, width, and height. |
I guess the linking with the hardware is the hardest part of the specification, because it seems there is no balance between being powerful, general and being simple. the above would mean that the VRAM has to be layout in a special way, i.e. a continuous section of VRAM in which sprites life in a specified way. It is not always clear whether its possible for the user to create that environment, that's why i proposed giving an array of pointers to sprites, i.e.
maketextbox(......,u32 spritec,void **spritevrampointers).
Same goes for bg, where it seems to me that specifying a bg (0-3), and then specifying a rectangle in the bg map is fairly general. Knowing the hardware it can easily be figured out where each bgtile sits. The assumption here is that the bg map stays constant.
I see it would be favorable to have a useful layout (as Tepples proposed), but in general the only layout one can assume is 'tiles'. Since the data to be drawn has to be buffered anyway (if it is to be written during vblank), one could try to buffer it in such a way that it can be quickly copied into any arrangement of tiles.
#122533 - sgeos - Tue Mar 20, 2007 12:23 am
Ant6n wrote: |
my idea of having some function -getnextchar- that can be called by the callback is that if the font uses 16 bit characters, the user can always combine the argument of the callback (the current byte) and getnextchar to a u16, or u32. |
This is really good for encoding formats that mix ASCII with multibyte characters (SJIS), but it is less efficient for encoding formats that always use 16 or 32 bit values. Why not provide getnextchar() and a typedef?
Ant6n wrote: |
Peek seems like a cool idea, it only needs to return a pointer to the next byt in the string. |
If getnextchar() exists, I'm not sure what I'd do with it, but it is cheap enough to implement so why not? Somebody might come up with something.
Ant6n wrote: |
the idea of using a big struct that declares offsets and array sizes for some of its members is that the data can easily be stored in some continuous fashion, i.e. a file. |
This can be done anyway.
Ant6n wrote: |
It also means there is only one big structure (of unkown length, but oh well) despite there being many dynamic members. |
I think the disadvantages outweigh the advantages. Unknown length can easily be solved:
Code: |
type_t myData[] =
{
// unknown number of members
};
int myDataMembers = sizeof(myData) / sizeof(type_t);
int myDataSize = sizeof(myData); |
If you really want to use a file, you can write size data to the file header when you export your data.
Ant6n wrote: |
Quote: | Or pass a pointer to a struct containing VRAM base address, width, and height. |
I guess the linking with the hardware is the hardest part of the specification, because it seems there is no balance between being powerful, general and being simple. |
You need to careful when defining what your library does, and more importantly, what it does not do. I actually recommend that you start with either BG text display or OBJ text display, but not both. I think that windows are out of scope.
Ant6n wrote: |
the above would mean that the VRAM has to be layout in a special way, |
As long as you provide a function that formats VRAM and you tell people how to use it this is fine. Many libraries have initialization requirements.
Ant6n wrote: |
i.e. a continuous section of VRAM in which sprites life in a specified way. |
I don't see any way around this for the sprites. All sprite based text display systems that I am aware of use continuous VRAM tiles and continuous OAM entries. This is the simplest way of doing things.
Ant6n wrote: |
It is not always clear whether its possible for the user to create that environment, |
Sure it is. For a tiled BG:
"To use this library you first need to use initBgMap(). It will format the BG for you. You will need to have at least X free tiles in VRAM for the map to use."
For sprites:
"To use this library you will need to have at least X free tiles in VRAM and at least one free OAM entry for each character you want to display."
Quote: |
that's why i proposed giving an array of pointers to sprites, i.e.
maketextbox(......,u32 spritec,void **spritevrampointers). |
I would rather just pass a base address. I can't see a situation where I wouldn't use a continuous section of VRAM.
Quote: |
Same goes for bg, where it seems to me that specifying a bg (0-3), and then specifying a rectangle in the bg map is fairly general. |
I think that you will have to specify a screen based block instead.
Quote: |
Knowing the hardware it can easily be figured out where each bgtile sits. The assumption here is that the bg map stays constant. |
You will need to tell the system which character base block is being used and what tile to start from.
Quote: |
I see it would be favorable to have a useful layout (as Tepples proposed), but in general the only layout one can assume is 'tiles'. |
If that layout simplifies things, it is probably worth forcing people to use it if they want to use your library. I don't know of a better way to implement tile based text.
Quote: |
void formatBg(int pScreenBaseBlock, int pX, int pY, int pW, int pH, int pTileOffset);
// Formats a square with an upper lefthand corner at (pX, pY).
//
// t = tile offset
//
// t+0*h+0 t+1*h+0 ... t+(w-1)*h+0
// t+0*h+1 t+1*h+1 ... t+(w-1)*h+1
// . . .
// . . .
// . . .
// t+1*h-1 t+2*h-1 ... t+w*h-1 |
Quote: |
Since the data to be drawn has to be buffered anyway (if it is to be written during vblank), one could try to buffer it in such a way that it can be quickly copied into any arrangement of tiles. |
If you use a formatted matrix, all you have to do is DMA tile data to VRAM during the vblank. If you use contiguous sprites, you will have to DMA sprite tile data and OAM entries to VRAM. I don't know of a faster simpler way of doing things. I also can't think of a situation where this would not be acceptable library behavior, but I would be happy to hear about one.
-Brendan
#122543 - Ant6n - Tue Mar 20, 2007 3:01 am
The sprite library that i have been setting up the last couple of months (don't habe much time for it) manages vram and sprite. If you wanna use that you have to load the sprite tiled bitmap (the picture information) and you have to create a sprite object that uses that bitmap. I only load the picture information into vram when its actually needed, and only put the sprite into oam when it's displayed. So after a while everything is totally out of order. To get some sprites that sit in vram in constant positions one can create some space, or one can create sprites that are always in some position in vram. I.e., you tell it "i want that sprite to always be in vram at the same spot". this has to be in a block either in front or after the sprites that get dynamicly loaded, otherwise things get too complicated to handle for me. But if you create and destroy these 'constant' sprites, after a while that memory gets noncontinuously allocable. To make a long story short, in this scenario it might not always be possible to have continuous sprite space. Anyhoo, I guess if one can give an array of sprites pointers, giving a continuous space of sprites is just a special case. So is the specially arranged block of bg vram vs figuring out the tile arrangement from hardware.
Quote: |
You will need to tell the system which character base block is being used and what tile to start from. |
If the bg (0-3) is supplied, the base block is bit 2-3 of bg<n>control.
I have to think about that typedef (make sure I don't subly make assumptions about the size of characters in a string), but I guess it makes sense.
After giving it some thought, I think its not really necessary to copy during vram. texting is not done 20 times a second, so one would probably not see much of flicker. And if it is really necessary, the user could just give a shadow ram block as oppossed to a block in vram, and copy him/herself.
Quote: |
I think the disadvantages outweigh the advantages. Unknown length can easily be solved: (...) |
Is that still true if there are multiple members that are arrays of unkown size, and it is not even known whether they actually exist? I.e. all widths and/or heights can be stored in array each, or they could be constant. The glyphs are of uknown size, and there is an unknown number of them. I would create one big struct like this
Code: |
typedef struct{
char[4] ID;
u32 size;
s32 charcount,charwidth,charheight,defaultxoffset,defaultyoffset, ... etc
u32 widthcount,withoffset; //points to array relative to struct base address
u32 heightcount,heightoffset;//same
u32 glyphcount,glyphoffset; //same
u32 charxoffsetcount,charxoffsetoffset;//same
u32 charyoffsetcount,charyoffsetoffset;//
u32 charwidth; //one could define it here, then one doesnt have to recompile despite using wide chars
u32 bpp,glyphwidth,glyphheight
...probably some more stuff
} Font |
Here the 2nd element gives the size of the whole struct, which has constant data in the beginning and dynamic in the end.
As far as the as the callback goes.. I think the thing could be done like this: when somebody calls print(textbox,string), the engine goes into printing mode. It copies the string into some internal buffer. When there is a callback, one is allowed to call a the library functions, plus a few functions only accessible in reading mode, when not in reading mode they do nothing (nextchar,peek,insert string,cancel print). Insert string inserts the string after the current position in the reading buffer. after '0' is reached, the engine goes out of print mode. The callback returns the glyph index to be print. The highest bits of the return are used for control information (i.e. 'not printable', 'new line', 'breakable'). One could use the highest 16 bits for control.
Would one have a font on the GBA that actually uses more than 65536 possible glyphs?
I see you would define a couple of structs instead, I dont understand how that would be more convenient. Maybe I am missing something
#122549 - sgeos - Tue Mar 20, 2007 5:29 am
Ant6n wrote: |
To get some sprites that sit in vram in constant positions one can create some space, or one can create sprites that are always in some position in vram. I.e., you tell it "i want that sprite to always be in vram at the same spot". this has to be in a block either in front or after the sprites that get dynamicly loaded, otherwise things get too complicated to handle for me. |
This is more or less how sprite text systems work- you reserve a fixed number, say half, of your sprites for text. VRAM is really more of an issue than OAM. Once you start dealing with thousands of glyphs, every character needs its own tiles.
Ant6n wrote: |
Anyhoo, I guess if one can give an array of sprites pointers, giving a continuous space of sprites is just a special case. |
"I want 64 sprites, starting here." If you are using a low level API, the sprite system should be happier with continuous VRAM/OAM usage. If your API has a way to just get the next sprite this may not matter. My fear is VRAM fragmentation.
Ant6n wrote: |
So is the specially arranged block of bg vram vs figuring out the tile arrangement from hardware. |
The advantage of regular schemes is that they let you treat VRAM/OAM as an array conceptually and most probably practically as well.
Quote: |
Quote: | You will need to tell the system which character base block is being used and what tile to start from. |
If the bg (0-3) is supplied, the base block is bit 2-3 of bg<n>control. |
Sure.
Quote: |
I have to think about that typedef (make sure I don't subly make assumptions about the size of characters in a string), but I guess it makes sense. |
Breaking the assumption that 1 char == 1 glyph is very important if you want to work with international texts. I suggest that you typedef to something like u32 while developing just to make sure that you can't forget.
If you intend to support multidirectional text, I recommend using a DTU(characters)RTL(lines) test at the same time just because it is basically the opposite of English (and all European languages that I am aware of).
Quote: |
After giving it some thought, I think its not really necessary to copy during vram. texting is not done 20 times a second, so one would probably not see much of flicker. And if it is really necessary, the user could just give a shadow ram block as oppossed to a block in vram, and copy him/herself. |
Some old SJIS display code I wrote flickered. Shadow RAM would work, although I guess that you can't read BGxCNT in that case.
Quote: |
Quote: | I think the disadvantages outweigh the advantages. Unknown length can easily be solved: (...) |
Is that still true if there are multiple members that are arrays of unkown size, and it is not even known whether they actually exist? |
Yes. Treating an array as a struct is silly.
Quote: |
I.e. all widths and/or heights can be stored in array each, or they could be constant. |
If you absolutely need a placeholder, you can do something like this or use a similar solution embedded in a struct:
Code: |
const type_t gWidthDummy[] = {0};
const type_t gWidthDummySize = 0;
const type_t gWidthDummyMembers = 0; |
Code: |
typedef struct{
char[4] ID;
u32 size;
s32 charcount,charwidth,charheight,defaultxoffset,defaultyoffset, ... etc
u32 widthcount,withoffset; //points to array relative to struct base address
u32 heightcount,heightoffset;//same
u32 glyphcount,glyphoffset; //same
u32 charxoffsetcount,charxoffsetoffset;//same
u32 charyoffsetcount,charyoffsetoffset;//
u32 charwidth; //one could define it here, then one doesnt have to recompile despite using wide chars
u32 bpp,glyphwidth,glyphheight
...probably some more stuff
} Font |
When does charcount != glyphcount? Do unprintable characters somehow matter? I may choose to put control characters at the end of my encoding format (0xFFFF~) and printable characters at the start (0x0000~).
Is PROPORTIONAL set using defaultxoffset,defaultyoffset?
I'm assuming that the newline offset is in there somewhere, probably under a different name...
What is the difference between charwidth,charheight and glyphwidth,glyphheight?
If the font has a proportional height, heightcount == glyphcount; there is one proportional height entry per glyph (unless you want a height callback).
If the font has a proportional width, widthcount == glyphcount; there is one proportional width entry per glyph (unless you want a width callback).
A typedef is better than charwidth:
Code: |
// the message table should use the library character type
const char_t *const gMessageTableW[] =
{
L"",
L"The problem is that I want to recompile here.",
NULL
};
// it may look like this
const char_t *const gMessageTable16[] =
{
{0x0000},
{0x0431,0x3947,0x00E9,0x00CC,0x0000}, // Or here
NULL
};
// or like this, although I doubt it
const char_t *const gMessageTable32[] =
{
{0x00000000},
{0x01423314,0x35964778,0x00E9C90A,0x00CC00CC,0x00000000}, // OK, probably not on the GBA =)
NULL
}; |
Quote: |
Here the 2nd element gives the size of the whole struct, which has constant data in the beginning and dynamic in the end. |
Sure. Are alignment issues covered? With ~6000 glyphs I'll probably to use s8 for proportional width/height.
Quote: |
It copies the string into some internal buffer. |
The string is read only, so you should be able to trace over it. I don't see why it needs to be copied.
Quote: |
When there is a callback, one is allowed to call a the library functions, plus a few functions only accessible in reading mode, when not in reading mode they do nothing (nextchar,peek,insert string,cancel print). |
This is reasonable. I would tell people not to call them outside of print mode and let broken undefined things happen if they are called in strange places. This is up to you.
Quote: |
The highest bits of the return are used for control information (i.e. 'not printable', 'new line', 'breakable'). One could use the highest 16 bits for control. |
This works.
Quote: |
Would one have a font on the GBA that actually uses more than 65536 possible glyphs? |
I doubt it. A more or less complete unicode font is a little over 60000. I can't imagine anyone needing more than that. If you allow font switching, they could always "bankswitch" fonts to use more than 65536 characters.
Quote: |
I see you would define a couple of structs instead, I dont understand how that would be more convenient. Maybe I am missing something |
Treating a single array as a struct is silly. With isolated tables you could define both vertical and horizontal versions of a font using the same glyphset.
Code: |
const glyphData_t gFontGlyph[] =
{
// 20,000 lines of font data
};
// Horizontal Proportional
const widthData_t gFontWidth[] =
{
// 500 lines of width data
};
// Vertical Proportional
const heightData_t gFontHeight[] =
{
// 500 lines of width data
};
const fontData_t gFontPropH =
{
gFontGlyph, // Glyph Data
0, // Newline X Offset
16, // Newline Y Offset
PROPORTIONAL, // Newchar X Offset
0, // Newchar Y Offset
gFontWidth, // Proportional Width
NULL, // Proportional Height
// anything else, bpp, etc
};
const fontData_t gFontPropV =
{
gFontGlyph, // Glyph Data
-16, // Newline X Offset
0, // Newline Y Offset
0, // Newchar X Offset
PROPORTIONAL, // Newchar Y Offset
gFontWidth, // Proportional Width
NULL, // Proportional Height
// anything else, bpp, etc
};
const fontData_t gFontFixH =
{
gFontGlyph, // Glyph Data
0, // Newline X Offset
16, // Newline Y Offset
16, // Newchar X Offset
0, // Newchar Y Offset
NULL, // Proportional Height
NULL, // Proportional Height
// anything else, bpp, etc
};
const fontData_t gFontFixV =
{
gFontGlyph, // Glyph Data
-16, // Newline X Offset
0, // Newline Y Offset
0, // Newchar X Offset
16, // Newchar Y Offset
NULL, // Proportional Height
NULL, // Proportional Height
// anything else, bpp, etc
}; |
-Brendan
#122553 - tepples - Tue Mar 20, 2007 6:47 am
Ant6n wrote: |
texting is not done 20 times a second |
It is if you are using the same library to draw the player's score.
Quote: |
Code: |
typedef struct{
char[4] ID;
u32 size;
s32 charcount,charwidth,charheight,defaultxoffset,defaultyoffset, ... etc
u32 widthcount,withoffset; //points to array relative to struct base address
u32 heightcount,heightoffset;//same
u32 glyphcount,glyphoffset; //same
u32 charxoffsetcount,charxoffsetoffset;//same
u32 charyoffsetcount,charyoffsetoffset;//
u32 charwidth; //one could define it here, then one doesnt have to recompile despite using wide chars
u32 bpp,glyphwidth,glyphheight
...probably some more stuff
} Font |
|
u32 for widths and heights? Isn't a u8 sufficient for text that fits on the GBA or DS screen?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#122556 - Ant6n - Tue Mar 20, 2007 7:01 am
of course, but these details can be worked out later (when its made sure that the alignment is right etc.). I like using header files for brainstorming, so they are floating alot until i actually finished the specification (and even then myself changing things, as long as there was no release things should be fine).
Actually it'd be better to use s8 on some of these; then -1 can have special meaning, i.e. 'PROPORTIONAL'. I was more trying to ask why this approach in general is less neat than using multiple arrays, as sgoes suggested.
I wonder, how much memory would people spare to an engine like for internal buffering?
#122565 - HyperHacker - Tue Mar 20, 2007 7:48 am
You can still use 0xFF instead of -1, and even make a #define out of it for convenience.
_________________
I'm a PSP hacker now, but I still <3 DS.
#122566 - sgeos - Tue Mar 20, 2007 7:50 am
Ant6n wrote: |
I like using header files for brainstorming, so they are floating alot until i actually finished the specification |
This is a fine way of doing things.
Ant6n wrote: |
Actually it'd be better to use s8 on some of these; |
Single item generic entries should probably use "int". Arrays that need to be kept compact need to worry about space.
Ant6n wrote: |
then -1 can have special meaning, i.e. 'PROPORTIONAL'. |
IIRC, you can set u8 to -1, but it will end up being 255. Not that it really matters. Effective values should be in the range of 0 to about 40, unless someone wants to encode tab as a really wide/tall character. A width of 127 should be enough.
Come to think of it, negative values might be legit for RTL writing systems. -128 might work better for PROPORTIONAL. It depends on how you want to handle things. Being able to use the same table for LTR and RTL would be neat. The table should be valid.
A mirror glyph mode (H-flip/V-flip/HV-flip) would be neat, but that is probably ultimately useless feature creep.
Quote: |
I was more trying to ask why this approach in general is less neat than using multiple arrays, as sgoes suggested. |
I'm not convinced that it is, really. You seem to want files. I like compiled data tables. It's a little easier to set up data table export filters. I do like having the option of recycling a 1300 ~ 6000 character glyphset, but I'll admit that chances are slim that both vertical and horizontal writing will be used in the same version of the game.
Quote: |
I wonder, how much memory would people spare to an engine like for internal buffering? |
String buffering or shadow VRAM? The problem with sting buffering is, how long is the string? Some strings are really long, especially once you start adding user input breaks and form feeds.
"And thus began the journey... [inputs][breaks]
[18 pages later; this is an intro]
...finally, they arrived at the gates of the small village."
"You know, my mommy tells her I talk her ear off and
now I don't have anyone to talk to because my mommy
told me to go outside and stop bothering her and...
[insert the middle of the longest run on sentence ever]
...potatoes."
-Brendan
#122570 - HyperHacker - Tue Mar 20, 2007 7:55 am
sgeos wrote: |
IIRC, you can set u8 to -1, but it will end up being 255. |
And GCC will complain.
Quote: |
A mirror glyph mode (H-flip/V-flip/HV-flip) would be neat, but that is probably ultimately useless feature creep. |
If you're using a text-mode layer, it takes hardly any effort to implement. Just set the tile's H/V flip flags; you already have to set the palette flags in the same byte.
_________________
I'm a PSP hacker now, but I still <3 DS.
#122572 - sgeos - Tue Mar 20, 2007 8:28 am
tepples wrote: |
u32 for widths and heights? Isn't a u8 sufficient for text that fits on the GBA or DS screen? |
Spacewise, yes, but the u8 should really be typedefed to something like fontspan_t.
HyperHacker wrote: |
You can still use 0xFF instead of -1, and even make a #define out of it for convenience. |
Always #define it. Things change. Always use typedefs. Things change.
HyperHacker wrote: |
sgeos wrote: | IIRC, you can set u8 to -1, but it will end up being 255. | And GCC will complain. |
How do I get it to complain? It should complain, but this didn't for me:
Code: |
// test.c
int main(void)
{
unsigned int x = -1;
return x;
} |
Code: |
USER@Stardust ~/c/test
$ gcc -Wall test.c -o test
USER@Stardust ~/c/test
$ gcc -v
Reading specs from /usr/lib/gcc/i686-pc-cygwin/3.4.4/specs
Configured with: /usr/build/package/orig/test.respin/gcc-3.4.4-3/configure --ver
bose --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc --libdir=/usr/lib --libe
xecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-langu
ages=c,ada,c++,d,f77,pascal,java,objc --enable-nls --without-included-gettext --
enable-version-specific-runtime-libs --without-x --enable-libgcj --disable-java-
awt --with-system-zlib --enable-interpreter --disable-libgcj-debug --enable-thre
ads=posix --enable-java-gc=boehm --disable-win32-registry --enable-sjlj-exceptio
ns --enable-hash-synchronization --enable-libstdcxx-debug
Thread model: posix
gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
USER@Stardust ~/c/test
$ |
Quote: |
Quote: | A mirror glyph mode (H-flip/V-flip/HV-flip) would be neat, but that is probably ultimately useless feature creep. | If you're using a text-mode layer, it takes hardly any effort to implement. Just set the tile's H/V flip flags; you already have to set the palette flags in the same byte. |
Once you start using meta tiles you need to flip the tile matrix as well. Sprites should be simple enough.
-Brendan
#122595 - tepples - Tue Mar 20, 2007 5:04 pm
sgeos wrote: |
Quote: | I was more trying to ask why this approach in general is less neat than using multiple arrays, as sgoes suggested. |
I'm not convinced that it is, really. You seem to want files. I like compiled data tables. |
The "files" approach is more viable on a platform without a large word-addressed memory, such as a Game Boy Advance game running from GBA Movie Player, a GBA game running from single-Pak multiplayer requesting files from the server over the serial link, or a Nintendo DS game.
Quote: |
The problem with sting buffering is, how long is the string? Some strings are really long, especially once you start adding user input breaks and form feeds. |
If you only buffer the current "form" and the next "form", that shouldn't be too much of a problem.
Quote: |
"And thus began the journey... [inputs][breaks]
[18 pages later; this is an intro]
...finally, they arrived at the gates of the small village." |
Ahh yes, the classic "second disc of Xenogears" school of game design. But do you really want to hang your entire cut scene system off your text engine?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#122628 - sgeos - Tue Mar 20, 2007 9:41 pm
Quote: |
Quote: | The problem with sting buffering is, how long is the string? Some strings are really long, especially once you start adding user input breaks and form feeds. |
If you only buffer the current "form" and the next "form", that shouldn't be too much of a problem. |
Even the form is going to vary from game to game. It you buffer the transformed form that is one thing, but once unprintable control characters show up all bets are off.
Quote: |
Quote: | "And thus began the journey... [inputs][breaks]
[18 pages later; this is an intro]
...finally, they arrived at the gates of the small village." |
Ahh yes, the classic "second disc of Xenogears" school of game design. But do you really want to hang your entire cut scene system off your text engine? |
No, but that doesn't mean that I won't have a message 18 forms long or longer somewhere else. With embedded character portraits, this is quite feasible. Consider something like Fire Emblem or Super Robot Wars- treating each dialogue as a single message (until bgs change/units get deployed, etc) is reasonable-
Code: |
script(SCR_STAGE_01_00); // load enemy base map
message(MES_STAGE_01_01); // plans at enemy base; 17 forms
script(SCR_STAGE_01_01); // launch enemy units
script(SCR_STAGE_01_02); // load battle map, deploy and move new units
message(MES_STAGE_01_02); // new units for this stage; 4 forms
script(SCR_STAGE_01_03); // deploy player units
message(MES_STAGE_01_03); // player meets new units; 31 forms
script(SCR_STAGE_01_04); // deploy enemy units
message(MES_STAGE_01_04); // ememy talks to new units; 7 forms
gamestart(); |
Naturally, all of this would actually exist in one big SCR_STAGE_01 script file (*) with the messages stored on the side and called from the script.
(*) this file may be exported to some other format before it run on the GBA (or DS, or toaster or whatever you want to run it on).
-Brendan
#122687 - HyperHacker - Wed Mar 21, 2007 6:00 am
sgeos wrote: |
How do I get it to complain? It should complain, but this didn't for me: |
Maybe it only does that with hex numbers then.
_________________
I'm a PSP hacker now, but I still <3 DS.
#122727 - sgeos - Wed Mar 21, 2007 3:49 pm
HyperHacker wrote: |
sgeos wrote: | How do I get it to complain? It should complain, but this didn't for me: | Maybe it only does that with hex numbers then. |
I created a new thread to talk about this.
-Brendan