View Issue Details

IDProjectCategoryLast Update
0000024AI War 1 / ClassicGraphical BugOct 5, 2010 6:46 pm
ReporterChris_McElligottPark Assigned Tokeith.lamothe  
Status resolvedResolutionfixed 
Summary0000024: Angled Line Accuracy
DescriptionKeith, whenever makes sense for you -- for the prerelease if possible wouldn't be bad -- can you take a look at DrawLineAngled? There's some wonkiness there (and always has been, back to the SlimDX days and before) with it drawing lines of different thicknesses. Also, if you have two points, it draws them slightly differently between P1 and P2 versus P2 and P1.

That second issue is completely because of some of the offsetting stuff I'm doing in an attempt to make the center of a 3px line line up with the center of a 1px line, rather than having them edge-aligned. To some extent, all the many (many, many) different permutations I've tried for the offsetting have just made things worse.

At the very least a pair of fresh eyes would be helpful.
TagsNo tags attached.
Internal Weight

Activities

Chris_McElligottPark

Oct 2, 2010 9:02 pm

administrator   ~0000007

The code, for anyone who wants to chip in:

    public bool DrawLineAngled( float P1X, float P1Y, float P2X, float P2Y, float FullThickness, Color DiffuseColor,
        ShaderType ShaderType, GameImage OverridingImage, float UVX, float UVY, UVUseType UVUseType, DrawIn DrawIn,
        bool DisallowPointFlipping )
    {
        #region Img Retrieval
        GameImage Img;

        if ( OverridingImage != null )
            Img = OverridingImage;
        else
        {
            if ( lineImage == null )
                lineImage = Game.Instance.GetGameImage( "Line" );
            Img = lineImage;
        }

        if ( Img == null )
            return false;
        if ( Img.Texture == null )
        {
            if ( !Img.IsCurrentlyLoading )
                Img.QueueForLoading();
            return false;
        }
        if ( !this.ActuallyDrawImages )
            return false;
        #endregion

        Material mat = Img.GetMaterial( ShaderType );
        if ( mat == null )
            return false;

        SpriteObject obj = Game.Instance.GetSpriteForImage( Img );
        if ( obj == null )
            return false;

        if ( DrawIn == DrawIn.GameUnits )
        {
            P1X -= Game.Instance.ViewportX;
            P1Y -= Game.Instance.ViewportY;
            P2X -= Game.Instance.ViewportX;
            P2Y -= Game.Instance.ViewportY;
        }

        if ( this.UseRenderScale )
        {
            FullThickness *= this.RenderScale;
            P1X = Mathf.RoundToInt( P1X * this.RenderScale );
            P1Y = Mathf.RoundToInt( P1Y * this.RenderScale );
            P2X = Mathf.RoundToInt( P2X * this.RenderScale );
            P2Y = Mathf.RoundToInt( P2Y * this.RenderScale );
        }
        else if ( DrawIn == DrawIn.GameUnits )
        {
            P1X = Mathf.RoundToInt( P1X * this.RenderScale );
            P1Y = Mathf.RoundToInt( P1Y * this.RenderScale );
            P2X = Mathf.RoundToInt( P2X * this.RenderScale );
            P2Y = Mathf.RoundToInt( P2Y * this.RenderScale );
        }

        if ( this.UseDiffuseOffset )
            DiffuseColor = ColorMath.SubtractColors( DiffuseColor, DiffuseOffsets );

        if ( !DisallowPointFlipping && ( P1X < P2X || P1Y < P2Y ) )
        {
            float p3X = P2X;
            float p3Y = P2Y;

            P2X = P1X;
            P2Y = P1Y;

            P1X = p3X;
            P1Y = p3Y;
        }

        #region half
        float half = FullThickness / 2f;
        if ( P1X > P2X )
        {
            P1X -= half;
            P2X -= half;
        }
        else
        {
            P1X += half;
            P2X += half;
        }

        if ( P1Y < P2Y )
        {
            P1Y -= half;
            P2Y -= half;
        }
        else
        {
            P1Y += half;
            P2Y += half;
        }
        #endregion

        float length = (float)Mat.DistanceBetweenPointsD( P1X, P1Y, P2X, P2Y );
        float angleDegrees = (float)Mat.AngleBetweenPointsDegreesDouble( P1X, P1Y, P2X, P2Y );

        Vector3 position = Game.Instance.MainCameraCamera.ScreenToWorldPoint(
            new Vector3( P1X, this.ActualHeight - P1Y, ZDepth ) );

        Quaternion quaternion = Quaternion.identity;
        angleDegrees = -angleDegrees;
        quaternion = this.RotateAround( new Vector3( position.x,
            position.y, position.z ), ref position, new Vector3( 0, 0, 1 ), ref angleDegrees );

        DelayedRenderer dr = DelayedRenderer.GetNextFree();
        switch ( UVUseType )
        {
            case UVUseType.None:
                {
                    float widthScale = length / Img.ImageSize;
                    float heightScale = FullThickness / Img.ImageSize;
                    Matrix4x4 matrix = Matrix4x4.TRS( position, quaternion, new Vector3( widthScale, heightScale, 1 ) );
                    dr.SetUVUseTypeNone( Img.ID, Img.Texture, ShaderType, mat, matrix, obj, DiffuseColor );
                }
                break;
            case UVUseType.ExtendedTiled:
                {
                    //float widthScale = length / Img.ImageSize;
                    float heightScale = FullThickness / Img.ImageSize;
                    Matrix4x4 matrix = Matrix4x4.TRS( position, quaternion, new Vector3( 1, heightScale, 1 ) );
                    dr.SetUVUseTypeExtended( Img.ID, Img.Texture, ShaderType, mat, matrix, obj, DiffuseColor, false, false,
                        length, Img.ImageSize, UVX, UVY );
                }
                break;
            case UVUseType.ExtendedStretched:
                {
                    float widthScale = length / Img.ImageSize;
                    float heightScale = FullThickness / Img.ImageSize;
                    Matrix4x4 matrix = Matrix4x4.TRS( position, quaternion, new Vector3( widthScale, heightScale, 1 ) );
                    dr.SetUVUseTypeExtended( Img.ID, Img.Texture, ShaderType, mat, matrix, obj, DiffuseColor, false, false,
                        Img.ImageSize, Img.ImageSize, UVX, UVY );
                }
                break;
        }

        return true;
    }

