MilGra
milgra
about
articles
projects

blogroll
bit-101
coding horror
blameit
failblog
beszeljukmac
sghu

navigation
posts
docs
admin

<<previous posts
2010-01-18 iPhone openGL ES basics - animation
Lets continue from "iPhone openGL ES basics - textures as point sprites"

Lets move our point sprites around. We need a few instance variables for this in the header. We need an array of GLfloats to store coordinates, two float for storing the two particles directions, the EAGLContext, and a NSTimer for simulation/screen refresh.

#import "GLView.h"
#import <OpenGLES/ES1/glext.h>

@interface MinimalAppDelegate : NSObject
{

NSTimer* timer;
UIWindow* window;
GLView* glview;
GLfloat* points;
EAGLContext* context;

float angleA;
float angleB;

}

- ( void ) update;
@end

Go back to MinimalAppDelegate implementation. We have to remove the drawing part from the bottom of applicationDidFinishLaunching method. We have to setup movement variables and the timer there instead.

angleA = ( float ) rand( ) / RAND_MAX * M_PI * 2;
angleB = ( float ) rand( ) / RAND_MAX * M_PI * 2;

points = malloc( sizeof( GLfloat ) * 4 );

points[ 0 ] = ( GLfloat ) rand( ) / RAND_MAX * 320;
points[ 1 ] = ( GLfloat ) rand( ) / RAND_MAX * 480;
points[ 2 ] = ( GLfloat ) rand( ) / RAND_MAX * 320;
points[ 3 ] = ( GLfloat ) rand( ) / RAND_MAX * 480;

// START TIMER

timer = [ NSTimer
scheduledTimerWithTimeInterval : ( NSTimeInterval ) 1.0 / 20.0
target : self
selector : @selector ( update )
userInfo : nil
repeats : YES ];


We have to move the drawing part to a separate function, which will be called by our NSTimer simultaneously. This will be "update".

First we need to refresh particle positions.

// modify direction

angleA += -.5 + ( float ) rand( ) / RAND_MAX * 1;
angleB += -.5 + ( float ) rand( ) / RAND_MAX * 1;

// update position

points[ 0 ] += sin( angleA ) * 10;
points[ 1 ] += cos( angleA ) * 10;
points[ 2 ] += sin( angleB ) * 10;
points[ 3 ] += cos( angleB ) * 10;

// check borders

if ( points[0] > 320 || points[0] < 0 || points[1]> 480 || points[1] < 0 ) angleA -= M_PI;
if ( points[2] > 320 || points[2] < 0 || points[3]> 480 || points[3] < 0 ) angleB -= M_PI;


Then let's move the texture sprite drawing code below

// enable texturing

glEnable( GL_TEXTURE_2D );

// assig vertex pointer

glVertexPointer( 2 , GL_FLOAT , 0 , points );

// set point size

glPointSize( 150 );

// draw vertexes

glDrawArrays( GL_POINTS , 0 , 2 );


Then, to make things more spectacular, we darken the whole scene, and we get a nice "glowing trail" effect. We will draw a simple square with the help of a triangle strip, we will use vertex coloring, so we have to switch off textures, and enable color array access.

The last part is :

// disable texturing

glDisable( GL_TEXTURE_2D );

// enable color array for writing

glEnableClientState( GL_COLOR_ARRAY );

// define screen sized square with transparency

GLfloat square [ ] = { 0 , 0 , 0 , 480 , 320 , 0 , 320 , 480 };
GLubyte colors [ ] = { 0 , 0 , 0 , 200 , 0 , 0 , 0 , 200 , 0 , 0 , 0 , 200 , 0 , 0 , 0 , 200 };

// assign vertex and color pointer

glVertexPointer( 2 , GL_FLOAT , 0 , square );
glColorPointer( 4 , GL_UNSIGNED_BYTE , 0 , colors );

// draw

glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 );

// disable color array before using texture

glDisableClientState( GL_COLOR_ARRAY );

// display renderbuffer content

[ context presentRenderbuffer : GL_RENDERBUFFER_OES ];


If you move the darkening part before the sprite drawing, you get brighter glows, check it in the source.

Download source.


2010-01-17 iPhone openGL ES basics - textures as point sprites
Okay, let's continue from "The minimal iphone opengl es application".

