Author Topic: Custom border problem with SpeechBubble module  (Read 677 times)

Héctor Bometón

  • Posts: 4
  • Superego
Custom border problem with SpeechBubble module
« on: 10 Jan 2018, 10:28 »

Hi!

I'm using the wonderful SpeechBubble Module but I'm having some trouble getting the border as I want it (since my progamming skills are quite lame).

I'd like the bubble to look like the one in the bottom, but the top one is the closest I can get:



I got the tail of the bubble figured out, but I don't know how to fix the rest of it.

The shadow would be basically like a duplicate of the bubble (but in x + 1, and y + 1). I'm not even sure that you can do this with the SpeechBubble module, but I'd appreciate any kind of help.

Thanks!

Héctor.

Snarky

  • Global Moderator
  • Posts: 6,707
  • Private Insultant
    • I can help with proof reading
    • I can help with translating
Re: Custom border problem with SpeechBubble module
« Reply #1 on: 10 Jan 2018, 21:01 »
Yeah, that's not possible in the module as of now. I suppose I could extend it to support it, but it's not a high priority.

For now, it's easier to hack the render function to do what you want. Try replacing the drawRoundedCorners32() and renderBubble32() functions in the module with these versions:

Spoiler: ShowHide
Code: Adventure Game Studio
  1. // Round off the corners of the bubble by erasing to transparent
  2. void drawRoundedCorners32(DrawingSurface* background, int left, int top, int right, int bottom)
  3. {
  4.   // Uses Bresenham's circle formula, found online
  5.   int r = _cornerRoundingRadius;
  6.  
  7.   int x = 0;
  8.   int y = r;
  9.   int p = 3 - 2 * r;
  10.   int dc = background.DrawingColor;
  11.   background.DrawingColor = COLOR_TRANSPARENT;
  12.   while (y >= x) // only formulate 1/8 of circle
  13.   {
  14.     // Erase background corners
  15.     // Top Left
  16.     background.DrawLine(left + r - x, top+r - y, left + r - x, top);
  17.     background.DrawLine(left + r - y, top+r - x, left + r - y, top);
  18.    
  19.     // Top Right
  20.     background.DrawLine(right - r + y, top+r - x,  right - r + y, top);
  21.     background.DrawLine(right - r + x, top+r - y,  right - r + x, top);
  22.    
  23.     // Bottom Left
  24.     background.DrawLine(left + r - x, bottom-r + y, left + r - x,  bottom);
  25.     background.DrawLine(left + r - y, bottom-r + x, left + r - y,  bottom);
  26.    
  27.     // Bottom Right
  28.     background.DrawLine(right - r + y, bottom-r + x, right - r + y, bottom);
  29.     background.DrawLine(right - r + x, bottom-r + y, right - r + x, bottom);
  30.  
  31.     if (p < 0)
  32.     {
  33.       p += 4*x + 6;
  34.       x++;
  35.     }
  36.     else
  37.     {
  38.       p += 4*(x - y) + 10;
  39.       x++;
  40.       y--;
  41.     }
  42.    }
  43.    background.DrawingColor = dc;
  44. }

