Pages: [1] 2 3 4
  Print  
Author Topic: GML: All draw_text functions +(string_width, _height, _width_ext, _height_ext)  (Read 12643 times)
Offline (Unknown gender) TheExDeus
Posted on: October 29, 2010, 01:34:35 PM

Developer
Joined: Apr 2008
Posts: 1886

View Profile
This is updated in 30.04.2011!
Description: These are all draw_text functions + string_width, _height and string_width_ext, and _height_ext functions. They are very optimized (thanks to Josh) and so they should work great.
Notice: They are mostly the same as GM ones, but GM's color interpolation and text position is a little different. There are two images to compare at the next page.
Functions:
Code: [Select]
void draw_set_font(int fnt);
void draw_text(int x,int y,string str);
void draw_text_color(int x,int y,string str,int c1,int c2,int c3,int c4,double a);

void draw_text_ext(int x,int y,string str, int sep, int w);
void draw_text_ext_color(int x,int y,string str, int sep,int w,int c1,int c2,int c3,int c4,double a);

void draw_text_transformed(double x,double y,string str,double xscale,double yscale,double rot);
void draw_text_transformed_color(double x,double y,string str,double xscale,double yscale,double rot,int c1,int c2,int c3,int c4,double a);

void draw_text_ext_transformed(double x,double y,string str,int sep,int w, double xscale,double yscale,double rot);
void draw_text_ext_transformed_color(double x,double y,string str,int sep,int w,double xscale,double yscale,double rot,int c1,int c2,int c3,int c4,double a);

unsigned int font_get_texture(int fnt);
int  font_add_sprite(int spr, unsigned char first, bool prop, int sep);
unsigned int font_get_texture_width(int fnt);
unsigned int font_get_texture_height(int fnt);

int string_width(string str);
int string_height(string str);

unsigned int string_width_ext(string str, int sep, int w);
unsigned int string_height_ext(string str, int sep, int w);

unsigned int string_width_line(string str, int line);
unsigned int string_width_ext_line(string str, int w, int line);
unsigned int string_width_ext_line_count(string str, int w);

You can download GSFont.h and .cpp in attachment, as well as a little screenshot. It shows draw_text_color and draw_text_ext_transformed_color.

P.s.: It wasn't as easy as I thought at the beginning. Mostly because of the trig for _transform and _ext functions that come with it.
Also, what do you suggest on dealing with the # newline character? The easiest thing would be searching for all # and then checking if / is in front of it, if its not then it is a newline char, if there is a / in front, then just replace /# with # and draw it. But I think there should be some better way, like using regular expressions, but that could end up being a lot slower.?

Also, "prop" argument doesn't work in font_add_sprite. With the font sprite I tried it with it just returns 0x0 size, so it doesn't draw anything. I will look into that if Josh doesn't.

edit: Nevermind about the # question. Enigma will do this automatically, at least Josh said so.

edit2: I added string_width, _height and _ext functions.
« Last Edit: April 29, 2011, 04:10:16 PM by HaRRiKiRi » Logged
Offline (Female) IsmAvatar
Reply #1 Posted on: October 29, 2010, 02:32:25 PM

LateralGM Developer
LGM Developer
Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 886

View Profile Email
Actually regex isn't all that slow. In fact, the term "regular" means that it should be able to search a string in runtime O(N) where N is the length of the string, which is the fastest runtime that you can search an unindexed, unsorted string for a single character (unless you know something about the string, of course).
Logged
Offline (Unknown gender) TheExDeus
Reply #2 Posted on: October 29, 2010, 02:55:45 PM

Developer
Joined: Apr 2008
Posts: 1886

View Profile
Well, then I will look into that. But I need to get the regex library right? There is regex built-in C++ x0 specification, but I guess we don't use that? Or use some 3rd party library like boost.regex. Regex could actually be implemented in Enigma as GML functions..
Logged
Offline (Female) IsmAvatar
Reply #3 Posted on: October 29, 2010, 04:15:48 PM

LateralGM Developer
LGM Developer
Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 886

