Charmed Quark Systems, Ltd. - Support Forums and Community

Full Version: Official RIVA thread
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
brianmount Wrote:Is there a parameter that determines the amount of blur applied to the text in the DrawTextFX message? I saw a field called passes or something like that, but I wasn't sure. If there is a parameter, what values does it take on, and how much blur results from the various settings?

You will probably end up having to just work it out by eye, because various algorithms will create more or less dense blurs with the same parameters. Gaussian blurs have 'orders' which control how much blurring they do, basically how many taps in the filter. In my gaussian blur code I have two 'fast' orders which are used to do rougher but reasonable quality blurring quickly. One does a smaller amount than the other. For any font size less than 20, I use the smaller one, else I use the larger one. And that really was just done by eye to get some reasonable result.

I would imagine that, if you have some blur algorithm, thorugh up a few sizes of text and make a similar break point on 20 points where you use a little less on things below that and a little more above, and just tweak until you get similar results.

The 'passes' parameter applies the blur that many times, to create a particular density of blur. For now, it's always going to be the same thing I believe and you can safely ignore it. I think that you will find it's always set to zero, which in my world lets the DrawTextFX command make it's own choice and it just sets it to two passes. You can just play around with whichever blur algorithm you choose to figure out what provides basically the same density of blur as what the regular viewer is providing.
Can you give a little more detail about the note in the protocol specification about needing to decrease the bounding rectangle before drawing blurred text to avoid clipping? Am I supposed to change the font size as well? Are the suggested insets independent of the font size?

Regarding the odd bitmap modes, I don't know what the graphic format is. Rob forwarded me the files as they exist on the CQC server, but my graphics program isn't able to decipher them. The server must be prepending some sort of data to the file or something. And Rob doesn't think he has the originals any longer. If we send you the CQC-ified files, would that enable you to tell what the format is?
brianmount Wrote:Can you give a little more detail about the note in the protocol specification about needing to decrease the bounding rectangle before drawing blurred text to avoid clipping? Am I supposed to change the font size as well? Are the suggested insets independent of the font size?

You don't need to change the font size. But, the bounding area of the widget shouldn't be drawn outside of. So if you are blurring by, say, 4 pixels, you'll have to adjust the left/right or top/bottom position by that much to correctly justify the text against that edge, since now the edge of the blur is the edge of the text, not the edge of the text itself.

It's somewhat of a by eye adjustment.

Quote:Regarding the odd bitmap modes, I don't know what the graphic format is. Rob forwarded me the files as they exist on the CQC server, but my graphics program isn't able to decipher them. The server must be prepending some sort of data to the file or something. And Rob doesn't think he has the originals any longer. If we send you the CQC-ified files, would that enable you to tell what the format is?

The test will be, are you getting any DrawBitmapMasked commands. That only happens when color based transparency is used, and that's the one that's not really being done right.
Maybe I misunderstood. I was thinking that my client was supposed to adjust the bounds. Is that right? Or do you just mean that the user, when designing the interface, should leave more space around the text? If the latter, then I don't need to worry about it. But if the RIVA client software does the adjustment, is it the case that I take the bounding box passed in the DrawTextFX command and shrink it down before drawing?
brianmount Wrote:Maybe I misunderstood. I was thinking that my client was supposed to adjust the bounds. Is that right? Or do you just mean that the user, when designing the interface, should leave more space around the text? If the latter, then I don't need to worry about it. But if the RIVA client software does the adjustment, is it the case that I take the bounding box passed in the DrawTextFX command and shrink it down before drawing?

The RIVA client would need to do it. It's not so much shrinking the bounding box, but shrinking the area that you do the justification within. The bounding area (if you mean the area the output is clipped to) would still be the overall widget area. But you just want to, during justification of the text within that area, adjust for the fact that the text is going to be three or four'ish pixels larger than the actual text after it's blurred, so you need to account for that.

So, you might take the original drawing area, and create another one with the sides imploded in by a few pixels (however much your blur ends up being) and use that for the actual calculation of the text for justification and wrapping purposes, but then use the original area for the clipping of the output. And of course when doing a drop shadow, the offset of the text drawn over the shadow would be relative to that inward adjusted position as well.

Does that make sense? I could send you my code for that, though I'm not sure it would make sense (given that I find it complicated and I wrote it :-) But I ultimately came up with a pretty sensible scheme to deal with the blurring and reflection and the positioning thereof and the horz/vertical offset values. Sometimes it treats the blur or the drop reflection as the text and the real text as the thing to offset and sometimes the other way around, depending on which thing would be the part that's up against the edge being justified against.

Give me a minute here. I'm waiting on a long build, so I'll try to go back and decipher it again and provide a summary of what I do.
Just for posterity's sake, here's my DrawTextFX method, which is on my graphics device wrapper class. Since this is down at the OS wrapper level, there's some direct calls to Windows APIs here, though most of it is still written in terms of my own framework. I thik it's semi-comprehensible with the comments, but let me know if any of it doesn't make any sense to you:

Code:
//
//  This method provides the support some some fancy text drawing effects.
//  We assume the desired font has been set on this device before we get
//  called.
//
tCIDLib::TVoid
TGraphDrawDev::DrawTextFX(  const   TString&            strText
                            , const TArea&              areaDraw
                            , const tCIDWnd::ETextFXs   eEffect
                            , const TRGBClr&            rgbClr1
                            , const TRGBClr&            rgbClr2
                            , const tCIDLib::EHJustify  eHJustify
                            , const tCIDLib::EVJustify  eVJustify
                            , const tCIDLib::TBoolean   bNoTextWrap
                            , const TPoint&             pntOffset
                            , const tCIDLib::TCard4     c4Passes)
{
    // If no text, then nothing to do
    if (strText.bIsEmpty())
        return;

    // Remember if this is a blur type effect
    const tCIDLib::TBoolean bBlurType
    (
        (eEffect == tCIDWnd::ETextFX_GaussianBlur)
        || (eEffect == tCIDWnd::ETextFX_DropShadow)
    );

    //
    //  Calculate where the text will be. We get the size of the text,
    //  either single line or wrapped. Then, if we are using one of the
    //  blue effects, then we adjust the size upwards to account for
    //  the blur area.
    //
    TArea areaText;
    if (bNoTextWrap)
        areaText = areaString(strText);
    else
        areaText = areaMLText(strText, areaDraw.c4Width());

    //
    //  We'll create temp bitmaps the size of the text area. But if a blur
    //  is used, we have to increase the size and we'll draw the text inwards
    //  from the edge.
    //
    TArea areaBmp(areaText);
    if (bBlurType)
        areaBmp.AdjustSize(10, 8);

    // If we have to do a reflection, this is how many rows in the reflection
    const tCIDLib::TCard4 c4ReflRows = tCIDLib::TCard4
    (
        areaBmp.szSize().c4Height() * 0.65
    );

    //
    //  We have a further complication if a drop shadow or reflection and
    //  there's an offset. If the offset is in the direction of the
    //  justification, then we cannot push the drop shadow in that direction.
    //  It would go out of the area. Instead we have to move the regular text
    //  in the inverse direction.
    //
    //  If the offset is in the opposite direction of the justification (or
    //  the justification is centered), then we can just move the regular
    //  text. So we set up an offset for each of them, either of which might
    //  be zero in one or both directions.
    //
    //  Note that for the reflection scenarios, negative vertical offsets are
    //  not an issue, since the reflection is always under the text and can
    //  only move downwards. And we use the opposite points in that case.
    //
    //  And, in the reflection scenario, if bottom jusified, we'll always
    //  move the text upwards by the number of reflection lines so that the
    //  reflection ends up bottom justifed (on top of any offset.)
    //
    TPoint pntShadowOfs;
    TPoint pntShadowTxtOfs;
    if (eEffect == tCIDWnd::ETextFX_DropShadow)
    {
        if (((pntOffset.i4X() < 0) && (eHJustify == tCIDLib::EHJustify_Left))
        ||  ((pntOffset.i4X() > 0) && (eHJustify == tCIDLib::EHJustify_Right)))
        {
            // Move the text the other way
            pntShadowTxtOfs.i4X(pntOffset.i4X() * -1);
        }
         else
        {
            // No special case, so the shadow can move
            pntShadowOfs.i4X(pntOffset.i4X());
        }

        if (((pntOffset.i4Y() < 0) && (eVJustify == tCIDLib::EVJustify_Top))
        ||  ((pntOffset.i4Y() > 0) && (eVJustify == tCIDLib::EVJustify_Bottom)))
        {
            pntShadowTxtOfs.i4Y(pntOffset.i4Y() * -1);
        }
         else
        {
            // No special case, so the shadow can move
            pntShadowOfs.i4Y(pntOffset.i4Y());
        }
    }
     else if ((eEffect == tCIDWnd::ETextFX_Reflected)
          ||  (eEffect == tCIDWnd::ETextFX_GradientRefl))
    {
        if (((pntOffset.i4X() < 0) && (eHJustify == tCIDLib::EHJustify_Left))
        ||  ((pntOffset.i4X() > 0) && (eHJustify == tCIDLib::EHJustify_Right)))
        {
            //
            //  Move the 'shadow' the other way, actually the real text in
            //  this case.
            //
            pntShadowOfs.i4X(pntOffset.i4X() * -1);
        }
         else
        {
            // No special case, so the reflection can move
            pntShadowTxtOfs.i4X(pntOffset.i4X());
        }

        if (eVJustify == tCIDLib::EVJustify_Bottom)
        {
            //
            //  Move the 'shadow' the other way, actually the real text
            //  in this case.
            //
            pntShadowOfs.i4Y(pntOffset.i4Y() * -1);

            pntShadowOfs.AdjustY(tCIDLib::TInt4(c4ReflRows) * -1);
        }
         else
        {
            // No special case, so the reflection can move
            pntShadowTxtOfs.i4Y(pntOffset.i4Y());
        }
    }

    // We draw the effect text into these bitmaps
    const TSize szBmp(areaBmp.szSize());
    TBitmap bmpDraw
    (
        szBmp
        , tCIDImage::EPixFmt_TrueAlpha
        , tCIDImage::EBitDepth_8
        , kCIDLib::True
    );

    // This is used to create the alpha mask
    TBitmap bmpMask
    (
        szBmp
        , tCIDImage::EPixFmt_TrueAlpha
        , tCIDImage::EBitDepth_8
        , kCIDLib::True
    );

    //
    //  The actual graphical text is drawn into the text area, centered
    //  in the bitmap area. In some cases the are the same size, so this
    //  will have no effect.
    //
    TArea areaFXText(areaText);
    areaFXText.CenterIn(areaBmp);
Continued...

Code:
// Now let's draw the text into the bitmap to manipulate
    {
        TGraphMemDev gdevDraw(*this, bmpDraw);
        TGraphMemDev gdevMask(*this, bmpMask);

        //
        //  And now let's draw the text into the bitmap. We justify it
        //  as it would be (left or right-wise anyway, in the final
        //  drawing.
        //
        {
            //
            //  Get a copy of the font handle of the our device so
            //  that we can set the same font on our mask device.
            //
            LOGFONT LogFont = {0};
            ::GetObject
            (
                ::GetCurrentObject(hdevThis(), OBJ_FONT)
                , sizeof(LOGFONT)
                , &LogFont
            );
            TFontSelAttrs fselToUse(LogFont);
            TGUIFont gfontToUse(fselToUse);
            TFontJanitor janFont(&gdevMask, &gfontToUse);

            gdevMask.eBackMixMode(tCIDWnd::EBackMixMode_Transparent);
            gdevMask.SetTextColor(facCIDWnd().rgbWhite);

            // And draw the text into the bitmap
            if (bNoTextWrap)
            {
                gdevMask.DrawText
                (
                    strText
                    , areaFXText
                    , eHJustify
                    , eVJustify
                );
            }
             else
            {
                gdevMask.DrawMultiText
                (
                    strText
                    , areaFXText
                    , eHJustify
                    , eVJustify
                    , kCIDLib::True
                );
            }
        }

        if ((eEffect == tCIDWnd::ETextFX_Gradient)
        ||  (eEffect == tCIDWnd::ETextFX_GradientRefl))
        {
            gdevDraw.GradientFill
            (
                areaBmp
                , rgbClr1
                , rgbClr2
                , tCIDWnd::EGradientDir_Vertical
            );
        }
         else if (eEffect == tCIDWnd::ETextFX_DropShadow)
        {
            gdevDraw.Fill(areaBmp, rgbClr2);
        }
         else
        {
            gdevDraw.Fill(areaBmp, rgbClr1);
        }

        TPixelArray& pixaDraw = bmpDraw.pixaData();
        TPixelArray& pixaMask = bmpMask.pixaData();

        // Tell it to do pre-multiplication as it applies (last parm)
        pixaDraw.CreateAlphaChannelFrom
        (
            pixaMask, TPoint::pntOrigin, kCIDLib::True
        );
    }

    // Blur the bitmap if it's a blur type
    if (bBlurType)
    {
        TPixelArray& pixaMask = bmpMask.pixaData();
        TPixelArray& pixaDraw = bmpDraw.pixaData();

        tCIDLib::TCard4 c4ActualPasses = c4Passes;
        if (!c4ActualPasses)
        {
            // They want us to provide default
            if (eEffect == tCIDWnd::ETextFX_GaussianBlur)
                c4ActualPasses = 2;
            else
                c4ActualPasses = 2;
        }
         else
        {
            if (c4ActualPasses > 6)
                c4ActualPasses = 6;
        }

        //
        //  We use one of the special blur orders that are used for creating
        //  fast blurs of a reasonable size, either 1 or 2. We try to adjust
        //  this based on font size, so that we use 1 for fonts under a
        //  certain size. This keeps the blur more in proportion to the
        //  font.
        //
        tCIDLib::TCard4 c4Order = 2;
        TEXTMETRIC OurMetrics;
        if (::GetTextMetricsW(hdevThis(), &OurMetrics))
        {
            if (OurMetrics.tmHeight < 20)
                c4Order = 1;
        }

        for (tCIDLib::TCard4 c4Index = 0; c4Index < c4ActualPasses; c4Index++)
            pixaDraw.GaussianBlur(c4Order, &pixaMask);
    }

    //
    //  Set a clip region so that we don't draw outside the lines.
    //
    TGUIRegion grgnClip(areaDraw);
    TRegionJanitor janClip(this, grgnClip, tCIDWnd::EClipMode_And);

    // Blit the image to the target area
    TArea areaTar(areaBmp);
    areaTar.JustifyIn(areaDraw, eHJustify, eVJustify);
    {
        TArea areaSrc(areaBmp);
        areaSrc.ZeroOrg();

        // If there's an offset, then apply that
        TArea areaShadTar(areaTar);
        areaShadTar.AdjustOrg(pntShadowOfs);

        AlphaBlit(bmpDraw, areaSrc, areaShadTar, 0xFF, kCIDLib::True);
    }

    //
    //  If they want it reflected, then we need to flip the image in the
    //  horizontal axis (i.e. make it upside down), and then apply an
    //  alpha gradient to it to make it go to completely transparent by
    //  haflway down.
    //
    if ((eEffect == tCIDWnd::ETextFX_GradientRefl)
    ||  (eEffect == tCIDWnd::ETextFX_Reflected))
    {
        if (c4ReflRows > 4)
        {
            TPixelArray& pixaDraw = bmpDraw.pixaData();
            pixaDraw.FlipVertically();
            pixaDraw.ScaleAlpha(tCIDLib::EDir_Below, 0, c4ReflRows);

            TArea areaReflSrc(areaBmp);
            areaReflSrc.c4Height(c4ReflRows);
            TArea areaReflTar(areaReflSrc);
            areaReflTar.i4X(areaTar.i4X());

            if (eVJustify == tCIDLib::EVJustify_Bottom)
            {
                // Put the reflection at the bottom
                areaReflTar.JustifyIn(areaDraw, eHJustify, eVJustify);
            }
             else
            {
                // Put it at the bottom of the regular text
                areaReflTar.i4Y(areaTar.i4Bottom());
            }

            areaReflTar.AdjustOrg(pntShadowTxtOfs);

            AlphaBlit(bmpDraw, areaReflSrc, areaReflTar, 0xFF, kCIDLib::True);
        }
    }

    //
    //  If doing a drop shadow, we can now just draw the text normaly over
    //  the top of the blur.
    //
    if (eEffect == tCIDWnd::ETextFX_DropShadow)
    {
        SetTextColor(rgbClr1);
        eBackMixMode(tCIDWnd::EBackMixMode_Transparent);

        //
        //  Take the bitmap area and justify it within the drawing area,
        //  which is how positioned the bitmap itself. Then center the
        //  text area within that, which is how the text was positioned
        //  within the bitmap. This should leave us at the same place.
        //
        areaBmp.JustifyIn(areaDraw, eHJustify, eVJustify);
        areaText.CenterIn(areaBmp);

        //
        //  It is inexplicable why this is required. The above adjustments
        //  of the area should leave this drawn text exactly centered over
        //  the blurred text, but it doesn't.
        //
        areaText.AdjustOrg(-2, -3);

        // Apply any drop shadow text offset we calculated above
        areaText.AdjustOrg(pntShadowTxtOfs);

        if (bNoTextWrap)
        {
            DrawText
            (
                strText
                , areaText
                , eHJustify
                , eVJustify
            );
        }
         else
        {
            DrawMultiText
            (
                strText
                , areaText
                , eHJustify
                , eVJustify
                , kCIDLib::True
            );
        }
    }
}
Thanks; I'll take a look.

