How to use CCRenderTexture to render DrawingPrimitives.DrawXXX() to texture with Cocos2D-XNA?

Topics: Sprites and SpriteBatch
Aug 3, 2013 at 8:32 PM
Edited Aug 3, 2013 at 8:48 PM
it seems different with cocos2d-x.

I wrote something as following, but it doesn't work, show nothing
 CCRect _rect ;
        CCRenderTexture _rt;

        public ctor(CCRect rect)
        {
            _rect = rect;
            _rt = new CCRenderTexture((int)_rect.Size.Width+3, (int)_rect.Size.Height+3);

            this.DrawSomething();

            _rt.AnchorPoint = CCPoint.AnchorMiddle;
            _rt.Position = this.ContentSize.Center;

            this.AddChild(_rt);
        }

public void DrawSomething()
        {
            _rt.Begin();

            CCDrawingPrimitives.Begin();
            CCDrawingPrimitives.DrawRect(_rect, new CCColor4B(Microsoft.Xna.Framework.Color.Blue));
      
            CCDrawingPrimitives.End();

            _rt.End();
        }
Coordinator
Aug 3, 2013 at 10:28 PM
Hi.

I wrote a test that worked:
        CCSize s = CCDirector.SharedDirector.WinSize;
        CCRenderTexture text = new CCRenderTexture((int)s.Width, (int)s.Height);

        CCDrawNode draw = new CCDrawNode();
        text.AddChild(draw, 10);
        text.Begin();
        // Draw polygons
        CCPoint[] points = new CCPoint[]
            {
                new CCPoint(s.Height / 4, 0),
                new CCPoint(s.Width, s.Height / 5),
                new CCPoint(s.Width / 3 * 2, s.Height)
            };
        draw.DrawPolygon(points, points.Length, new CCColor4F(1, 0, 0, 0.5f), 4, new CCColor4F(0, 0, 1, 1));
        text.End();
        AddChild(text, 24);
There is a new node named CCDrawNode, which is used for drawing stuff from the physics libraries. This node when added as a child to the CCRenderTexture does render the primitives you want.

I'll try a test that is exactly what you describe next. Doing the above will get you going though. I put that code in the ctor of the test.
Coordinator
Aug 3, 2013 at 10:31 PM
Aug 4, 2013 at 12:02 AM
Edited Aug 4, 2013 at 12:02 AM
thanks a lot.

I tested, but I found that it doesn't work in a subclass of CCSprite, of course works in subclass of CCLayer.
What's wrong?
Coordinator
Aug 4, 2013 at 5:48 AM
CCSprite only displays the DisplayFrame, which is texture2d.

You need to set the DisplayFrame of the sprite to the rendered texture.
Aug 4, 2013 at 12:14 PM
Edited Aug 4, 2013 at 12:18 PM
totallyevil wrote:
CCSprite only displays the DisplayFrame, which is texture2d.

You need to set the DisplayFrame of the sprite to the rendered texture.
Thanks, but doesn't work with following 2 approaches which i have tried:

1) Render texture in CCLayer, and new a CCSprite with CCRenderTexture.Sprite.Texture ( I already added CCDrawNode into CCRenderTexture.Sprite ),
and add the CCSprite to the CCLayer.

2) In the ctor of the subclass of CCSprite, render texture, and invoke InitWithSpriteFrame() with the rendered texture.
Coordinator
Aug 4, 2013 at 4:21 PM
so I understand the problem now,

you have a CCSprite instance, and you want to overlay primitive drawing on that sprite?

You want to do this by adding the draw primitives as a node child of CCSprite?

Then you want to do this as a CCRenderTexture??

So your node hierarchy would look like
CCRenderTexture
    |-- CCSprite
            |---- CCDrawNode
Is this correct?
Aug 4, 2013 at 4:26 PM
Edited Aug 4, 2013 at 4:51 PM
Yes, kinda of. Anyway, I want draw some stuff in an independent CCSprite, make the drawing be part of the CCSprite
OR draw some stuff outside CCSprite, then new a CCSprite with CCSprite(Texture2D) ctor or CCSprite(CCSpriteFrame) in which the parameters are from CCRenderTexure
CCSprite
     | -- CCRenderTexture
                    |--CCSprite
                             | -- CCDrawNode


OR

new CCSprite(Texture2D)
                  ^
                  | --> CCRenderTexture.CCSprite.Texture

OR

CCSprite newSprite = CCRenderTexture.CCSprite     