View Profile Email
Regex in EGML would be extremely useful. But for the purpose of finding non-escaped #s in strings... it's overkill. It's really not that hard to do an char *num = indexof(str,'#') and then num != str && *(num-1) != '/'
Logged
Offline (Male) RetroX
Reply #4 Posted on: October 29, 2010, 04:27:09 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
It's even simpler than that.

Code: [Select]
for (size_t i = 0; i < str.size(); i++)
{
  if (str[i] == '#' && (i == 0 || str[i-1] != '\\'))
  {
    str[i]='\n';
  }
}

Also, it's C++0x, not C++x0.  The standard C library supports regex, and I think that it would be a good idea to implement it into ENIGMA.
« Last Edit: October 29, 2010, 04:29:47 PM by RetroX » Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Female) IsmAvatar
Reply #5 Posted on: October 29, 2010, 04:59:21 PM

LateralGM Developer
LGM Developer
Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 886

View Profile Email
That's what I meant, I just didn't feel like writing the code out. In fact, I don't know if GM does this, but if "//#" is displays the / glyph followed by a newline, you could do that with a boolean that toggles for each '/' encountered, and you don't have to look backwards then.

Also, watch out for EnigmaSettings.cppStrings, which is currently not passed to Enigma yet, but is togglable by the user. When toggled, # is treated as a literal # glyph, and / no longer serves as an escape character.
« Last Edit: October 29, 2010, 05:02:13 PM by IsmAvatar » Logged
Offline (Unknown gender) TheExDeus
Reply #6 Posted on: October 29, 2010, 05:04:56 PM

Developer
Joined: Apr 2008
Posts: 1886

View Profile
But doing that on every draw call? What I want is to make text functions actually usable. I haven't benchmarked anything yet, but in GM having a long multi-line string was the slowest thing ever.

Also, multi line text in code editor doesn't trow errors, but it trows errors on compile. GM allows this, so maybe Enigma should too.
Logged
Offline (Male) Josh @ Dreamland
Reply #7 Posted on: October 29, 2010, 06:18:36 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2934

View Profile Email
First off, I'm quite impressed at how quickly you got on this; I haven't even announced that fonts were in.

More importantly, I have to express some concerns before I adopt these:
1) Trig functions and multiple multiplication operations are performed in each loop iteration for the transformed font functions. That is a costly move compared to what could be accomplished with a simple precalculation (considering none of them are dynamic, as far as I know).
2) I was not quite done with linear fonts at the time of commit. For example, look what happens to the "I" in this screen shot. It's not the spacing that concerns me as much as the fact that "I" is only one pixel wide. I fear the worst.

Your work is, of course, appreciated greatly nonetheless. Neither of those are a serious detriment; I will just need to go over them when I have a few more answers.

Good work.


Also, I was looking into regex for ENIGMA, but the best interpreter out there for C++ is apparently Boost, and they totally fucking overkill everything. I just want a damn preg_match and preg_replace for ENIGMA; it shouldn't be 65 source files and it shouldn't have a fucking config file. Damn it.

And one more thing: in case you're wondering where that screenshot came from, it started out as an example someone posted on the GMC, which I stumbled upon looking for an explanation of the parameters to font_add_sprite().
« Last Edit: October 29, 2010, 06:25:52 PM by Josh @ Dreamland » Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Male) RetroX
Reply #8 Posted on: October 29, 2010, 06:26:48 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Eh, I messed up.
Code: [Select]
for (size_t i = 0; i < str.size(); i++)
{
  if (str[i] == '#')
  {
    if (i > 0 || str[i-1] == '\\')
    {
      str.erase(--str[i],1);
    }
    else
    {
      str[i]='\n';
    }
  }
}
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) Josh @ Dreamland
Reply #9 Posted on: October 29, 2010, 06:32:09 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2934

View Profile Email
Please don't do that.
ENIGMA lets you choose how to escape string literals. There are two settings, though you can't yet switch between them:
1) GML. "Quote inside quote looks like " + '"this."' + " Newlines are escaped from '#' automatically."
2) C++. "Quote inside quote looks like \"this.\" Newlines must use \\r\\n, like this: \r\n ^ line ^ \r\n # does nothing."
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Male) RetroX
Reply #10 Posted on: October 29, 2010, 06:36:12 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Right.  I'll let you work on that.

