Using Opengl
<Google>WIKI</Google>
Drawing Using OpenGL
If you want to draw with OpenGL directly do the following:
You have to:
- Add /System/Library/Frameworks/Opengl.framework
- import the Header
#import <OpenGL/OpenGL.h> #import <OpenGL/glu.h>
- Subclass BRRenderLayer
- add a method (void)renderLayer;
- In renderLayer do the following:
- (void)renderLayer { int oldMatMode; glGetIntegerv(GL_MATRIX_MODE, &oldMatMode); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPerspective(45.0, 16.0/9.0, 0.1, 100.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); gluLookAt( 0.0,0.0,-10.0, 0.0,0.0,0.0, 0.0,1.0,0.0 ); _rot += 0.2; glRotatef(_rot,0.0,1.0,0.0); glBegin(GL_TRIANGLES); glColor4f(1.0,.0,.0,_alpha); glVertex3f(0.0,0.0,0.5); glVertex3f(1.0,0.0,0.5); glVertex3f(1.0,1.0,0.5); glEnd(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glFlush(); glMatrixMode(oldMatMode); }
_rot is a member variable of your subclass. Initialize it with 0.0 or something
The important part is to:
- If you enable something (for instance GL_TEXTURE_RECTANGLE_ARB, used by most BR layers), always disable it at the end.
- glPush/PopMatrix all the matrices you change
- Reset the glMatrixMode to the old one after you are done.
You do not need to call [super renderLayer] unless you want the superclass's drawing to appear on top of yours. BRRenderLayer does nothing in -renderLayer, and you will usually implement this function yourself to provide all your own rendering. Similarly, you usually should not explicitly enable/disable blending in your render routine; the scene is set up for blending using glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA). The framework may disable this, however. So if you *need* blending, or if you need a different algorithm, *always* fetch the the current setting first, and restore that upon completion.
Periodic Updates
Updates are fairly simple to do, although a proper, clean implementation requires a couple of extra things:
Firstly, call [self setNeedsUpdates: YES]
to get your layer attached to the CoreVideo rendering callback (usually called with each refresh, or thereabouts). You then need to implement the function - (BOOL) updateFrameForTime: (const CVTimeStamp *) timeStamp
in your layer. This function will be called each time the CoreVideo refresh timer fires.
For the structure declaration, you need to include <QuartzCore/CVBase.h>. The structure declaration looks as follows:
typedef struct { uint32_t version; // Currently will be 0. int32_t videoTimeScale; // Video timescale (units per second) int64_t videoTime; // This represents the start of a frame (or field for interlaced) .. think vsync - still not 100% sure on the name uint64_t hostTime; // Host root timebase time double rateScalar; // Current rate as measured by the timestamps divided by the nominal rate int64_t videoRefreshPeriod; // Hint for nominal output rate CVSMPTETime smpteTime; uint64_t flags; uint64_t reserved; } CVTimeStamp;
Because the callbacks aren't guaranteed to occur at specific intervals known at compile-time, it is advised that you do the following:
- Add two member variables to your class:
double _timeFreq;
anddouble _prevTime;
. - In your initializer, do the following:
_timeFreq = CVGetHostClockFrequency( );
- Implement the
-updateFrameForTime:
function similar to the following, to update on a specific schedule:
- (BOOL) updateFrameForTime: (const CVTimeStamp *) time { BOOL result = NO; @synchronized(self) { double hostTime = (double) time->hostTime; double now = hostTime / _timeFreq; // this will not update unless 1/30th of a second has passed since the last update if ( now < _prevTime + (1.0 / 30.0) ) { // returning NO will cause the layer to NOT be redrawn result = NO; } else { // change whatever you want to change here, as a function of time elapsed // return YES to have your layer redrawn result = YES; } } return ( result ); }
Adding Effects to a Layer
There is a means of rendering a layer using 'effects' — this is seen for example on the scrolling done by menu items whose title is too long to fit within the allotted space. In that case, the text (as it scrolls, using the method outlined above) fades in and out on each side. This is achieved by settings an effects delegate on the layer. The delegate is not retained, so it is appropriate for a layer to set itself as its own effects delegate, like so:
[self setEffectsDelegate: self];
The effects are applied through a texture. When an effects delegate is set for a layer, a BRPBufferTexture object is created (the _effectsTexture member variable). Then when the layer is rendered (-renderLayer is called by a private method in BRRenderLayer), the GL context is set to that of the pixel buffer, and so -renderLayer actually draws into that buffer. Then the buffer is passed to the effects delegate, which should implement - (void) renderLayerTexture: (BRTexture *) texture
to create the 'effects' by drawing the texture on screen with any chosen transformations.
For example, to implement a fade similar to the one in BRAutoScrollingTextLayer, you can use the following implementation:
- (void) renderLayerTexture: (BRTexture *) texture { /* This is defined in <BackRow/CDStructures.h> struct BRTextureInfo { unsigned int textureID; unsigned int target; // GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_2D, etc. struct _NSSize size; // The size of the texture float topLeft[2]; // vectors for the corners of the image float topRight[2]; float bottomLeft[2]; float bottomRight[2]; }; */ const struct BRTextureInfo * texInfo = [texture textureInfo]; // enable the texture's target and bind in the texture glEnable( texInfo->target ); glBindTexture( texInfo->target, texInfo->textureID ); // using GL_QUAD_STRIP, because we'll be defining vertical lines as the fade endpoints, not whole rectangles glBegin( GL_QUAD_STRIP ); // the distance within the texture for the fade float inset = texInfo->size.width * 0.05f; // start at black for the left-hand end: glColor4f( 0.0f, 0.0f, 0.0f, 0.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0.0f, 0.0f ); glTexCoord2f( 0.0f, texInfo->size.height ); glVertex2f( 0.0f, texInfo->size.height ); // now fade up to white a little way in glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); glTexCoord2f( inset, 0.0f ); glVertex2f( inset, 0.0f ); glTexCoord2f( inset, texInfo->size.height ); glVertex2f( inset, texInfo->size.height ); // begins to fade out here (next white point) glTexCoord2f( texInfo->size.width - inset, 0.0f ); glVertex2f( texInfo->size.width - inset, 0.0f ); glTexCoord2f( texInfo->size.width - inset, texInfo->size.height ); glVertex2f( texInfo->size.width - inset, texInfo->size.height ); // fades to black by the end of the texture glColor4f( 0.0f, 0.0f, 0.0f, 0.0f ); glTexCoord2f( texInfo->size.width, 0.0f ); glVertex2f( texInfo->size.width, 0.0f ); glTexCoord2f( texInfo->size.width, texInfo->size.height ); glVertex2f( texInfo->size.width, texInfo->size.height ); glEnd( ); // release the texture glBindTexture( texInfo->target, 0 ); // disable the target glDisable( texInfo->target ); }