keith.lamothe

Oct 4, 2010 6:27 pm

administrator   ~0000304

* Improvements to angled line drawing accuracy.

Chris_McElligottPark

Oct 4, 2010 7:24 pm

administrator   ~0000306

Still not perfect, but it's certainly much improved!

Keith's revised code:

     public bool DrawLineAngled( float P1X, float P1Y, float P2X, float P2Y, float FullThickness, Color DiffuseColor,
        ShaderType ShaderType, GameImage OverridingImage, float UVX, float UVY, UVUseType UVUseType, DrawIn DrawIn,
        bool DisallowPointFlipping )
    {
        #region Img Retrieval
        GameImage Img;

        if ( OverridingImage != null )
            Img = OverridingImage;
        else
        {
            if ( lineImage == null )
                lineImage = Game.Instance.GetGameImage( "Line" );
            Img = lineImage;
        }

        if ( Img == null )
            return false;
        if ( Img.Texture == null )
        {
            if ( !Img.IsCurrentlyLoading )
                Img.QueueForLoading();
            return false;
        }
        if ( !this.ActuallyDrawImages )
            return false;
        #endregion

        Material mat = Img.GetMaterial( ShaderType );
        if ( mat == null )
            return false;

        SpriteObject obj = Game.Instance.GetSpriteForImage( Img );
        if ( obj == null )
            return false;

        if ( DrawIn == DrawIn.GameUnits )
        {
            P1X -= Game.Instance.ViewportX;
            P1Y -= Game.Instance.ViewportY;
            P2X -= Game.Instance.ViewportX;
            P2Y -= Game.Instance.ViewportY;
        }

        if ( this.UseRenderScale )
        {
            FullThickness *= this.RenderScale;
            P1X = P1X * this.RenderScale;
            P1Y = P1Y * this.RenderScale;
            P2X = P2X * this.RenderScale;
            P2Y = P2Y * this.RenderScale;
        }
        else if ( DrawIn == DrawIn.GameUnits )
        {
            P1X = P1X * this.RenderScale;
            P1Y = P1Y * this.RenderScale;
            P2X = P2X * this.RenderScale;
            P2Y = P2Y * this.RenderScale;
        }

        if ( this.UseDiffuseOffset )
            DiffuseColor = ColorMath.SubtractColors( DiffuseColor, DiffuseOffsets );

        if ( !DisallowPointFlipping && ( P1X < P2X || P1Y < P2Y ) )
        {
            float p3X = P2X;
            float p3Y = P2Y;

            P2X = P1X;
            P2Y = P1Y;

            P1X = p3X;
            P1Y = p3Y;
        }

        int relativeQuadrantOfPoint2;
        if ( P1X < P2X )
        {
            if ( P1Y < P2Y )
            {
                relativeQuadrantOfPoint2 = 2;
            }
            else
            {
                relativeQuadrantOfPoint2 = 3;
            }
        }
        else
        {
            if ( P1Y < P2Y )
            {
                relativeQuadrantOfPoint2 = 1;
            }
            else
            {
                relativeQuadrantOfPoint2 = 4;
            }
        }

        #region half
        float half = FullThickness / 2f;

        if ( relativeQuadrantOfPoint2 == 1 )
        {
            //DiffuseColor = Color.red;
            P1X -= half;
            P2X -= half;
            P1Y -= half;
            P2Y -= half;
        }
        else if ( relativeQuadrantOfPoint2 == 2 )
        {
            //DiffuseColor = Color.green;
            P1X -= half;
            P2X -= half;
            P1Y += half;
            P2Y += half;
        }
        else if ( relativeQuadrantOfPoint2 == 3 )
        {
            //DiffuseColor = Color.blue;
            P1X += half;
            P2X += half;
            P1Y += half;
            P2Y += half;
        }
        else
        {
            //DiffuseColor = Color.yellow;
            P1X += half;
            P2X += half;
            P1Y -= half;
            P2Y -= half;
        }
        #endregion

        float length = (float)Mat.DistanceBetweenPointsD( P1X, P1Y, P2X, P2Y );
        float angleDegrees = (float)Mat.AngleBetweenPointsDegreesDouble( P1X, P1Y, P2X, P2Y );

        Vector3 position = Game.Instance.MainCameraCamera.ScreenToWorldPoint(
            new Vector3( P1X, this.ActualHeight - P1Y, ZDepth ) );

        Quaternion quaternion = Quaternion.identity;
        angleDegrees = -angleDegrees;
        quaternion = this.RotateAround( new Vector3( position.x,
            position.y, position.z ), ref position, new Vector3( 0, 0, 1 ), ref angleDegrees );

        DelayedRenderer dr = DelayedRenderer.GetNextFree();
        switch ( UVUseType )
        {
            case UVUseType.None:
                {
                    float widthScale = length / Img.ImageSize;
                    float heightScale = FullThickness / Img.ImageSize;
                    Matrix4x4 matrix = Matrix4x4.TRS( position, quaternion, new Vector3( widthScale, heightScale, 1 ) );
                    dr.SetUVUseTypeNone( Img.ID, Img.Texture, ShaderType, mat, matrix, obj, DiffuseColor );
                }
                break;
            case UVUseType.ExtendedTiled:
                {
                    //float widthScale = length / Img.ImageSize;
                    float heightScale = FullThickness / Img.ImageSize;
                    Matrix4x4 matrix = Matrix4x4.TRS( position, quaternion, new Vector3( 1, heightScale, 1 ) );
                    dr.SetUVUseTypeExtended( Img.ID, Img.Texture, ShaderType, mat, matrix, obj, DiffuseColor, false, false,
                        length, Img.ImageSize, UVX, UVY );
                }
                break;
            case UVUseType.ExtendedStretched:
                {
                    float widthScale = length / Img.ImageSize;
                    float heightScale = FullThickness / Img.ImageSize;
                    Matrix4x4 matrix = Matrix4x4.TRS( position, quaternion, new Vector3( widthScale, heightScale, 1 ) );
                    dr.SetUVUseTypeExtended( Img.ID, Img.Texture, ShaderType, mat, matrix, obj, DiffuseColor, false, false,
                        Img.ImageSize, Img.ImageSize, UVX, UVY );
                }
                break;
        }

        return true;
    }
    #endregion

