Author Topic: Antialiased TTF LucasArts style speech? (didn't think so) [SOLVED]  (Read 2138 times)

monkey0506

  • SEND PIZZA.
    • Best Innovation Award Winner 2017, for his work to help AGS games reach the widest possible audience - through popular distribution platforms (Steam, Galaxy) as well as other operating systems (Android, Linux)
    • monkey0506 worked on one or more games that won an AGS Award!
    •  
    • monkey0506 worked on one or more games that was nominated for an AGS Award!
Okay so I searched in the forums and found this thread which linked to this tracker entry both of which are old.

My question is, has this changed? Is there a way to enable AA on a TTF font with LA style speech short of completely rendering the text myself. I ask coz it seems a bit funny that when the dialog options are displayed it works but the actual speech doesn't. :D
« Last Edit: 22 Nov 2009, 16:11 by monkey_05_06 »

Re: Antialiased TTF LucasArts style speech?
« Reply #1 on: 22 Nov 2009, 00:38 »
No, it's still not possible and you can't even truly work around it since text can't be rendered antialiased on a background-less GUI and DrawingSurface functions don't support alpha channels.

However, since you can now use normal script commands directly in your dialog script it HAS become a lot easier to create a custom Say function, and I wrote a bit of code that renders pretty smooth looking text by using an aliased outline and anti-aliased inner text. You can find the script in this thread, though unfortunately the example pics were on the americangirlscout server and are no longer working. I wrote a 2.72 compatible version for Tolworthy's Dante game, and he posted a screenshot of the script in action on his blog. Due to the lo-res coordinates limitation in 2.72 the outline in those shots is a few pixels thick, but the original script should render a crisp looking 1 pixel outline.
« Last Edit: 22 Nov 2009, 00:40 by GarageGothic »

monkey0506

  • SEND PIZZA.
    • Best Innovation Award Winner 2017, for his work to help AGS games reach the widest possible audience - through popular distribution platforms (Steam, Galaxy) as well as other operating systems (Android, Linux)
    • monkey0506 worked on one or more games that won an AGS Award!
    •  
    • monkey0506 worked on one or more games that was nominated for an AGS Award!
Re: Antialiased TTF LucasArts style speech?
« Reply #2 on: 22 Nov 2009, 05:46 »
DrawingSurface functions don't support alpha channels

That's not true. They just don't draw the alpha channel (that is the channel isn't copied, it is used) so if the surface is transparent then you get the pink haze. :P

Actually I encountered that exact problem with my custom dialog rendering, so I'm already doing this:

Code: [Select]
void DrawCharacter(this DrawingSurface*, Character *theCharacter) {
  if (theCharacter == null) return;
  ViewFrame *frame = Game.GetViewFrame(theCharacter.View, theCharacter.Loop, theCharacter.Frame);
  DynamicSprite *sprite;
  int graphic = frame.Graphic;
  if (frame.Flipped) {
    sprite = DynamicSprite.CreateFromExistingSprite(graphic, true);
    sprite.Flip(eFlipLeftToRight);
  }
  if (theCharacter.Scaling != 100) {
    int scale = theCharacter.Scaling;
    if (sprite == null) sprite = DynamicSprite.CreateFromExistingSprite(graphic, true);
    sprite.Resize((Game.SpriteWidth[graphic] * scale) / 100, (Game.SpriteHeight[graphic] * scale) / 100);
  }
  Region *rat = Region.GetAtRoomXY(theCharacter.x, theCharacter.y);
  if ((rat != null) && (rat != region[0]) && (rat.TintEnabled)) {
    if (sprite == null) sprite = DynamicSprite.CreateFromExistingSprite(graphic, true);
    sprite.Tint(rat.TintRed, rat.TintGreen, rat.TintBlue, rat.TintSaturation, 100);
  }
  if (sprite != null) graphic = sprite.Graphic;
  this.DrawImage(theCharacter.x - (Game.SpriteWidth[graphic] / 2) - GetViewportX(), theCharacter.y - Game.SpriteHeight[graphic] - theCharacter.z - GetViewportY(), graphic, theCharacter.Transparency);
  if (sprite != null) sprite.Delete();
}

void DrawObject(this DrawingSurface*, Object *theObject) {
  if ((theObject == null) || (!theObject.Graphic)) return;
  DynamicSprite *sprite;
  int graphic = theObject.Graphic;
  if (theObject.View) {
    ViewFrame *frame = Game.GetViewFrame(theObject.View, theObject.Loop, theObject.Frame);
    if (frame.Flipped) {
      sprite = DynamicSprite.CreateFromExistingSprite(frame.Graphic, true);
      sprite.Flip(eFlipLeftToRight);
    }
  }
  int scale = GetScalingAt(theObject.X, theObject.Y);
  if ((!theObject.IgnoreScaling) && (scale != 100)) {
    if (sprite == null) sprite = DynamicSprite.CreateFromExistingSprite(graphic, true);
    sprite.Resize((Game.SpriteWidth[graphic] * scale) / 100, (Game.SpriteHeight[graphic] * scale) / 100);
  }
  Region *rat = Region.GetAtRoomXY(theObject.X, theObject.Y);
  if ((rat != null) && (rat != region[0]) && (rat.TintEnabled)) {
    if (sprite == null) sprite = DynamicSprite.CreateFromExistingSprite(graphic, true);
    sprite.Tint(rat.TintRed, rat.TintGreen, rat.TintBlue, rat.TintSaturation, 100);
  }
  if (sprite != null) graphic = sprite.Graphic;
  this.DrawImage(theObject.X, theObject.Y - Game.SpriteHeight[graphic], graphic, theObject.Transparency);
  if (sprite != null) sprite.Delete();
}

function dialog_options_render(DialogOptionsRenderingInfo *info) {
  // Clear the area
  info.Surface.Clear();
  // AGS doesn't currently support alpha channeled DrawingSurface transparency. This should flatten it
  DynamicSprite *sprite = DynamicSprite.CreateFromBackground();
  DrawingSurface *surface = sprite.GetDrawingSurface();
  int i = 0;
  while ((i < Game.CharacterCount) || (i < Room.ObjectCount)) {
    if ((i < Game.CharacterCount) && (character[i].Room == player.Room)) surface.DrawCharacter(character[i]);
    if (i < Room.ObjectCount) {
      surface.DrawObject(object[i]);
      if (object[i].Graphic) {
        int scale = GetScalingAt(object[i].X, object[i].Y);
        int ow = (Game.SpriteWidth[object[i].Graphic] * scale) / 100;
        int oh = (Game.SpriteHeight[object[i].Graphic] * scale) / 100;
        if (object[i].IgnoreScaling) {
          ow = Game.SpriteWidth[object[i].Graphic];
          oh = Game.SpriteHeight[object[i].Graphic];
        }
        int ox1 = object[i].X;
        int ox2 = ox1 + ow;
        int j = 0;
        while (j < Game.CharacterCount) {
          if (character[j].Room == player.Room) {
            ViewFrame *frame = Game.GetViewFrame(character[j].View, character[j].Loop, character[j].Frame);
            int cw = (Game.SpriteWidth[frame.Graphic] * character[j].Scaling) / 100;
            int cx1 = character[j].x - (cw / 2);
            if ((((cx1 + cw) >= ox1) && (cx1 <= ox2)) && (character[j].y > object[i].Baseline)) surface.DrawCharacter(character[j]);
          }
          j++;
        }
      }
    }
    i++;
  }
  surface.Release();
  sprite.Crop(info.X, info.Y, info.Width, info.Height);
  info.Surface.DrawImage(0, 0, sprite.Graphic);
  sprite.Delete();
  i = 1;
  int ypos = 0;
  // Render all the options that are enabled
  // ...
}

Basically I have to take a copy of the background, merge in all the characters and objects, crop the image, and then draw the dialog options on top of that. The reason I can't use a screenshot is because it would catch the mouse cursor as it moves around, and if the text changed (i.e. scrolling, turning an option on/off) it would catch the old text as well.

So basically if you want to get AA text with LA style speech you could do it by finding the bounding box for the text and applying the same process.

I just didn't know if there was an easier way. I'm already discovering just how much work actually goes into these game things. :=

Oh and though this does take into account flipped frames, it blatantly ignores z-orders, baselines, scaling, etc. So if those are important to you, you may want to revise the code appropriately. ;) I've modified the code now so it respects character z-orders, baselines, scaling, and transparency. It respects region tinting but I can't think of a way to use character, object, or ambient tinting.
« Last Edit: 30 Nov 2009, 00:28 by monkey_05_06 »

Re: Antialiased TTF LucasArts style speech?
« Reply #3 on: 22 Nov 2009, 11:45 »
Quote
That's not true. They just don't draw the alpha channel (that is the channel isn't copied, it is used) so if the surface is transparent then you get the pink haze.  :P

Oh, you're such a know-it-all  :P

How is that script working out for you? I wrote a similar function for my refraction module, not because of the cursor but just because CreateFromScreenShot is so goddamn slow in Direct3D mode and I need to call it from repeatedly_execute. And it did implement z-order, tinting, scaling etc., but I found the main problem was that there's no way of supporting walkbehinds, so I have to be real careful of where I place my refraction objects on the screen. I would imagine this to be an even larger problems when used for dialogs that can be run virtually anywhere on the screen?

monkey0506

  • SEND PIZZA.
    • Best Innovation Award Winner 2017, for his work to help AGS games reach the widest possible audience - through popular distribution platforms (Steam, Galaxy) as well as other operating systems (Android, Linux)
    • monkey0506 worked on one or more games that won an AGS Award!
    •  
    • monkey0506 worked on one or more games that was nominated for an AGS Award!
Re: Antialiased TTF LucasArts style speech?
« Reply #4 on: 22 Nov 2009, 16:07 »
Quote
That's not true. They just don't draw the alpha channel (that is the channel isn't copied, it is used) so if the surface is transparent then you get the pink haze.  :P

Oh, you're such a know-it-all  :P

Hence the gratuitous sticking-my-tongue-out-in-your-general-direction action! :=

How is that script working out for you? I wrote a similar function...but I found the main problem was that there's no way of supporting walkbehinds, so I have to be real careful of where I place my refraction objects on the screen. I would imagine this to be an even larger problems when used for dialogs that can be run virtually anywhere on the screen?

The script is working out well for what I'm using it for. The reason it doesn't support scaling, z-orders, and the like is quite simply because I'm not using any of those! ;D

As for walk-behinds those are completely overrated. Use an Object or Character instead. C'mon people! How else are you gonna get it AA-smooth for your high-res game. 8)

Edit: Also (overuse of smileys aside) it seems to me that the custom dialog rendering isn't updated every single game loop (like rep_ex(_always) would do) but rather just when the mouse cursor has moved over the area covered by the DialogOptionsRenderingInfo object. So that can only help the performance here.
« Last Edit: 22 Nov 2009, 16:11 by monkey_05_06 »