Code: Adventure Game Studio
  1. // Draw a speech bubble in 32-bit (using transparency)
  2. DynamicSprite* renderBubble32(this Character*, String message, bool talkTail)
  3. {
  4.   // Calculate text dimensions
  5.   int textWidth = _maxTextWidth;
  6.   if(textWidth <= 0)
  7.     textWidth = calculateDefaultTextWidth(this);
  8.   textWidth = _minInt(textWidth, System.ViewportWidth - _paddingLeft - _paddingRight);
  9.   int textHeight = GetTextHeight(message, Game.SpeechFont, textWidth);
  10.   textWidth = calculateExactTextWidth(message, Game.SpeechFont, textWidth, textHeight);
  11.  
  12.   // Calculate bubble dimensions
  13.   int totalWidth = textWidth + _paddingLeft + _paddingRight;
  14.   int bubbleHeight = textHeight + _paddingTop + _paddingBottom;
  15.   int totalHeight;
  16.   if(talkTail)
  17.     totalHeight = bubbleHeight + _talkTailHeight;
  18.   else
  19.     totalHeight = bubbleHeight + _thinkTailHeight;
  20.  
  21.   // Set up the canvases
  22.   DynamicSprite* bubbleSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  23.   DrawingSurface* bubbleSurface = bubbleSprite.GetDrawingSurface();
  24.   //bubbleSurface.Clear();
  25.  
  26.   DynamicSprite* bgSprite; DrawingSurface* bgSurface;
  27.   DynamicSprite* borderSprite; DrawingSurface* borderSurface;
  28.   bgSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  29.   bgSurface = bgSprite.GetDrawingSurface();
  30.   borderSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  31.   borderSurface = borderSprite.GetDrawingSurface();
  32.  
  33.   int bgColor = mixColors(this.SpeechColor, _backgroundColor, _backgroundSpeechTint);
  34.   int borderColor = mixColors(this.SpeechColor, _borderColor, _borderSpeechTint);
  35.  
  36.   // Draw!
  37.   bgSurface.DrawingColor = bgColor;
  38.   borderSurface.DrawingColor = borderColor;
  39.   bgSurface.DrawRectangle(0, 0, totalWidth-2, bubbleHeight-2);
  40.   borderSurface.DrawRectangle(1,  1, totalWidth-1, bubbleHeight-1);
  41.   drawRoundedCorners32(bgSurface, 0, 0, totalWidth-1, bubbleHeight);
  42.   drawRoundedCorners32(borderSurface, 1, 1, totalWidth, bubbleHeight+1);
  43.   String tail[]; int tailWidth; int tailHeight;
  44.   if(talkTail)
  45.   {
  46.     tail = _talkTail; tailWidth = _talkTailWidth; tailHeight = _talkTailHeight;
  47.   }
  48.   else
  49.   {
  50.     tail = _thinkTail; tailWidth = _thinkTailWidth; tailHeight = _thinkTailHeight;
  51.   }
  52.   bgSurface.drawPixelArray(tail, totalWidth/2-tailWidth, bubbleHeight-1, tailWidth, tailHeight, 'O', false, false);
  53.  borderSurface.drawPixelArray(tail, totalWidth/2-tailWidth+1, bubbleHeight, tailWidth, tailHeight, 'O', false, false);
  54.  
  55.   borderSurface.Release();
  56.   bubbleSurface.DrawImage(0, 0, borderSprite.Graphic, _borderTransparency);
  57.   borderSprite.Delete();
  58.  
  59.   bgSurface.Release();
  60.   bubbleSurface.DrawImage(0, 0, bgSprite.Graphic, _backgroundTransparency);
  61.   bgSprite.Delete();
  62.  
  63.   bubbleSurface.DrawingColor = this.SpeechColor;
  64.   int outlineColor = mixColors(this.SpeechColor, _textOutlineColor, _textOutlineSpeechTint);
  65.   if(_textOutlineWidth > 0)
  66.     bubbleSurface.drawStringWrappedOutline(_paddingLeft, _paddingTop, textWidth, _textOutlineStyle, Game.SpeechFont, _textAlign, message, _textTransparency, outlineColor, _textOutlineWidth);
  67.   else
  68.     bubbleSurface.drawStringWrappedAA(_paddingLeft, _paddingTop, textWidth, Game.SpeechFont, _textAlign, message, _textTransparency);
  69.  
  70.   bubbleSurface.Release();
  71.   return bubbleSprite;
  72. }

(This won't work correctly if you set the speech bubble background to be semi-transparent. You can make the border/shadow transparent, though.)
« Last Edit: 10 Jan 2018, 22:04 by Snarky »

Héctor Bometón

  • Posts: 4
  • Superego
Re: Custom border problem with SpeechBubble module
« Reply #2 on: 11 Jan 2018, 06:23 »

Oh! Great!

I just tested it and it's definitely closer to what I wanted.

Thank you! :)

Snarky

  • Global Moderator
  • Posts: 6,707
  • Private Insultant
    • I can help with proof reading
    • I can help with translating
Re: Custom border problem with SpeechBubble module
« Reply #3 on: 11 Jan 2018, 07:00 »
That's good, but 'closer'? Doesn't it give exactly the result in your example?

Héctor Bometón

  • Posts: 4
  • Superego
Re: Custom border problem with SpeechBubble module
« Reply #4 on: 12 Jan 2018, 15:56 »

Not exactly...

These are the results with different corner radius settings:



The rest of the settings:

Code: Adventure Game Studio
  1.  
  2.   // Set default values
  3.   SpeechBubble.set_InvisibleFont(-1);
  4.   SpeechBubble.set_TextAlign(eAlignCentre);
  5.  
  6.   SpeechBubble.set_BackgroundColor(15);
  7.   SpeechBubble.set_BorderColor(0);
  8.  
  9.   SpeechBubble.set_BackgroundTransparency(0);
  10.   SpeechBubble.set_BorderTransparency(10);
  11.  
  12.   SpeechBubble.set_MaxTextWidth(-1);
  13.   SpeechBubble.set_CornerRoundingRadius(3);
  14.   SpeechBubble.set_PaddingTop(5);
  15.   SpeechBubble.set_PaddingBottom(4);
  16.   SpeechBubble.set_PaddingLeft(9);
  17.   SpeechBubble.set_PaddingRight(9);
  18.  
  19.   _talkTail = new String[6];
  20.   _talkTail[0] = " OOOOX";
  21.   _talkTail[1] = "  OOOX";
  22.   _talkTail[2] = "   OOX";
  23.   _talkTail[3] = "    OX";
  24.   _talkTail[4] = "     X";
  25.   _talkTail[5] = null;
  26.   //_talkTail[9] = null;
  27.   SpeechBubble.set_TalkTail(_talkTail); // Just to set height/width
  28.  

