|
Josh @ Dreamland
|
|
Reply #16 Posted on: October 30, 2010, 09:53:19 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Oh, perhaps you took a different approach than I would have. ...Actually, looking at your code, your approach is exactly what I was about to suggest, only your precalculations are fewer than they could be. Also, I don't understand something...
ulcx = xx + g.tx * xscale * cvp + g.ty * yscale * cv2;
ulcy = yy - g.tx * xscale * svp - g.ty * yscale * sv2;
Why are you subtracting the texture coordinate from it? the texture coordinate is between 1 and 0... From what I can tell. ulcx should just be xx...
Also, you do a lot of xscale * cx... this is the sort of thing that I was going to precalculate, and here's why: Your method is very close to what I think is the fastest. When you draw text, even rotated, the text is still following a linear pattern: You can trace a line across the tops of the glyphs. So all we really need is a sort of slope calculation based on trig.
This is about as efficient as I can see making the function:
void draw_text_transformed(double x,double y,string str,double xscale,double yscale,double rot) { if (currentfont == -1) return; font *fnt = fontstructarray[currentfont]; if (cur_bou_tha_noo_sho_eve_cha_eve != fnt->texture) glBindTexture(GL_TEXTURE_2D, cur_bou_tha_noo_sho_eve_cha_eve = fnt->texture); float xx = (float)x, yy = (float)y; float w, h = fnt->height*yscale; rot *= M_PI/180; const float sv = sin(rot), cv = cos(rot), svx = sv*xscale, cvx = cv*xscale, hi = h * -sv, sw = fnt->height/3 * cvx, sh = fnt->height/3 * svx; glBegin(GL_QUADS); for (unsigned i = 0; i < str.length(); i++) { if (str[i] == '\r') xx = x, yy += hi, i += str[i+1] == '\n'; else if (str[i] == '\n') xx = x, yy += hi; else if (str[i] == ' ') xx += sw, yy -= sh; else { fontglyph &g = fnt->glyphs[(unsigned char)(str[i] - fnt->glyphstart) % fnt->glyphcount]; w = (g.x2-g.x), h = (g.y2-g.y); glTexCoord2f(g.tx, g.ty); glVertex2f(xx, yy); glTexCoord2f(g.tx2, g.ty); glVertex2f(xx + w * cvx, yy - w * svx);
const float lx = xx + h * svx; const float ly = yy + h * cvx; glTexCoord2f(g.tx2, g.ty2); glVertex2f(lx + w * cvx, ly - w * svx); glTexCoord2f(g.tx, g.ty2); glVertex2f(lx, ly); xx += g.xs * cvx; yy -= g.xs * svx; } } glEnd(); }
Also, don't sweat string manipulation. The only way the user could tell the difference between escaping # at compile time or treating it special at run time is to use chr(whatever) and concatenate. Other than that, if they try += "#", they'll just be saying += "\r\n", etc, etc.
|
|
|
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
|
|
|
TheExDeus
|
|
Reply #17 Posted on: October 30, 2010, 10:23:47 am |
|
|
Joined: Apr 2008
Posts: 1860
|
Also, I don't understand something... Yeah, redundancy is the key. I knew that only one cos and one sin function call should be needed, because I was following the same logic about the line, but I couldn't come up with something useful at that moment, so I basically used lengthdir_x and _y type of thing. I will see if I can make them as efficient as yours. edit: You got to love optimizing code. Especially when it goes from 8 trig functions per symbol, to 2 trig functions per call. Even then thou, I think it was faster than GM. edit2: Uploaded the new .cpp file. Now every transform function has only two trig calls, one cos and one sin. I am thinking of adding string_width_ext_transformed and other similiar functions. I think they should of been in GM, as for example, you want to place a rocket ship at the end of the rotating text.. Even thou it can be done with knowing the angle (which you know because you rotate the text) and using lengthdir+string_width, but still, this could be useful as a built-in function. edit3: Also, what would be the best way to load fonts on the fly? I know that Josh previously had some way to render vector fonts. If a ttf file would be loaded and then just drawn on a texture, then it would work great. I am looking into 3rd party libraries like FreeType, and it looks promising, but also an overkill. The only thing I want is to recreate font_add function.
|
|
« Last Edit: October 30, 2010, 01:16:24 pm by HaRRiKiRi »
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #18 Posted on: October 31, 2010, 10:21:14 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
> Even then thou, I think it was faster than GM. It probably was. Or, at least, just as fast.
> Also, what would be the best way to load fonts on the fly? If I knew that, I'd have done it years ago.
|
|
|
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
|
|
|
|
IsmAvatar
|
|
Reply #20 Posted on: October 31, 2010, 09:27:52 pm |
|
|
LateralGM Developer
Location: Pennsylvania/USA Joined: Apr 2008
Posts: 877
|
When you draw text, even rotated, the text is still following a linear pattern: You can trace a line across the tops of the glyphs. Er... Maybe I'm taking this out of context here, but since when has this been true? Glyphs should only be aligned by their baseline, which is usually closer to the bottom of the glyph (even for the "p", "g", "q", and "y" glyphs). Most notably, your theory falls apart for capitalisation - the top of the "c" and "C" glyphs should not align.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #21 Posted on: November 01, 2010, 07:52:02 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Mmmyes. Wonder which one the code uses.
Can't test/fix now; off to class.
Worst case scenario: It's broken and we have to add svx*g-> to each xx and cvx * g->y to each yy...
|
|
« Last Edit: November 01, 2010, 07:53:41 am 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
|
|
|
|
TheExDeus
|
|
Reply #23 Posted on: April 24, 2011, 08:37:04 am |
|
|
Joined: Apr 2008
Posts: 1860
|
As Enigma finally supports fonts, then this topic could get a new life. All of the functions worked, but that was with the sprite fonts and they also didn't follow some rules. 1. The origin of the text wasn't at the top left, but the bottom left. I fixed that by doing this: yy = y+fnt->height. It looks almost exactly like the GM's, but this makes it draw a few pixels lower than GM. Dunno how GM does it then. 2. _ext functions cut the text when it was already out of the boundary defined by "width" argument. The only way I thought I could fix this is by doing a loop inside a loop, which is quite painful. This is the code:
//The following is certainly not pretty, but this is the best way I thought of to replicate GM's function void draw_text_ext(int x,int y,string str, int sep, int w) { font *fnt = fontstructarray[currentfont];
if (bound_texture != fnt->texture) glBindTexture(GL_TEXTURE_2D, bound_texture = fnt->texture);
int xx = x, yy = y+fnt->height, width = 0, tw = 0; glBegin(GL_QUADS); for (unsigned i = 0; i < str.length(); i++) { if (str[i] == '\r') xx = x, yy += (sep+2 ? fnt->height : sep), i += str[i+1] == '\n'; else if (str[i] == '\n') xx = x, yy += (sep+2 ? fnt->height : sep); else if (str[i] == ' ') xx += fnt->height/3, width = xx-x; tw = 0; for (unsigned c = i+1; c < str.length(); c++) //This is getting messy { if (str[c] == ' ') break; fontglyph &g = fnt->glyphs[(unsigned char)(str[c] - fnt->glyphstart) % fnt->glyphcount]; tw += g.xs; }
if (width+tw >= w && w != -1) xx = x, yy += (sep==-1 ? fnt->height : sep), width = 0, tw = 0; else { fontglyph &g = fnt->glyphs[(unsigned char)(str[i] - fnt->glyphstart) % fnt->glyphcount]; glTexCoord2f(g.tx, g.ty); glVertex2i(xx + g.x, yy + g.y); glTexCoord2f(g.tx2, g.ty); glVertex2i(xx + g.x2, yy + g.y); glTexCoord2f(g.tx2, g.ty2); glVertex2i(xx + g.x2, yy + g.y2); glTexCoord2f(g.tx, g.ty2); glVertex2i(xx + g.x, yy + g.y2); xx += g.xs; width = xx-x; } } glEnd(); } Question is if anyone can think of a better way. This works exactly like GM's, but this cuts words in the middle if the "width" is too small. I don't actually see why it does that, as cutting should occur only in spaces.
Anyway, I am still reworking the rest of the functions and in time, this could be committed.
|
|
|
Logged
|
|
|
|
|
|
|
Josh @ Dreamland
|
|
Reply #27 Posted on: April 26, 2011, 10:42:52 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Oh, I see. You're doing text wrapping. That's fine, I think. The reason it's cutting in the middle of words is because you handle it at all letters, not just space. Add braces around the indented block after "else if (str[i] == ' ')".
Once you do that, it will bring the complexity down to O(N) (Really, a synonymous O(2N), but that's a sacrifice I believe is necessary).
|
|
« Last Edit: April 26, 2011, 10:53:09 am 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
|
|
|
TheExDeus
|
|
Reply #28 Posted on: April 29, 2011, 04:24:43 pm |
|
|
Joined: Apr 2008
Posts: 1860
|
Ok, so I updated all the functions. They all work correctly as far as I have tested them. They are not so pretty thou, as fixing the positioning required some additional math to be added. I did try to precompute everything as much as possible, but some things are still character based. If anyone has any optimizations in mind then please share. The .cpp and .h is at the first page. I have two comparison pictures here: http://img854.imageshack.us/i/textinenigma.png/http://img852.imageshack.us/i/textingamemaker80.png/One is in GM and the other in ENIGMA. Also side by side picture here: http://img26.imageshack.us/i/textcompare.jpg/As you can see there isn't much of a change. Its better if you can overlay one on the other, but it is possible to see slight size and color differences. I think colors are interpolated more properly in ENIGMA thou as in GM you can't actually get a black corner when a color is set to black. The biggest difference is in draw_text_ext_transformed as in GM it splits into 4 lines while in ENIGMA it splits into 3. Don't know why GM does that, as it clearly isn't out of bounds. If I increase the width to 301 instead of 300, then GM doesn't split. So its probably some rounding bug. Also, in Enigma screen you can see arrows pointing in the draw_text_ext_color example. This is done to show off some new functions I added. In GM doing that would be quite a pain, but now in Enigma you can draw them just with this simple code: for (int i=0; i<string_width_ext_line_count(str,w); i+=1){ twi = string_width_ext_line(str, w, i); draw_arrow(430+w, 75+string_height("M")*(i+0.5),430+twi, 75+string_height("M")*(i+0.5), 10, 3, 1); } So basically you can get width of a specific line inside a multiline string. The full source can be downloaded from the attachment bellow. If no one finds any bugs or does some optimization then I think this could be committed. I will do this myself if no one else will. I will also write wiki entry just like I did for curves and shapes.
|
|
|
Logged
|
|
|
|
|
|