then put CCSprite which contains the rendered texture onto a CCLayer                             
Coordinator
Aug 6, 2013 at 6:06 PM
I just did this in one of our games to highlight touch zones on a map. The difference here is that I used a Layer as my parent instead of a sprite.
    public RegionMapLayer(Map map)
    {
        string asset = map.AssetName;
        if (!string.IsNullOrEmpty(asset))
        {
            CCSprite img = new CCSprite(asset);
            img.AnchorPoint = CCPoint.Zero;
            img.Position = CCPoint.Zero;
            AddChild(img);
        }
        _MyMap = map;
        CCDrawNode node = new CCDrawNode();
        foreach (MapArea a in map.Areas)
        {
            CCRect r = a.BoundsInMap;
            CCPoint[] points = new CCPoint[]
            {
                new CCPoint(r.Origin.X, r.Origin.Y),
                new CCPoint(r.Origin.X + r.Size.Width, r.Origin.Y),
                new CCPoint(r.Origin.X + r.Size.Width, r.Origin.Y + r.Size.Height),
                new CCPoint(r.Origin.X, r.Origin.Y + r.Size.Height)
            };
            node.DrawPolygon(points, points.Length, new CCColor4F(1, 0, 0, 0.5f), 4, new CCColor4F(0, 0, 1, 1));
        }
        AddChild(node, 25);
    }
Aug 6, 2013 at 8:42 PM
Thank you very much.

The CCSprite which I want to make is for CCProgressTimer.
Now I found that put any subclass that derived from CCSprite as
the parameter of the CCProgressTimer(CCSprite), the progress timer will not show.

Correct me if I'm wrong.
Coordinator
Aug 6, 2013 at 8:56 PM
public class ScoreProgressMeter : CCLayerRGBA
{
    private CCProgressTimer _Progress;
    private CCSprite _Background;
    private int[] _Scores;

    public ScoreProgressMeter(int maxScore) : base()
    {
        _Background = new CCSprite("images/score_meter");
        _Background.Position = new CCPoint(128f, 21f);
        AddChild(_Background, 1);
        _Progress = new CCProgressTimer("images/progress1");
        _Progress.Position = new CCPoint(128f, 21f);
        _Progress.Percentage = 0;
        _Progress.Type = CCProgressTimerType.Bar;
        _Progress.Midpoint = new CCPoint(0, 0); // Set it horizontal with x=1
        _Progress.BarChangeRate = new CCPoint(1, 0);
        AddChild(_Progress, 2);
    }

    public int[] Scores
    {
        set
        {
            _Scores = value;
        }
    }

    private float Clamp(float v)
    {
        if (v > 100f)
        {
            return (100f);
        }
        if (v < 0f)
        {
            return(0f);
        }
        return (v);
    }

    /// <summary>
    /// Updates the display percentage of the progress.
    /// </summary>
    public int Score
    {
        set
        {
            if (_Scores == null || _Scores.Length == 0)
            {
                return;
            }
            _Progress.Percentage = 100;
            for (int i = 0; i < _Scores.Length; i++)
            {
                if (_Scores[i] > value)
                {
                    _Progress.Percentage = Clamp((float)value / (float)_Scores[i] * 100f);
                    break;
                }
            }
        }
    }
}
Aug 6, 2013 at 9:12 PM
Edited Aug 6, 2013 at 9:15 PM
thank you.

I meant code like following pseudo code:
public class CustomSprite : CCSprite
{}

CustomSprite customSprite = new CustomSprite();

CCProgressTimer progressTimer = new CCProgressTimer(customSprite);   //  <--- like this
the progressTimer will not appear. but if replace customSprite with an instance of CCSprite or just an image path, it's OK.
Coordinator
Aug 6, 2013 at 9:48 PM
what are you doing in your custom sprite? Is that the CCRenderTexture that you are trying to do above?

What if you do

CCRenderTexture myRenderTexture;

CCProgressTimer progressTimer = new CCProgressTimer(myRenderTexture.CCSprite);
Coordinator
Aug 6, 2013 at 9:49 PM
Also make sure you give the progress timer a value of 0 - 100, not 0 - 1. It's on a scale of 0% to 100% ... 0 to 100.
Aug 6, 2013 at 9:58 PM
Thanks, you response very fast.

Yes, I know how to use CCProgressTimer as I said. I've done CCProgressTimer with CCSprite or just an image which was OK.
the CustomeSprite with or without CCRenderTexture in it, passed to CCProgressTimer, the timer doesn't show.
Coordinator
Aug 7, 2013 at 2:47 AM
Can you do me a favor? Can you put together a test case and issue a PR back to us that we can then integrate into our tests and see how to fix this?

If I do it, then I'll probably make something that works and we'll be back to the same circular argument.

thanks!
Aug 7, 2013 at 11:12 PM
Edited Aug 7, 2013 at 11:14 PM
sorry for make you confuse, just pass an instance of following CCProgressMask to CCProgressTimer:
CCProgressTimer progressTimer = new CCProgressTimer(new (CCProgressMask()));

after the progress timer started, cannot see it.
 public class CCProgressMask : CCSprite
    {
        CCRect _rect ;
       
        CCDrawNode draw;

        public CCProgressMask(CCRect rect)
        {
          
            this.DrawProgressRect();
                               
            this.AddChild(draw);

        }

        public void DrawProgressRect()
        {
            draw = new CCDrawNode();
        

            draw.DrawDot(this.AnchorPoint, 5f, new CCColor4F(1, 0, 1, 1));
            draw.DrawSegment(this.AnchorPoint, this.BoundingBox.UpperRight, 5f,
                             new CCColor4F(0, 0, 1, 1));

        }
               
    }