Anyone else have any ideas?

keith.lamothe

Oct 5, 2010 12:24 am

administrator   ~0000346

Can you tell me what specifically it's not doing properly now? Is the center of the exact end of the line supposed to coincide pixel-perfect exactly with the center of the endpoint-ship?

Chris_McElligottPark

Oct 5, 2010 12:25 am

administrator   ~0000347

Right. The center of the endpoint of the line should be on the center of ship.

keith.lamothe

Oct 5, 2010 12:29 am

administrator   ~0000348

Ok, there's a few more things I can try, then.

Chris_McElligottPark

Oct 5, 2010 12:37 am

administrator   ~0000350

Ok -- thanks. It's already much better based on what you did, though. I never could get it that good. ;)

keith.lamothe

Oct 5, 2010 4:34 pm

administrator   ~0000399

* Further improvements to line drawing accuracy.

How about now? :)

keith.lamothe

Oct 5, 2010 4:35 pm

administrator   ~0000400

Just realized that my offset computation duplicates a computation (line length) that is done later, so that could be optimized a bit, but let's see if it actually works.

Chris_McElligottPark

Oct 5, 2010 6:46 pm

administrator   ~0000402

Looks great! Wow, that's so incredibly much better. I put in that last little efficiency boost with the length only to be calculated once, and that didn't seem to affect accuracy. So looks like this can FINALLY be put to rest, after almost two years! Nice work, Keith! :D

