<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Fancy Rat Studios &#187; cocos2d</title>
	<atom:link href="http://fancyratstudios.com/tag/cocos2d/feed/" rel="self" type="application/rss+xml" />
	<link>http://fancyratstudios.com</link>
	<description>A Fancy Rat Blog</description>
	<lastBuildDate>Mon, 15 Mar 2010 21:34:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>ProgressTimer for cocos2d</title>
		<link>http://fancyratstudios.com/2010/02/programming/progresstimer-for-cocos2d/</link>
		<comments>http://fancyratstudios.com/2010/02/programming/progresstimer-for-cocos2d/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 23:49:45 +0000</pubDate>
		<dc:creator>Lam</dc:creator>
				<category><![CDATA[cocos2d]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[bar]]></category>
		<category><![CDATA[indicator]]></category>
		<category><![CDATA[loading]]></category>
		<category><![CDATA[progress]]></category>
		<category><![CDATA[radial]]></category>
		<category><![CDATA[timer]]></category>

		<guid isPermaLink="false">http://fancyratstudios.com/?p=126</guid>
		<description><![CDATA[Every Monday, Wednesday and Friday I will put my thoughts on game design concepts and ideas into words so for today let&#8217;s focus on a topic that I hope many games will use. A Loading indicator! The problem at hand Sometimes we will need to process data or have an in-game wait or delay. We [...]]]></description>
			<content:encoded><![CDATA[<p>Every Monday, Wednesday and Friday I will put my thoughts on game design concepts and ideas into words so for today let&#8217;s focus on a topic that I hope many games will use. A Loading indicator!</p>
<h2>The problem at hand</h2>
<p>Sometimes we will need to process data or have an in-game wait or delay. We can&#8217;t let users wait without any visual indication so generally we&#8217;ll implement a loading progress image. This simple concept is shown below.<br />
<a href="http://fancyratstudios.com/wp-content/uploads/2010/02/progress-timer-1.png"><img src="http://fancyratstudios.com/wp-content/uploads/2010/02/progress-timer-1.png" alt="" title="progress-timer-1" width="271" height="64" class="alignnone size-full wp-image-135" /></a><br />
If that&#8217;s what you are also aiming to do then read ahead!<br />
<span id="more-126"></span></p>
<h2>Discovery</h2>
<p>We want a solution that can work for any image type and is setup for cocos2d-iphone. A really neat idea is that we can map triangles using opengl to show certain portions of the image.</p>
<p>We see that for the mapping to work, we&#8217;ll use:</p>
<ol>
<li>the midpoint vertex (vertex 0)</li>
<li>the 12 o&#8217;clock vertex (vertex 1)</li>
<li>each corner edge up-to, (vertex 2-5)</li>
<li>the point created from the progress percentage (vertex 6)</li>
</ol>
<p><a href="http://fancyratstudios.com/wp-content/uploads/2010/02/texture-mapping-triangles.png"><img src="http://fancyratstudios.com/wp-content/uploads/2010/02/texture-mapping-triangles.png" alt="" title="texture-mapping-triangles" width="209" height="231" class="alignnone size-full wp-image-181" /></a><br />
Not too hard when we really get down to solving it.</p>
<h2>Let&#8217;s implement the thing</h2>
<p>First we setup a <strong>ProgressTimer</strong> class that inherits a <strong>CCNode</strong> so we can add it to the engine.<br />
<strong>ProgressTimer</strong>, at it&#8217;s core, will hold the percentage value, a texture, and the vertex data so we can render the object in opengl. (Note that the sample below has more because I&#8217;ve implemented the option to change its opacity and color. I&#8217;ve also added different progress timer types.)</p>
<h3>ProgressTimer.h</h3>
<pre class="brush: objc; title: ;">
typedef enum {
	kProgressTimerTypeRadialCCW,
	kProgressTimerTypeRadialCW,
	kProgressTimerTypeHorizontalBarLR,
	kProgressTimerTypeHorizontalBarRL,
	kProgressTimerTypeVerticalBarBT,
	kProgressTimerTypeVerticalBarTB,
} ProgressTimerType;

@interface ProgressTimer : CCNode {
	ProgressTimerType	type_;
	float				percentage_;
	CCTexture2D			*texture_;

	int					vertexDataCount_;
	ccV2F_C4F_T2F		*vertexData_;

	int					indicesCount_;
	GLubyte				*indices_;

	GLubyte				opacity_;
	ccColor3B			color_;
	ccBlendFunc			blendFunc_;
}
///
//	Change the percentage to change progress.
///
@property ProgressTimerType type;
///
//     The percentage of progress from 0..100
///
@property float percentage;
@property (retain) CCTexture2D *texture;
@property ccColor3B color;
@property GLubyte opacity;
@property ccBlendFunc blendFunc;

///
//	Creates a progress timer with the texture as the shape the timer goes through
///
+ (id) progressWithTexture:(CCTexture2D*) aTexture;
- (id) initWithTexture:(CCTexture2D*) aTexture;

@end
</pre>
<p>We&#8217;ll skip the basic initializing and destruction of variables and get right to the most important piece. The mapping of the image in order to create the radial indicator.</p>
<p>Every time a user changes the percentage we will update the ProgressTimer vertex data.</p>
<pre class="brush: objc; title: ;">

-(void)setPercentage:(float) percentage
{
	if(percentage_ &lt; 0.f)
		percentage_ = 0.f;
	else if(percentage &gt; 100.0f)
		percentage_  = 100.f;
	else
		percentage_ = percentage;

	[self updateProgress];
}
</pre>
<p><strong>ProgressTimer</strong>&#8216;s <em>updateProgress</em> will call <em>updateRadial</em> if our type is set to <em>kProgressTimerTypeRadialCCW</em> or <em>kProgressTimerTypeRadialCCW</em>. Radial type is our pie slice indicator and the CW/CCW suffix represents it&#8217;s rotation direction (clockwise or counter-clockwise).</p>
<p>What we will do is understand the implementation details of developing the radial slices.</p>
<p>Every radial update, we will release all vertex data memory on the heap.</p>
<h3>ProgressTimer.m <em>updateRadial</em></h3>
<pre class="brush: objc; title: ;">
	//	release all previous information
	if(vertexData_){
		free(vertexData_);
		vertexData_ = 0;
		vertexDataCount_ = 0;
	}

	if(indices_){
		free(indices_);
		indices_ = 0;
		indicesCount_ = 0;
	}

	//	If percentage is zero it's quicker not to create the vertexData
	if(percentage_ == 0.f)
		return;
</pre>
<h3>Finding that midpoint</h3>
<p>The easiest vertex point to find on the image is the midpoint and as an added bonus we will use a <strong>CCNode</strong>&#8216;s <em>anchorPoint</em> so we have a choice for the center. The midpoint has to be adjusted by the actual texture maximums since we don&#8217;t always deal with texture sizes with powers of 2. Once we have the midpoint we now have enough information to find the next needed vertex.</p>
<pre class="brush: objc; title: ;">
	CGPoint tMax = ccp(texture_.maxS,texture_.maxT);
	CGPoint midpoint = ccpCompMult(self.anchorPoint, tMax);
</pre>
<p>ccCompMult is just a multiplying each component of the two points together</p>
<pre class="brush: objc; title: ;">
CGPoint ccpCompMult(CGPoint a, CGPoint b)
{
	return ccp(a.x * b.x, a.y * b.y);
}
</pre>
<h3>The percentage point</h3>
<p>Now we find the vertex point based on the <strong>ProgressTimer</strong> percentage.<br />
<a href="http://fancyratstudios.com/wp-content/uploads/2010/02/finding-rotation-point.png"><img src="http://fancyratstudios.com/wp-content/uploads/2010/02/finding-rotation-point.png" alt="" title="finding-rotation-point" width="201" height="204" class="alignnone size-full wp-image-168" /></a></p>
<p>We can find the angle needed to rotate from the 12 o&#8217;clock position.<br />
Taking that angle, the point of rotation is found by doing a vector rotation from the vertex at the 12 o&#8217;clock to the percentage point.</p>
<pre class="brush: objc; title: ;">
	float alpha = percentage_ / 100.f;
	//	Otherwise we can get the angle from the alpha
	float angle = 2.f*M_PI * ( type_ == kProgressTimerTypeRadialCW? alpha : 1.f - alpha);

	//	We find the vector to do a hit detection based on the percentage
	//	We know the first vector is the one @ 12 o'clock (top,mid) so we rotate
	//	from that by the progress angle around the midpoint pivot
	CGPoint percentagePt = ccpRotateByAngle(ccp(midpoint.x, 0.f), midpoint, angle);
</pre>
<p>ccpRotateByAngle takes our point and a pivot and rotates it around the pivot by the angle.</p>
<pre class="brush: objc; title: ;">
CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle) {
	CGPoint r = ccpSub(v, pivot);
	float t = r.x;
	double cosa = cosf(angle), sina = sinf(angle);
	r.x = t*cosa - r.y*sina;
	r.y = t*sina + r.y*cosa;
	r = ccpAdd(r, pivot);
	return r;
}
</pre>
<p>We&#8217;re almost there but the rotated point isn&#8217;t the correct point needed for the vertex data. What we really need is the intersection point from the line edge of the texture and the percentage line.<br />
<a href="http://fancyratstudios.com/wp-content/uploads/2010/02/finding-hit-point.png"><img src="http://fancyratstudios.com/wp-content/uploads/2010/02/finding-hit-point.png" alt="" title="finding-hit-point" width="221" height="217" class="alignnone size-full wp-image-169" /></a></p>
<p>How I attacked this problem is that the texture coordinates need to be in an array so we can quickly find the correct edge for the intersection test.</p>
<pre class="brush: cpp; title: ;">
#define kProgressTextureCoordsCount 4
const CGPoint kProgressTextureCoords[kProgressTextureCoordsCount] = {{0,0},{0,1},{1,1},{1,0}};
</pre>
<p><a href="http://fancyratstudios.com/wp-content/uploads/2010/02/texture-corner-vertex.png"><img src="http://fancyratstudios.com/wp-content/uploads/2010/02/texture-corner-vertex.png" alt="" title="texture-corner-vertex" width="228" height="244" class="alignnone size-full wp-image-174" /></a><br />
As I finished writing this I noted that maximum texture coordinate values are always 0 and 1 so let&#8217;s represent the array as a sequence of bits 00011110 (which corresponds to 0x1e).</p>
<p>So I rewrote the array as</p>
<pre class="brush: cpp; title: ;">
#define kProgressTextureCoordsCount 4
const char kProgressTextureCoords = 0x1e;
</pre>
<p>And a function that will give me the corresponding texture coordinates for an index value. It pretty much operates at the bit level to retrieve the correct value (if this is confusing I may write a lesson on bit operations).</p>
<pre class="brush: objc; title: ;">
-(CGPoint)boundaryTexCoord:(char)index
{
	if (index &lt; kProgressTextureCoordsCount) {
		switch (type_) {
			case kProgressTimerTypeRadialCW:
				return ccp((kProgressTextureCoords&gt;&gt;((index&lt;&lt;1)+1))&amp;1,(kProgressTextureCoords&gt;&gt;(index&lt;&lt;1))&amp;1);
			case kProgressTimerTypeRadialCCW:
				return ccp((kProgressTextureCoords&gt;&gt;(7-(index&lt;&lt;1)))&amp;1,(kProgressTextureCoords&gt;&gt;(7-((index&lt;&lt;1)+1)))&amp;1);
			default:
				break;
		}
	}
	return CGPointZero;
}
</pre>
<p>Now we have the texture corner coordinates; we now need the edge of the texture and the percentage point line.</p>
<p>We can find the nearest edge based on the alpha value. Since we need 2 points for the line, we grab the previous index and make sure the previous index is wrapped within our array bounds.</p>
<pre class="brush: objc; title: ;">
	int index = roundf(kProgressTextureCoordsCount*alpha);
	int pIndex = (index + (kProgressTextureCoordsCount - 1))%kProgressTextureCoordsCount;

	CGPoint edgePtA = [self boundaryTexCoord:index % kProgressTextureCoordsCount];
	CGPoint edgePtB = [self boundaryTexCoord:pIndex];
</pre>
<p>The percentage line is just the midpoint and the percentage point.</p>
<p><em>ccpLineIntersect</em> returns true if an intersection occurred. We pass it 4 points that make up 2 lines.<br />
L1 = p2 &#8211; p1<br />
L2 = p4 &#8211; p3<br />
Then we grab the hit point using the returned &#8216;s&#8217; or &#8216;t&#8217; value.<br />
hit = midpoint + (percentagePoint &#8211; midpoint)*t;</p>
<pre class="brush: cpp; title: ;">
bool ccpLineIntersect(CGPoint p1, CGPoint p2,
								 CGPoint p3, CGPoint p4,
								 float *s, float *t){
	CGPoint p13, p43, p21;
	float d1343, d4321, d1321, d4343, d2121;
	float numer, denom;

	p13 = ccpSub(p1, p3);

	p43 = ccpSub(p4, p3);

	//Roughly equal to zero but with an epsilon deviation for float
	//correction
	if (ccpFuzzyEqual(p43, CGPointZero, kCGPointEpsilon))
		return false;

	p21 = ccpSub(p2, p1);

	//Roughly equal to zero
	if (ccpFuzzyEqual(p21,CGPointZero, kCGPointEpsilon))
		return false;

	d1343 = ccpDot(p13, p43);
	d4321 = ccpDot(p43, p21);
	d1321 = ccpDot(p13, p21);
	d4343 = ccpDot(p43, p43);
	d2121 = ccpDot(p21, p21);

	denom = d2121 * d4343 - d4321 * d4321;
	if (fabs(denom) &lt; kCGPointEpsilon)
		return false;
	numer = d1343 * d4321 - d1321 * d4343;

	*s = numer / denom;
	*t = (d1343 + d4321 *(*s)) / d4343;
	return true;
}
</pre>
<p>We pass the points into our intersect formula (notice we multiply the corner components by tMax since we need the actual texture coordinates and sometimes we&#8217;ll have images that are not powers of 2.</p>
<pre class="brush: objc; title: ;">
//	s and t are returned by ccpLineIntersect which explains how to use them
	float s = 0, t = 0;
	ccpLineIntersect(ccpCompMult(edgePtA,tMax), ccpCompMult(edgePtB,tMax),
					 midpoint, percentagePt, &amp;s, &amp;t);

	//	get the hit point
	CGPoint hit = ccpAdd(midpoint, ccpMult(ccpSub(r2, midpoint),t));
</pre>
<p>We have all our needed points calculated! Now all that&#8217;s left is creating the vertex data.</p>
<h2>Creating Our Vertex Data</h2>
<p>To create the vertex data we first need to convert texture coordinates (in the 0..1) range to actual vertex coordinates [0..imageSize] which I have written below.</p>
<pre class="brush: objc; title: ;">
///
//	@returns the vertex position from the texture coordinate
///
-(CGPoint)vertexFromTexCoord:(CGPoint) texCoord
{
	if (texture_) {
		float min = 0, maxW = texture_.contentSize.width, maxH = texture_.contentSize.height;
		return ccp(lerp(min, maxW, texCoord.x/texture_.maxS),
				   lerp(min, maxH, (1.f -(texCoord.y/texture_.maxT))));
	} else {
		return CGPointZero;
	}
}
</pre>
<p>Now we have all that we need to create our vertex data what we&#8217;ll do is first store the midpoint position. Then the point at 12 o&#8217;clock on the texture.</p>
<p>Now we add each corner of the texture into the vertex array until we reach the hit point and we add the hit point last.</p>
<p>After the vertex data is complete we begin creating the triangle by setting up the indexes. Let&#8217;s take a look at our original setup of vertex data.<br />
<a href="http://fancyratstudios.com/wp-content/uploads/2010/02/texture-mapping-triangles.png"><img src="http://fancyratstudios.com/wp-content/uploads/2010/02/texture-mapping-triangles.png" alt="" title="texture-mapping-triangles" width="209" height="231" class="alignnone size-full wp-image-181" /></a><br />
To create triangles from the example vertexes above we can see that the indexes will hold.</p>
<pre>
indices_ = {0,1,2, 0,2,3, 0,4,5, 0,5,6};
</pre>
<p>The code is shown below:</p>
<pre class="brush: objc; title: ;">
	//	The size of the vertex data is the index from the hitpoint
	//	the 3 is for the midpoint, 12 o'clock point and hitpoint position.
	vertexDataCount_ = index + 3;
	vertexData_ = malloc(vertexDataCount_ * sizeof(ccV2F_C4F_T2F));

	//	First we populate the array with the midpoint, then all
	//	vertices/texcoords/colors of the 12 'o clock start and edges and the hitpoint
	vertexData_[0].texCoords = (ccTex2F){midpoint.x, midpoint.y};
	vertexData_[0].vertices = [self vertexFromTexCoord:midpoint];

	vertexData_[1].texCoords = (ccTex2F){midpoint.x, 0.f};
	vertexData_[1].vertices = [self vertexFromTexCoord:ccp(midpoint.x, 0.f)];

	for(int i = 0; i &lt; index; ++i){
		CGPoint texCoords = ccpCompMult([self boundaryTexCoord:i], tMax);

		vertexData_[i+2].texCoords = (ccTex2F){texCoords.x, texCoords.y};
		vertexData_[i+2].vertices = [self vertexFromTexCoord:texCoords];
	}

	//	hitpoint will go last
	vertexData_[vertexDataCount_ - 1].texCoords = (ccTex2F){hit.x, hit.y};
	vertexData_[vertexDataCount_ - 1].vertices = [self vertexFromTexCoord:hit];	

	indicesCount_ = 3 * (index + 1);
	indices_ = malloc(indicesCount_ * sizeof(GLubyte));

	//	We only go up to index since we do three increments
	for(int i=0;i &lt; indicesCount_/3; ++i){
		indices_[3*i] = 0;
		indices_[3*i + 1] = i + 1;
		indices_[3*i + 2] = i + 2;
	}
</pre>
<p>The only thing left to do is draw our vertex data</p>
<h3><strong>ProgressTimer</strong> <em>draw</em></h3>
<pre class="brush: objc; title: ;">
	glBindTexture(GL_TEXTURE_2D, texture_.name);
	glVertexPointer(2, GL_FLOAT, sizeof(ccV2F_C4F_T2F), &amp;vertexData_[0].vertices);
	glTexCoordPointer(2, GL_FLOAT, sizeof(ccV2F_C4F_T2F), &amp;vertexData_[0].texCoords);
	glColorPointer(4, GL_FLOAT, sizeof(ccV2F_C4F_T2F), &amp;vertexData_[0].colors);
	glDrawElements(GL_TRIANGLES, indicesCount_, GL_UNSIGNED_BYTE, indices_);
</pre>
<p>And now we have a ProgressTimer indicator. If you want to see the demo file of this tutorial then just click on the link.</p>
<div class="clearfix download-wrapper">
<a href="http://dl.dropbox.com/u/271717/ProgressDemo.zip"><span class="xcode-download-icon" style="vertical-align:text-top;"></span></a><br />
<a class="download" href="http://dl.dropbox.com/u/271717/ProgressDemo.zip">Download the XCode Demo</a>
</div>
<p>This demo uses the fast, easy and open source cocos2d framework.<br />
<a href="http://www.cocos2d-iphone.org/"><img src="http://fancyratstudios.com/wp-content/uploads/2010/02/official-cocos-logo-landscape-happy-300x89.png" alt="" title="cocos2d" width="300" height="89" class="alignnone size-medium wp-image-195" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://fancyratstudios.com/2010/02/programming/progresstimer-for-cocos2d/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>

