milgra
about
articles
projects
blogroll
bit-101
coding horror
blameit
failblog
beszeljukmac
sghu
navigation
posts
docs
admin
|
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
|
<<previous posts
|