Regarding the images, there isn't a DrawBitmapMasked message in the RIVA protocol, correct? I am getting the masked alpha blit messages, but the ones with the odd bitmap modes are DrawBitmap messages, if I recall correctly.
brianmount Wrote:Thanks; I'll take a look.

Regarding the images, there isn't a DrawBitmapMasked message in the RIVA protocol, correct? I am getting the masked alpha blit messages, but the ones with the odd bitmap modes are DrawBitmap messages, if I recall correctly.

Oh, yeh, that's right. I'm losing my mind. Now I remember the discussion fro the other day. There isn't one, and they are being passed through as regular draw bitmap commands for some silly reason. We need to add a DrawBitmapMasked command. And I'm sure that, if you are getting bogus raster ops values, that's why. Because it also isn't setting that field.

So as soon as we get 3.2 out, I'll jump onto the V2 protocol changes and get that done, and we'll fix this and the other things you guys have been asking for. So, soon now.
We have a template that contains a PNG file. The original PNG did not define a transparent color, but Rob marked white as transparent in the interface editor. In the editor, the image shows up masked properly, but my program is missing the transparency, and showing a white fill rectangle around the image.

What is the effect of setting a transparent color in the interface editor? What sort of file do you wind up sending? Will it use color transparency, or alpha transparency?
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39