Let's go to the point in MinimalAppDelegate where we bind glview's layer to opengl's renderbuffer.

[ context renderbufferStorage : GL_RENDERBUFFER_OES fromDrawable : ( CAEAGLLayer * ) glview.layer ];

So we want some texture. The simplest form of a texture in opengl is a point sprite. OpenGL maps the given texture to the wanted point with the wanted size. Sounds simple, and it is.

First we have to load an image we want to use as a texture. Create a gradient sphere with alpha in a photo editor, save it as a transparent png.
We use UIImage for loading the image.

CGImageRef brushImage = [ UIImage imageNamed : @"Particle.png" ].CGImage;

We have to extract the raw byte data from the image, we use Core Foundation's DataGetBytePointer function to get the pointer to the byte array provided by CGImage's dataprovider.

GLubyte* brushData = ( GLubyte * ) CFDataGetBytePtr( CGDataProviderCopyData ( CGImageGetDataProvider ( brushImage ) ) );

We have it now, texture generation comes

GLuint brushTexture;
glGenTextures( 1 , &brushTexture );
glBindTexture( GL_TEXTURE_2D , brushTexture );

Let's set up a linear filter for the texture

glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR );

And finally create the texture from our bytearray

glTexImage2D( GL_TEXTURE_2D , 0 , GL_RGBA , CGImageGetWidth( brushImage ) , CGImageGetHeight( brushImage ) , 0 , GL_RGBA , GL_UNSIGNED_BYTE , brushData );

Yaaay. Don't forget to free brushData array.

We have the texture, let's draw it as point sprites.We want to see smooth alpha transitions, so we have to enable alpha blending.

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

Let's set up the screen's dimensions for orthographic projection and for the viewport.

glMatrixMode( GL_PROJECTION );
glOrthof( 0 , 320 , 0 , 480 , -1 , 1 );
glViewport( 0 , 0 , 320 , 480 );

Enable 2D textures and point sprites.

glEnable( GL_TEXTURE_2D );
glEnable( GL_POINT_SPRITE_OES );
glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE );

Set up points for the sprites

glPointSize( 100 );
GLfloat points [ ] = { 130 , 200 , 100 , 204 };

Enable vertex array for writing

glEnableClientState(GL_VERTEX_ARRAY);

Assign vertex pointer

glVertexPointer( 2 , GL_FLOAT , 0 , points );

And finally, draw vertexes.

glDrawArrays( GL_POINTS , 0 , 2 );

And display renderbuffer.

[ context presentRenderbuffer : GL_RENDERBUFFER_OES ];


Run/debug it, you'll see two beautiful intersecting clouds :D

Download source.

MilGra


2010-01-16 The minimal iPhone openGL ES application
Let's use the source from the previous tutorial, "The minimal iPhone application".

We will need an openGL ES framework. Right click on Frameworks folder, Add -> Existing Frameworks, select an OpenGLES framework, click Add. If you don't know how to locate one, create a new openGLES project, right click on OpenGLES.framework under frameworks, and check the full path. We also need the QuartzCore framework for CAEAGLLayer. Do as above.

To show an openGL output, we need a core animation gl layer to bind the renderbuffer to, and UIView has this. So we need an UIView instance. But its not that simple, by default UIView's layer is a CALayer instance, but openGL context needs a CAEAGLLayer instance to work, so we have to mimic it. We need a new class which extends UIView, and we have to override UIView's "layerClass" class method definition.

Right click on Classes, Add -> New File -> Objective-C class -> Next -> name it GLView.m, click Finish. Delete the #import from the header file. Extend it from UIView.

#import

@interface GLView : UIView
{

}

@end

Only one thing is needed in the implementation file, the layerClass override :

#import "GLView.h"

@implementation GLView

+ ( Class )
layerClass
{

return [ CAEAGLLayer class ];

}

@end

So from now on it will tell that its layer is a caeagllayer instance. Great. We made two additional files for almost nothing. Quite a shitty solution from Apple.

Yesokay, lets get back to MinimalAppDelegate. We have to instantiate our layer. We need a new property in the header :

GLView* glview;

don't forget to import

#import "GLView.h"

we also need to import the openGL ES1 extensions