Why does \r\n have to be used?  That's not even a correct escape for Windows; it's \n\r.  Why not just use \n?
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) Josh @ Dreamland
Reply #11 Posted on: October 29, 2010, 07:20:32 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2934

View Profile Email
1) It is \r\n
2) The \r is optional in everything not strictly Microsoft (IE, not Notepad).
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) TheExDeus
Reply #12 Posted on: October 30, 2010, 03:59:55 AM

Developer
Joined: Apr 2008
Posts: 1886

View Profile
Quote
1) Trig functions and multiple multiplication operations are performed in each loop iteration for the transformed font functions. That is a costly move compared to what could be accomplished with a simple precalculation (considering none of them are dynamic, as far as I know).
I do know that trig is costly, and I did my best to optimize it by calculating sin(rot) and cos(rot) only once. Also, cos(M_PI+rot) and sin(M_PI/2+rot) can be calculated only once and so on. So I will optimize it as much as I can. In the end it will be about 8 trig functions (4 sin and 4 cos I think) that is calculated in each draw call, but not for each symbol. So it shouldn't be that slow... should it? The only slow thing that needs to be calculated for every symbol is sqrt(x^2+y^2) (Pythagoras theorem), but it could be possible to fix that too.
So I will optimize the code a bit, and maybe clean it up a bit too. Then I will show it again. :)

Quote
ENIGMA lets you choose how to escape string literals. There are two settings, though you can't yet switch between them:
1) GML. "Quote inside quote looks like " + '"this."' + " Newlines are escaped from '#' automatically."
2) C++. "Quote inside quote looks like \"this.\" Newlines must use \\r\\n, like this: \r\n ^ line ^ \r\n # does nothing."
Ou, so we don't need to add that for every draw text function? :D Nice. :)

edit: Ok, I changed transform functions so all trig is calculated only once per call. Not once per symbol. This should speed it up a lot, but I want Enigma to use LGM Font resource before I benchmark.

edit2: That sqrt() could be removed by just taking width as xx*xx + yy*yy and then comparing it to w*w no? Because I have heard that sqrt() is slow.

edit3: Ok, reuploaded again. Now sqrt() is replaced and so should be even faster.

edit4: Also, that "ENIGMA lets you choose how to escape string literals", I know how it would work on compile time, but if I need to change the string while running the game? Wouldn't it need to have something to do with # replacing in the functions themselves? Or you will need a way to catch the argument going to the text function and replace #, and only then pass the changed string to the function. Not sure how that would work.

edit5: I hate double posting so this editing will continue. :D
I just added string_width, _height and _ext functions. They do work as far as I tested them, but I did found a bug in string() function. string() doesn't return the correct string when there is unsigned int as an argument. I thought as string_width can't be negative I will use unsigned int as the return type, and it works further in calculations (like position and stuff), but when I put draw_text(10,10,string(string_height())) it will shows "322" for example, and "32" is the actual height, and that extra 2 is a bug. So.. just giving the heads up. :)

Also, I would suggest cleaning up the files. There are a lot of outdated, and as far I as I know, unused files. Like GMsprite.h and so on. 
« Last Edit: October 30, 2010, 08:30:14 AM by HaRRiKiRi » Logged
Offline (Unknown gender) TGMG
Reply #13 Posted on: October 30, 2010, 08:31:29 AM

Developer
Joined: Jun 2008
Posts: 107

View Profile WWW Email
Thanks HaRRiKiRi nice work :D
Looking forward to converting these to openglES/ES2 when they are done :)
Logged
me
GMbed 2.0 :: Embed you gm games in websites.
Offline (Male) RetroX
Reply #14 Posted on: October 30, 2010, 09:20:42 AM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
1) It is \r\n
2) The \r is optional in everything not strictly Microsoft (IE, not Notepad).
Okay, it is \r\n. :V
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Pages: [1] 2 3 4
  Print