Issue History

Date Modified Username Field Change
Oct 2, 2010 9:01 pm Chris_McElligottPark New Issue
Oct 2, 2010 9:01 pm Chris_McElligottPark Status new => assigned
Oct 2, 2010 9:01 pm Chris_McElligottPark Assigned To => keith.lamothe
Oct 2, 2010 9:02 pm Chris_McElligottPark Note Added: 0000007
Oct 4, 2010 6:27 pm keith.lamothe Note Added: 0000304
Oct 4, 2010 6:27 pm keith.lamothe Status assigned => resolved
Oct 4, 2010 6:27 pm keith.lamothe Resolution open => fixed
Oct 4, 2010 7:24 pm Chris_McElligottPark Note Added: 0000306
Oct 4, 2010 7:24 pm Chris_McElligottPark Status resolved => feedback
Oct 4, 2010 7:24 pm Chris_McElligottPark Resolution fixed => reopened
Oct 5, 2010 12:24 am keith.lamothe Note Added: 0000346
Oct 5, 2010 12:25 am Chris_McElligottPark Note Added: 0000347
Oct 5, 2010 12:25 am Chris_McElligottPark Status feedback => assigned
Oct 5, 2010 12:29 am keith.lamothe Note Added: 0000348
Oct 5, 2010 12:37 am Chris_McElligottPark Note Added: 0000350
Oct 5, 2010 4:34 pm keith.lamothe Note Added: 0000399
Oct 5, 2010 4:34 pm keith.lamothe Status assigned => resolved
Oct 5, 2010 4:34 pm keith.lamothe Resolution reopened => fixed
Oct 5, 2010 4:35 pm keith.lamothe Note Added: 0000400
Oct 5, 2010 6:46 pm Chris_McElligottPark Note Added: 0000402
Apr 14, 2014 9:29 am Chris_McElligottPark Category Bug - Graphical Issue => Graphical Bug