¿Maybe I did something wrong?

Thanks again!

Snarky

  • Global Moderator
  • Posts: 6,707
  • Private Insultant
    • I can help with proof reading
    • I can help with translating
Re: Custom border problem with SpeechBubble module
« Reply #5 on: 13 Jan 2018, 12:02 »
No, the mistake was mine. (I was a little drunk when I wrote it.) Try this for the two functions:

Spoiler: ShowHide
Code: Adventure Game Studio
  1. // Round off the corners of the bubble by erasing to transparent
  2. void drawRoundedCorners32(DrawingSurface* background, int left, int top, int right, int bottom)
  3. {
  4.   // Uses Bresenham's circle formula, found online
  5.   int r = _cornerRoundingRadius - 1;
  6.  
  7.   int x = 0;
  8.   int y = r;
  9.   int p = 3 - 2 * r;
  10.   int dc = background.DrawingColor;
  11.   background.DrawingColor = COLOR_TRANSPARENT;
  12.   while (y >= x) // only formulate 1/8 of circle
  13.   {
  14.     // Erase background corners
  15.     // Top Left
  16.     background.DrawLine(left + r - x, top+r - y, left + r - x, top);
  17.     background.DrawLine(left + r - y, top+r - x, left + r - y, top);
  18.    
  19.     // Top Right
  20.     background.DrawLine(right - r + y, top+r - x,  right - r + y, top);
  21.     background.DrawLine(right - r + x, top+r - y,  right - r + x, top);
  22.    
  23.     // Bottom Left
  24.     background.DrawLine(left + r - x, bottom-r + y, left + r - x,  bottom);
  25.     background.DrawLine(left + r - y, bottom-r + x, left + r - y,  bottom);
  26.    
  27.     // Bottom Right
  28.     background.DrawLine(right - r + y, bottom-r + x, right - r + y, bottom);
  29.     background.DrawLine(right - r + x, bottom-r + y, right - r + x, bottom);
  30.  
  31.     if (p < 0)
  32.     {
  33.       p += 4*x + 6;
  34.       x++;
  35.     }
  36.     else
  37.     {
  38.       p += 4*(x - y) + 10;
  39.       x++;
  40.       y--;
  41.     }
  42.    }
  43.    background.DrawingColor = dc;
  44. }

