Wednesday, November 25, 2009

Generics your easy road to the simple life

There have been some comments recently asking what was the best way to use Generics in C#, so here’s a short blog which sheds some light.  Generics were probably the most powerful feature to go into .Net and they allowed developers to define structures, without committing to actual data types.  That may sound very complicated but its really not that hard to wrap your head around.

Simple Generic Lists

One of the simplest examples is taken directly from an existing Framework.  Within this we have lots of Collections classes for example CompanyCollection, ContactCollection, etc. and these are explicitly created with lots of code for getting a group, array of Company or Contact items from the CompanySearch class. 

It's usually seen in this type of context:

// Get a collection of companies

CompanyCollection compCollection = CompanySearch.Browes();

string companyName = compCollection[0].CompName;  // display the first company name

Generics give you the same thing out of the box using the List<> function.

// Get a collection of companies using Generics

List<Company> compCollection = CompanySearch.Browes();

string companyName = compCollection[0].CompName;

So what's the advantage?  Well for one we don't need the CompanyCollection.cs class file which will save a developer having to write it (cut/paste or use replicator and perhaps introduce bugs).  Secondly it's been developed using core functions so it's faster than anything you could write yourself.  Also it's guaranteed to give us a stable upgrade path as .Net progresses.

The Syntax

Taking this example a little further, I hear “What’s all this <> crap in the code?”.  Well simply, this is the class you are passing into a “generic” (i.e. self defined) method.  An easy way to describe this is to think of it as a cut/paste job for the class.  Below is an extract of the CompanyCollection class with a Browse method.

using System;
using System.Collections;

namespace BusinessObjects.Companies
{
    public class CompanyCollection : CollectionBase
    {
        public CompanyColelction Browse()
        {
              CompanyCollection results = new CompanyCollection();
              … some code to find a bunch of records and put them in results …
              return results;
        }
}

If you wanted the same thing for Contacts you would probably cut/paste the code into a new file and replace every occurrence of “"CompanyCollection” with “ContactCollection”.  With Generics you would say something like this.

using System;
using System.Collections;

namespace BusinessObjects.Companies
{
    public class GenericList<T>
    {
        public GenericList<T> Browse()
        {
              GenericList<T> results = new GenericList<T>();
              … some code to find a bunch of records and put them in results …
              return results;
        }
}

Here at compile time the .Net Framework will replace the “T” above with the object value you are passing to the method.

GenericList<Company> myCompanyCollection = new GenericList<Company>();  // replace “T”
myCompanyCollection.Browse();

and

GenericList<Contact> myContactCollection = new GenericList<Contact>(); // replace “T”
myContactCollection.Browse();

Hence in the compiled DLL, you do actually get two classes “generic classes” but you only have to write (or edit, debug, etc.) one!

Thursday, November 19, 2009

Some coding tips and advice

I've been doing some refactoring code recently and want to share some tips and tricks that could help developers in future efforts.  These are just suggestions so feel free to use or ignore any of them, but keep in mind that they would make things a little easier for everyone in the long run.

Temp Files and Paths

I've seen in a few places that developers have been placing files into the C:\temp directory.  Nothing wrong with this; however did you know that .NET makes it a lot easier now?

Before:    string fullFileName = @"c:\temp\" + someFileName;
The main problem here this is that it assumes that the "c:\temp\" directory exists and if you want to change it we have to recompile the source code.

After:      string fullFileName = String.Format("{0}{1}", Path.GetTempPath(),
                                                                                 Path.GetTempFileName());
The "Path" class in .NET will gives you lots of extra options for dealing with folders and files.  The "GetTempPath" method will return the value set in the %Temp% environment variable which is default in Windows.  "GetTempFileName" will give you a random filename which can be very handy if you are creating temp files.  Another handy methods are "GetFileNameWithoutExtension" which means you can add any extension you want to a file.

Getting rid of old code

You all know how much I *hate* to leave old code hanging around, but leaving an entire classes really gets me going!  The current Framework is chock full of classes that are old, duplicated or simply in need of a serious rewrite, but we can't delete them as there is the ever present "Possibility" of breaking the old ASP code.  To address this we can use the "Obsolete" attribute to show a class should no longer be used.

