Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: monkey0506 on Thu 11/10/2007 21:22:00

Title: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overlays
Post by: monkey0506 on Thu 11/10/2007 21:22:00
Wouldn't it be nice if there were some way to render text as a sprite?

Workaround:

DynamicSprite* RenderTextAsSprite(int width, FontType font, int color, String text, Alignment align) {
  if ((width <= 0) || (font < 0) || (font >= Game.FontCount) || (text == null) || (text == "")) return null;
  DynamicSprite* sprite = DynamicSprite.CreateFromScreenShot(width, GetTextHeight(text, font, width));
  DrawingSurface* surface = sprite.GetDrawingSurface();
  surface.Clear();
  if (color < 0) color = 0;
  surface.DrawingColor = color;
  String buffer = "";
  int i = 0, w = 0, y = 0;
  while (i < text.Length) {
    if (GetTextWidth(buffer.AppendChar(text.Chars[i]), font) <= width) buffer = buffer.AppendChar(text.Chars[i]);
    else {
      while ((buffer.Contains(" ") != -1) && (buffer.Chars[buffer.Length - 1] != ' ')) {
        buffer = buffer.Truncate(buffer.Length - 1);
        i--;
        }
      w = GetTextWidth(buffer, font);
      if (align == eAlignLeft) surface.DrawString(0, y, font, buffer);
      else if (align == eAlignCentre) surface.DrawString((width - w) / 2, y, font, buffer);
      else if (align == eAlignRight) surface.DrawString(width - w, y, font, buffer);
      y += GetTextHeight(buffer, font, w + 1);
      i--;
      buffer = "";
      }
    i++;
    }
  w = GetTextWidth(buffer, font);
  if (align == eAlignLeft) surface.DrawString(0, y, font, buffer);
  else if (align == eAlignCentre) surface.DrawString((width - w) / 2, y, font, buffer);
  else if (align == eAlignRight) surface.DrawString(width - w, y, font, buffer);
  surface.Release();
  return sprite;
  }


Such a function would also provide a workaround for the outstanding request for aligned textual overlays (http://www.adventuregamestudio.co.uk/yabb/index.php?topic=27721.0) (using a graphical overlay instead):

Overlay* OverlayCreateTextualAligned(int x, int y, int width, FontType font, int color, String text, Alignment align) {
  DynamicSprite* sprite = RenderTextAsSprite(width, font, color, text, align);
  if (sprite == null) return null;
  return Overlay.CreateGraphical(x, y, sprite.Graphic, true);
  }


BUG NOTE: Scripting the workaround for the text rendering function actually led me to discover what I believe would be considered bugs in AGS. For example, when using hyphens (-) and periods/full stops/dots (.) as separators instead of whitespace (to see how AGS handled width-based line-breaking), I often found that characters at the end of the line were lost. Even when using Character.Say I found similar results with characters disappearing. Since I considered this a bug, I've tried to make sure that the above workaround function does not lose such characters in the jet stream.
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overlays
Post by: Pumaman on Thu 11/10/2007 21:29:54
DrawingSurface.DrawMessageWrapped almost does this, except that it's based on a room message rather than a script string. If this method was adapted to take a String and an Alignment, would that resolve the situation for you?
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overl
Post by: monkey0506 on Fri 12/10/2007 03:31:55
Well basically that is what I've done I suppose. 8)

However, did you see this part?

Quote from: monkey_05_06BUG NOTE: Scripting the workaround for the text rendering function actually led me to discover what I believe would be considered bugs in AGS. For example, when using hyphens (-) and periods/full stops/dots (.) as separators instead of whitespace (to see how AGS handled width-based line-breaking), I often found that characters at the end of the line were lost. Even when using Character.Say I found similar results with characters disappearing. Since I considered this a bug, I've tried to make sure that the above workaround function does not lose such characters in the jet stream.

If it makes any difference in trying to replicate the problem I was using the String "This is a long message that should wrap to multiple lines.", width 150 pixels, default speech font.

On the note of the function however...couldn't DrawingSurface.DrawString just be made to take width and Alignment parameters? I understand that the basic idea behind leaving in the "..." part is backward compatibility...but all that would really need to be modified would be to encapsulate the String parameter and the formatting parameters with a String.Format(). Now that we can call String.Format to supply formatting Strings as parameters to functions, the ability of individual functions to format strings isn't as important (at least IMO).
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overlays
Post by: Pumaman on Fri 12/10/2007 19:22:12
If there are no spaces in your string, AGS isn't very good at wrapping it. I'll take a look and see if I can improve things.
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overl
Post by: monkey0506 on Sat 13/10/2007 03:22:42
I'd noticed. ;D Thanks for taking a look at this though Chris. You're the greatest.
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overl
Post by: naltimari on Wed 17/10/2007 20:50:06
I was after the same thing (render text as sprite), but this code only works in AGS 3.0 (beta). Can you point me to some code that does this for AGS 2.72?

Actually, I ended up coding something myself:


DynamicSprite *ds;

function TextAsSprite(String s, int color)
{
int o = GetGameOption(OPT_ANTIALIASFONTS);
int w = GetTextWidth(s, Game.NormalFont);
int h = GetTextHeight(s, Game.NormalFont, w);

SetGameOption(OPT_ANTIALIASFONTS, 0);
RawSaveScreen();

RawSetColorRGB(255,0,255);
RawDrawRectangle(0, 0, w, h);
RawSetColor(color);
RawPrint(0, 0, s);
ds = DynamicSprite.CreateFromBackground(0, 0, 0, w, h);

RawRestoreScreen();
SetGameOption(OPT_ANTIALIASFONTS, o);

return ds.Graphic;
}


Which I can use by calling, for example,


RawDrawImageTransparent(20, 20, TextAsSprite("Hello, World", 15), 50);


The above code works, but it has a couple of disadvantages:
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overl
Post by: Ashen on Wed 17/10/2007 22:00:23
Quote
Function returns int, not DynamicSprite*, so you cant have access to properties of the sprite (height, width, etc)
What if you create a new DynamicSprite, based on the returned int value, e.g:

DynamicSprite *sprite = DynamicSprite.CreateFromExistingSprite(TextAsSprite("Hello, World", 15));
RawDrawImageTransparent(20, 20 - sprite.Height, sprite.Graphic, 50);


You could also declare TextAsSprite as a DynamicSprite rather than a function:

DynamicSprite *TextAsSprite(String s, int color)
{
// Blah blah blah

return ds;
}


However, I think you'd still need to use a 'dummy' DynamicSprite to access the properties - you couldn't directly use
TextAsSprite("Hello, World", 15).Graphic, for example - so you might as well stick with using function.
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overl
Post by: monkey0506 on Wed 17/10/2007 22:34:01
The benefit to making it return a DynamicSprite* instead of returning an int would be that when you do:

DynamicSprite* ds = TextAsSprite(...);

Only one DynamicSprite is actually created in memory whereas:

DynamicSprite* ds = DynamicSprite.CreateFromExistingSprite(TextAsSprite(...));

Creates two sprites.
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overl
Post by: naltimari on Wed 17/10/2007 22:59:10
QuoteThe benefit to making it return a DynamicSprite* instead of returning an int would be that...

Exactly. But AFAIK, AGS 2.72 functions can't return any pointers, right? From what I saw on your first post, AGS 3.0 changed that. :)
Title: Re: SUGGESTION: DynamicSprite.CreateFromString/WORKAROUND: Aligned Textual Overl
Post by: monkey0506 on Wed 17/10/2007 23:01:25
Nooooooo, AGS 2.72 functions can return pointers. Just replace function with DynamicSprite*.