Cocos2dx implements erasure, I .e., eraser Effect

Source: Internet
Author: User

Cocos2dx implements the eraser Effect

Dionysoslai ([email protected]) 2014/8/25

In the previous project, I was playing a picture book game and demanded an erasure effect. For details about the effect, see picture book "I Am a Tyrannosaurus". At that time, due to the tight project, is to take online Code directly to use (thanks to the younger brother row.ng introduction, specific blog, see the address, http://zengrong.net/post/2067.htm ). At that time, I did not do some specific optimization work on it. Some principles seemed to be understandable. Today, after work, I have rewritten the code and clarified the knowledge point from the beginning to the end. I must be able to understand the entire workflow.

 

Functional requirements of the eraser:

1. Achieve the erasure effect: Click the position and drag the path to erase the path. Faults and serrations are not allowed during the fast drag process.

2. The erased shape. It is best to customize it. By default, You can provide square and circular shapes. It is best to provide custom image shapes.

3. Determine whether the image has been erased.

4. If the erased shape is too small, it is inevitable that some small residual points may be difficult to pay attention to during the erased process. During the erasure process, the residual points must be erased automatically.

 

Function Analysis:

1.Erasure effect implementation:

A. the so-called "erasure" means to remove the RGB and Alpha values of the image to be erased. The two images can be mixed. Here we will briefly introduce the Mixing Principle in OpenGL.

In OpenGL, the original primary color and the color to be painted are "processed" to get a new color, and then the new color is painted on the canvas again. Here, the color we will draw is called "Source color", and the original color is called "target color ".

In the "some processing" section above, the source color and the target color are taken out respectively, multiplied by a factor (here, the corresponding factor, we call it "source factor" and "Target Factor"), and then add the two (of course, it can not be an addition, it can be a subtraction, or take the maximum values of the two, and so on, in the new version of OpenGL, you can set the calculation method) to obtain a new color value. Assume that the four components of the source color (red, green, blue, and alpha) are (RS, GS, BS, as), and the four components of the target color are (Rd, Gd, BD, AD), and the source factor is (Sr, SG, Sb, SA), and the target factor is (DR, DG, DB, DA ). The new color generated by the hybrid operation can be expressed:


 

Of course, if a certain component exceeds the maximum value, it is automatically intercepted.

The source and target factors can be set through the glblendfunc function. Glblendfunc has two parameters. The former indicates the source factor, and the latter indicates the target factor. These two parameters can be multiple values. The following describes several commonly used parameters.

Gl_zero: 0.0 is used as the factor, which is equivalent to not using this color for hybrid operation.

Gl_one: 1.0 is used as the factor. In fact, this color is used completely in the hybrid operation.

Gl_src_alpha: indicates that the alpha value of the source color is used as a factor.

Gl_dst_alpha: Use the Alpha value of the target color as a factor.

Gl_one_minus_src_alpha: Used to subtract the Alpha value of the source color from 1.0 as a factor. Gl_one_minus_dst_alpha: the Alpha value of the target color minus 1.0 is used as a factor.

Based on OpenGL, if we set the color value of the source color to 0 and the source and target factors to gl_oen and gl_zero respectively, the specific values of the new color are as follows:

Note: Rs, GS, BS, and as are all 0.

Therefore, the erasure effect can be easily implemented. The detailed code is as follows:

M_peraser-> setposition (point); ccblendfunc blendfunc = {gl_one, gl_zero}; // <set the mixed mode, source --- 1, Target --- 0m_peraser-> setblendfunc (blendfunc ); m_prtex-> begin (); m_peraser-> visit (); m_prtex-> end ();

 

If it is a custom shape (the custom shape we discuss here is the shape provided by the image, rather than the one we draw ourselves-it is no different from the previous one because it is drawn by ourselves ). There are special requirements for images, that is, the middle shape of the image must be hollow out, and the external alpha channel must be 255. As shown in:


(* ^__ ^ *) Xi ......, Here is an animal picture (this is an animal picture book game). It is hollow out inside its contour, And the Alpha is the largest for the outside. Then we set the source and target factors to gl_one_minus_src_alpha and gl_src_alpha respectively.

The new color is as follows:

In the external region: gl_one_minus_src_alpha = 0; gl_src_alpha = 1. The new color value is as follows:


Or the original value.

In the internal region: gl_one_minus_src_alpha = 1; gl_src_alpha = 0. The new color value is as follows:



We can see that all values are 0.

The Code is as follows:

Ccsprite * drawsprite = ccsprite: createwithtexture (m_drawtextture); drawsprite-> setposition (point); ccblendfunc blendfunc = {strong, gl_src_alpha}; // <sets the mixed mode, source --- 1-Alpha, target --- alphadrawsprite-> setblendfunc (blendfunc); m_prtex-> begin (); drawsprite-> visit (); m_prtex-> end ();

B. Use Dynamic textures to change the texture.

Texture changes dynamically when the erased effect is used. Here, we use ccrendertexture to achieve dynamic texture change. For the specific usage of ccrendertexture, you can see the description language in the engine:

To render things into it, simply construct arender target, call begin on it, call visit on any Cocos scenes or objects torender them, and call end.

In fact, it is the following paragraph:

  1. Create a new ccrendertexture. Here, you can specify the width and height of the texture to be created ..
  2. Call the ccrendertexture: Begin. This method starts OpenGL, and then any drawing command will be rendered to the ccrendertexture, rather than painted to the screen.
  3. You can use the original OpenGL call to draw a texture, or you can use the defined visit method in the cocos2d object. (This visit method calls some OpenGL commands to draw cocos2d objects)
  4. Call ccrendertexture: end. This method renders the texture and closes the channel for rendering to the ccrendertexture.
  5. Create a sprite from the generated texture. You can now use the sprite. Texture attribute of ccrendertexture to easily create a new Sprite.
Here, I will refer to the Zilong Shan Ren's blog "(translated) How to Use ccrendertexture to create a dynamic texture". For details, see http://www.cnblogs.com/andyque/archive/2011/07/01/2095479.html. In the blog, the dynamic texture creation method of ccrendertexture is described in detail. The following describes how to add a Sprite texture to the ccrendertexture file:
Ccsprite * sprite = ccsprite: Create (pszfilename); spritesize = sprite-> getcontentsize (); // After the Sprite is added to the texture, its Center Coordinate should be set to (0, 0) this is because the texture center is (0, 0). Of course, you can set its offset coordinates. Sprite-> setanchorpoint (CCP (0.f, 0.f )); // sprite-> setposition (CCP (spritesize. width/2.f, spritesize. height/2.f)); m_prtex = ccrendertexture: Create (spritesize. width, spritesize. height); m_prtex-> setposition (ccpointzero); this-> addchild (m_prtex); m_prtex-> begin (); sprite-> visit (); m_prtex-> end ();

C. Avoid faults and serrations

The reason for faults and serrations is that the first and second points received by the system during the rapid Erasure process may have a large displacement deviation. If you simply process the information of these two vertices, many vertices will be missing, rather than being painted. As a result, faults and serrations occur.

Therefore, if we simply judge whether the distance between two points exceeds a certain degree, we can process them again. The distance between the two depends on the number of points to be extracted for processing. Here, I have to deal with a simple judgment that the distance exceeds 1 (obviously, this will be more accurate, but the consumable performance is large and can be changed as appropriate ). The code below is as follows:

Void erasersprite: cctouchmoved (cocos2d: cctouch * ptouch, cocos2d: ccevent * pevent) {If (m_beraser) {ccpoint = ptouch-> getlocation (); ccpoint normal = ccpnormalize (point-m_touchPoint); // process too much movement at a time, resulting in omission in the middle, or serrations; while (1) {If (ccpdistance (point, m_touchpoint) <1.f) {/* m_peraser-> setposition (-this-> getposition () + point + spritesize/2.f); */erasebyblend (-this-> getposition () + point + spritesize/2.f); break;} m_touchpoint = m_touchpoint + normal * 1.f;/* m_peraser-> setposition (-this-> getposition () + m_touchpoint + spritesize/2.f ); */erasebyblend (-this-> getposition () + m_touchpoint + spritesize/2.f);} m_touchpoint = point ;}}


2. Erase the shape

The erased shape is actually mentioned above. Here is a brief introduction. If vertices or circles are used, you can use custom nodes, that is, ccdrawnode. Ccdrawnode extensions can also be used in ccclippingnode to implement custom cropping templates. The following code deletes the square and circular shapes:

Square shape:

m_pEraser = CCDrawNode::create();float width = 10.f;        m_pEraser->drawDot(CCPointZero, width, ccc4f(0,0,0,0));

Circular shape:

M_peraser = ccdrawnode: Create (); // draw a circular area float fradius = 30366f; // <the radius of the circle const int ncount = 100; /// <use the positive 100 edge to simulate the const float coef = 2.0f * (float) m_pi/ncount; /// <calculate the angle between each two adjacent vertex and the center static ccpoint circle [ncount]; // <vertex array for (unsigned int I = 0; I <ncount; I ++) {float rads = I * coef; // <radian circle [I]. X = fradius * cosf (rads); // <xcircle [I] of the vertex. y = fradius * sinf (rads); // <y} m_peraser-> drawpolygon (CIR CLE, ncount, ccc4f (0, 0, 0, 0), 0, ccc4f (0, 0, 0, 0); // draw this polygon!

A custom image shape is actually a Sprite object.


3. Determine whether the image has been erased

To determine whether the image is erased, the basic idea is to determine the pixel value of the texture point by point. When all pixels are 0, the image has been erased.

First, obtain the image information of the texture. The key function is newccimage. The Code is as follows:


        CCImage* image = new CCImage();image = m_pRTex->newCCImage(true);

Note that you must manually delete the image.

Second, obtain the pixel value of each position. The Code is as follows:

unsigned char *pixel = data_ + (x + y * image->getWidth()) * m;// You can see/change pixels' RGBA value(0-255) here !unsigned int r = (unsigned int)*pixel;unsigned int g = (unsigned int)*(pixel + 1);unsigned int b = (unsigned int)*(pixel + 2) ;        unsigned int a = (unsigned int)*(pixel + 3);

X and Y represent positions.

 

The complete code is as follows:

Bool erasersprite: geteraserok () {m_beraserok = false; ccimage * image = new ccimage (); image = m_prtex-> newccimage (true); int M = 3; if (image-> hasalpha () {M = 4;} unsigned char * Data _ = image-> getdata (); int x = 0, y = 0; /// here we need a point, that is, the Center Coordinate of OpenGL is in the upper left corner of the For (x = 0; x <spritesize. width; ++ X) {for (y = 0; y <spritesize. height; ++ y) {unsigned char * pixel = data _ + (x + y * image-> getwidth () * m; // you can see/ Change pixels 'rgba value (0-255) Here! Unsigned int r = (unsigned INT) * pixel; unsigned int G = (unsigned INT) * (pixel + 1); unsigned int B = (unsigned INT) * (pixel + 2); unsigned int A = (unsigned INT) * (pixel + 3); If (R! = 0 & G! = 0 & B! = 0 &! = 0) {m_beraserok = false; break ;}} if (spritesize. height! = Y) {break;} If (x = spritesize. width & Y = spritesize. height) {m_beraserok = true;} Delete image; return this-> m_beraserok ;}

Here, refer to the article: Getting andsetting the RGB/rgba value of a pixel in a ccsprite (cocos2d-x), detailed address: http://stackoverflow.com/questions/9665700/getting-and-setting-the-rgb-rgba-value-of-a-pixel-in-a-ccsprite-cocos2d-x

Well, this part took me a whole morning. I didn't expect it to be like this, and I didn't have the best foot in the front.

4. Cleanup of residual points

There are no good ideas for this problem.

Finally, visit https://github.com/dionysoslai/erasersprite. At the same time, if you have any good suggestions for residual issues, remember to call me! Thank you!













Cocos2dx implements erasure, I .e., eraser Effect

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.