    [Obsolete("This class is a deprecated! use Company from DataAccessObjects Namespace.")]
    public class Company
    {     ......     }

We can also say something like this  [Obsolete("This class is a deprecated and will throw a compile error!", true)].  This is Visual Studio will generate a compile error, but it's probably not something you'd want to do unless you really wanted to spend a long time testing.

Never..Never.. Never.. Swallow Errors!

I've seen this type of code all over every project and it's really bad practice.

     try { someCode;
           someMoreCode; }
     catch (Exception e) { }
AAGHHH!!! having a catch with nothing in it is like driving drunk with your eyes closed and having no insurance, it's just saying "If I crash, just keep going and leave all that damage for someone else".

     try { someCode;
           someMoreCode; }
     catch (Exception e) { throw new e;}
This is a little (but not much) better than the last example; least this this we acknowledge that a problem took place.  The problem with this approach is that as we're throwing a "new e" so we actually loose the strack trace and if the error is deep in the bowls of the code you'll have a hard job finding the cause.

     try { someCode;
           someMoreCode; }
     catch (Exception e) { throw;}

This will give you both the error and the stack trace, but really at this point its probably easier to just say:

         someCode;
         someMoreCode;

So what's the moral of our story?  NEVER have a try-catch block unless you actually need to do something with it, log the error, throw a different error, it’s up to you but please do something in the catch block.

Creating Projects in the right folder

A very minor thing on the list is to keep an eye on the directory when you're adding a new project to an existing solution.  By default if I was to add a new project to a solution it will go under the root folder.  There however a text box on the New Project dialogue which gives you the option to add a subdirectory name.

Friday, November 13, 2009

PSTools .. it’s great to find a good tool for once!

I was looking for a way to run scripts on a remote server and found this great set of tools that are freely available from Microsoft.

PSTools; this is basically a set of tools that let you manage a remote server as if it was a local one.  this contains a number of different commands which are all listed on the website.  I’m going to integrate the PSExec command into the project Build Scripts.

Monday, November 9, 2009

Unit Testing types for developers

Well you all know I'm a big fan of Unit Testing but did you know all the different types of tests you can run?  In this Blog I'll go over some of the examples:

A simple class to test

First we need a simple class to test so I'll use a very, very simple addition and division example called SimpleClass.  It contains two methods Add and Division both of which take two integers and return results.  Here is the basic code....

    public class SimpleClass
    {
        /// <summary>
        /// Add two values
        /// </summary>
        /// <param name="first">first value to add</param>
        /// <param name="second">second value to add</param>
        /// <returns>sum of both values</returns>
        public int Add(int first, int second)
        {
            return first + second;
        }

        /// <summary>
        /// Divide two values
        /// </summary>
        /// <param name="first">first value to divide</param>
        /// <param name="second">second value to divide</param>
        /// <returns>division of both values</returns>
        public decimal Divide(int first, int second)
        {
            return first / second;
        }
    }

Lets get down to the testing.

First off all you need a class decorated with the attribute [TestFixture] this will tell NUnit GUI to run the test from the external program.  Here you can see a basic test thats you've probably see a few times before.

    [TestFixture]
    public class TestingExamples
    {
        [Test(Description="Basic Test")]
        public void SimpleClass_Test_A_Simple_Method()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }
    }

It's saying pass the values 10 and 20 into the Add method and expect to get the result 30.  Simple really, and probably the type of test you'l want to write over and over again.  Howere there are other options available.

Repeat Test

        [Test(Description = "Repeat Test"), Repeat(30)]
        public void SimpleClass_Repeat_Test()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

By adding the Repeat(30) attribute to the test as shown this will run the test 30 times.  In this example it's not really a very useful test but if for example you want to test load on a server or perhaps populate a number of rows in a database it can be very useful.

Multipule Value Test

