{"id":3077,"date":"2014-01-05T20:54:52","date_gmt":"2014-01-05T19:54:52","guid":{"rendered":"http:\/\/t-machine.org\/?p=3077"},"modified":"2014-01-28T14:02:49","modified_gmt":"2014-01-28T13:02:49","slug":"glkit-extended-refactoring-the-view-controller","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2014\/01\/05\/glkit-extended-refactoring-the-view-controller\/","title":{"rendered":"GLKit Extended: Refactoring the View Controller"},"content":{"rendered":"<p>If you&#8217;ve been following my tutorials on <a href=\"http:\/\/t-machine.org\/index.php\/2013\/09\/08\/opengl-es-2-basic-drawing\/\">OpenGL ES 2 for iOS<\/a>, by the time you finish Texturing (Part 6 or so) you&#8217;ll have a lot of code crammed into a single UIViewController. This is intentional: the tutorials are largely self-contained, and only create classes and objects where OpenGL itself uses class-like-things.<\/p>\n<p>&#8230;but most of the code is re-used from tutorial to tutorial, and it&#8217;s getting in the way. It&#8217;s time for some refactoring.<br \/>\n<!--more--><\/p>\n<h2>UIViewController vs GLKViewController<\/h2>\n<p>Recap: Both these classes are provided by Apple; <a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/GLkit\/Reference\/GLKViewController_ClassRef\/Reference\/Reference.html\">GLKViewController<\/a> is a UIViewController that&#8217;s been modified for OpenGL apps. It has the simplest possible interface &#8211; a single &#8220;update&#8221; method that you override, which is called (automatically) once per frame.<\/p>\n<p>As I explained in <a href=\"http:\/\/t-machine.org\/index.php\/2013\/09\/08\/opengl-es-2-basic-drawing\/\">the first GL ES 2 tutorial<\/a>, everything in OpenGL revolves around the Draw call. Most engines recognize this, so we&#8217;ll subclass GLKViewController and replace:<br \/>\n<!--more--><\/p>\n<ol>\n<li><em>Once per frame:<\/em> call &#8220;update&#8221;; no intelligence\n<\/ol>\n<p>&#8230;with:<\/p>\n<ol>\n<li><em>In viewDidLoad:<\/em> Correct setup of EAGLContext (required)\n<li><em>In viewDidLoad:<\/em> Pre-Create all the Draw calls needed for the app\n<li><em>Once per frame:<\/em> For each Draw call in the list:\n<ol>\n<li>&#8230;update all the OpenGL per-Draw settings\n<li>&#8230;update the OpenGL Shader settings\n<li>&#8230;render the Draw call\n<li>&#8230;reset any OpenGL state that &#8220;must&#8221; be turned off immediately after use (e.g. GL_SCISSOR)\n<\/ol>\n<\/ol>\n<p>Most of this is identical for all apps &#8211; we can create a single base class &#8220;GLK2DrawCallViewController&#8221;, and put the code in there. A few items will be unique from app to app (e.g. the list of Draw calls actually rendered!); we do those with their own public methods so that you can write a subclass per-app which only overrides the methods it needs to change.<\/p>\n<p><em>GLK2DrawCallViewController.h<\/em>:<br \/>\n[objc]<br \/>\n@interface GLK2DrawCallViewController : GLKViewController<\/p>\n<p>@property(nonatomic,retain) EAGLContext* localContext;<br \/>\n@property(nonatomic, retain) NSMutableArray* drawCalls;<br \/>\n[\/objc]<\/p>\n<p>This class manages the EAGLContext correctly, and populates the drawCalls &#8211; most subclasses can ignore these properties. But some special effects will require you to access the super-class&#8217;s data here.<\/p>\n<p>[objc]<br \/>\n-(NSMutableArray*) createAllDrawCalls;<br \/>\n-(void) willRenderFrame;<br \/>\n-(void) willRenderDrawCallUsingVAOShaderProgramAndDefaultUniforms:(GLK2DrawCall*) drawCall;<br \/>\n@end<br \/>\n[\/objc]<\/p>\n<p>One callback to create the Draw calls &#8211; this is essential, if you don&#8217;t implement it, nothing will be drawn.<\/p>\n<p>The other two are optional, although the one about &#8220;willRender&#8230;.Using&#8230;Uniforms&#8221; is needed for most non-trivial shaders (any shader where a Uniform is changing from frame to frame &#8211; e.g. whenever your 3D objects are moving).<\/p>\n<p>Internally, it&#8217;s all existing code that I&#8217;ve simply moved around.<\/p>\n<h3>Usage<\/h3>\n<p>Usage is exceptionally simple: change your ViewController.h in your app project to extend the new class:<\/p>\n<p><em>ViewController.h<\/em>:<br \/>\n[objc]<br \/>\n@interface ViewController : GLK2DrawCallViewController<br \/>\n[\/objc]<\/p>\n<p>&#8230;and override the special method for creating Draw calls. Move all your tutorial \/ logic there:<\/p>\n<p><em>ViewController.h<\/em>:<br \/>\n[objc]<br \/>\n-(NSMutableArray*) createAllDrawCalls<br \/>\n{<br \/>\n\t\/** All the local setup for the ViewController *\/<br \/>\n\tNSMutableArray* result = [NSMutableArray array];<\/p>\n<p>\t\/** &#8212; Draw Call 1: clear the background<br \/>\n\t *\/<br \/>\n\tGLK2DrawCall* simpleClearingCall = [[GLK2DrawCall new] autorelease];<br \/>\n\tsimpleClearingCall.shouldClearColorBit = TRUE;<br \/>\n\t[simpleClearingCall setClearColourRed:0.5 green:0 blue:0 alpha:1];<br \/>\n\t[result addObject: simpleClearingCall];<\/p>\n<p>&#8230; etc<br \/>\n\treturn result;<br \/>\n}<br \/>\n[\/objc]<\/p>\n<p><em>Source files on Github:<\/em><\/p>\n<ul>\n<li><em><a href=\"https:\/\/github.com\/adamgit\/GL2KitExtensions\/blob\/Part7Refactoring\/GLKX-Library\/GLKX-Library\/OpenGL%20with%20UIKit\/GLK2DrawCallViewController.h\">GLK2DrawCallViewController.h<\/a><\/em>\n<li><em><a href=\"https:\/\/github.com\/adamgit\/GL2KitExtensions\/blob\/Part7Refactoring\/GLKX-Library\/GLKX-Library\/OpenGL%20with%20UIKit\/GLK2DrawCallViewController.m\">GLK2DrawCallViewController.m<\/a><\/em>\n<\/ul>\n<h2>Re-using the &#8220;draw one triangle&#8221; code<\/h2>\n<p>The tutorials frequently use &#8220;draw a single triangle&#8221; to demonstrate new code. It would be great to re-use this code &#8211; we use it a lot for debugging, not just for tutorials. But it can&#8217;t live inside the OpenGL API: to keep the API small and easy to learn, it only includes commands for talking to the GPU efficiently.<\/p>\n<p>With desktop GL they solved this problem by creating <a href=\"http:\/\/www.opengl.org\/archives\/resources\/faq\/technical\/glu.htm\">a separate, &#8220;optional&#8221; library called GLU<\/a>. Because GLU is purely software &#8211; it has no access to hardware, instead using GL to do all the GPU work &#8211; you can copy\/paste GLU code and use it with different versions of GL, often with little or no changes.<\/p>\n<blockquote><p>\nNOTE: I&#8217;m not including this code in the GLKit-Extended library &#8211; it&#8217;s stuff that would be written differently for different 3D engines, and I want the library to be pure and simple. Instead, I&#8217;m including it in the GLKit-Extended Demo project, and you can copy\/paste the file direct to your own projects if you choose\n<\/p><\/blockquote>\n<p>Sadly, most GLU code won&#8217;t work with GL ES unless you tweak it &#8211; GLU uses lots of outdated commands that were stripped to make GL ES cheaper to implement. But we can copy the idea&#8230;<\/p>\n<p><em>CommonGLEngineCode.h<\/em>:<br \/>\n[objc]<br \/>\n@interface CommonGLEngineCode : NSObject<br \/>\n+(GLK2DrawCall*) drawCallWithUnitTriangleAtOriginUsingShaders:(GLK2ShaderProgram*) shaderProgram;<br \/>\n+(GLK2DrawCall*) drawCallWithUnitCubeAtOriginUsingShaders:(GLK2ShaderProgram*) shaderProgram;<br \/>\n&#8230; over time, we&#8217;ll add more and more &quot;re-usable&quot; methods here&#8230;<br \/>\n@end<br \/>\n[\/objc]<\/p>\n<p>Each method assumes that you&#8217;ve NOT CHANGED ANYTHING in the camera-setup of OpenGL &#8211; you&#8217;re using an unconfigured, default frustum etc. i.e. the projection is Orthogonal, and only shows things from (-1,-1,-1) to (1,1,1). It sticks a 1-unit wide triangle (or cube) roughly in the middle of the screen.<\/p>\n<p>If the methods were 100% generic, they&#8217;d take another argument: a dictionary of GLK2Attributes, each one &#8220;tagged&#8221; so the method knows which ones to fill with 3D positions, which to fill with 2D texture co-ordinates, etc. For simplicity, I&#8217;ve assumed that you pass in a pre-compiled GLK2ShaderProgram containing a shader pair with:<\/p>\n<ul>\n<li>REQUIRED: an Attribute named &#8220;position&#8221; which you&#8217;ll read to get the 3D position of each vertex\n<li>OPTIONAL: an Attribute named &#8220;textureCoordinate&#8221; which you&#8217;ll read if you&#8217;re using Texturing to get a texture-co-ordinate ranging (0-1) in X (i.e. &#8220;u&#8221;) and (0-1) in Y (i.e. &#8220;v&#8221;)\n<\/ul>\n<h3>Usage<\/h3>\n<p>Combining this with the new GLK2DrawCallViewController above, we get something like:<\/p>\n<p><em>ViewController.h<\/em>:<br \/>\n[objc]<br \/>\n-(NSMutableArray*) createAllDrawCalls<br \/>\n{<br \/>\n\t\/** All the local setup for the ViewController *\/<br \/>\n\tNSMutableArray* result = [NSMutableArray array];<\/p>\n<p>\tGLK2DrawCall* dcTri = [CommonGLEngineCode drawCallWithUnitTriangleAtOriginUsingShaders:<br \/>\n\t\t\t\t\t\t   [GLK2ShaderProgram shaderProgramFromVertexFilename:@&quot;VertexProjectedWithTexture&quot; fragmentFilename:@&quot;FragmentWithTexture&quot;]];<br \/>\n\tGLK2Uniform* samplerTexture1 = [dcTri.shaderProgram uniformNamed:@&quot;s_texture1&quot;];<\/p>\n<p>&#8230;OPTIONAL (if you&#8217;re using texture-mapping in your shaders):<\/p>\n<p>\tGLK2Texture* texture = [GLK2Texture textureNamed:@&quot;tex2&quot;];<br \/>\n\t[dcTri setTexture:texture forSampler:samplerTexture1];<\/p>\n<p>\t[result addObject:dcTri];<br \/>\n&#8230;<br \/>\n\treturn result;<br \/>\n}<br \/>\n[\/objc]<\/p>\n<p><em>Source files on Github:<\/em><\/p>\n<ul>\n<li><em><a href=\"https:\/\/github.com\/adamgit\/GL2KitExtensions\/blob\/Part7Refactoring\/GLKX-Demo\/Classes\/CommonGLEngineCode.h\">CommonGLEngineCode.h<\/a><\/em>\n<li><em><a href=\"https:\/\/github.com\/adamgit\/GL2KitExtensions\/blob\/Part7Refactoring\/GLKX-Demo\/Classes\/CommonGLEngineCode.m\">CommonGLEngineCode.m<\/a><\/em>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;ve been following my tutorials on OpenGL ES 2 for iOS, by the time you finish Texturing (Part 6 or so) you&#8217;ll have a lot of code crammed into a single UIViewController. This is intentional: the tutorials are largely self-contained, and only create classes and objects where OpenGL itself uses class-like-things. &#8230;but most of [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[51,20],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3077"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=3077"}],"version-history":[{"count":12,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3077\/revisions"}],"predecessor-version":[{"id":3108,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3077\/revisions\/3108"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=3077"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=3077"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=3077"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}