#import <OpenGLES/ES1/glext.h>

The result :

#import "GLView.h"
#import <OpenGLES/ES1/glext.h>

@interface MinimalAppDelegate : NSObject
{

UIWindow* window;
GLView* glview;

}

@end


And in the implementation we instantiate our newly created GLView class:

glview = [ [ GLView alloc ] initWithFrame : [ [ UIScreen mainScreen ] bounds ] ];

Lets add this view as a subview to the main window.

[ window addSubview : glview ];

now we can create our openGL ES1 context.

EAGLContext* context = [ [ EAGLContext alloc ] initWithAPI : kEAGLRenderingAPIOpenGLES1 ];

Set it as the active context :

[ EAGLContext setCurrentContext : context ];

From now on we can work with the context. We need a color and a frame buffer. Let's generate names for them.

GLuint colorBuffer;
GLuint frameBuffer;

glGenFramebuffersOES( 1 , &frameBuffer );
glGenRenderbuffersOES( 1 , &colorBuffer );

Bind framebuffer as framebuffer, colorbuffer as renderbuffer.

glBindFramebufferOES( GL_FRAMEBUFFER_OES , frameBuffer );
glBindRenderbufferOES( GL_RENDERBUFFER_OES , colorBuffer );

We have to attach the colorBuffer to the frameBuffer as color attachment.

glFramebufferRenderbufferOES( GL_FRAMEBUFFER_OES , GL_COLOR_ATTACHMENT0_OES , GL_RENDERBUFFER_OES , colorBuffer );

The only thing left is binding glview's layer to opengl's renderbuffer.

[ context renderbufferStorage : GL_RENDERBUFFER_OES fromDrawable : ( CAEAGLLayer * ) glview.layer ];

Now we can do something spectacular, for example, setting the background color to dark green.

glClearColor( 0 , .3 , 0 , 1.0 );
glClear( GL_COLOR_BUFFER_BIT );

And display the render buffer :

[ context presentRenderbuffer : GL_RENDERBUFFER_OES ];

Yaaaay! If you run/debug the application, you will see a beautiful dark green color on your opengl layer.

Download source.

MilGra


2010-01-15 The minimal iPhone application
"Keep it as small and simple as possible" - me, all the time

Xcode, New Project -> Application -> Window Based Application, name it Minimal, and Save.

What you see in xcode now is the plain iphone application. But there are still too many unnecessary things there. We are real programmers, we won't need the interface builder descriptor, so right click on MainWindow.xib, select delete, and move to trash. Open Minimal-Info.plist as plain text file, and delete the last key-string node from it ( with MSMainNibFile and MainWindow ).
Let's remove Coregraphics.framework from frameworks, we don't need it. Right click on it, delete, move to trash.
Let's check main.m. Delete NSAutoreleasePool initialization and the release lines, we are real programmers, we want total control, not autorelease sh*t. :) Without these two lines we can simplify this function, move UIApplicationMain init after return, and remove UIKit import from the top, its already in the prefix header. We also have to tell UIApplicationMain which is our Delegate class. The result should look like this :

int main ( int countX , char *wordsX[ ] )
{

return UIApplicationMain( countX , wordsX , nil , @"MinimalAppDelegate" );

}

Let's check MinimalAppDelegate.h. Delete the @property line, we don't want to set, get and synthesize the window. Also remove UIKit import.

MinimalAppDelegate.m comes. Remove @synthesize window. Let's create it "manually". Normally it is synthesized based on the interface builder file, but we deleted that.
Let's create an UIWindow instance with the screen's dimensions :

window = [ [ UIWindow alloc ] initWithFrame : [ [ UIScreen mainScreen ] bounds ] ];

The result :

@implementation MinimalAppDelegate


- ( void )
applicationDidFinishLaunching : ( UIApplication* ) application
{

window = [ [ UIWindow alloc ] initWithFrame : [ [ UIScreen mainScreen ] bounds ] ];
[ window makeKeyAndVisible ];

}


- ( void )
dealloc
{

[ window release ];
[ super dealloc ];

}


@end