        [Test(Description="Multivalue Test")]
        [TestCase(10,20,30)]
        [TestCase(1,2,3)]
        [TestCase(7,6,13)]
        public void SimpleClass_TestCase_With_Many_Inputs(int
firstInput, int secondInput, int expectedResult)
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(firstInput, secondInput);
            Assert.IsTrue(result == expectedResult, "Result was not correct!");
        }

Here I'm calling the test 3 times but passing 3 different values and testing against 3 different results.  By using the [TestCase] attribute you can just add more and more values to the same test.

Expected Exception Test

        [Test(Description = "Expected Exception Test")]
        [ExpectedException(typeof(DivideByZeroException),
ExpectedMessage = "divide", MatchType = MessageMatch.Contains)]
        public void SimpleClass_TestCase_Divide_By_Zero()
        {
            SimpleClass simpleClass = new SimpleClass();
            decimal result = simpleClass.Divide(0, 0);
        }

Here is a divide test that throws a divide by Zero error.  By using the ExpectedException attribute we catch the error thrown by the .Net function and then checks it's the correct one, in this case System.DivideByZeroException.  It also checks the message text for the text "divide" and uses the MessageMatch.Contains attribute to indicate the text can exist anywhere in the error message.

Explicit

        [Test(Description = "Only Run when Explicitly chosen"), Explicit]
        public void SimpleClass_Explicit_Test_Of_Method()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

This is an interesting one for us in that it will only run when you "explicitly" select it to run using TestRunner or the Nunit GUI, if not it will be ignored during test runs.  You'd use this function if you wanted to have a UI test or specific test that won't run on the Build server.

MaxTime and TimeOut

        [Test(Description = "Maxtime Test"), MaxTime(20)]
        public void  SimpleClass_Max_Time_In_Mili_Seconds()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

        [Test(Description = "Timeout Test"), Timeout(20)]
        public void SimpleClass_Ensure_Long_Running_Process_Does_Not_Time_Out()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

Timed tests are great for performance tests, here we specify that both tests need to run within 20 miliseconds.  What's the difference between them?  Well not a lot really so it's probably best to stick to Timeout and ignore MaxTime.

