<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Learn OpenGL ES</title>
	
	<link>http://www.learnopengles.com</link>
	<description>Learn how to develop mobile graphics using OpenGL ES 2</description>
	<lastBuildDate>Mon, 14 Apr 2014 19:52:24 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8.3</generator>
	<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/LearnOpenglEs" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="learnopengles" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">LearnOpenglEs</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>OpenGL Roundup, April 10, 2014: GDC 2014 Report, libgdx 1.0, Data-Oriented Design and More…</title>
		<link>http://www.learnopengles.com/opengl-roundup-april-10-2014-gdc-2014-report-libgdx-1-0-data-oriented-design-and-more/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=opengl-roundup-april-10-2014-gdc-2014-report-libgdx-1-0-data-oriented-design-and-more</link>
		<comments>http://www.learnopengles.com/opengl-roundup-april-10-2014-gdc-2014-report-libgdx-1-0-data-oriented-design-and-more/#comments</comments>
		<pubDate>Thu, 10 Apr 2014 17:05:51 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Native Development (C, C++)]]></category>
		<category><![CDATA[Roundups]]></category>
		<category><![CDATA[asm.js]]></category>
		<category><![CDATA[data-oriented design]]></category>
		<category><![CDATA[DirectX]]></category>
		<category><![CDATA[emscripten]]></category>
		<category><![CDATA[GDC 2014]]></category>
		<category><![CDATA[GLKit]]></category>
		<category><![CDATA[in-app purchases]]></category>
		<category><![CDATA[jnigen]]></category>
		<category><![CDATA[libgdx]]></category>
		<category><![CDATA[NDK]]></category>
		<category><![CDATA[PNaCL]]></category>
		<category><![CDATA[RoboVM]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2232</guid>
		<description><![CDATA[Top stories GDC 2014 Report libgdx: We’ll go 1.0 next weekend! Recent posts A Performance Comparison Between Java and C on the Nexus 5 How Powerful Is Your Nexus 7? Finishing up Our Native Air Hockey Project with Touch Events and Basic Collision Detection Android native development Android on x86: Java Native Interface and the Android [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><strong>Top stories</strong></p>
<p><a href="http://www.altdevblogaday.com/2014/04/04/gdc-2014-report/">GDC 2014 Report</a></p>
<p>libgdx: <a href="http://www.badlogicgames.com/wordpress/">We’ll go 1.0 next weekend!</a></p>
<p><strong>Recent posts</strong></p>
<p><a href="http://www.learnopengles.com/a-performance-comparison-between-java-and-c-on-the-nexus-5/">A Performance Comparison Between Java and C on the Nexus 5</a></p>
<p><a href="http://www.learnopengles.com/how-powerful-is-your-nexus-7/">How Powerful Is Your Nexus 7?</a></p>
<p><a href="http://www.learnopengles.com/finishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection/">Finishing up Our Native Air Hockey Project with Touch Events and Basic Collision Detection</a></p>
<p><strong>Android native development</strong></p>
<p><a href="http://www.drdobbs.com/architecture-and-design/android-on-x86-java-native-interface-and/240166271">Android on x86: Java Native Interface and the Android Native Development Kit </a></p>
<p><a href="http://www.badlogicgames.com/wordpress/?p=3264">jnigen wiki page</a></p>
<p><a href="http://thebreakfastpost.com/2012/01/21/wrapping-a-c-library-with-jni-introduction/">Wrapping a C++ library with JNI – introduction</a></p>
<p><strong>Game industry &amp; development</strong></p>
<p><a href="http://www.baekdal.com/opinion/how-inapp-purchases-has-destroyed-the-industry/">How In-app Purchases Have Destroyed The Industry</a></p>
<p><a href="http://sealedabstract.com/iphone/how-in-app-purchase-is-not-really-destroying-the-games-industry/">How in-app purchase is not really destroying the games industry</a></p>
<p><a href="http://www.altdevblogaday.com/2013/11/08/how-to-become-a-graphics-programmer-in-the-games-industry/">How to become a Graphics Programmer in the games industry</a></p>
<p><a href="http://www.altdevblogaday.com/2013/11/22/the-indie-roadmap/">The indie roadmap</a></p>
<p><a href="http://blog.codinghorror.com/you-dont-need-millions-of-dollars/">You Don&#8217;t Need Millions of Dollars</a></p>
<p><strong>Online books and references</strong></p>
<p><a href="http://www.dataorienteddesign.com/dodmain/dodmain.html">Data-Oriented Design</a></p>
<p><a href="http://gameprogrammingpatterns.com/index.html">Game Programming Patterns</a></p>
<p><a href="https://wiki.mozilla.org/Platform/GFX/MobileGPUs">Platform/GFX/MobileGPUs</a></p>
<p><strong>OpenGL articles &amp; tutorials</strong></p>
<p><a href="http://t-machine.org/index.php/2013/11/09/opengl-dumb-mistakes-the-mysterious-perfect-circular-hole/">OpenGL dumb mistakes: the mysterious Perfect Circular Hole</a></p>
<p><a href="http://t-machine.org/index.php/2013/08/29/glkit-to-the-max-opengl-es-2-0-for-ios-part-1-features/">GLKit to the max: OpenGL ES 2.0 for iOS</a></p>
<p><strong>Web development</strong></p>
<p><a href="http://flohofwoe.blogspot.ca/2013/12/asset-loading-in-emscripten-and-pnacl.html">Asset loading in emscripten and PNaCl</a></p>
<p><a href="http://people.mozilla.org/~lwagner/gdc-pres/gdc-2014.html">Compiling to the Web</a></p>
<p><a href="https://blog.mozilla.org/blog/2013/12/12/first-3d-commercial-web-game-powered-by-asm-js-unveiled/">First 3D Commercial Web Game Powered By asm.js Unveiled</a></p>
<p><a href="http://acko.net/blog/on-asmjs/">On Asm.js</a></p>
<p><a href="http://multimedia.cx/eggs/playing-with-emscripten-and-asm-js/">Playing With Emscripten and ASM.js</a></p>
<p><strong>Misc</strong></p>
<p><a href="http://flohofwoe.blogspot.ca/2013/10/farewell-directx.html">Farewell DirectX</a></p>
<p><a href="http://channel9.msdn.com/Events/Build/2014/2-661">Modern C++: What you need to know</a></p>
<p><a href="http://c0de517e.blogspot.ca/2013/12/never-again-in-graphics-unforgivable.html">Never Again in Graphics: Unforgivable graphic curses.</a></p>
<p><a href="http://www.badlogicgames.com/wordpress/?p=3253">Support RoboVM (and get Java 8 and other Goodies)</a></p>
<strong><a href="http://www.learnopengles.com/opengl-roundup-april-10-2014-gdc-2014-report-libgdx-1-0-data-oriented-design-and-more/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fopengl-roundup-april-10-2014-gdc-2014-report-libgdx-1-0-data-oriented-design-and-more%2F&amp;title=OpenGL%20Roundup%2C%20April%2010%2C%202014%3A%20GDC%202014%20Report%2C%20libgdx%201.0%2C%20Data-Oriented%20Design%20and%20More%E2%80%A6" id="wpa2a_4"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/opengl-roundup-april-10-2014-gdc-2014-report-libgdx-1-0-data-oriented-design-and-more/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A performance comparison between Java and C on the Nexus 5</title>
		<link>http://www.learnopengles.com/a-performance-comparison-between-java-and-c-on-the-nexus-5/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=a-performance-comparison-between-java-and-c-on-the-nexus-5</link>
		<comments>http://www.learnopengles.com/a-performance-comparison-between-java-and-c-on-the-nexus-5/#comments</comments>
		<pubDate>Tue, 08 Apr 2014 01:31:32 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Native Development (C, C++)]]></category>
		<category><![CDATA[ART]]></category>
		<category><![CDATA[Clang]]></category>
		<category><![CDATA[clang3.4]]></category>
		<category><![CDATA[Dalvik]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[gcc4.8]]></category>
		<category><![CDATA[NDK]]></category>
		<category><![CDATA[Nexus 5]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2293</guid>
		<description><![CDATA[Android phones have been growing ever more powerful with time, with the Nexus 5 sporting a auad-core 2.3 GHz Krait 400; this is a very powerful CPU for a mobile phone. With most Android apps being written in Java, does Java allow us to access all of that power? Or, put another way, is Java [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Android phones have been growing ever more powerful with time, with the Nexus 5 sporting a auad-core 2.3 GHz Krait 400; this is a very powerful CPU for a mobile phone. With most Android apps being written in Java, does Java allow us to access all of that power? Or, put another way, is Java <em>efficient</em> enough, allowing tasks to complete more quickly and allowing the CPU to idle more, saving precious battery life?</p>
<p>In this post, I will take a look at a DSP filter adapted from coefficients generated with <a href="http://www-users.cs.york.ac.uk/~fisher/mkfilter/">mkfilter</a>, and compare three different implementations: one in C, one in Java, and one in Java with some manual optimizations. The source for these tests can be downloaded at the end of this post.</p>
<p>To compare the results, I ran the filter over an array of random data on the Nexus 5, and the compared the results to the fastest implementation. In the following table, a lower runtime is better, with the fastest implementation getting a relative runtime of 1.</p>
<table>
<colgroup>
<col />
<col />
<col /></colgroup>
<tbody>
<tr>
<th>Execution environment</th>
<th>Options</th>
<th>Relative runtime (lower is better)</th>
</tr>
<tr>
<td>gcc 4.8</td>
<td></td>
<td style="text-align: right;">1.00</td>
</tr>
<tr>
<td>gcc 4.8</td>
<td>(LOCAL_ARM_NEON := true) -ffast-math -O3</td>
<td style="text-align: right;">1.02</td>
</tr>
<tr>
<td>gcc 4.8</td>
<td>-ffast-math -O3</td>
<td style="text-align: right;">1.05</td>
</tr>
<tr>
<td>clang 3.4</td>
<td>(LOCAL_ARM_NEON := true) -ffast-math -O3</td>
<td style="text-align: right;">1.27</td>
</tr>
<tr>
<td>clang 3.4</td>
<td>-ffast-math -O3</td>
<td style="text-align: right;">1.42</td>
</tr>
<tr>
<td>clang 3.4</td>
<td></td>
<td style="text-align: right;">1.43</td>
</tr>
<tr>
<td>ART (manually-optimized)</td>
<td></td>
<td style="text-align: right;">2.22</td>
</tr>
<tr>
<td>Dalvik (manually-optimized)</td>
<td></td>
<td style="text-align: right;">2.87</td>
</tr>
<tr>
<td>ART (normal code)</td>
<td></td>
<td style="text-align: right;">7.99</td>
</tr>
<tr>
<td>Dalvik (normal code)</td>
<td></td>
<td style="text-align: right;">17.78</td>
</tr>
</tbody>
</table>
<p>The statically-compiled C code gave the best execution times, followed by ART and then by Dalvik. The C code uses JNI via <code>GetShortArrayRegion</code> and <code>SetShortArrayRegion</code> to marshal the data from Java to C, and then back from C to Java once processing has completed.</p>
<p>The best performance came courtesy of GCC 4.8, with little variation between the different additional optimization options. Clang&#8217;s ARM builds are not quite as optimized as GCC&#8217;s; toggling LOCAL_ARM_NEON := true in the NDK makefile also makes a clear difference in performance.</p>
<p>Even the slowest native build using clang is not more than 43% slower than the best native build using gcc. Once we switch to Java, the variance starts to increase significantly, with the best runtime about 2.2x slower than native code, and the worst runtime a staggering 17.8x slower.</p>
<p>What explains the large difference? For one, it appears that both ART and Dalvik are limited in the amount of static optimizations that they are capable of. This is understandable in the case of Dalvik, since it uses a JIT and it&#8217;s also much older, but it is disappointing in the case of ART, since it uses ahead-of-time compilation.</p>
<p>Is there a way to speed up the Java code? I decided to try it out, by applying the same static optimizations I would have expected the compiler to do, like converting modulo to bit masks and inlining function calls. These changes resulted in one massive and hard to read function, but they also dramatically improved the runtime performance, with Dalvik speeding up from a 17.8x penalty to 2.9x, and ART speeding up from an 8.0x penalty to 2.2x.</p>
<p>The downside of this is that the code has to be abused to get this additional performance, and it still doesn&#8217;t come close to matching the ahead-of-time code generated by gcc and clang, which can surpass that performance without similar abuse of the code. The NDK is still a viable option for those looking for improved performance and more efficient code which consumes less battery over time.</p>
<p>Just for fun, I decided to try things out on a laptop with a 2.6 GHz Intel Core i7. For this table, the relative results are in the <em>other</em> direction, with 1x corresponding to the best time on the Nexus 5, 2x being twice as fast, and so on. The table starts with the best results first, as before.</p>
<table>
<colgroup>
<col />
<col />
<col /></colgroup>
<tbody>
<tr>
<th>Execution environment</th>
<th>Options</th>
<th>Relative speed (higher is better)</th>
</tr>
<tr>
<td>clang 3.4</td>
<td>-O3 -ffast-math -flto</td>
<td style="text-align: right;">8.38x</td>
</tr>
<tr>
<td>clang 3.4</td>
<td>-O3 -ffast-math</td>
<td style="text-align: right;">6.09x</td>
</tr>
<tr>
<td>Java SE 1.7u51 (manually-optimized)</td>
<td>-XX:+AggressiveOpts</td>
<td style="text-align: right;">5.25x</td>
</tr>
<tr>
<td>Java SE 1.6u65 (manually-optimized)</td>
<td></td>
<td style="text-align: right;">3.85x</td>
</tr>
<tr>
<td>Java SE 1.6 (normal code)</td>
<td></td>
<td style="text-align: right;">2.44x</td>
</tr>
</tbody>
</table>
<p>As on the Nexus 5, the C code runs faster, but to Java&#8217;s credit, the gap between the best &amp; result result is less than 4x, which is much less variance than we see with Dalvik or ART. Java 1.6 and 1.7 are very close to each other, unless &#8220;-XX:+AggressiveOpts&#8221; is used; with that option enabled, 1.7 is able to pull ahead.</p>
<p>There is still an unfortunate gap between the &#8220;normal&#8221; code and the manually-optimized code, which really should be closable with static analysis and inlining.</p>
<p>The other interesting result is that the gap between mobile and PC is closing over time, and even more so if you take power consumption into account. It&#8217;s quite impressive to see that as far as single-core performance goes, the PC and smartphone are closer than ever.</p>
<h3>Conclusion</h3>
<p>Recent Android devices are getting very powerful, and with the new ART runtime, common Java code can be executed quickly enough to keep user interfaces responsive and users happy.</p>
<p>Sometimes, though, we need to go further, and write demanding code that needs to run quickly and efficiently. With the latest Android devices, these algorithms may be able to run quickly enough in the Dalvik VM or with ART, but then we have to ask ourselves: is the benefit of using a single language worth the cost of lower performance? This isn&#8217;t just an academic question: lower performance means that we need to ask our users to give us more CPU cycles, which shortens their device&#8217;s battery life, heats up their phones, and makes them wait longer for results, and all because we didn&#8217;t want to write the code in another language.</p>
<p>For these reasons, writing some of our code in C/C++, FORTRAN, or another native language can still make a lot of sense.</p>
<p>For more reading on this topic, check out <a href="http://www.learnopengles.com/how-powerful-is-your-nexus-7/">How Powerful is Your Nexus 7?</a></p>
<h3>Source</h3>
<h5>dsp.c</h5>
<pre class="brush: cpp; title: ; notranslate">#include &amp;quot;dsp.h&amp;quot;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;limits&amp;gt;

static constexpr int int16_min = std::numeric_limits&amp;lt;int16_t&amp;gt;::min();
static constexpr int int16_max = std::numeric_limits&amp;lt;int16_t&amp;gt;::max();

static inline int16_t clamp(int input)
{
     return std::max(int16_min, std::min(int16_max, input));
}

static inline int get_offset(const FilterState&amp;amp; filter_state, int relative_offset)
{
     return (filter_state.current + relative_offset) % filter_state.size;
}

static inline void push_sample(FilterState&amp;amp; filter_state, int16_t sample)
{
     filter_state.input[get_offset(filter_state, 0)] = sample;
     ++filter_state.current;
}

static inline int16_t get_output_sample(const FilterState&amp;amp; filter_state)
{
     return clamp(filter_state.output[get_offset(filter_state, 0)]);
}

static inline void apply_lowpass(FilterState&amp;amp; filter_state)
{
     double* x = filter_state.input;
     double* y = filter_state.output;

     y[get_offset(filter_state, 0)] =
       (  1.0 * (1.0 / 6.928330802e+06) * (x[get_offset(filter_state, -10)] + x[get_offset(filter_state,  -0)]))
     + ( 10.0 * (1.0 / 6.928330802e+06) * (x[get_offset(filter_state,  -9)] + x[get_offset(filter_state,  -1)]))
     + ( 45.0 * (1.0 / 6.928330802e+06) * (x[get_offset(filter_state,  -8)] + x[get_offset(filter_state,  -2)]))
     + (120.0 * (1.0 / 6.928330802e+06) * (x[get_offset(filter_state,  -7)] + x[get_offset(filter_state,  -3)]))
     + (210.0 * (1.0 / 6.928330802e+06) * (x[get_offset(filter_state,  -6)] + x[get_offset(filter_state,  -4)]))
     + (252.0 * (1.0 / 6.928330802e+06) *  x[get_offset(filter_state,  -5)])

     + (  -0.4441854896 * y[get_offset(filter_state, -10)])
     + (   4.2144719035 * y[get_offset(filter_state,  -9)])
     + ( -18.5365677633 * y[get_offset(filter_state,  -8)])
     + (  49.7394321983 * y[get_offset(filter_state,  -7)])
     + ( -90.1491003509 * y[get_offset(filter_state,  -6)])
     + ( 115.3235358151 * y[get_offset(filter_state,  -5)])
     + (-105.4969191433 * y[get_offset(filter_state,  -4)])
     + (  68.1964705422 * y[get_offset(filter_state,  -3)])
     + ( -29.8484881821 * y[get_offset(filter_state,  -2)])
     + (   8.0012026712 * y[get_offset(filter_state,  -1)]);
}

void apply_lowpass(FilterState&amp;amp; filter_state, const int16_t* input, int16_t* output, int length)
{
     for (int i = 0; i &amp;lt; length; ++i) {
          push_sample(filter_state, input[i]);
          apply_lowpass(filter_state);
          output[i] = get_output_sample(filter_state);
     }
}</pre>
<h5>dsp.h</h5>
<pre class="brush: cpp; title: ; notranslate">#include &amp;lt;cstdint&amp;gt;

struct FilterState {
	static constexpr int size = 16;

    double input[size];
    double output[size];
	unsigned int current;

	FilterState() : input{}, output{}, current{} {}
};

void apply_lowpass(FilterState&amp;amp; filter_state, const int16_t* input, int16_t* output, int length);</pre>
<p>Here is the Java adaptation of the C code:</p>
<pre class="brush: java; title: ; notranslate">package com.example.perftest;

import com.example.perftest.DspJavaManuallyOptimized.FilterState;

public class DspJava {
	public static class FilterState {
		static final int size = 16;

		final double input[] = new double[size];
		final double output[] = new double[size];

		int current;
	}

	static short clamp(short input) {
		return (short) Math.max(Short.MIN_VALUE, Math.min(Short.MAX_VALUE, input));
	}

	static int getOffset(FilterState filterState, int relativeOffset) {
		return ((filterState.current + relativeOffset) % FilterState.size + FilterState.size) % FilterState.size;
	}

	static void pushSample(FilterState filterState, short sample) {
		filterState.input[getOffset(filterState, 0)] = sample;
		++filterState.current;
	}

	static short getOutputSample(FilterState filterState) {
		return clamp((short) filterState.output[getOffset(filterState, 0)]);
	}
	
	static void applyLowpass(FilterState filterState) {
		final double[] x = filterState.input;
		final double[] y = filterState.output;

		y[getOffset(filterState, 0)] =
		   (  1.0 * (1.0 / 6.928330802e+06) * (x[getOffset(filterState, -10)] + x[getOffset(filterState,  -0)]))
		 + ( 10.0 * (1.0 / 6.928330802e+06) * (x[getOffset(filterState,  -9)] + x[getOffset(filterState,  -1)]))
		 + ( 45.0 * (1.0 / 6.928330802e+06) * (x[getOffset(filterState,  -8)] + x[getOffset(filterState,  -2)]))
		 + (120.0 * (1.0 / 6.928330802e+06) * (x[getOffset(filterState,  -7)] + x[getOffset(filterState,  -3)]))
		 + (210.0 * (1.0 / 6.928330802e+06) * (x[getOffset(filterState,  -6)] + x[getOffset(filterState,  -4)]))
		 + (252.0 * (1.0 / 6.928330802e+06) *  x[getOffset(filterState,  -5)])

		 + (  -0.4441854896 * y[getOffset(filterState, -10)])
		 + (   4.2144719035 * y[getOffset(filterState,  -9)])
		 + ( -18.5365677633 * y[getOffset(filterState,  -8)])
		 + (  49.7394321983 * y[getOffset(filterState,  -7)])
		 + ( -90.1491003509 * y[getOffset(filterState,  -6)])
		 + ( 115.3235358151 * y[getOffset(filterState,  -5)])
		 + (-105.4969191433 * y[getOffset(filterState,  -4)])
		 + (  68.1964705422 * y[getOffset(filterState,  -3)])
		 + ( -29.8484881821 * y[getOffset(filterState,  -2)])
		 + (   8.0012026712 * y[getOffset(filterState,  -1)]);
	}

	public static void applyLowpass(FilterState filterState, short[] input, short[] output, int length) {
		for (int i = 0; i &amp;lt; length; ++i) {
			pushSample(filterState, input[i]);
			applyLowpass(filterState);
			output[i] = getOutputSample(filterState);
		}
	}
}</pre>
<p>Since all of the Java runtimes tested don&#8217;t exploit static optimization opportunities as well as it seems that they could, here is an optimized version that has been inlined and has the modulo replaced with a bit mask:</p>
<pre class="brush: java; title: ; notranslate">package com.example.perftest;

public class DspJavaManuallyOptimized {
	public static class FilterState {
		static final int size = 16;

		final double input[] = new double[size];
		final double output[] = new double[size];

		int current;
	}

	public static void applyLowpass(FilterState filterState, short[] input, short[] output, int length) {
		for (int i = 0; i &amp;lt; length; ++i) {
			filterState.input[(filterState.current + 0) &amp;amp; (FilterState.size - 1)] = input[i];
			++filterState.current;
			final double[] x = filterState.input;
			final double[] y = filterState.output;

			y[(filterState.current + 0) &amp;amp; (FilterState.size - 1)] =
			   (  1.0 * (1.0 / 6.928330802e+06) * (x[(filterState.current + -10) &amp;amp; (FilterState.size - 1)] + x[(filterState.current + -0) &amp;amp; (FilterState.size - 1)]))
			 + ( 10.0 * (1.0 / 6.928330802e+06) * (x[(filterState.current + -9) &amp;amp; (FilterState.size - 1)] + x[(filterState.current + -1) &amp;amp; (FilterState.size - 1)]))
			 + ( 45.0 * (1.0 / 6.928330802e+06) * (x[(filterState.current + -8) &amp;amp; (FilterState.size - 1)] + x[(filterState.current + -2) &amp;amp; (FilterState.size - 1)]))
			 + (120.0 * (1.0 / 6.928330802e+06) * (x[(filterState.current + -7) &amp;amp; (FilterState.size - 1)] + x[(filterState.current + -3) &amp;amp; (FilterState.size - 1)]))
			 + (210.0 * (1.0 / 6.928330802e+06) * (x[(filterState.current + -6) &amp;amp; (FilterState.size - 1)] + x[(filterState.current + -4) &amp;amp; (FilterState.size - 1)]))
			 + (252.0 * (1.0 / 6.928330802e+06) *  x[(filterState.current + -5) &amp;amp; (FilterState.size - 1)])

			 + (  -0.4441854896 * y[(filterState.current + -10) &amp;amp; (FilterState.size - 1)])
			 + (   4.2144719035 * y[(filterState.current + -9) &amp;amp; (FilterState.size - 1)])
			 + ( -18.5365677633 * y[(filterState.current + -8) &amp;amp; (FilterState.size - 1)])
			 + (  49.7394321983 * y[(filterState.current + -7) &amp;amp; (FilterState.size - 1)])
			 + ( -90.1491003509 * y[(filterState.current + -6) &amp;amp; (FilterState.size - 1)])
			 + ( 115.3235358151 * y[(filterState.current + -5) &amp;amp; (FilterState.size - 1)])
			 + (-105.4969191433 * y[(filterState.current + -4) &amp;amp; (FilterState.size - 1)])
			 + (  68.1964705422 * y[(filterState.current + -3) &amp;amp; (FilterState.size - 1)])
			 + ( -29.8484881821 * y[(filterState.current + -2) &amp;amp; (FilterState.size - 1)])
			 + (   8.0012026712 * y[(filterState.current + -1) &amp;amp; (FilterState.size - 1)]);
			output[i] = (short) Math.max(Short.MIN_VALUE, Math.min(Short.MAX_VALUE, (short) filterState.output[(filterState.current + 0) &amp;amp; (FilterState.size - 1)]));
		}
	}
}</pre>
<strong><a href="http://www.learnopengles.com/a-performance-comparison-between-java-and-c-on-the-nexus-5/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fa-performance-comparison-between-java-and-c-on-the-nexus-5%2F&amp;title=A%20performance%20comparison%20between%20Java%20and%20C%20on%20the%20Nexus%205" id="wpa2a_8"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/a-performance-comparison-between-java-and-c-on-the-nexus-5/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>How Powerful Is Your Nexus 7?</title>
		<link>http://www.learnopengles.com/how-powerful-is-your-nexus-7/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=how-powerful-is-your-nexus-7</link>
		<comments>http://www.learnopengles.com/how-powerful-is-your-nexus-7/#comments</comments>
		<pubDate>Thu, 03 Apr 2014 18:09:46 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Articles]]></category>
		<category><![CDATA[Native Development (C, C++)]]></category>
		<category><![CDATA[ART]]></category>
		<category><![CDATA[computational fluid mechanics]]></category>
		<category><![CDATA[Dalvik]]></category>
		<category><![CDATA[FORTRAN]]></category>
		<category><![CDATA[NDK]]></category>
		<category><![CDATA[Nexus 7]]></category>
		<category><![CDATA[RenderScript]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2264</guid>
		<description><![CDATA[The following post is based on a paper generously contributed by Jerome Huck, a senior aerospace/defence engineer, scientist, and author. A link to figures and the code can be found at the bottom of this post. So you want to run some heavy-duty algorithms on your Android device, and you&#8217;re wondering what is the best environment [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><em>The following post is based on a paper generously contributed by Jerome Huck, a senior aerospace/defence engineer, scientist, and author. A link to figures and the code can be found at the bottom of this post.</em></p>
<p>So you want to run some heavy-duty algorithms on your Android device, and you&#8217;re wondering what is the best environment to use, and whether your Nexus 7 tablet would be up to the job. In this post, based upon a paper generously contributed by Jerome Huck, a senior aerospace engineer &amp; scientist, we&#8217;ll take a look at a test involving some heavy-duty computational fluid dynamics equations, and we&#8217;ll compare the execution times on a PC and a Nexus 7 tablet.</p>
<h2>Implementation languages</h2>
<p>Which language &amp; development environment is the best fit? The Eclipse SDK is one obvious choice to go, with development usually done in Java. Unlocking additional performance through native C &amp; C++ code can also be done via the Native Development Kit (NDK), though this adds complexity due to the mixing of Java, C/C++, and JNI glue code.</p>
<p>What if you want to develop directly on your device? Thanks to the openness of Google Play, there are many options available. The <a style="line-height: 1.5;" href="https://play.google.com/store/apps/details?id=com.aide.ui">Java AIDE</a> will allow you to write, compile and run programs directly on your Android tablet.</p>
<p>For native performance, C/C++ are available through <a href="https://play.google.com/store/apps/details?id=com.n0n3m4.droidc">C4DROID</a> and <a href="https://play.google.com/store/apps/details?id=com.pdaxrom.cctools">CCTOOLS</a>, an implementation of the GNU GCC 4.8.1 compiler. Fortran is also available for download from CCTOOLS&#8217;s menu.</p>
<p>Python development is available via <a style="line-height: 1.5;" href="https://play.google.com/store/search?q=QPython&amp;c=apps">QPython</a> or <a style="line-height: 1.5;" href="https://play.google.com/store/search?q=Kivy&amp;c=apps">Kivy</a>. QPython implements the Python language but is still in beta stage; the Kivy Launcher enables you to run Kivy applications, an open source Python library for rapid development. Kivy applications can also make use of innovative user interfaces, including multi-touch apps.</p>
<p>So, just how powerful is your Nexus 7? Java, Basic, C/C++, Python and Fortran all seem like good candidates to evaluate the power of a Nexus 7 with a test case.</p>
<h2>The Test Case</h2>
<p>The test developed by Jerome involves some heavy-duty math, of the type often employed by scientists and engineers. Here are the details, as specified by Jerome and edited for formatting within this post:</p>
<blockquote><p>For evaluating the performance, let&#8217;s use a test case using computational fluid dynamics algorithms, including Navier-Stokes fluid equations, the Maxwell electromagnetism equations, forming the magnetohydrodynamics (MHD) set of equations. The original Fortran code was published in <a style="line-height: 1.5;" href="http://www.amazon.com/s/?_encoding=UTF8&amp;camp=1789&amp;creative=390957&amp;field-keywords=an%20introduction%20to%20fluid%20dynamics&amp;linkCode=ur2&amp;sprefix=An%20introduction%20to%20flui%2Caps%2C464&amp;tag=digipom-20&amp;url=search-alias%3Daps" target="_blank">An Introduction to Computational Fluid Mechanics</a><img style="border: none !important; margin: 0px !important;" alt="" src="https://ir-na.amazon-adsystem.com/e/ir?t=digipom-20&amp;l=ur2&amp;o=1" width="1" height="1" border="0" /> by Chuen-Yen-Chow, in 1983. The MHD stationary flow calculation is no longer included in the 2011 update by Biringen and Chow, but the details pertaining to the equations discretization, stability analysis, and so on can still be found in their Benard and Taylor instabilities example of the instationary solution of Navier-Stokes equations coupled with the temperature equation.</p>
<p>For simplicity, a stream-vorticity formulation is used. Standard boundary conditions, or even simplified ones, are used, with a value or derivative given. Discretization of the nonlinear terms in the Navier-Stokes, the one involving the velocity components, was, historically, a source of problems. The numerical scheme has to properly capture the flow direction.</p>
<p>Upwind differencing form solves this problem. The spatial difference is on the upwind side of the point indexed (i,j). This numerical scheme is only first order by reference to a Taylor series expansion. The second order upwind schemes introduces non physical behaviour, such as oscillations. Total Variation Diminishing (TVD) schemes are a cure to this problem. They introduce stable, non-oscillatory, high order schemes, preserving monotonicity, with no overshot or undershoot for the solution. They are the result of more than 30 years of research in CFD.</p>
<p>Only the upwind scheme was present in the original Fortran code. It was rewritten using a general TVD formulation. Corner Transport Upwind (CTU) was also added as an experiment, and not fully tested. Details can be in good CFD books such as <a href="http://www.amazon.com/gp/product/0131274988/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0131274988&amp;linkCode=as2&amp;tag=digipom-20">An Introduction to Computational Fluid Dynamics: The Finite Volume Method (2nd Edition)</a><img style="border: none !important; margin: 0px !important;" alt="" src="http://ir-na.amazon-adsystem.com/e/ir?t=digipom-20&amp;l=as2&amp;o=1&amp;a=0131274988" width="1" height="1" border="0" /> by Versteeg and Malalasekera, or <a href="http://www.amazon.com/gp/product/0521009243/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0521009243&amp;linkCode=as2&amp;tag=digipom-20">Finite Volume Methods for Hyperbolic Problems</a><img style="border: none !important; margin: 0px !important;" alt="" src="http://ir-na.amazon-adsystem.com/e/ir?t=digipom-20&amp;l=as2&amp;o=1&amp;a=0521009243" width="1" height="1" border="0" /> by Leveque.</p>
<p>The solution procedure is straightforward. The current flow, RH variable, is solved via the Laplace equation solver. Then the electromagnetic force, EM variable, is computed. Time stepping is used to find the solution of the flow until the convergence criteria are matched, error or maximum step. A Poisson solver is used.</p>
<p>Comments are given in the Fortran source code.</p>
<p>The results are presented for a Reynolds number of 50, a magnetic pressure number C of 0.3, using the upwind scheme.</p></blockquote>
<h2>Execution times on a PC</h2>
<p>Before looking at the Nexus 7 results, let&#8217;s first compare the results on the PC. Here are the results that Jerome obtained on a i3 2.1 GHz laptop, running Windows 7 64-bit:</p>
<table>
<colgroup>
<col />
<col style="text-align: right;" /> </colgroup>
<tbody>
<tr>
<td>GNU Fortran</td>
<td style="text-align: right;">62ms</td>
</tr>
<tr>
<td>GNU GCC</td>
<td style="text-align: right;">78ms</td>
</tr>
<tr>
<td>Oracle Java JDK 7u45</td>
<td style="text-align: right;">150ms</td>
</tr>
<tr>
<td>PyPy 2.0</td>
<td style="text-align: right;">1020ms</td>
</tr>
<tr>
<td>Python 3.3.2</td>
<td style="text-align: right;">6780ms</td>
</tr>
</tbody>
</table>
<p>For this particular run, Fortran is the best, with C a close second; the Java JDK also put in a good showing here. The interpreted languages are very disappointing, as expected.</p>
<p>Even with the slower execution times, some scientists are still moving some their code to Python; they want to benefit from the scripting capabilities of interpreted languages. Users don&#8217;t need to edit the source code to change the boundary equations or add a subroutine to solve a particular equation. <a href="http://www.ctcms.nist.gov/fipy/">FiPy</a>, a finite volume code from NIST, uses this approach. However, most of the critical parts are still written in C or in Fortran.</p>
<p>Another approach is to use a dedicated language such the one implemented in <a href="http://www.freefem.org/ff++/">FreeFem++</a>, a partial differential equation solver. With this tool, a problem with one billion unknowns was solved in 2 minutes on the Curie Thin Node, a CEA machine. The CEA is the French Atomic Energy and Alternative Energies Commission.</p>
<h2>What does the Nexus 7 has to offer?</h2>
<p>Let&#8217;s now take a look at the results on a 1.2 GHz 2012 Nexus 7; the 2013 model, with its Qualcomm Snapdragon S4 Pro at 1.5 GHz, may boost these results a step further.</p>
<table>
<colgroup>
<col />
<col style="text-align: right;" /> </colgroup>
<tbody>
<tr>
<td>Fortran CCTOOLS with -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3 -03</td>
<td style="text-align: right;">70ms</td>
</tr>
<tr>
<td>Fortran CCTOOLS with -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3 -02</td>
<td style="text-align: right;">79ms</td>
</tr>
<tr>
<td>C99 C4DROID with -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3 -02 (64-bit floats)</td>
<td style="text-align: right;">120ms</td>
</tr>
<tr>
<td>C99 C4DROID with -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3 (32-bit floats)</td>
<td style="text-align: right;">380ms</td>
</tr>
<tr>
<td>C99 C4DROID with mfloat-abi=softfp (32-bit floats)</td>
<td style="text-align: right;">394ms</td>
</tr>
<tr>
<td>C99 C4DROID with -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3 (32-bit floats)</td>
<td style="text-align: right;">420ms</td>
</tr>
<tr>
<td>C99 C4DROID with mfloat-abi=softfp (64-bit floats)</td>
<td style="text-align: right;">450ms</td>
</tr>
<tr>
<td>C4DROID with -msoft-float (32-bit floats)</td>
<td style="text-align: right;">1163ms</td>
</tr>
<tr>
<td>C4DROID with -msoft-float (64-bit floats)</td>
<td style="text-align: right;">1500ms</td>
</tr>
<tr>
<td>Java compiled with Eclipse</td>
<td style="text-align: right;">1563ms</td>
</tr>
<tr>
<td>Java AIDE with dex optimizations</td>
<td style="text-align: right;">2100ms</td>
</tr>
<tr>
<td>Java AIDE</td>
<td style="text-align: right;">3030ms</td>
</tr>
<tr>
<td>QPython</td>
<td style="text-align: right;">24702ms</td>
</tr>
</tbody>
</table>
<p>These are the best execution times. Some variance was seen with C4DROID, while CCTOOLS was more stable overall. As before, we can see the same ranking, with Fortran emerging as the leader, and C, Java, and Python following behind. With the proper compiler flags, CCTOOLS Fortran is even competitive against the PC, which is a very good result.</p>
<p>The Java results, on the other hand, are quite bad. Is it a fault of the Dalvik virtual machine? Results may improve with the ART runtime, but they&#8217;d have to improve dramatically to come close to the performance of optimized FORTRAN and C.</p>
<p>Python, with an execution time of over 24 seconds, can definitely be forgotten for serious scientific computations.</p>
<h2>Verdict</h2>
<p>The Nexus 7 2012 is very powerful on this particular test, when running Fortran or C code compiled to native machine code. Can these good results be extrapolated to more demanding programs, and software that needs more time to run?</p>
<p>The Nexus 7 tablets are very high-quality products, and Android is a smart and fun operating system to use. The 2012 model is already quite powerful, and the 2013 should see even better results; all that&#8217;s needed is a dedicated approach to unleash the power sleeping within those processors.</p>
<p><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2014/03/paper_and_code.zip">Paper, equations, and code</a></p>
<p><em>This blog post is based on work generously contributed by Jerome Huck, a <em>senior aerospace/defence engineer, scientist, and author. </em>Jerome graduated from the École nationale supérieure de l&#8217;aéronautique et de l&#8217;espace in Toulouse, and has worked on various projects including the Hermes space shuttle, Rafale fighter, and is the author of &#8220;<a href="http://laboratoire.vulcain.pagesperso-orange.fr">The Fire of the Magicians</a>&#8220;.<br />
</em></p>
<strong><a href="http://www.learnopengles.com/how-powerful-is-your-nexus-7/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fhow-powerful-is-your-nexus-7%2F&amp;title=How%20Powerful%20Is%20Your%20Nexus%207%3F" id="wpa2a_12"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/how-powerful-is-your-nexus-7/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Finishing Up Our Native Air Hockey Project With Touch Events and Basic Collision Detection</title>
		<link>http://www.learnopengles.com/finishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=finishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection</link>
		<comments>http://www.learnopengles.com/finishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection/#comments</comments>
		<pubDate>Fri, 08 Nov 2013 14:51:43 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Air Hockey Project]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Android Tutorials]]></category>
		<category><![CDATA[Articles]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iOS Tutorials]]></category>
		<category><![CDATA[Native Development (C, C++)]]></category>
		<category><![CDATA[WebGL]]></category>
		<category><![CDATA[WebGL Tutorials]]></category>
		<category><![CDATA[emscripten]]></category>
		<category><![CDATA[linmath.h]]></category>
		<category><![CDATA[touch events]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2200</guid>
		<description><![CDATA[In this post in the air hockey series, we&#8217;re going to wrap up our air hockey project and add touch event handling and basic collision detection with support for Android, iOS, and emscripten. Prerequisites This lesson continues the air hockey project series, building upon the code from GitHub for ‘article-3-matrices-and-objects’. Here are the previous posts in this series: [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In this post in the <a href="http://www.learnopengles.com/developing-a-simple-game-of-air-hockey-using-c-and-opengl-es-2-for-android-ios-and-the-web/">air hockey series</a>, we&#8217;re going to wrap up our air hockey project and add touch event handling and basic collision detection with support for Android, iOS, and emscripten.</p>
<h3>Prerequisites</h3>
<p>This lesson continues the <a href="http://www.learnopengles.com/developing-a-simple-game-of-air-hockey-using-c-and-opengl-es-2-for-android-ios-and-the-web/">air hockey project series</a>, building upon <a href="https://github.com/learnopengles/airhockey/tree/article-3-matrices-and-objects">the code from GitHub for ‘article-3-matrices-and-objects’</a>. Here are the previous posts in this series:</p>
<h4>Setting up a simple build system</h4>
<ul>
<li><a href="http://www.learnopengles.com/calling-opengl-from-android-using-the-ndk/">Calling OpenGL from C on Android by using the NDK</a></li>
<li><a title="Calling OpenGL from C on iOS, Sharing Common Code with Android" href="http://www.learnopengles.com/calling-opengl-from-c-on-ios-sharing-common-code-with-android/" rel="bookmark">Calling OpenGL from C on iOS, Sharing Common Code with Android</a></li>
<li><a href="http://www.learnopengles.com/calling-opengl-from-c-on-the-web-by-using-emscripten-sharing-common-code-with-android-and-ios/">Calling OpenGL from C on the Web by Using Emscripten, Sharing Common Code with Android and iOS</a></li>
</ul>
<h4>Adding support for PNG loading into a texture</h4>
<ul>
<li><a href="http://www.learnopengles.com/loading-a-png-into-memory-and-displaying-it-as-a-texture-with-opengl-es-2-using-almost-the-same-code-on-ios-android-and-emscripten/">Loading a PNG into Memory and Displaying It as a Texture with OpenGL ES 2, Using (Almost) the Same Code on iOS, Android, and Emscripten</a></li>
<li><a href="http://www.learnopengles.com/loading-a-png-into-memory-and-displaying-it-as-a-texture-with-opengl-es-2-adding-support-for-ios/">Loading a PNG into Memory and Displaying It as a Texture with OpenGL ES 2: Adding Support for iOS</a></li>
<li><a href="http://www.learnopengles.com/loading-a-png-into-memory-and-displaying-it-as-a-texture-with-opengl-es-2-adding-support-for-emscripten/">Loading a PNG into Memory and Displaying It as a Texture with OpenGL ES 2: Adding Support for Emscripten</a></li>
</ul>
<h4>Adding a 3d perspective, mallets, and a puck</h4>
<ul>
<li><a href="http://www.learnopengles.com/adding-a-3d-perspective-and-object-rendering-to-our-air-hockey-project-in-native-c-code/">Adding a 3d Perspective and Object Rendering to Our Air Hockey Project in Native C Code</a></li>
</ul>
<h3>Updating our game code for touch interaction</h3>
<p>The first thing we&#8217;ll do is update the core to add touch interaction to the game. We&#8217;ll first need to add some helper functions to a new core file called <em>geometry.h</em>.</p>
<h4>geometry.h</h4>
<p>Let&#8217;s start off with the following code:</p>
<pre class="brush: cpp; title: ; notranslate">#include &quot;linmath.h&quot;
#include

typedef struct {
	vec3 point;
	vec3 vector;
} Ray;

typedef struct {
	vec3 point;
	vec3 normal;
} Plane;

typedef struct {
	vec3 center;
	float radius;
} Sphere;</pre>
<p>These are a few <code>typedef</code>s that build upon <em>linmath.h</em> to add a few basic types that we&#8217;ll use in our code. Let&#8217;s wrap up <em>geometry.h</em>:</p>
<pre class="brush: cpp; title: ; notranslate">static inline int sphere_intersects_ray(Sphere sphere, Ray ray);
static inline float distance_between(vec3 point, Ray ray);
static inline void ray_intersection_point(vec3 result, Ray ray, Plane plane);

static inline int sphere_intersects_ray(Sphere sphere, Ray ray) {
	if (distance_between(sphere.center, ray) &lt; sphere.radius)
		return 1;
	return 0;
}

static inline float distance_between(vec3 point, Ray ray) {
	vec3 p1_to_point;
	vec3_sub(p1_to_point, point, ray.point);
	vec3 p2_to_point;
	vec3 translated_ray_point;
	vec3_add(translated_ray_point, ray.point, ray.vector);
	vec3_sub(p2_to_point, point, translated_ray_point);

	// The length of the cross product gives the area of an imaginary
	// parallelogram having the two vectors as sides. A parallelogram can be
	// thought of as consisting of two triangles, so this is the same as
	// twice the area of the triangle defined by the two vectors.
	// http://en.wikipedia.org/wiki/Cross_product#Geometric_meaning
	vec3 cross_product;
	vec3_mul_cross(cross_product, p1_to_point, p2_to_point);
	float area_of_triangle_times_two = vec3_len(cross_product);
	float length_of_base = vec3_len(ray.vector);

	// The area of a triangle is also equal to (base * height) / 2. In
	// other words, the height is equal to (area * 2) / base. The height
	// of this triangle is the distance from the point to the ray.
	float distance_from_point_to_ray = area_of_triangle_times_two / length_of_base;
	return distance_from_point_to_ray;
}

// http://en.wikipedia.org/wiki/Line-plane_intersection
// This also treats rays as if they were infinite. It will return a
// point full of NaNs if there is no intersection point.
static inline void ray_intersection_point(vec3 result, Ray ray, Plane plane) {
	vec3 ray_to_plane_vector;
	vec3_sub(ray_to_plane_vector, plane.point, ray.point);

	float scale_factor = vec3_mul_inner(ray_to_plane_vector, plane.normal)
					   / vec3_mul_inner(ray.vector, plane.normal);

	vec3 intersection_point;
	vec3 scaled_ray_vector;
	vec3_scale(scaled_ray_vector, ray.vector, scale_factor);
	vec3_add(intersection_point, ray.point, scaled_ray_vector);
	memcpy(result, intersection_point, sizeof(intersection_point));
}</pre>
<p>We&#8217;ll do a <a href="http://en.wikipedia.org/wiki/Line–sphere_intersection">line-sphere intersection test</a> to see if we&#8217;ve touched the mallet using our fingers or a mouse. Once we&#8217;ve grabbed the mallet, we&#8217;ll do a <a href="http://en.wikipedia.org/wiki/Line-plane_intersection">line-plane intersection test</a> to determine where to place the mallet on the board.</p>
<h4>game.h</h4>
<p>We&#8217;ll need two new function prototypes in <em>game.h</em>:</p>
<pre class="brush: cpp; title: ; notranslate">void on_touch_press(float normalized_x, float normalized_y);
void on_touch_drag(float normalized_x, float normalized_y);</pre>
<p><strong>game.c</strong></p>
<p>Now we can begin the implementation in <em>game.c</em>. Add the following in the appropriate places to the top of the file:</p>
<pre class="brush: cpp; title: ; notranslate">#include &quot;geometry.h&quot;
// ...
static const float puck_radius = 0.06f;
static const float mallet_radius = 0.08f;

static const float left_bound = -0.5f;
static const float right_bound = 0.5f;
static const float far_bound = -0.8f;
static const float near_bound = 0.8f;
// ...
static mat4x4 inverted_view_projection_matrix;

static int mallet_pressed;
static vec3 blue_mallet_position;
static vec3 previous_blue_mallet_position;
static vec3 puck_position;
static vec3 puck_vector;

static Ray convert_normalized_2D_point_to_ray(float normalized_x, float normalized_y);
static void divide_by_w(vec4 vector);
static float clamp(float value, float min, float max);</pre>
<p>We&#8217;ll now begin with the code for handling a touch press:</p>
<pre class="brush: cpp; title: ; notranslate">void on_touch_press(float normalized_x, float normalized_y) {
	Ray ray = convert_normalized_2D_point_to_ray(normalized_x, normalized_y);

	// Now test if this ray intersects with the mallet by creating a
	// bounding sphere that wraps the mallet.
	Sphere mallet_bounding_sphere = (Sphere) {
	   {blue_mallet_position[0],
		blue_mallet_position[1],
		blue_mallet_position[2]},
	mallet_height / 2.0f};

	// If the ray intersects (if the user touched a part of the screen that
	// intersects the mallet's bounding sphere), then set malletPressed =
	// true.
	mallet_pressed = sphere_intersects_ray(mallet_bounding_sphere, ray);
}

static Ray convert_normalized_2D_point_to_ray(float normalized_x, float normalized_y) {
	// We'll convert these normalized device coordinates into world-space
	// coordinates. We'll pick a point on the near and far planes, and draw a
	// line between them. To do this transform, we need to first multiply by
	// the inverse matrix, and then we need to undo the perspective divide.
	vec4 near_point_ndc = {normalized_x, normalized_y, -1, 1};
	vec4 far_point_ndc = {normalized_x, normalized_y,  1, 1};

    vec4 near_point_world, far_point_world;
    mat4x4_mul_vec4(near_point_world, inverted_view_projection_matrix, near_point_ndc);
    mat4x4_mul_vec4(far_point_world, inverted_view_projection_matrix, far_point_ndc);

	// Why are we dividing by W? We multiplied our vector by an inverse
	// matrix, so the W value that we end up is actually the *inverse* of
	// what the projection matrix would create. By dividing all 3 components
	// by W, we effectively undo the hardware perspective divide.
    divide_by_w(near_point_world);
    divide_by_w(far_point_world);

	// We don't care about the W value anymore, because our points are now
	// in world coordinates.
	vec3 near_point_ray = {near_point_world[0], near_point_world[1], near_point_world[2]};
	vec3 far_point_ray = {far_point_world[0], far_point_world[1], far_point_world[2]};
	vec3 vector_between;
	vec3_sub(vector_between, far_point_ray, near_point_ray);
	return (Ray) {
		{near_point_ray[0], near_point_ray[1], near_point_ray[2]},
		{vector_between[0], vector_between[1], vector_between[2]}};
}

static void divide_by_w(vec4 vector) {
	vector[0] /= vector[3];
	vector[1] /= vector[3];
	vector[2] /= vector[3];
}</pre>
<p>This code first takes normalized touch coordinates which it receives from the Android, iOS or emscripten front ends, and then turns those touch coordinates into a 3D ray in world space. It then intersects the 3D ray with a bounding sphere for the mallet to see if we&#8217;ve touched the mallet.</p>
<p>Let&#8217;s continue with the code for handling a touch drag:</p>
<pre class="brush: cpp; title: ; notranslate">void on_touch_drag(float normalized_x, float normalized_y) {
	if (mallet_pressed == 0)
		return;

	Ray ray = convert_normalized_2D_point_to_ray(normalized_x, normalized_y);
	// Define a plane representing our air hockey table.
	Plane plane = (Plane) {{0, 0, 0}, {0, 1, 0}};

	// Find out where the touched point intersects the plane
	// representing our table. We'll move the mallet along this plane.
	vec3 touched_point;
	ray_intersection_point(touched_point, ray, plane);

	memcpy(previous_blue_mallet_position, blue_mallet_position,
		sizeof(blue_mallet_position));

	// Clamp to bounds
	blue_mallet_position[0] =
		clamp(touched_point[0], left_bound + mallet_radius, right_bound - mallet_radius);
	blue_mallet_position[1] = mallet_height / 2.0f;
	blue_mallet_position[2] =
		clamp(touched_point[2], 0.0f + mallet_radius, near_bound - mallet_radius);

	// Now test if mallet has struck the puck.
	vec3 mallet_to_puck;
	vec3_sub(mallet_to_puck, puck_position, blue_mallet_position);
	float distance = vec3_len(mallet_to_puck);

	if (distance &lt; (puck_radius + mallet_radius)) {
		// The mallet has struck the puck. Now send the puck flying
		// based on the mallet velocity.
		vec3_sub(puck_vector, blue_mallet_position, previous_blue_mallet_position);
	}
}

static float clamp(float value, float min, float max) {
	return fmin(max, fmax(value, min));
}</pre>
<p>Once we&#8217;ve grabbed the mallet, we move it across the air hockey table by intersecting the new touch point with the table to determine the new position on the table. We then move the mallet to that new position. We also check if the mallet has struck the puck, and if so, we use the movement distance to calculate the puck&#8217;s new velocity.</p>
<p>We next need to update the lines that initialize our objects inside <code>on_surface_created()</code> as follows:</p>
<pre class="brush: cpp; title: ; notranslate">puck = create_puck(puck_radius, puck_height, 32, puck_color);
	red_mallet = create_mallet(mallet_radius, mallet_height, 32, red);
	blue_mallet = create_mallet(mallet_radius, mallet_height, 32, blue);

	blue_mallet_position[0] = 0;
	blue_mallet_position[1] = mallet_height / 2.0f;
	blue_mallet_position[2] = 0.4f;
	puck_position[0] = 0;
	puck_position[1] = puck_height / 2.0f;
	puck_position[2] = 0;
	puck_vector[0] = 0;
	puck_vector[1] = 0;
	puck_vector[2] = 0;</pre>
<p>The new <em>linmath.h</em> has merged in the custom code we added to our <em>matrix_helper.h</em>, so we no longer need that file. As part of those changes, our perspective method call in <code>on_surface_changed()</code> now needs the angle entered in radians, so let&#8217;s update that method call as follows:</p>
<pre class="brush: cpp; title: ; notranslate">mat4x4_perspective(projection_matrix, deg_to_radf(45),
	(float) width / (float) height, 1.0f, 10.0f);</pre>
<p>We can then update <code>on_draw_frame()</code> to add the new movement code. Let&#8217;s first add the following to the top, right after the call to <code>glClear()</code>:</p>
<pre class="brush: cpp; title: ; notranslate">// Translate the puck by its vector
	vec3_add(puck_position, puck_position, puck_vector);

	// If the puck struck a side, reflect it off that side.
	if (puck_position[0] &lt; left_bound + puck_radius 
	 || puck_position[0] &gt; right_bound - puck_radius) {
		puck_vector[0] = -puck_vector[0];
		vec3_scale(puck_vector, puck_vector, 0.9f);
	}
	if (puck_position[2] &lt; far_bound + puck_radius
	 || puck_position[2] &gt; near_bound - puck_radius) {
		puck_vector[2] = -puck_vector[2];
		vec3_scale(puck_vector, puck_vector, 0.9f);
	}

	// Clamp the puck position.
	puck_position[0] = 
		clamp(puck_position[0], left_bound + puck_radius, right_bound - puck_radius);
	puck_position[2] = 
		clamp(puck_position[2], far_bound + puck_radius, near_bound - puck_radius);

	// Friction factor
	vec3_scale(puck_vector, puck_vector, 0.99f);</pre>
<p>This code will update the puck&#8217;s position and cause it to go bouncing around the table. We&#8217;ll also need to add the following after the call to <code>mat4x4_mul(view_projection_matrix, projection_matrix, view_matrix);</code>:</p>
<pre class="brush: cpp; title: ; notranslate">mat4x4_invert(inverted_view_projection_matrix, view_projection_matrix);</pre>
<p>This sets up the inverted view projection matrix, which we need for turning the normalized touch coordinates back into world space coordinates.</p>
<p>Let&#8217;s finish up the changes to <em>game.c</em> by updating the following calls to <code>position_object_in_scene()</code>:</p>
<pre class="brush: cpp; title: ; notranslate">position_object_in_scene(blue_mallet_position[0], blue_mallet_position[1],
	blue_mallet_position[2]);
// ...
position_object_in_scene(puck_position[0], puck_position[1], puck_position[2]);</pre>
<h3>Adding touch events to Android</h3>
<p>With these changes in place, we now need to link in the touch events from each platform. We&#8217;ll start off with Android:</p>
<h4>MainActivity.java</h4>
<p>In <i>MainActivity.java</i>, we first need to update the way that we create the renderer in <code>onCreate()</code>:</p>
<pre class="brush: java; title: ; notranslate">final RendererWrapper rendererWrapper = new RendererWrapper(this);
// ...
glSurfaceView.setRenderer(rendererWrapper);</pre>
<p>Let&#8217;s add the touch listener:</p>
<pre class="brush: java; title: ; notranslate">glSurfaceView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
	if (event != null) {
		// Convert touch coordinates into normalized device
		// coordinates, keeping in mind that Android's Y
		// coordinates are inverted.
		final float normalizedX = (event.getX() / (float) v.getWidth()) * 2 - 1;
		final float normalizedY = -((event.getY() / (float) v.getHeight()) * 2 - 1);

		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			glSurfaceView.queueEvent(new Runnable() {
			@Override
			public void run() {
				rendererWrapper.handleTouchPress(normalizedX, normalizedY);
			}});
		} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
			glSurfaceView.queueEvent(new Runnable() {
			@Override
			public void run() {
				rendererWrapper.handleTouchDrag(normalizedX, normalizedY);
			}});
		}

		return true;
	} else {
		return false;
	}
}});</pre>
<p>This touch listener takes the incoming touch events from the user, converts them into normalized coordinates in OpenGL&#8217;s normalized device coordinate space, and then calls the renderer wrapper which will pass the event on into our native code.</p>
<h4>RendererWrapper.java</h4>
<p>We&#8217;ll need to add the following to <em>RendererWrapper.java</em>:</p>
<pre class="brush: java; title: ; notranslate">public void handleTouchPress(float normalizedX, float normalizedY) {
		on_touch_press(normalizedX, normalizedY);
	}

	public void handleTouchDrag(float normalizedX, float normalizedY) {
		on_touch_drag(normalizedX, normalizedY);
	}

	private static native void on_touch_press(float normalized_x, float normalized_y);

	private static native void on_touch_drag(float normalized_x, float normalized_y);</pre>
<h4>renderer_wrapper.c</h4>
<p>We&#8217;ll also need to add the following to <em>renderer_wrapper.c</em> in our <em>jni</em> folder:</p>
<pre class="brush: cpp; title: ; notranslate">JNIEXPORT void JNICALL Java_com_learnopengles_airhockey_RendererWrapper_on_1touch_1press(
	JNIEnv* env, jclass cls, jfloat normalized_x, jfloat normalized_y) {
	UNUSED(env);
	UNUSED(cls);
	on_touch_press(normalized_x, normalized_y);
}

JNIEXPORT void JNICALL Java_com_learnopengles_airhockey_RendererWrapper_on_1touch_1drag(
	JNIEnv* env, jclass cls, jfloat normalized_x, jfloat normalized_y) {
	UNUSED(env);
	UNUSED(cls);
	on_touch_drag(normalized_x, normalized_y);
}</pre>
<p>We now have everything in place for Android, and if we run the app, it should look similar to as seen below:</p>
<div id="attachment_2208" style="width: 178px" class="wp-caption aligncenter"><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/11/air-hockey-with-touch-android.png"><img class="size-medium wp-image-2208" alt="Air Hockey with touch, running on a Galaxy Nexus" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/11/air-hockey-with-touch-android-168x300.png" width="168" height="300" /></a><p class="wp-caption-text">Air Hockey with touch, running on a Galaxy Nexus</p></div>
<h3>Adding support for iOS</h3>
<p>To add support for iOS, we need to update <em>ViewController.m</em> and add support for touch events. To do that and update the frame rate at the same time, let&#8217;s add the following to <code>viewDidLoad:</code> before the call to <code>[self setupGL]</code>:</p>
<pre class="brush: objc; title: ; notranslate">view.userInteractionEnabled = YES;
self.preferredFramesPerSecond = 60;</pre>
<p>To listen to the touch events, we need to override a few methods. Let&#8217;s add the following methods before <code>- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect</code>:</p>
<pre class="brush: objc; title: ; notranslate">static CGPoint getNormalizedPoint(UIView* view, CGPoint locationInView)
{
    const float normalizedX = (locationInView.x / view.bounds.size.width) * 2.f - 1.f;
    const float normalizedY = -((locationInView.y / view.bounds.size.height) * 2.f - 1.f);
    return CGPointMake(normalizedX, normalizedY);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    UITouch* touchEvent = [touches anyObject];
    CGPoint locationInView = [touchEvent locationInView:self.view];
    CGPoint normalizedPoint = getNormalizedPoint(self.view, locationInView);
    on_touch_press(normalizedPoint.x, normalizedPoint.y);
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    UITouch* touchEvent = [touches anyObject];
    CGPoint locationInView = [touchEvent locationInView:self.view];
    CGPoint normalizedPoint = getNormalizedPoint(self.view, locationInView);
    on_touch_drag(normalizedPoint.x, normalizedPoint.y);
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
}</pre>
<p>This is similar to the Android code in that it takes the input touch event, converts it to OpenGL&#8217;s normalized device coordinate space, and then sends it on to our game code.</p>
<p>Our iOS app should look similar to the following image:</p>
<div id="attachment_2221" style="width: 169px" class="wp-caption aligncenter"><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/11/airhockey-with-touch-on-ios.png"><img src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/11/airhockey-with-touch-on-ios-159x300.png" alt="Air Hockey with touch, on iOS" width="159" height="300" class="size-medium wp-image-2221" /></a><p class="wp-caption-text">Air Hockey with touch, on iOS</p></div>
<h3>Adding support for emscripten</h3>
<p>Adding support for emscripten is just as easy. Let&#8217;s first add the following to the top of <em>main.c</em>:</p>
<pre class="brush: cpp; title: ; notranslate">static void handle_input();
// ...
int is_dragging;</pre>
<p>At the beginning of <code>do_frame()</code>, add a call to <code>handle_input();</code>:</p>
<pre class="brush: cpp; title: ; notranslate">static void do_frame()
{
	handle_input();
	// ...</pre>
<p>Add the following for <code>handle_input</code>:</p>
<pre class="brush: cpp; title: ; notranslate">static void handle_input()
{
	glfwPollEvents();
	const int left_mouse_button_state = glfwGetMouseButton(GLFW_MOUSE_BUTTON_1);
	if (left_mouse_button_state == GLFW_PRESS) {
		int x_pos, y_pos;
		glfwGetMousePos(&amp;x_pos, &amp;y_pos);
		const float normalized_x = ((float)x_pos / (float) width) * 2.f - 1.f;
	    const float normalized_y = -(((float)y_pos / (float) height) * 2.f - 1.f);

		if (is_dragging == 0) {
			is_dragging = 1;
			on_touch_press(normalized_x, normalized_y);
		} else {
			on_touch_drag(normalized_x, normalized_y);
		}
	} else {
		is_dragging = 0;
	}
}</pre>
<p>This code sets <code>is_dragging</code> depending on whether we just clicked the primary mouse button or if we&#8217;re currently dragging the mouse. Depending on the case, we&#8217;ll call either <code>on_touch_press</code> or <code> on_touch_drag</code>. The code to normalize the coordinates is the same as in Android and iOS, and indeed a case could be made to abstract out into the common game code, and just pass in the raw coordinates relative to the view size to that game code.</p>
<p>After compiling with <em>emcc make</em>, we should get output similar to the below:</p>
<div align="center"><iframe src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/11/airhockey.html" height="1030" width="100%" align="middle"></iframe></div>
<h3>Exploring further</h3>
<p>That concludes our air hockey project! The full source code for this lesson can be found at the <a href="https://github.com/learnopengles/airhockey/tree/article-4-adding-touch">GitHub project</a>. You can find a more in-depth look at the concepts behind the project from the perspective of Java Android in <a href="http://pragprog.com/book/kbogla/opengl-es-2-for-android">OpenGL ES 2 for Android: A Quick-Start Guide</a>. For exploring further, there are many things you could add, like improved graphics, support for sound, a simple AI, multiplayer (on the same device), scoring, or a menu system.</p>
<p>Whether you end up using a commercial cross-platform solution like <a href="http://wiki.unity3d.com/index.php/Main_Page">Unity</a> or <a href="http://en.wikipedia.org/wiki/Corona_(software_development_kit)">Corona</a>, or whether you decide to go the independent route, I hope this series was helpful to you and most importantly, that you enjoy your future projects ahead and have a lot of fun with them. <img src="http://www.learnopengles.com/wordpress/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> </p>
<strong><a href="http://www.learnopengles.com/finishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Ffinishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection%2F&amp;title=Finishing%20Up%20Our%20Native%20Air%20Hockey%20Project%20With%20Touch%20Events%20and%20Basic%20Collision%20Detection" id="wpa2a_16"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/finishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OpenGL Roundup, November 4, 2013</title>
		<link>http://www.learnopengles.com/opengl-roundup-november-4-2013/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=opengl-roundup-november-4-2013</link>
		<comments>http://www.learnopengles.com/opengl-roundup-november-4-2013/#comments</comments>
		<pubDate>Mon, 04 Nov 2013 18:55:43 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Native Development (C, C++)]]></category>
		<category><![CDATA[Roundups]]></category>
		<category><![CDATA[WebGL]]></category>
		<category><![CDATA[libgdx]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2193</guid>
		<description><![CDATA[Android 4.4 for Game Developers APPS WORLD LONDON 2013 New Adventures in C++ with Cinder and More Objectively Stylish &#8211; The NYTimes Objective-C style guide. Vivante Unveils Less than 1 mm2 OpenGL ES 2.0 GPU for Wearables and Internet of Things (IoT) Devices Why use a Graphics Library instead of an Engine? (Ex: OpenGL vs Unity) &#8211; [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.badlogicgames.com/wordpress/?p=3231">Android 4.4 for Game Developers</a></p>
<p><a href="http://www.badlogicgames.com/wordpress/?p=3224">APPS WORLD LONDON 2013</a></p>
<p><a href="http://isocpp.org/blog/2013/10/new-adventures-in-cxx-with-cinder-and-more">New Adventures in C++ with Cinder and More</a></p>
<p><a href="http://open.blogs.nytimes.com/2013/08/01/objectively-stylish/">Objectively Stylish</a> &#8211; The <a href="https://github.com/NYTimes/objective-c-style-guide">NYTimes Objective-C style guide</a>.</p>
<p id="h1Headline"><a href="http://www.prnewswire.com/news-releases/vivante-unveils-less-than-1-mm2-opengl-es-20-gpu-for-wearables-and-internet-of-things-iot-devices-226732531.html">Vivante Unveils Less than 1 mm2 OpenGL ES 2.0 GPU for Wearables and Internet of Things (IoT) Devices</a></p>
<p><a href="http://www.gamedev.net/topic/649480-why-use-a-graphics-library-instead-of-an-engine-ex-opengl-vs-unity/">Why use a Graphics Library instead of an Engine? (Ex: OpenGL vs Unity) &#8211; Graphics Programmin<wbr />g and Theory &#8211; GameDev.ne<wbr />t</a></p>
<p>From the <a href="http://www.badlogicgames.com/wordpress/?p=3236">libgdx blog</a>: &#8220;<a href="http://software.intel.com/" target="_blank">Intel Developer Zone</a> and <a href="http://bit.ly/18dUwpW" target="_blank">BeMyApp</a> are holding a couple of code fests over the next few weeks in <a href="http://androidcodefest.bemyapp.com/" target="_blank">Berlin</a>, <a href="http://codefest.bemyapp.com/" target="_blank">New York and Santa Clara</a>. During these events, Intel will help you port your Android apps using native code to x86, free of charge!&#8221;</p>
<p>Check out the source code for the new <a href="http://acko.net">acko.net</a> front end: <a href="https://github.com/unconed/fuse10/">https://github.com/unconed/fuse10/</a>.</p>
<strong><a href="http://www.learnopengles.com/opengl-roundup-november-4-2013/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fopengl-roundup-november-4-2013%2F&amp;title=OpenGL%20Roundup%2C%20November%204%2C%202013" id="wpa2a_20"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/opengl-roundup-november-4-2013/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL Roundup, October 28, 2013: Narasimha Live Wallpaper, Military Mobile and more…</title>
		<link>http://www.learnopengles.com/opengl-roundup-october-28-2013-narasimha-live-wallpaper-military-mobile-and-more/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=opengl-roundup-october-28-2013-narasimha-live-wallpaper-military-mobile-and-more</link>
		<comments>http://www.learnopengles.com/opengl-roundup-october-28-2013-narasimha-live-wallpaper-military-mobile-and-more/#comments</comments>
		<pubDate>Mon, 28 Oct 2013 17:17:58 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Roundups]]></category>
		<category><![CDATA[Live wallpapers]]></category>
		<category><![CDATA[Military Mobile]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2170</guid>
		<description><![CDATA[This time around, we have some new live wallpapers as well as a new Android application using OpenGL ES 2.0. Check them out below&#8230; 3D Ganesh Live Wallpaper https://play.google.com/store/apps/details?id=com.justharinama.ganeshlivewallpaper 3D Narasimha Live Wallpaper https://play.google.com/store/apps/details?id=com.justharinaam.narasimha 3D Jagannath Live Wallpaper https://play.google.com/store/apps/details?id=com.justharinama.skynormalwall Military Mobile Military Mobile features accurate information regarding Military Bases, Military Ribbons, and Military Ranks. Military [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>This time around, we have some new live wallpapers as well as a new Android application using OpenGL ES 2.0. Check them out below&#8230;</p>
<h3>3D Ganesh Live Wallpaper</h3>
<p><a href="https://play.google.com/store/apps/details?id=com.justharinama.ganeshlivewallpaper"><img class="aligncenter size-medium wp-image-2174" alt="3d-ganesh-live-wallpaper" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/10/3d-ganesh-live-wallpaper-168x300.jpg" width="168" height="300" /></a></p>
<p><a href="https://play.google.com/store/apps/details?id=com.justharinama.ganeshlivewallpaper">https://play.google.com/store/apps/details?id=com.justharinama.ganeshlivewallpaper</a></p>
<h3>3D Narasimha Live Wallpaper</h3>
<p><a href="https://play.google.com/store/apps/details?id=com.justharinaam.narasimha"><img class="aligncenter size-medium wp-image-2176" alt="3d-narasimha-live-wallpaper" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/10/3d-narasimha-live-wallpaper-168x300.jpg" width="168" height="300" /></a></p>
<p><a href="3D Narasimha Live Wallpaper">https://play.google.com/store/apps/details?id=com.justharinaam.narasimha</a></p>
<h3>3D Jagannath Live Wallpaper</h3>
<p><a href="https://play.google.com/store/apps/details?id=com.justharinama.skynormalwall"><img class="aligncenter size-medium wp-image-2178" alt="3d-jagannath-live-wallpaper" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/10/3d-jagannath-live-wallpaper-168x300.jpg" width="168" height="300" /></a></p>
<p><a href="https://play.google.com/store/apps/details?id=com.justharinama.skynormalwall">https://play.google.com/store/apps/details?id=com.justharinama.skynormalwall</a></p>
<h3>Military Mobile</h3>
<div><a href="https://play.google.com/store/apps/details?id=com.savageking.empireofbases">Military Mobile</a> features accurate information regarding Military Bases, Military Ribbons, and Military Ranks. Military Mobile also comes with quizzes on US Military subject matter, as well as a rich set of social features.</div>
<div align="center"><a href="https://play.google.com/store/apps/details?id=com.savageking.empireofbases"><img class="size-medium wp-image-2182" alt="military-mobile-1" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/10/military-mobile-1-168x300.png" width="168" height="300" /></a>&nbsp;<a href="https://play.google.com/store/apps/details?id=com.savageking.empireofbases"><img class="size-medium wp-image-2183" alt="military-mobile-2" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/10/military-mobile-2-168x300.png" width="168" height="300" /></a>&nbsp;<a href="https://play.google.com/store/apps/details?id=com.savageking.empireofbases"><img class="size-medium wp-image-2184" alt="military-mobile-3" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/10/military-mobile-3-168x300.png" width="168" height="300" /></a></div>
<p>&nbsp;<br />
<a href="https://play.google.com/store/apps/details?id=com.savageking.empireofbases">https://play.google.com/store/apps/details?id=com.savageking.empireofbases</a></p>
<div><a href="https://play.google.com/store/apps/details?id=com.savageking.empireofbases"><img class="aligncenter size-medium wp-image-2180" alt="militarymobile_qrcode" src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/10/militarymobile_qrcode-300x300.png" width="300" height="300" /></a></div>
<div>You can also <a href="https://www.facebook.com/pages/Military-Mobile/166169226920321">check out the Facebook page here</a>.</div>
<p>&nbsp;<br />
Until next time!</p>
<strong><a href="http://www.learnopengles.com/opengl-roundup-october-28-2013-narasimha-live-wallpaper-military-mobile-and-more/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fopengl-roundup-october-28-2013-narasimha-live-wallpaper-military-mobile-and-more%2F&amp;title=OpenGL%20Roundup%2C%20October%2028%2C%202013%3A%20Narasimha%20Live%20Wallpaper%2C%20Military%20Mobile%20and%20more%E2%80%A6" id="wpa2a_24"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/opengl-roundup-october-28-2013-narasimha-live-wallpaper-military-mobile-and-more/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL Roundup, October 1, 2013: Hexscreen 3D Live Wallpaper and more…</title>
		<link>http://www.learnopengles.com/opengl-roundup-october-1-2013-hexscreen-3d-live-wallpaper-and-more/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=opengl-roundup-october-1-2013-hexscreen-3d-live-wallpaper-and-more</link>
		<comments>http://www.learnopengles.com/opengl-roundup-october-1-2013-hexscreen-3d-live-wallpaper-and-more/#comments</comments>
		<pubDate>Fri, 20 Sep 2013 14:58:15 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Roundups]]></category>
		<category><![CDATA[libgdx]]></category>
		<category><![CDATA[Live wallpaper]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2157</guid>
		<description><![CDATA[A fellow developer and blogger, Hisham, has released his Hexscreen 3D Live Wallpaper to the market, and it looks quite cool. Check it out: The wallpaper can be downloaded from Google Play. In other news&#8230; Libgdx and Bullet Physics on iOS via RoboVM Comment on the blog Copyright &#169; 2012 This work is licensed under [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>A fellow developer and blogger, Hisham, has released his <a href="http://ghoshehsoft.wordpress.com/2013/09/20/hexscreen-3d-live-wallapper-for-your-android/">Hexscreen 3D Live Wallpaper</a> to the market, and it looks quite cool. Check it out:</p>
<p><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/hexscreen-1.png"><img src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/hexscreen-1-300x187.png" alt="Hexscreen" width="300" height="187" class="aligncenter size-medium wp-image-2164" /></a></p>
<p><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/hexscreen-2.png"><img src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/hexscreen-2-300x175.png" alt="Hexscreen" width="300" height="175" class="aligncenter size-medium wp-image-2165" /></a></p>
<p><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/hexscreen-3.png"><img src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/hexscreen-3-168x300.png" alt="Hexscreen" width="168" height="300" class="aligncenter size-medium wp-image-2166" /></a></p>
<p>The wallpaper can be downloaded from <a href="https://play.google.com/store/apps/details?id=com.ghoscher.hexscreen">Google Play</a>.</p>
<p>In other news&#8230;</p>
<p><a href="http://www.badlogicgames.com/wordpress/?p=3211">Libgdx and Bullet Physics on iOS via RoboVM</a></p>
<strong><a href="http://www.learnopengles.com/opengl-roundup-october-1-2013-hexscreen-3d-live-wallpaper-and-more/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fopengl-roundup-october-1-2013-hexscreen-3d-live-wallpaper-and-more%2F&amp;title=OpenGL%20Roundup%2C%20October%201%2C%202013%3A%20Hexscreen%203D%20Live%20Wallpaper%20and%20more%E2%80%A6" id="wpa2a_28"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/opengl-roundup-october-1-2013-hexscreen-3d-live-wallpaper-and-more/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL Roundup, September 19, 2013</title>
		<link>http://www.learnopengles.com/opengl-roundup-september-19-2013/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=opengl-roundup-september-19-2013</link>
		<comments>http://www.learnopengles.com/opengl-roundup-september-19-2013/#comments</comments>
		<pubDate>Thu, 19 Sep 2013 15:30:19 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Native Development (C, C++)]]></category>
		<category><![CDATA[Roundups]]></category>
		<category><![CDATA[WebGL]]></category>
		<category><![CDATA[libgdx]]></category>
		<category><![CDATA[RoboVM]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2107</guid>
		<description><![CDATA[Here&#8217;s the beginning of a new series on OpenGL ES 2.0 for iOS, using Apple&#8217;s GLKit. GLKit to the max: OpenGL ES 2.0 for iOS – Part 1: GLKit Features OpenGL ES 2: How does it draw? ROBOVM BACKEND IN LIBGDX NIGHTLIES AND FIRST PERFORMANCE FIGURES! - Libgdx is moving to a new backend for iOS [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s the beginning of a new series on OpenGL ES 2.0 for iOS, using Apple&#8217;s GLKit.</p>
<ul>
<li><a href="http://www.altdevblogaday.com/2013/08/29/glkit-to-the-max-opengl-es-2-0-for-ios-part-1-glkit-features/">GLKit to the max: OpenGL ES 2.0 for iOS – Part 1: GLKit Features</a></li>
<li><a href="http://www.altdevblogaday.com/2013/09/09/opengl-es-2-how-does-it-draw/">OpenGL ES 2: How does it draw?</a></li>
</ul>
<p><a href="http://www.badlogicgames.com/wordpress/?p=3161">ROBOVM BACKEND IN LIBGDX NIGHTLIES AND FIRST PERFORMANCE FIGURES!</a> - Libgdx is moving to a new backend for iOS that uses <a href="http://www.robovm.org/">RoboVM</a>, a Java to machine code compiler for iOS. Initial performance figures look good!</p>
<p><a href="http://acko.net/blog/zero-to-sixty-in-one-second/">Zero to Sixty in One Second</a> - the developer &amp; designer behind acko.net has redesigned his header and website using WebGL, and I have to say that it looks very cool.</p>
<p>And now for something completely different&#8230;</p>
<p><a href="http://molecularmusings.wordpress.com/2013/08/27/using-runtime-compiled-c-code-as-a-scripting-language/">Using runtime-compiled C++ code as a scripting language</a>.</p>
<strong><a href="http://www.learnopengles.com/opengl-roundup-september-19-2013/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fopengl-roundup-september-19-2013%2F&amp;title=OpenGL%20Roundup%2C%20September%2019%2C%202013" id="wpa2a_32"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/opengl-roundup-september-19-2013/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adding a 3d Perspective and Object Rendering to Our Air Hockey Project in Native C Code</title>
		<link>http://www.learnopengles.com/adding-a-3d-perspective-and-object-rendering-to-our-air-hockey-project-in-native-c-code/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=adding-a-3d-perspective-and-object-rendering-to-our-air-hockey-project-in-native-c-code</link>
		<comments>http://www.learnopengles.com/adding-a-3d-perspective-and-object-rendering-to-our-air-hockey-project-in-native-c-code/#comments</comments>
		<pubDate>Wed, 18 Sep 2013 11:45:27 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Air Hockey Project]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Android Tutorials]]></category>
		<category><![CDATA[Articles]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iOS Tutorials]]></category>
		<category><![CDATA[Native Development (C, C++)]]></category>
		<category><![CDATA[WebGL]]></category>
		<category><![CDATA[WebGL Tutorials]]></category>
		<category><![CDATA[emscripten]]></category>
		<category><![CDATA[linmath.h]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2111</guid>
		<description><![CDATA[For this post in the air hockey series, we&#8217;ll learn how to render our scene from a 3D perspective, as well as how to add a puck and two mallets to the scene. We&#8217;ll also see how easy it is to bring these changes to Android, iOS, and emscripten. Prerequisites This lesson continues the air [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>For this post in the <a href="http://www.learnopengles.com/developing-a-simple-game-of-air-hockey-using-c-and-opengl-es-2-for-android-ios-and-the-web/">air hockey series</a>, we&#8217;ll learn how to render our scene from a 3D perspective, as well as how to add a puck and two mallets to the scene. We&#8217;ll also see how easy it is to bring these changes to Android, iOS, and emscripten.</p>
<h3>Prerequisites</h3>
<p>This lesson continues the <a href="http://www.learnopengles.com/developing-a-simple-game-of-air-hockey-using-c-and-opengl-es-2-for-android-ios-and-the-web/">air hockey project series</a>, building upon <a href="https://github.com/learnopengles/airhockey/tree/article-2-loading-png-file">the code from GitHub for ‘article-2-loading-png-file’</a>. Here are the previous posts in this series:</p>
<h4>Setting up a simple build system</h4>
<ul>
<li><a href="http://www.learnopengles.com/calling-opengl-from-android-using-the-ndk/">Calling OpenGL from C on Android by using the NDK</a></li>
<li><a title="Calling OpenGL from C on iOS, Sharing Common Code with Android" href="http://www.learnopengles.com/calling-opengl-from-c-on-ios-sharing-common-code-with-android/" rel="bookmark">Calling OpenGL from C on iOS, Sharing Common Code with Android</a></li>
<li><a href="http://www.learnopengles.com/calling-opengl-from-c-on-the-web-by-using-emscripten-sharing-common-code-with-android-and-ios/">Calling OpenGL from C on the Web by Using Emscripten, Sharing Common Code with Android and iOS</a></li>
</ul>
<h4>Adding support for PNG loading into a texture</h4>
<ul>
<li><a href="http://www.learnopengles.com/loading-a-png-into-memory-and-displaying-it-as-a-texture-with-opengl-es-2-using-almost-the-same-code-on-ios-android-and-emscripten/">Loading a PNG into Memory and Displaying It as a Texture with OpenGL ES 2, Using (Almost) the Same Code on iOS, Android, and Emscripten</a></li>
<li><a href="http://www.learnopengles.com/loading-a-png-into-memory-and-displaying-it-as-a-texture-with-opengl-es-2-adding-support-for-ios/">Loading a PNG into Memory and Displaying It as a Texture with OpenGL ES 2: Adding Support for iOS</a></li>
<li><a href="http://www.learnopengles.com/loading-a-png-into-memory-and-displaying-it-as-a-texture-with-opengl-es-2-adding-support-for-emscripten/">Loading a PNG into Memory and Displaying It as a Texture with OpenGL ES 2: Adding Support for Emscripten</a></li>
</ul>
<h3>Adding support for a matrix library</h3>
<p>The first thing we&#8217;ll do is add support for a matrix library so we can use the same matrix math on all three platforms, and then we&#8217;ll introduce the changes to our code from the top down. There are a lot of libraries out there, so I decided to use <a href="https://github.com/datenwolf/linmath.h">linmath.h</a> by Wolfgang Draxinger for its simplicity and compactness. Since it&#8217;s on GitHub, we can easily add it to our project by running the following git command from the root <em>airhockey/</em> folder:</p>
<p><code>git submodule add https://github.com/datenwolf/linmath.h.git src/3rdparty/linmath</code></p>
<h3>Updating our game code</h3>
<p>We&#8217;ll introduce all of the changes from the top down, so let&#8217;s begin by replacing everything inside <em>game.c</em> as follows:</p>
<h4>Headers and declarations</h4>
<pre class="brush: cpp; title: ; notranslate">#include &quot;game.h&quot;
#include &quot;game_objects.h&quot;
#include &quot;asset_utils.h&quot;
#include &quot;buffer.h&quot;
#include &quot;image.h&quot;
#include &quot;linmath.h&quot;
#include &quot;math_helper.h&quot;
#include &quot;matrix.h&quot;
#include &quot;platform_gl.h&quot;
#include &quot;platform_asset_utils.h&quot;
#include &quot;program.h&quot;
#include &quot;shader.h&quot;
#include &quot;texture.h&quot;

static const float puck_height = 0.02f;
static const float mallet_height = 0.15f;

static Table table;
static Puck puck;
static Mallet red_mallet;
static Mallet blue_mallet;

static TextureProgram texture_program;
static ColorProgram color_program;

static mat4x4 projection_matrix;
static mat4x4 model_matrix;
static mat4x4 view_matrix;

static mat4x4 view_projection_matrix;
static mat4x4 model_view_projection_matrix;

static void position_table_in_scene();
static void position_object_in_scene(float x, float y, float z);</pre>
<p>We&#8217;ve added all of the new includes, constants, variables, and function declarations that we&#8217;ll need for our new game code. We&#8217;ll use <code>Table</code>, <code>Puck</code>, and <code>Mallet</code> to represent our drawable objects, <code>TextureProgram</code> and <code>ColorProgram</code> to represent our shader programs, and the <code>mat4x4</code> (a datatype from linmath.h) matrices for our OpenGL matrices. In our draw loop, we&#8217;ll call position_table_in_scene() to position the table, and position_object_in_scene() to position our other objects.</p>
<p>For those of you who have also followed the Java tutorials from <a href="http://pragprog.com/book/kbogla/opengl-es-2-for-android">OpenGL ES 2 for Android: A Quick-Start Guide</a>, you&#8217;ll recognize that this has a lot in common with the air hockey project from the first part of the book. The code for that project can be freely downloaded from <a href="http://pragprog.com/titles/kbogla/source_code">The Pragmatic Bookshelf</a>.</p>
<h4><code>on_surface_created()</code></h4>
<pre class="brush: cpp; title: ; notranslate">void on_surface_created() {
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glEnable(GL_DEPTH_TEST);

	table = create_table(
		load_png_asset_into_texture(&quot;textures/air_hockey_surface.png&quot;));

	vec4 puck_color = {0.8f, 0.8f, 1.0f, 1.0f};
	vec4 red = {1.0f, 0.0f, 0.0f, 1.0f};
	vec4 blue = {0.0f, 0.0f, 1.0f, 1.0f};

	puck = create_puck(0.06f, puck_height, 32, puck_color);
	red_mallet = create_mallet(0.08f, mallet_height, 32, red);
	blue_mallet = create_mallet(0.08f, mallet_height, 32, blue);

	texture_program = get_texture_program(build_program_from_assets(
		&quot;shaders/texture_shader.vsh&quot;, &quot;shaders/texture_shader.fsh&quot;));
	color_program = get_color_program(build_program_from_assets(
		&quot;shaders/color_shader.vsh&quot;, &quot;shaders/color_shader.fsh&quot;));
}</pre>
<p>Our new <code>on_surface_created()</code> enables depth-testing, initializes the table, puck, and mallets, and loads in the shader programs.</p>
<h4><code>on_surface_changed(int width, int height)</code></h4>
<pre class="brush: cpp; title: ; notranslate">void on_surface_changed(int width, int height) {
	glViewport(0, 0, width, height);
	mat4x4_perspective(projection_matrix, 45, (float) width / (float) height, 1, 10);
	mat4x4_look_at(view_matrix, 0.0f, 1.2f, 2.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
}</pre>
<p>Our new <code>on_surface_changed(int width, int height)</code> now takes in two parameters for the width and the height, and it sets up a projection matrix, and then sets up the view matrix to be slightly above and behind the origin, with an eye position of (0, 1.2, 2.2).</p>
<h4><code>on_draw_frame()</code></h4>
<pre class="brush: cpp; title: ; notranslate">void on_draw_frame() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    mat4x4_mul(view_projection_matrix, projection_matrix, view_matrix);

	position_table_in_scene();
    draw_table(&amp;table, &amp;texture_program, model_view_projection_matrix);

	position_object_in_scene(0.0f, mallet_height / 2.0f, -0.4f);
	draw_mallet(&amp;red_mallet, &amp;color_program, model_view_projection_matrix);

	position_object_in_scene(0.0f, mallet_height / 2.0f, 0.4f);
	draw_mallet(&amp;blue_mallet, &amp;color_program, model_view_projection_matrix);

	// Draw the puck.
	position_object_in_scene(0.0f, puck_height / 2.0f, 0.0f);
	draw_puck(&amp;puck, &amp;color_program, model_view_projection_matrix);
}</pre>
<p>Our new <code>on_draw_frame()</code> positions and draws the table, mallets, and the puck.</p>
<p>Because we changed the definition of <code>on_surface_changed()</code>, we also have to change the declaration in <em>game.h</em>. Change <code>void on_surface_changed();</code> to <code>void on_surface_changed(int width, int height);</code>.</p>
<h4>Adding new helper functions</h4>
<pre class="brush: cpp; title: ; notranslate">static void position_table_in_scene() {
	// The table is defined in terms of X &amp; Y coordinates, so we rotate it
	// 90 degrees to lie flat on the XZ plane.
	mat4x4 rotated_model_matrix;
	mat4x4_identity(model_matrix);
	mat4x4_rotate_X(rotated_model_matrix, model_matrix, deg_to_radf(-90.0f));
	mat4x4_mul(
		model_view_projection_matrix, view_projection_matrix, rotated_model_matrix);
}

static void position_object_in_scene(float x, float y, float z) {
	mat4x4_identity(model_matrix);
	mat4x4_translate_in_place(model_matrix, x, y, z);
	mat4x4_mul(model_view_projection_matrix, view_projection_matrix, model_matrix);
}</pre>
<p>These functions update the matrices to let us position the table, puck, and mallets in the scene. We&#8217;ll define all of the extra functions that we need soon.</p>
<h3>Adding new shaders</h3>
<p>Now we&#8217;ll start drilling down into each part of the program and make the changes necessary for our game code to work. Let&#8217;s begin by updating our shaders. First, let&#8217;s rename our vertex shader <em>shader.vsh</em> to <em>texture_shader.vsh</em> and update it as follows:</p>
<h4><em>texture_shader.vsh</em></h4>
<pre class="brush: cpp; title: ; notranslate">uniform mat4 u_MvpMatrix;

attribute vec4 a_Position;
attribute vec2 a_TextureCoordinates;

varying vec2 v_TextureCoordinates;

void main()
{
    v_TextureCoordinates = a_TextureCoordinates;
    gl_Position = u_MvpMatrix * a_Position;
}</pre>
<p>We can rename our fragment shader <em>shader.fsh</em> to <em>texture_shader.fsh</em> without making any other changes.</p>
<p>We&#8217;ll also need a new set of shaders to render our puck and mallets. Let&#8217;s add the following new shaders:</p>
<h4><em>color_shader.vsh</em></h4>
<pre class="brush: cpp; title: ; notranslate">uniform mat4 u_MvpMatrix;
attribute vec4 a_Position;
void main()
{
    gl_Position = u_MvpMatrix * a_Position;
}</pre>
<h4><em>color_shader.fsh</em></h4>
<pre class="brush: cpp; title: ; notranslate">precision mediump float;
uniform vec4 u_Color;
void main()
{
    gl_FragColor = u_Color;
}</pre>
<h3>Creating our game objects</h3>
<p>Now we&#8217;ll add support for generating and drawing our game objects. Let&#8217;s begin with <em>game_objects.h</em>:</p>
<pre class="brush: cpp; title: ; notranslate">#include &quot;platform_gl.h&quot;
#include &quot;program.h&quot;
#include &quot;linmath.h&quot;

typedef struct {
	GLuint texture;
	GLuint buffer;
} Table;

typedef struct {
	vec4 color;
	GLuint buffer;
	int num_points;
} Puck;

typedef struct {
	vec4 color;
	GLuint buffer;
	int num_points;
} Mallet;

Table create_table(GLuint texture);
void draw_table(const Table* table, const TextureProgram* texture_program, mat4x4 m);

Puck create_puck(float radius, float height, int num_points, vec4 color);
void draw_puck(const Puck* puck, const ColorProgram* color_program, mat4x4 m);

Mallet create_mallet(float radius, float height, int num_points, vec4 color);
void draw_mallet(const Mallet* mallet, const ColorProgram* color_program, mat4x4 m);</pre>
<p>We&#8217;ve defined three C structs to hold the data for our table, puck, and mallets, and we&#8217;ve declared functions to create and draw these objects.</p>
<h4>Drawing a table</h4>
<p>Let&#8217;s continue with <em>game_objects.c</em>:</p>
<pre class="brush: cpp; title: ; notranslate">#include &quot;game_objects.h&quot;
#include &quot;buffer.h&quot;
#include &quot;platform_gl.h&quot;
#include &quot;program.h&quot;
#include &quot;linmath.h&quot;
#include &lt;math.h&gt;

// Triangle fan
// position X, Y, texture S, T
static const float table_data[] = { 0.0f,  0.0f, 0.5f, 0.5f,
        						   -0.5f, -0.8f, 0.0f, 0.9f,
        						   	0.5f, -0.8f, 1.0f, 0.9f,
        						   	0.5f,  0.8f, 1.0f, 0.1f,
        						   -0.5f,  0.8f, 0.0f, 0.1f,
        						   -0.5f, -0.8f, 0.0f, 0.9f};

Table create_table(GLuint texture) {
	return (Table) {texture, 
		create_vbo(sizeof(table_data), table_data, GL_STATIC_DRAW)};
}

void draw_table(const Table* table, const TextureProgram* texture_program, mat4x4 m)
{
	glUseProgram(texture_program-&gt;program);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, table-&gt;texture);
	glUniformMatrix4fv(texture_program-&gt;u_mvp_matrix_location, 1, 
		GL_FALSE, (GLfloat*)m);
	glUniform1i(texture_program-&gt;u_texture_unit_location, 0);

	glBindBuffer(GL_ARRAY_BUFFER, table-&gt;buffer);
	glVertexAttribPointer(texture_program-&gt;a_position_location, 2, GL_FLOAT,
		GL_FALSE, 4 * sizeof(GL_FLOAT), BUFFER_OFFSET(0));
	glVertexAttribPointer(texture_program-&gt;a_texture_coordinates_location, 2, GL_FLOAT,
		GL_FALSE, 4 * sizeof(GL_FLOAT), BUFFER_OFFSET(2 * sizeof(GL_FLOAT)));
	glEnableVertexAttribArray(texture_program-&gt;a_position_location);
	glEnableVertexAttribArray(texture_program-&gt;a_texture_coordinates_location);
	glDrawArrays(GL_TRIANGLE_FAN, 0, 6);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
}</pre>
<p>After the imports, this is the code to create and draw the table data. This is essentially the same as what we had before, with the coordinates adjusted a bit to change the table into a rectangle.</p>
<h4>Generating circles and cylinders</h4>
<p>Before we can draw a puck or a mallet, we&#8217;ll need to add some helper functions to draw a circle or a cylinder. Let&#8217;s define those now:</p>
<pre class="brush: cpp; title: ; notranslate">static inline int size_of_circle_in_vertices(int num_points) {
	return 1 + (num_points + 1);
}

static inline int size_of_open_cylinder_in_vertices(int num_points) {
	return (num_points + 1) * 2;
}</pre>
<p>We first need two helper functions to calculate the size of a circle or a cylinder in terms of vertices. A circle drawn as a triangle fan has one vertex for the center, <code>num_points</code> vertices around the circle, and one more vertex to close the circle. An open-ended cylinder drawn as a triangle strip doesn&#8217;t have a center point, but it does have two vertices for each point around the circle, and two more vertices to close off the circle.</p>
<pre class="brush: cpp; title: ; notranslate">static inline int gen_circle(float* out, int offset, 
	float center_x, float center_y, float center_z, 
	float radius, int num_points)
{
	out[offset++] = center_x;
	out[offset++] = center_y;
	out[offset++] = center_z;

	int i;
	for (i = 0; i &lt;= num_points; ++i) {
		float angle_in_radians = ((float) i / (float) num_points) 
                               * ((float) M_PI * 2.0f);
		out[offset++] = center_x + radius * cos(angle_in_radians);
		out[offset++] = center_y;
		out[offset++] = center_z + radius * sin(angle_in_radians);
	}

	return offset;
}</pre>
<p>This code will generate a circle, given a center point, a radius, and the number of points around the circle.</p>
<pre class="brush: cpp; title: ; notranslate">static inline int gen_cylinder(float* out, int offset, 
	float center_x, float center_y, float center_z, 
	float height, float radius, int num_points)
{
	const float y_start = center_y - (height / 2.0f);
	const float y_end = center_y + (height / 2.0f);

	int i;
	for (i = 0; i &lt;= num_points; i++) {
		float angle_in_radians = ((float) i / (float) num_points) 
                               * ((float) M_PI * 2.0f);

		float x_position = center_x + radius * cos(angle_in_radians);
		float z_position = center_z + radius * sin(angle_in_radians);

		out[offset++] = x_position;
		out[offset++] = y_start;
		out[offset++] = z_position;

		out[offset++] = x_position;
		out[offset++] = y_end;
		out[offset++] = z_position;
	}

	return offset;
}</pre>
<p>This code will generate the vertices for an open-ended cylinder. Note that for both the circle and the cylinder, the loop goes from 0 to <code>num_points</code>, so the first and last points around the circle are duplicated in order to close the loop around the circle.</p>
<h4>Drawing a puck</h4>
<p>Let&#8217;s add the code to generate and draw the puck:</p>
<pre class="brush: cpp; title: ; notranslate">Puck create_puck(float radius, float height, int num_points, vec4 color)
{
	float data[(size_of_circle_in_vertices(num_points) 
              + size_of_open_cylinder_in_vertices(num_points)) * 3];

	int offset = gen_circle(data, 0, 0.0f, height / 2.0f, 0.0f, radius, num_points);
	gen_cylinder(data, offset, 0.0f, 0.0f, 0.0f, height, radius, num_points);

	return (Puck) {{color[0], color[1], color[2], color[3]},
				   create_vbo(sizeof(data), data, GL_STATIC_DRAW),
				   num_points};
}</pre>
<p>A puck contains one open-ended cylinder, and a circle to top off that cylinder.</p>
<pre class="brush: cpp; title: ; notranslate">void draw_puck(const Puck* puck, const ColorProgram* color_program, mat4x4 m)
{
	glUseProgram(color_program-&gt;program);

	glUniformMatrix4fv(color_program-&gt;u_mvp_matrix_location, 1, GL_FALSE, (GLfloat*)m);
	glUniform4fv(color_program-&gt;u_color_location, 1, puck-&gt;color);

	glBindBuffer(GL_ARRAY_BUFFER, puck-&gt;buffer);
	glVertexAttribPointer(color_program-&gt;a_position_location, 3, GL_FLOAT, 
		GL_FALSE, 0, BUFFER_OFFSET(0));
	glEnableVertexAttribArray(color_program-&gt;a_position_location);

	int circle_vertex_count = size_of_circle_in_vertices(puck-&gt;num_points);
	int cylinder_vertex_count = size_of_open_cylinder_in_vertices(puck-&gt;num_points);

	glDrawArrays(GL_TRIANGLE_FAN, 0, circle_vertex_count);
	glDrawArrays(GL_TRIANGLE_STRIP, circle_vertex_count, cylinder_vertex_count);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}</pre>
<p>To draw the puck, we pass in the uniforms and attributes, and then we draw the circle as a triangle fan, and the cylinder as a triangle strip.</p>
<h4>Drawing a mallet</h4>
<p>Let&#8217;s continue with the code to create and draw a mallet:</p>
<pre class="brush: cpp; title: ; notranslate">Mallet create_mallet(float radius, float height, int num_points, vec4 color)
{
	float data[(size_of_circle_in_vertices(num_points) * 2 
	          + size_of_open_cylinder_in_vertices(num_points) * 2) * 3];

	float base_height = height * 0.25f;
	float handle_height = height * 0.75f;
	float handle_radius = radius / 3.0f;

	int offset = gen_circle(data, 0, 0.0f, -base_height, 0.0f, radius, num_points);
	offset = gen_circle(data, offset, 
		0.0f, height * 0.5f, 0.0f, 
		handle_radius, num_points);
	offset = gen_cylinder(data, offset, 
		0.0f, -base_height - base_height / 2.0f, 0.0f, 
		base_height, radius, num_points);
	gen_cylinder(data, offset, 
		0.0f, height * 0.5f - handle_height / 2.0f, 0.0f, 
		handle_height, handle_radius, num_points);

	return (Mallet) {{color[0], color[1], color[2], color[3]},
					 create_vbo(sizeof(data), data, GL_STATIC_DRAW),
				     num_points};
}</pre>
<p>A mallet contains two circles and two open-ended cylinders, positioned and sized so that the mallet&#8217;s base is wider and shorter than the mallet&#8217;s handle.</p>
<pre class="brush: cpp; title: ; notranslate">void draw_mallet(const Mallet* mallet, const ColorProgram* color_program, mat4x4 m)
{
	glUseProgram(color_program-&gt;program);

	glUniformMatrix4fv(color_program-&gt;u_mvp_matrix_location, 1, GL_FALSE, (GLfloat*)m);
	glUniform4fv(color_program-&gt;u_color_location, 1, mallet-&gt;color);

	glBindBuffer(GL_ARRAY_BUFFER, mallet-&gt;buffer);
	glVertexAttribPointer(color_program-&gt;a_position_location, 3, GL_FLOAT, 
	GL_FALSE, 0, BUFFER_OFFSET(0));
	glEnableVertexAttribArray(color_program-&gt;a_position_location);

	int circle_vertex_count = size_of_circle_in_vertices(mallet-&gt;num_points);
	int cylinder_vertex_count = size_of_open_cylinder_in_vertices(mallet-&gt;num_points);
	int start_vertex = 0;

	glDrawArrays(GL_TRIANGLE_FAN, start_vertex, circle_vertex_count); 
	start_vertex += circle_vertex_count;
	glDrawArrays(GL_TRIANGLE_FAN, start_vertex, circle_vertex_count); 
	start_vertex += circle_vertex_count;
	glDrawArrays(GL_TRIANGLE_STRIP, start_vertex, cylinder_vertex_count); 
	start_vertex += cylinder_vertex_count;
	glDrawArrays(GL_TRIANGLE_STRIP, start_vertex, cylinder_vertex_count);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}</pre>
<p>Drawing the mallet is similar to drawing the puck, except that now we draw two circles and two cylinders.</p>
<h3>Adding math helper functions</h3>
<p>We&#8217;ll need to add a helper function that we&#8217;re currently using in <em>game.c</em>; create a new header file called <em>math_helper.h</em>, and add the following code:</p>
<pre class="brush: cpp; title: ; notranslate">#include &lt;math.h&gt;

static inline float deg_to_radf(float deg) {
	return deg * (float)M_PI / 180.0f;
}</pre>
<p>Since C&#8217;s trigonometric functions expect passed-in values to be in radians, we&#8217;ll use this function to convert degrees into radians, where needed.</p>
<h3>Adding matrix helper functions</h3>
<p>While <em>linmath.h</em> contains a lot of useful functions, there&#8217;s a few missing that we need for our game code. Create a new header file called <em>matrix.h</em>, and begin by adding the following code, all adapted from Android&#8217;s OpenGL <code>Matrix</code> class:</p>
<pre class="brush: cpp; title: ; notranslate">#include &quot;linmath.h&quot;
#include &lt;math.h&gt;
#include &lt;string.h&gt;

/* Adapted from Android's OpenGL Matrix.java. */

static inline void mat4x4_perspective(mat4x4 m, float y_fov_in_degrees, 
	float aspect, float n, float f)
{
	const float angle_in_radians = (float) (y_fov_in_degrees * M_PI / 180.0);
	const float a = (float) (1.0 / tan(angle_in_radians / 2.0));

	m[0][0] = a / aspect;
	m[1][0] = 0.0f;
	m[2][0] = 0.0f;
	m[3][0] = 0.0f;

	m[1][0] = 0.0f;
	m[1][1] = a;
	m[1][2] = 0.0f;
	m[1][3] = 0.0f;

	m[2][0] = 0.0f;
	m[2][1] = 0.0f;
	m[2][2] = -((f + n) / (f - n));
	m[2][3] = -1.0f;

	m[3][0] = 0.0f;
	m[3][1] = 0.0f;
	m[3][2] = -((2.0f * f * n) / (f - n));
	m[3][3] = 0.0f;
}</pre>
<p>We&#8217;ll use <code>mat4x4_perspective()</code> to setup a perspective projection matrix.</p>
<pre class="brush: cpp; title: ; notranslate">static inline void mat4x4_translate_in_place(mat4x4 m, float x, float y, float z)
{
	int i;
    for (i = 0; i &lt; 4; ++i) {
        m[3][i] += m[0][i] * x
        		+  m[1][i] * y
        		+  m[2][i] * z;
    }
}</pre>
<p>This helper function lets us translate a matrix in place.</p>
<pre class="brush: cpp; title: ; notranslate">static inline void mat4x4_look_at(mat4x4 m,
		float eyeX, float eyeY, float eyeZ,
		float centerX, float centerY, float centerZ,
		float upX, float upY, float upZ)
{
	// See the OpenGL GLUT documentation for gluLookAt for a description
	// of the algorithm. We implement it in a straightforward way:

	float fx = centerX - eyeX;
	float fy = centerY - eyeY;
	float fz = centerZ - eyeZ;

	// Normalize f
	vec3 f_vec = {fx, fy, fz};
	float rlf = 1.0f / vec3_len(f_vec);
	fx *= rlf;
	fy *= rlf;
	fz *= rlf;

	// compute s = f x up (x means &quot;cross product&quot;)
	float sx = fy * upZ - fz * upY;
	float sy = fz * upX - fx * upZ;
	float sz = fx * upY - fy * upX;

	// and normalize s
	vec3 s_vec = {sx, sy, sz};
	float rls = 1.0f / vec3_len(s_vec);
	sx *= rls;
	sy *= rls;
	sz *= rls;

	// compute u = s x f
	float ux = sy * fz - sz * fy;
	float uy = sz * fx - sx * fz;
	float uz = sx * fy - sy * fx;

	m[0][0] = sx;
	m[0][1] = ux;
	m[0][2] = -fx;
	m[0][3] = 0.0f;

	m[1][0] = sy;
	m[1][1] = uy;
	m[1][2] = -fy;
	m[1][3] = 0.0f;

	m[2][0] = sz;
	m[2][1] = uz;
	m[2][2] = -fz;
	m[2][3] = 0.0f;

	m[3][0] = 0.0f;
	m[3][1] = 0.0f;
	m[3][2] = 0.0f;
	m[3][3] = 1.0f;

	mat4x4_translate_in_place(m, -eyeX, -eyeY, -eyeZ);
}</pre>
<p>We can use <code>mat4x4_look_at()</code> like a camera, and use it to position the scene in a certain way.</p>
<h3>Adding shader program wrappers</h3>
<p>We&#8217;re almost done the changes to our core code. Let&#8217;s wrap up those changes by adding the following code:</p>
<h4><em>program.h</em></h4>
<pre class="brush: cpp; title: ; notranslate">#pragma once
#include &quot;platform_gl.h&quot;

typedef struct {
	GLuint program;

	GLint a_position_location;
	GLint a_texture_coordinates_location;
	GLint u_mvp_matrix_location;
	GLint u_texture_unit_location;
} TextureProgram;

typedef struct {
	GLuint program;

	GLint a_position_location;
	GLint u_mvp_matrix_location;
	GLint u_color_location;
} ColorProgram;

TextureProgram get_texture_program(GLuint program);
ColorProgram get_color_program(GLuint program);</pre>
<h4><em>program.c</em></h4>
<pre class="brush: cpp; title: ; notranslate">#include &quot;program.h&quot;
#include &quot;platform_gl.h&quot;

TextureProgram get_texture_program(GLuint program)
{
	return (TextureProgram) {
			program,
			glGetAttribLocation(program, &quot;a_Position&quot;),
			glGetAttribLocation(program, &quot;a_TextureCoordinates&quot;),
			glGetUniformLocation(program, &quot;u_MvpMatrix&quot;),
			glGetUniformLocation(program, &quot;u_TextureUnit&quot;)};
}

ColorProgram get_color_program(GLuint program)
{
	return (ColorProgram) {
			program,
			glGetAttribLocation(program, &quot;a_Position&quot;),
			glGetUniformLocation(program, &quot;u_MvpMatrix&quot;),
			glGetUniformLocation(program, &quot;u_Color&quot;)};
}</pre>
<h3>Adding support for Android</h3>
<p>We first need to update <em>Android.mk</em> and add the following to <code>LOCAL_SRC_FILES</code>:</p>
<pre class="brush: plain; title: ; notranslate">				   $(CORE_RELATIVE_PATH)/game_objects.c \
                   $(CORE_RELATIVE_PATH)/program.c \</pre>
<p>We also need to add a new <code>LOCAL_C_INCLUDES</code>:</p>
<pre class="brush: plain; title: ; notranslate">LOCAL_C_INCLUDES += $(PROJECT_ROOT_PATH)/3rdparty/linmath/</pre>
<p>We then need to update <em>renderer_wrapper.c</em> and change the call to <code>on_surface_changed();</code> to <code>	on_surface_changed(width, height);</code>. Once we&#8217;ve done that, we should be able to run the app on our Android device, and it should look similar to the following image:</p>
<div id="attachment_2136" style="width: 178px" class="wp-caption aligncenter"><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/airhockey-galaxy-nexus.png"><img src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/airhockey-galaxy-nexus-168x300.png" alt="Air hockey, running on a Galaxy Nexus" width="168" height="300" class="size-medium wp-image-2136" /></a><p class="wp-caption-text">Air hockey, running on a Galaxy Nexus</p></div>
<h3>Adding support for iOS</h3>
<p>For iOS, we just need to open up the Xcode project and add the necessary references to <em>linmath.h</em> and our new core files to the appropriate folder groups, and then we need to update <em>ViewController.m</em> and change <code>on_surface_changed();</code> to the following:
<pre class="brush: objc; title: ; notranslate">on_surface_changed([[self view] bounds].size.width, [[self view] bounds].size.height);</pre>
<p>Once we run the app, it should look similar to the following image:</p>
<div id="attachment_2137" style="width: 169px" class="wp-caption aligncenter"><a href="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/airhockey-iphone-simulator.png"><img src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/airhockey-iphone-simulator-159x300.png" alt="Air hockey, running on the iPhone simulator" width="159" height="300" class="size-medium wp-image-2137" /></a><p class="wp-caption-text">Air hockey, running on the iPhone simulator</p></div>
<h3>Adding support for emscripten</h3>
<p>For emscripten, we need to update the <em>Makefile</em> and add the following lines to <code>SOURCES</code>:</p>
<pre class="brush: plain; title: ; notranslate">		  ../../core/game_objects.c \
		  ../../core/program.c \</pre>
<p>We&#8217;ll also need to add the following lines to <code>OBJECTS</code>:</p>
<pre class="brush: plain; title: ; notranslate">		  ../../core/game_objects.o \
		  ../../core/program.o \</pre>
<p>We then just need to update <em>main.c</em>, move the constants <code>width</code> and <code>height</code> from inside <code>init_gl()</code> to outside the function near the top of the file, and update the call to <code>on_surface_changed();</code> to <code>on_surface_changed(width, height);</code>. We can then build the file by calling <code>emmake make</code>, which should produce a file that looks as follows:</p>
<div align="center"><iframe src="http://www.learnopengles.com/wordpress/wp-content/uploads/2013/09/airhockey.html" height="1030" width="100%" align="middle"></iframe></div>
<p>See how easy that was? Now that we have a minimal cross-platform framework in place, it&#8217;s very easy for us to bring changes to the core code across to each platform.</p>
<h3>Exploring further</h3>
<p>The full source code for this lesson can be found at the <a href="https://github.com/learnopengles/airhockey/tree/article-3-matrices-and-objects">GitHub project</a>. In the <a href="http://www.learnopengles.com/finishing-up-our-native-air-hockey-project-with-touch-events-and-basic-collision-detection/">next post</a>, we&#8217;ll take a look at user input so we can move our mallet around the screen.</p>
<strong><a href="http://www.learnopengles.com/adding-a-3d-perspective-and-object-rendering-to-our-air-hockey-project-in-native-c-code/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fadding-a-3d-perspective-and-object-rendering-to-our-air-hockey-project-in-native-c-code%2F&amp;title=Adding%20a%203d%20Perspective%20and%20Object%20Rendering%20to%20Our%20Air%20Hockey%20Project%20in%20Native%20C%20Code" id="wpa2a_36"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/adding-a-3d-perspective-and-object-rendering-to-our-air-hockey-project-in-native-c-code/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>OpenGL Roundup, September 12, 2013</title>
		<link>http://www.learnopengles.com/opengl-roundup-september-12-2013/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=opengl-roundup-september-12-2013</link>
		<comments>http://www.learnopengles.com/opengl-roundup-september-12-2013/#comments</comments>
		<pubDate>Thu, 12 Sep 2013 16:25:36 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Roundups]]></category>
		<category><![CDATA[OpenGL ES 3.0]]></category>
		<category><![CDATA[Project Anarchy]]></category>

		<guid isPermaLink="false">http://www.learnopengles.com/?p=2090</guid>
		<description><![CDATA[As some of you may already know, Apple recently announced the iPhone 5s &#38; 5c at their annual iPhone event, and one of the new updates is that the iPhone 5s will also be coming with support for OpenGL ES 3.0! Google announced support for OpenGL ES 3.0 with their release of Android 4.3 not [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As some of you may already know, Apple recently announced the iPhone 5s &amp; 5c at their annual iPhone event, and one of the new updates is that the iPhone 5s will also be coming with support for OpenGL ES 3.0! Google announced support for OpenGL ES 3.0 with their release of Android 4.3 not too long ago, so the new version is slowly making its way onto mobile devices.</p>
<p>OpenGL ES 3.0 is backwards-compatible with OpenGL ES 2.0, so everything you learned about OpenGL ES 2.0 still applies. This post from Phoronix goes into more detail about what the new version brings: <a href="http://www.phoronix.com/scan.php?page=news_item&amp;px=MTE1ODQ">A Look At OpenGL ES 3.0: Lots Of Good Stuff</a>.</p>
<p>On to the roundup:</p>
<p><a href="http://ghoshehsoft.wordpress.com/">Ghoshehsoft&#8217;s Blog</a> - A look at many topics related to OpenGL ES 2.0 on Android.</p>
<p><a href="http://projectanarchy.com/">Project Anarchy</a> - &#8220;Project Anarchy is a complete end to end game engine and state-of-the-art toolset for mobile. Project Anarchy also comprises a vibrant game development community centered right here at <a href="http://www.projectanarchy.com/">www.projectanarchy.com</a>. Project Anarchy includes an entirely free license to ship your game on iOS, Android and Tizen platforms.&#8221;</p>
<p><a href="http://flohofwoe.blogspot.ca/2013/08/emscripten-and-pnacl-build-systems.html">emscripten and PNaCl: Build Systems</a></p>
<p><a href="http://hacksoflife.blogspot.ca/2013/08/what-does-gpusreturnguiltyforhardwarere.html">What Does gpus_ReturnGuiltyForHardwareRestart Mean?</a></p>
<p><a href="http://hacksoflife.blogspot.ca/2013/08/theoretical-engineering-occlusion.html">Theoretical Engineering: Occlusion Culling for BrickSmith</a></p>
<strong><a href="http://www.learnopengles.com/opengl-roundup-september-12-2013/#respond" title="Leave a comment">Comment on the blog</a></strong>
<hr /><small>Copyright &copy; 2012<br /> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.<br /> The use of this feed on other websites that do not comply to the CC-BY-SA 3.0 breaches copyright. If this content is not in your news reader, the page you are viewing may be an infringement of the copyright. (Digital Fingerprint:<br /> e5945dcc83892602ba406e1f54f77ae6)</small><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.learnopengles.com%2Fopengl-roundup-september-12-2013%2F&amp;title=OpenGL%20Roundup%2C%20September%2012%2C%202013" id="wpa2a_40"><img src="http://www.learnopengles.com/wordpress/wp-content/plugins/add-to-any/share_save_256_24.png" width="256" height="24" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.learnopengles.com/opengl-roundup-september-12-2013/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 1.760 seconds. --><!-- Cached page generated by WP-Super-Cache on 2014-04-14 19:52:32 --><!-- Compression = gzip -->