Code: Adventure Game Studio
  1. // Draw a speech bubble in 32-bit (using transparency)
  2. DynamicSprite* renderBubble32(this Character*, String message, bool talkTail)
  3. {
  4.   // Calculate text dimensions
  5.   int textWidth = _maxTextWidth;
  6.   if(textWidth <= 0)
  7.     textWidth = calculateDefaultTextWidth(this);
  8.   textWidth = _minInt(textWidth, System.ViewportWidth - _paddingLeft - _paddingRight);
  9.   int textHeight = GetTextHeight(message, Game.SpeechFont, textWidth);
  10.   textWidth = calculateExactTextWidth(message, Game.SpeechFont, textWidth, textHeight);
  11.  
  12.   // Calculate bubble dimensions
  13.   int totalWidth = textWidth + _paddingLeft + _paddingRight;
  14.   int bubbleHeight = textHeight + _paddingTop + _paddingBottom;
  15.   int totalHeight;
  16.   if(talkTail)
  17.     totalHeight = bubbleHeight + _talkTailHeight;
  18.   else
  19.     totalHeight = bubbleHeight + _thinkTailHeight;
  20.  
  21.   // Set up the canvases
  22.   DynamicSprite* bubbleSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  23.   DrawingSurface* bubbleSurface = bubbleSprite.GetDrawingSurface();
  24.   //bubbleSurface.Clear();
  25.  
  26.   DynamicSprite* bgSprite; DrawingSurface* bgSurface;
  27.   DynamicSprite* borderSprite; DrawingSurface* borderSurface;
  28.   bgSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  29.   bgSurface = bgSprite.GetDrawingSurface();
  30.   borderSprite = DynamicSprite.Create(totalWidth, totalHeight, true);
  31.   borderSurface = borderSprite.GetDrawingSurface();
  32.  
  33.   int bgColor = mixColors(this.SpeechColor, _backgroundColor, _backgroundSpeechTint);
  34.   int borderColor = mixColors(this.SpeechColor, _borderColor, _borderSpeechTint);
  35.  
  36.   // Draw!
  37.   bgSurface.DrawingColor = bgColor;
  38.   borderSurface.DrawingColor = borderColor;
  39.   bgSurface.DrawRectangle(0, 0, totalWidth-2, bubbleHeight-2);
  40.   borderSurface.DrawRectangle(1,  1, totalWidth-1, bubbleHeight-1);
  41.   if(_cornerRoundingRadius > 0)
  42.   {
  43.     drawRoundedCorners32(bgSurface, 0, 0, totalWidth-2, bubbleHeight-2);
  44.     drawRoundedCorners32(borderSurface, 1, 1, totalWidth-1, bubbleHeight-1);
  45.   }
  46.   String tail[]; int tailWidth; int tailHeight;
  47.   if(talkTail)
  48.   {
  49.     tail = _talkTail; tailWidth = _talkTailWidth; tailHeight = _talkTailHeight;
  50.   }
  51.   else
  52.   {
  53.     tail = _thinkTail; tailWidth = _thinkTailWidth; tailHeight = _thinkTailHeight;
  54.   }
  55.   bgSurface.drawPixelArray(tail, totalWidth/2-tailWidth, bubbleHeight-1, tailWidth, tailHeight, 'O', false, false);
  56.  borderSurface.drawPixelArray(tail, totalWidth/2-tailWidth+1, bubbleHeight, tailWidth, tailHeight, 'O', false, false);
  57.  
  58.   borderSurface.Release();
  59.   bubbleSurface.DrawImage(0, 0, borderSprite.Graphic, _borderTransparency);
  60.   borderSprite.Delete();
  61.  
  62.   bgSurface.Release();
  63.   bubbleSurface.DrawImage(0, 0, bgSprite.Graphic, _backgroundTransparency);
  64.   bgSprite.Delete();
  65.  
  66.   bubbleSurface.DrawingColor = this.SpeechColor;
  67.   int outlineColor = mixColors(this.SpeechColor, _textOutlineColor, _textOutlineSpeechTint);
  68.   if(_textOutlineWidth > 0)
  69.     bubbleSurface.drawStringWrappedOutline(_paddingLeft, _paddingTop, textWidth, _textOutlineStyle, Game.SpeechFont, _textAlign, message, _textTransparency, outlineColor, _textOutlineWidth);
  70.   else
  71.     bubbleSurface.drawStringWrappedAA(_paddingLeft, _paddingTop, textWidth, Game.SpeechFont, _textAlign, message, _textTransparency);
  72.  
  73.   bubbleSurface.Release();
  74.   return bubbleSprite;
  75. }

Note that I've also adjusted how the corner rounding parameter is used: you might want to increase it by 1 to get the same results as with the original version.

One thing: it looks like you're editing the initSpeechBubble() function in order to configure the module. This is not how it's meant to be used: You're not supposed to edit the module code at all (except as otherwise instructed). Rather, as the header documentation explains, you're supposed to configure it from outside, e.g. in your game's GlobalScript. For your settings, that would be something like:

Spoiler: ShowHide
Code: Adventure Game Studio
  1. // in GlobalScript.asc
  2.  
  3. function game_start()
  4. {
  5.   // Setup SpeechBubble module
  6.   SpeechBubble.CornerRoundingRadius = 3;
  7.   SpeechBubble.PaddingTop = 5;
  8.   SpeechBubble.PaddingBottom = 4;
  9.   SpeechBubble.PaddingLeft = 9;
  10.   SpeechBubble.PaddingRight =9;
  11.  
  12.   // (You don't need the shadow any more, it's now drawn automatically)
  13.   String tail[] = new String[5];
  14.   tail[0] = " OOOO";
  15.   tail[1] = "  OOO";
  16.   tail[2] = "   OO";
  17.   tail[3] = "    O";
  18.   tail[4] = null;
  19.  
  20.   SpeechBubble.TalkTail = tail;
  21. }

However, when I test, I see that that last line doesn't work – an AGS limitation I wasn't aware of. I will fix it so you can write:

Code: Adventure Game Studio
  1.   SpeechBubble.SetTalkTail(tail);

In the mean time you can leave the setup as you have it.

Héctor Bometón

  • Posts: 4
  • Superego
Re: Custom border problem with SpeechBubble module
« Reply #6 on: 06 Sep 2018, 09:09 »

Dude... I just logged in after some time and I realized I dindn't thank you for this. I'm so sorry!

It's working wonderfully now. Thank you very much!

Héctor.