Platform

        [Test(Description = ".Net exclude test"), Platform(Exclude = "NET-2.0")]
        public void SimpleClass_Exclude_DotNet_Tests()
        {
            // Other options relevant to us
            // WinXP, Win2003Server, Vista, Net-1.1, Mono
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

Probably not something we'd use very often but it may be useful in the future.  Here we specify that we this test should not be run under .Net 2.  Again the test is not important here what is important is that we can say things like only run a test on a Windows 2003 Server or only run the test on XP.

Random Values

        [Test(Description = "Random value generation test")]
        public void SimpleClass_Random_Values(
            [Values(10, 20, 30)] int firstValue,
            [Random(1, 50, 5)] int secondValue)
        {
            // run 15 times.. 3 values by 5 random numbers
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(firstValue, secondValue);
            int testResult = firstValue + secondValue;
            Assert.IsTrue(result == testResult, "Result was not correct!");
        }

Finally sometimes you just can't be assed coming up with test data so in this case we use the [Random] attribute.  By saying [Random(1,50,5) int ]  I'm saying choose a number between 1 and 50 and run that test 5 times.  I've also added 3 additional [Values] 10,20 and 30 this means the test will run 15 times, i.e. 3 by 5

Monday, October 26, 2009

Adding an Application Icon using MonoTouch

Minor thing this time, I just wanted to add an icon to my application and wanted to see how that could be done with MonoTouch.


First off you need a PNG files, on a Mac its easy to get a PNG by just using the <Shift><Command>4 command. I happened to we watch Dr Who at the time so I dragged it across the area I wanted and bingo I get the file on my Desktop.


Now we create a folder called Resources in the project solution by right clicking the project and selecting Add / New Folder and enter the name "Resources". Next you drag the PNG file from the desktop into the folder and select "Copy" from the dialogue which will place the file into the project.


OK, now we're at the stage of linking it up. Right click the project and select "Options". In the Project Options dialogue go down to the "Build" section and select the "iPhone Application". Here you'll see the "Application Icon" option where you can select the icon from the list.



Adding Gestures to OpenGL application

In my last post I created a spinning 3DCube using MonoTouch which was a big step for me into the area of graphics. This time I want to try to control the objects rotation using gestures. Simply put, I want the default behavior to be a spinning cube, but if I press the screen the spinning should stop and I should be able to move the view manually using my finger.

Starting and stopping the animation

First need to make the View aware of the Touch events by adding the Touch Began and TouchEnded events. Edit the Cube3DView.cs class and add the event delegates.

[MonoTouch.Foundation.Export(&quot;touchesBegan:withEvent:&quot;)]

public override void TouchesBegan (MonoTouch.Foundation.NSSet touches, UIEvent evt)

{

Console.WriteLine(&quot;Click began&quot;);

StopAnimation();

}

[MonoTouch.Foundation.Export(&quot;touchesEnded:withEvent:&quot;)]

public override void TouchesEnded (MonoTouch.Foundation.NSSet touches, UIEvent evt)

{

Console.WriteLine(&quot;Click ended&quot;);

StartAnimation();

}

When doing this I noticed that there was a bug in the original code, setting the AnimationTimer to null did not stop the image rotation. So I had to invalidate the timer altogether, I’m not sure why at this stage but I’ll get back to it…

public void StopAnimation ()

{

AnimationTimer = null;

AnimationTimer.Invalidate ();

}


Changing the orientation with a finger

At first this seemed like a simple step to just change the orientation angle of the rotation but as you’ll see it’s never quite as easy at that. First off I needed to find the point on the view where we start the touch and the point where the finger was taken off the screen. This can then be passed back into the rotation function.

First I needed to add some extra code to store the X and Y coordinates. In the Code3DView.cs file we add two private variables.

PointF location; // global for drag

PointF _startLocation; // global for tourch start

Now we add come code to the TouchBegin and TouchEnd methods, we also add a new TouchMoved method. I’ve highlighted the code changes below.

[MonoTouch.Foundation.Export(&quot;touchesBegan:withEvent:&quot;)]

public override void TouchesBegan (MonoTouch.Foundation.NSSet touches, UIEvent evt)

{

var touch = (UITouch) evt.TouchesForView (this).AnyObject;

startLocation = touch.LocationInView(this);

StopAnimation ();

}


[MonoTouch.Foundation.Export(&quot;touchesMoved:withEvent:&quot;)]
public override void TouchesMoved (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
var touch = (UITouch) evt.TouchesForView (this).AnyObject;
location = this.Frame.Location;
location.X = touch.LocationInView(this).X;
location.Y = touch.LocationInView(this).Y;
}

[MonoTouch.Foundation.Export(&quot;touchesEnded:withEvent:&quot;)]
public override void TouchesEnded (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
float angle = TrigonometryHelper.Angle(startLocation.X, _startLocation.Y, _location.X, _location.Y);
GL.Rotate (angle, 1.0f, 1.0f, 1.0f);
StartAnimation ();
}

You’ll see that I had to add a new helper class to the project called TrigonometryHelper this is a simple set of code to help me calculate some of the values. Google is your friend when it comes down to this type of thing. Create a new empty class called TrigonometryHelper.cs and past in the following code.

using System;
namespace DCudeDemo
{
public static class TrigonometryHelper
{
public static float Angle(double px1, double py1, double px2, double py2)
{
// Negate X and Y values
double pxRes = px2 - px1;
double pyRes = py2 - py1;
double angle = 0.0;

// Calculate the angle
if (pxRes == 0.0)
{
if (pxRes == 0.0)
angle = 0.0;
else if (pyRes > 0.0)
angle = System.Math.PI / 2.0;
else
angle = System.Math.PI * 3.0 / 2.0;
}
else if (pyRes == 0.0)
{
if (pxRes > 0.0)
angle = 0.0;
else
angle = System.Math.PI;
}
else
{
if (pxRes < 0.0)
angle = System.Math.Atan(pyRes / pxRes) + System.Math.PI;
else if (pyRes < 0.0)
angle = System.Math.Atan(pyRes / pxRes) + (2 * System.Math.PI);
else
angle = System.Math.Atan(pyRes / pxRes);
}
// Convert to degrees
angle = angle * 180 / System.Math.PI;
return float.Parse(angle.ToString());
}
}
}

This is a class that I’m sure will begin to expand in functionality later.


Compiling and running the application now allows you to change the orientation of the cube with your finger.


















Sunday, October 25, 2009

3D Cube using MonoTouch on the iPhone


I've been trying out some OpenGL code on the iPhone which is way out of my comfort zone. It's the first time i've posted anything using MonoTouch also, but with any luck if I can continue to work in this area it may lead to some new innovations. My first project in this area would be to create a 3D cube and rotate it. Sounds simple, but finding posting and same code using MonoTouch turn out to be impossible. "How hard can it be?" I said to myself, well .. lets see....

Creating the project

MonoTouch and MonoDevelop makes this very easy indeed, just start the IDE and select File/New/Solution, select iPhone/iPhone MonoTouch Project and give it the name 3DCubeDemo.




Click Forward and then OK.


This will give you a standard project structure with a Main.cs file which is the same as the ApplicationDelegate and a MainWindow.xib file which is the InterfaceBuilder file for defining the interface.



Adding our View


First step is to create a view onto which we can apply our 3D Cube. Double Click the MainWindow.xib file which should start Interface Builder.


Drag a new view Control from the "Windows, Views & Bars" section in the Library onto the Window.



Change the View class field to "Cube3DView" and the Interface Name to Cube3DView.


Select the App Delegate and Create a new outlet called cude3DView. Then connect this to the view by dragging the link to the View called Cube3DView.




Save the file and close InterfaceBuilder.


Doing the code thing...


When you save the file in interface Builder you'll see that it automatically updates your MainWindow.xib.designer.cs file with a partial class called Cube3DView and add a property to the AppDelegate called cube3Dview. This is all fine if we just wanted to use the out of the box UIView methods but in this case we need a bit more access. best thing to do is modify the property so it returns a full Cude3DView class as opposed to the default UIView.

[MonoTouch.Foundation.Connect("cube3DView")]
private MonoTouch.UIKit.UIView cube3DView {

get {

return ((MonoTouch.UIKit.UIView)(this.GetNativeField("cube3DView")));
}

set {
this.SetNativeField("cube3DView", value);
}

}

becomes

[MonoTouch.Foundation.Connect("cube3DView")]
private Cube3DView cube3DView {

get {

return ((Cube3DView)(this.GetNativeField("cube3DView")));
}

set {
this.SetNativeField("cube3DView", value);
}

}


and
// Base type probably should be MonoTouch.UIKit.UIView or subclass

[MonoTouch.Foundation.Register("Cube3DView")]
public partial class Cube3DView {
}

becomes

// Base type probably should be MonoTouch.UIKit.UIView or subclass
[MonoTouch.Foundation.Register("Cube3DView")]
public partial class Cube3DView : MonoTouch.UIKit.UIView {
}

Note: This is a problem for the moment as once you edit the view again in InterfaceBuilder it will overwrite your changes. I'll keep looking out for better solutions using partial classes.

Creating the Model and link to OpenGL.

Create a new class file called Cube3DViewand place the following code into the file. I've bolded some of the more interesting areas;

using System;
using System.Drawing;
using MonoTouch.CoreAnimation;
using MonoTouch.CoreGraphics;
using MonoTouch.Foundation;
using MonoTouch.OpenGLES;
using MonoTouch.UIKit;
using MonoTouch.ObjCRuntime;
using OpenTK.Graphics;
using OpenTK.Graphics.ES11;
using OpenTK.Platform;
using OpenTK.Platform.iPhoneOS;

namespace DCudeDemo
{
public partial class Cube3DView : UIView {
int BackingWidth;
int BackingHeight;
iPhoneOSGraphicsContext Context;
uint ViewRenderBuffer, ViewFrameBuffer;
uint DepthRenderBuffer;
NSTimer AnimationTimer;
internal double AnimationInterval;

const bool UseDepthBuffer = false;

[Export ("layerClass")]
public static Class LayerClass ()
{
return new Class (typeof (CAEAGLLayer));
}

[Export ("initWithCoder:")]
public Cube3DView (NSCoder coder) : base (coder)
{
CAEAGLLayer eaglLayer = (CAEAGLLayer) Layer;
eaglLayer.Opaque = true;
eaglLayer.DrawableProperties = NSDictionary.FromObjectsAndKeys (
new NSObject []{NSNumber.FromBoolean(false), EAGLColorFormat.RGBA8},
new NSObject []{EAGLDrawableProperty.RetainedBacking, EAGLDrawableProperty.ColorFormat}
);
Context = (iPhoneOSGraphicsContext) ((IGraphicsContextInternal) GraphicsContext.CurrentContext).Implementation;

Context.MakeCurrent(null);
AnimationInterval = 1.0 / 60.0;
}

void DrawView ()
{
float[] cube = {
-0.5f, 0.5f, 0.5f, // vertex[0]
0.5f, 0.5f, 0.5f, // vertex[1]
0.5f, -0.5f, 0.5f, // vertex[2]
-0.5f, -0.5f, 0.5f, // vertex[3]
-0.5f, 0.5f, -0.5f, // vertex[4]
0.5f, 0.5f, -0.5f, // vertex[5]
0.5f, -0.5f, -0.5f, // vertex[6]
-0.5f, -0.5f, -0.5f, // vertex[7]
};


byte[] triangles = {
1, 0, 2, // front
3, 2, 0,
6, 4, 5, // back
4, 6, 7,
4, 7, 0, // left
7, 3, 0,
1, 2, 5, //right
2, 6, 5,
0, 1, 5, // top
0, 5, 4,
2, 3, 6, // bottom
3, 7, 6,
};

float[] cubeColors = {
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
};

Context.MakeCurrent(null);
GL.Oes.BindFramebuffer (All.FramebufferOes, ViewFrameBuffer);
GL.Viewport (0, 0, BackingWidth, BackingHeight);

GL.Enable(All.CullFace);
GL.MatrixMode (All.Projection);
GL.LoadIdentity ();
GL.Ortho (-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
GL.MatrixMode (All.Modelview);
GL.Rotate (3.0f, 0.0f, 2.0f, 1.0f);

GL.ClearColor (0.5f, 0.5f, 0.5f, 1.0f);
GL.Clear ((uint) All.ColorBufferBit);

GL.VertexPointer(3, All.Float, 0, cube);
GL.EnableClientState (All.VertexArray);
GL.ColorPointer (4, All.Float, 0, cubeColors);
GL.EnableClientState (All.ColorArray);
GL.DrawElements(All.Triangles, 36, All.UnsignedByte, triangles);

GL.Oes.BindRenderbuffer (All.RenderbufferOes, ViewRenderBuffer);
Context.EAGLContext.PresentRenderBuffer ((uint) All.RenderbufferOes);
}

public override void LayoutSubviews ()
{
Context.MakeCurrent(null);
DestroyFrameBuffer ();
CreateFrameBuffer ();
DrawView ();
}

bool CreateFrameBuffer ()
{
GL.Oes.GenFramebuffers (1, ref ViewFrameBuffer);
GL.Oes.GenRenderbuffers (1, ref ViewRenderBuffer);

GL.Oes.BindFramebuffer (All.FramebufferOes, ViewFrameBuffer);
GL.Oes.BindRenderbuffer (All.RenderbufferOes, ViewRenderBuffer);
Context.EAGLContext.RenderBufferStorage ((uint) All.RenderbufferOes, (CAEAGLLayer) Layer);
GL.Oes.FramebufferRenderbuffer (All.FramebufferOes,
All.ColorAttachment0Oes,
All.RenderbufferOes,
ViewRenderBuffer);

GL.Oes.GetRenderbufferParameter (All.RenderbufferOes, All.RenderbufferWidthOes, ref BackingWidth);
GL.Oes.GetRenderbufferParameter (All.RenderbufferOes, All.RenderbufferHeightOes, ref BackingHeight);

if (GL.Oes.CheckFramebufferStatus (All.FramebufferOes) != All.FramebufferCompleteOes) {
Console.Error.WriteLine("failed to make complete framebuffer object {0}",
GL.Oes.CheckFramebufferStatus (All.FramebufferOes));
}
return true;
}

void DestroyFrameBuffer ()
{
GL.Oes.DeleteFramebuffers (1, ref ViewFrameBuffer);
ViewFrameBuffer = 0;
GL.Oes.DeleteRenderbuffers (1, ref ViewRenderBuffer);
ViewRenderBuffer = 0;

if (DepthRenderBuffer != 0) {
GL.Oes.DeleteRenderbuffers (1, ref DepthRenderBuffer);
DepthRenderBuffer = 0;
}
}

public void StartAnimation ()
{
AnimationTimer = NSTimer.CreateRepeatingScheduledTimer (TimeSpan.FromSeconds (AnimationInterval), () => DrawView ());
}

public void StopAnimation ()
{
AnimationTimer = null;
}

public void SetAnimationTimer (NSTimer timer)
{
AnimationTimer.Invalidate ();
AnimationTimer = timer;
}

public void SetAnimationInterval (double interval)
{
AnimationInterval = interval;
if (AnimationTimer != null) {
StopAnimation ();
StartAnimation ();
}
}
}
}

I can't really take all the credit for this script as it's mainly a modification of the 2D sample provided on the MonoTouch site. There were however a number of changes needed to work this into a 3D model. The "cube[]" array of floats contains all the data for the model, these are simple X, Y, Z coordinates positioned from 0,0,0 at the centre. The triangles byte array for geometry, where I get a bit fuzzy on the whole thing, check out the iPhone OpenGL article which I used as a base for my example. The other functions should be self explanatory GL.Rotate, GL.VertexPointer and GL.DrawElements are where all the data comes together.

Once you compile you'll get the error "The type or namespace 'OpenTK' could not be found" error. OpenTK is simply the Mono implementation of the OpenGL infrastructure so all you need to do is add this as a project reference. <Ctrl> Click the References folder in your solution and select "Edit References...".



Click the OpenTK reference and click OK.


Finally we need to initialize this new class correctly in the Main.cs file. Open the Main.cs file and add the following using commands at the top of the file.

using OpenTK.Platform;


using MonoTouch.OpenGLES;


Modify the Main entry point to the application so it tells the UIApplication that we will be making use of OpenGL.


static void Main (string[] args)

{

using (var c = Utilities.CreateGraphicsContext(EAGLRenderingAPI.OpenGLES1)) {

UIApplication.Main (args);

}

}


Modify the AppDelegate "FinishedLoading" method so that it initializes the animation;

public override bool FinishedLaunching (UIApplication app, NSDictionary options)

{

// If you have defined a view, add it here:

// window.AddSubview (navigationController.View);

window.MakeKeyAndVisible ();

cube3DView.AnimationInterval = 1.0 / 60.0;

cube3DView.StartAnimation();

return true;

}


Compile and run the application and you should see the following appear in the simulator:



How good is that!?!