You can debug and run the application. Let's check the project's folder. We have three files in the root, the prefix, the plist and main.m, and two files for MinimalAppDelegate class under classes folder. If you do a release build, you will find that the size of the binary is 17704 bytes, so this seems the minimal size of a compiled application, of course you can short it with one-char method and attribute names, but it won't be readable then, so it won't be that simple to work with, and our first and only rule would be harmed.

Here is the link to the project source.

MilGra


2009-11-01 Termite is out!!!
After three weeks of heavy development and objective-c exploration my first iPhone game is out :D

Termite

It wasn't easy. After ten years of java/actionscript i had to rediscover c, and learn its smalltalk like objective extensions. Then a lot of experimenting came, and i started writing Termite under the project name "The Swarm". In the first phase i used Quartz for rendering, but after the first few crowded scenes i had to consider using openGL, because Quartz was really slow over 2-300 particles, and openGL can easily render 10000 on a 3G.

Of course, 10000 ants wouldn't be possible, beacuse of the continuous proximity detection. I had a few issues with that, first every actor cheked every actor, and it became really slow because of the tremendous array enumerations, so i turned to collosion grid, and the speed became fair.

After finishing the engine, i realized that i will need fix levels, not just random and custom ones, so in the last two weeks i was figuring out new levels.

In the last week I bought a worn down scratchy used iphone, the cheapest in the market, and started testing, and everything was fine. So, I did the final steps, compiled the app with the distribution certificate, and its out.

I know the gfx is quite modest, but its old school man!!! :D I'm sure the playability is okay, i really love playing this on the subway.

So keep it playing while my next game ( which will be 3D, yeaaaah ) is coming.

MilGra


2009-06-22 One of the best programming tools ever made!!!
And that is sdedit. The quick sequence diagram editor. Its awesome, its heaven, its salvation.

Its like a command line uml sequence diagram drawer. There is a descriptor script on the left, and the diagram on the right. Only with a few lines of description you can create complex diagrams, it supports multithreading, and everything possible.

I was in pain in the past four days, i’ve tried a lot of sequence diagram editors, standalone and eclipse-plugins, free and closed source, but they were all so difficult to use, click a lot for a little change, to insert a thread, or it was impossible at all.

And then i found sdedit. I was surprised, is it possible to describe complex diagrams with simple commands? And yes, since it draws sequence diagrams, sequencing elements is straightforward.

Should be industry-standard.

Thank you Marcus Strauch.



2009-06-10 Quick flash to java switch
I would like to help out those few sad souls who want to switch from flash/flex to java to create some graphical stuff.

I just want to show the basic idea, let’s draw a simple red square.
In flash its simple, since flash is for creating graphics, the main class has to be a Sprite or a MovieClip, and you can directly access the graphics interface of these two, and can draw directly.

In flash, since the first frame is the main sprite, you simply can write

graphics.beginFill( 0xff0000 , 1 );
graphics.drawRect( 0 , 0 , 100 , 100 );

in flex, it looks like this :

Source Code

and there is it.

In java, since its a general purpose programming language, its more complicated.
We need a window, where we can show our graphics, and then we need a component where we can paint our stuff. But still, we can do it quite simply in one class.

To create a window, we simply instantiate java.awt.Frame class, and for drawing we will use the java.awt.Canvas class, which is the simplest component for drawing.

Consider java.awt.Frame as the Stage in flash, and java.awt.Canvas as the main Sprite. So, here we go :

Source Code

The biggest difference that we cannot draw immediately, we have to wait for jvm’s inner call to the paint( Graphics g ) method, altough we can request it by calling the repaint( ) method.

We have an easier job with an applet, because Applet main class is a Panel subclass in which we have the paint method, and its already in a window.

MilGra


2009-05-16 Iteration hell
a very common problem in java when you are iterating through some list, and an external thread or the thread itself wants to modify the underlying list

Source Code

to avoid concurrent modification exception, the most common solution is to use an iterator and add/delete the new element with it, or, if it is safe for the same thread, use synchronization to handle external threads.

my problem is that both solution needs too many cpu cycles.
for most cases, the solution below is the best :

Source Code

so if the original list is changed, we clone it before iterating through, and modification of the original array won’t affect iteration. but beware, its only good if a plus cycle doesn’t matter on the objects ( no destruction happens before removing the element ).
in those cases good old iterator has to be used.

MilGra


powered by kure