Sources/Classes/Toolkits/Model/OpenGL/IBO/Base/OpenGLIBO.m
//--------------------------------------------------------------------------- |
// |
// File: OpenGLIBO.m |
// |
// Abstract: Utility class that implements a method for generating a |
// 3D object using IBOs. |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by |
// Apple Inc. ("Apple") in consideration of your agreement to the |
// following terms, and your use, installation, modification or |
// redistribution of this Apple software constitutes acceptance of these |
// terms. If you do not agree with these terms, please do not use, |
// install, modify or redistribute this Apple software. |
// |
// In consideration of your agreement to abide by the following terms, and |
// subject to these terms, Apple grants you a personal, non-exclusive |
// license, under Apple's copyrights in this original Apple software (the |
// "Apple Software"), to use, reproduce, modify and redistribute the Apple |
// Software, with or without modifications, in source and/or binary forms; |
// provided that if you redistribute the Apple Software in its entirety and |
// without modifications, you must retain this notice and the following |
// text and disclaimers in all such redistributions of the Apple Software. |
// Neither the name, trademarks, service marks or logos of Apple Inc. |
// may be used to endorse or promote products derived from the Apple |
// Software without specific prior written permission from Apple. Except |
// as expressly stated in this notice, no other rights or licenses, express |
// or implied, are granted by Apple herein, including but not limited to |
// any patent rights that may be infringed by your derivative works or by |
// other works in which the Apple Software may be incorporated. |
// |
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
// |
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
// POSSIBILITY OF SUCH DAMAGE. |
// |
// Copyright (c) 2009-2011 Apple Inc., All rights reserved. |
// |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#import "OpenGLIBO.h" |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Data Structures |
//--------------------------------------------------------------------------- |
struct OpenGLBuffer |
{ |
GLint count; |
GLuint name; |
GLenum type; |
GLenum target; |
GLenum usage; |
GLenum access; |
GLsizei stride; |
}; |
typedef struct OpenGLBuffer OpenGLBuffer; |
//--------------------------------------------------------------------------- |
struct OpenGLVoidPtr |
{ |
GLsizeiptr size; |
GLintptr offset; |
const GLvoid *data; |
}; |
typedef struct OpenGLVoidPtr OpenGLVoidPtr; |
//--------------------------------------------------------------------------- |
struct OpenGLShortPtr |
{ |
GLsizeiptr size; |
GLintptr offset; |
const GLshort *data; |
}; |
typedef struct OpenGLShortPtr OpenGLShortPtr; |
//--------------------------------------------------------------------------- |
struct OpenGLGeometry |
{ |
OpenGLBuffer buffer; |
OpenGLVoidPtr vertices; |
OpenGLVoidPtr normals; |
GLvoid *pointer; |
}; |
typedef struct OpenGLGeometry OpenGLGeometry; |
//--------------------------------------------------------------------------- |
struct OpenGLElements |
{ |
OpenGLBuffer buffer; |
OpenGLShortPtr indices; |
GLshort *pointer; |
}; |
typedef struct OpenGLElements OpenGLElements; |
//--------------------------------------------------------------------------- |
struct OpenGLIBOData |
{ |
GLsizeiptr size; |
OpenGLGeometry geometry; |
OpenGLElements elements; |
}; |
typedef struct OpenGLIBOData OpenGLIBOData; |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Macros |
//--------------------------------------------------------------------------- |
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Constructor |
//--------------------------------------------------------------------------- |
static OpenGLIBODataRef OpenGLIBOCreate(const GLenum type) |
{ |
OpenGLIBODataRef pIBO = (OpenGLIBODataRef)calloc(1, sizeof(OpenGLIBOData)); |
if( pIBO != NULL ) |
{ |
pIBO->size = 0; |
pIBO->geometry.buffer.name = 0; |
pIBO->geometry.buffer.count = 3; |
pIBO->geometry.buffer.stride = 0; |
pIBO->geometry.buffer.type = type; |
pIBO->geometry.buffer.target = GL_ARRAY_BUFFER; |
pIBO->geometry.buffer.usage = GL_STREAM_DRAW; |
pIBO->geometry.buffer.access = GL_READ_WRITE; |
pIBO->geometry.pointer = NULL; |
pIBO->geometry.vertices.offset = 0; |
pIBO->geometry.vertices.size = 0; |
pIBO->geometry.vertices.data = NULL; |
pIBO->geometry.normals.offset = 0; |
pIBO->geometry.normals.size = 0; |
pIBO->geometry.normals.data = NULL; |
pIBO->elements.pointer = NULL; |
pIBO->elements.buffer.name = 0; |
pIBO->elements.buffer.stride = 0; |
pIBO->elements.buffer.type = GL_SHORT; |
pIBO->elements.buffer.target = GL_ELEMENT_ARRAY_BUFFER; |
pIBO->elements.buffer.usage = GL_STATIC_DRAW; |
pIBO->elements.buffer.access = GL_READ_WRITE; |
pIBO->elements.indices.offset = 0; |
pIBO->elements.indices.size = 0; |
pIBO->elements.indices.data = NULL; |
} // if |
return( pIBO ); |
} // OpenGLIBOCreate |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Destructors |
//--------------------------------------------------------------------------- |
static void OpenGLIBODeleteGeometry(OpenGLIBODataRef pIBO) |
{ |
if( pIBO->geometry.buffer.name ) |
{ |
glDeleteBuffers( 1, &pIBO->geometry.buffer.name ); |
pIBO->geometry.buffer.name = 0; |
} // if |
} // OpenGLIBODeleteGeometry |
//--------------------------------------------------------------------------- |
static void OpenGLIBODeleteElements(OpenGLIBODataRef pIBO) |
{ |
if( pIBO->elements.buffer.name ) |
{ |
glDeleteBuffers( 1, &pIBO->elements.buffer.name ); |
pIBO->elements.buffer.name = 0; |
} // if |
} // OpenGLIBODeleteElements |
//--------------------------------------------------------------------------- |
static void OpenGLIBODeleteBuffers(OpenGLIBODataRef pIBO) |
{ |
OpenGLIBODeleteGeometry(pIBO); |
OpenGLIBODeleteElements(pIBO); |
} // OpenGLIBODeleteBuffers |
//--------------------------------------------------------------------------- |
static void OpenGLIBODelete(OpenGLIBODataRef pIBO) |
{ |
if( pIBO != NULL ) |
{ |
OpenGLIBODeleteBuffers(pIBO); |
free( pIBO ); |
pIBO = NULL; |
} // if |
} // OpenGLIBODelete |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Utilities - Acquire |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOAcquireGeometry(OpenGLIBODataRef pIBO) |
{ |
glGenBuffers(1, &pIBO->geometry.buffer.name); |
if( pIBO->geometry.buffer.name ) |
{ |
pIBO->size = pIBO->geometry.vertices.size + pIBO->geometry.normals.size; |
glBindBuffer(pIBO->geometry.buffer.target, pIBO->geometry.buffer.name); |
{ |
glBufferData(pIBO->geometry.buffer.target, |
pIBO->size, |
0, |
pIBO->geometry.buffer.usage); |
glBufferSubData(pIBO->geometry.buffer.target, |
0, |
pIBO->geometry.vertices.size, |
pIBO->geometry.vertices.data); |
glBufferSubData(pIBO->geometry.buffer.target, |
pIBO->geometry.vertices.size, |
pIBO->geometry.normals.size, |
pIBO->geometry.normals.data); |
} |
glBindBuffer(pIBO->geometry.buffer.target, 0); |
} // if |
return( pIBO->geometry.buffer.name != 0); |
} // OpenGLIBOAcquireGeometry |
//--------------------------------------------------------------------------- |
// |
// Create a VBO for an index array. |
// |
// Target of this VBO is GL_ELEMENT_ARRAY_BUFFER and usage is GL_STATIC_DRAW |
// |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOAcquireElements(OpenGLIBODataRef pIBO) |
{ |
glGenBuffers(1, &pIBO->elements.buffer.name); |
if( pIBO->elements.buffer.name ) |
{ |
glBindBuffer( pIBO->elements.buffer.target, pIBO->elements.buffer.name ); |
{ |
glBufferData(pIBO->elements.buffer.target, |
pIBO->elements.indices.size, |
pIBO->elements.indices.data, |
pIBO->elements.buffer.usage); |
} |
glBindBuffer(pIBO->elements.buffer.target, 0); |
} // if |
return( pIBO->elements.buffer.name != 0); |
} // OpenGLIBOAcquireElements |
//--------------------------------------------------------------------------- |
// |
// Create a vertex name objects. Try to put both vertex coordinates |
// and normal arrays in the same name object. |
// |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOAcquire(OpenGLIBODataRef pIBO) |
{ |
BOOL success = OpenGLIBOAcquireGeometry(pIBO); |
if( success ) |
{ |
success = OpenGLIBOAcquireElements(pIBO); |
if( !success ) |
{ |
glDeleteBuffers(1, &pIBO->geometry.buffer.name); |
} // else |
} // if |
return( success ); |
} // OpenGLIBOAcquire |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Utilities - Bind/Unbind |
//--------------------------------------------------------------------------- |
// |
// Bind to display the geometry |
// |
//--------------------------------------------------------------------------- |
static void OpenGLIBOBind(OpenGLIBODataRef pIBO) |
{ |
glBindBuffer(pIBO->geometry.buffer.target, |
pIBO->geometry.buffer.name); |
glNormalPointer(pIBO->geometry.buffer.type, |
0, |
BUFFER_OFFSET(pIBO->geometry.normals.offset)); |
glVertexPointer(pIBO->geometry.buffer.count, |
pIBO->geometry.buffer.type, |
pIBO->geometry.buffer.stride, |
BUFFER_OFFSET(0)); |
glBindBuffer(pIBO->elements.buffer.target, |
pIBO->elements.buffer.name); |
glIndexPointer(pIBO->elements.buffer.type, |
pIBO->elements.buffer.stride, |
BUFFER_OFFSET(0)); |
} // OpenGLIBOBind |
//--------------------------------------------------------------------------- |
// |
// Unbind to revert back to the original state(s) |
// |
//--------------------------------------------------------------------------- |
static void OpenGLIBOUnbind(OpenGLIBODataRef pIBO) |
{ |
glBindBuffer(pIBO->elements.buffer.target, 0); |
glBindBuffer(pIBO->geometry.buffer.target, 0); |
} // OpenGLIBOUnbind |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Utilities - Copiers |
//--------------------------------------------------------------------------- |
// |
// Update the vertices in an IBO. |
// |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOCopyElements(const GLvoid *ptrSrc, |
const GLsizeiptr size, |
OpenGLIBODataRef pIBO) |
{ |
BOOL success = size < pIBO->elements.indices.size; |
if( success ) |
{ |
glBindBuffer(pIBO->elements.buffer.target, |
pIBO->elements.buffer.name); |
GLvoid *ptrDst = glMapBuffer(pIBO->elements.buffer.target, |
pIBO->elements.buffer.access); |
success = ptrDst != NULL; |
if( success ) |
{ |
memcpy(ptrDst, ptrSrc, size); |
glUnmapBuffer(pIBO->elements.buffer.target); |
} // if |
glBindBuffer(pIBO->elements.buffer.target, 0); |
} // if |
return( success ); |
} // OpenGLIBOCopyElements |
//--------------------------------------------------------------------------- |
// |
// Update the vertices in an IBO. |
// |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOCopyArray(const bool isNormals, |
const GLvoid *ptrSrc, |
const GLsizeiptr size, |
OpenGLIBODataRef pIBO) |
{ |
BOOL success = NO; |
GLsizeiptr offset = 0; |
if( isNormals ) |
{ |
offset = pIBO->geometry.vertices.size; |
success = (size + offset) < pIBO->size; |
} // if |
else |
{ |
success = size < pIBO->geometry.vertices.size; |
} // else |
if( success ) |
{ |
glBindBuffer(pIBO->geometry.buffer.target, |
pIBO->geometry.buffer.name); |
GLvoid *ptrDst = glMapBuffer(pIBO->geometry.buffer.target, |
pIBO->geometry.buffer.access); |
success = ptrDst != NULL; |
if( success ) |
{ |
if( offset > 0 ) |
{ |
ptrDst += offset; |
} // if |
memcpy(ptrDst, ptrSrc, size); |
glUnmapBuffer(pIBO->geometry.buffer.target); |
} // if |
glBindBuffer(pIBO->geometry.buffer.target, 0); |
} // if |
return( success ); |
} // OpenGLIBOCopyArray |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private - Utilities - Map/Unmap |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOMapArray(OpenGLIBODataRef pIBO) |
{ |
BOOL success = NO; |
glBindBuffer(pIBO->geometry.buffer.target, |
pIBO->geometry.buffer.name); |
pIBO->geometry.pointer = glMapBuffer(pIBO->geometry.buffer.target, |
pIBO->geometry.buffer.access); |
success = pIBO->geometry.pointer != NULL; |
return( success ); |
} // OpenGLIBOMapArray |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOUnmapArray(OpenGLIBODataRef pIBO) |
{ |
BOOL success = glUnmapBuffer(pIBO->geometry.buffer.target); |
glBindBuffer(pIBO->geometry.buffer.target, 0); |
return( success ); |
} // OpenGLIBOUnmapArray |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOMapElements(OpenGLIBODataRef pIBO) |
{ |
BOOL success = NO; |
glBindBuffer(pIBO->elements.buffer.target, |
pIBO->elements.buffer.name); |
pIBO->elements.pointer = (GLshort *)glMapBuffer(pIBO->elements.buffer.target, |
pIBO->elements.buffer.access); |
success = pIBO->elements.pointer != NULL; |
return( success ); |
} // OpenGLIBOMapElements |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOUnmapElements(OpenGLIBODataRef pIBO) |
{ |
BOOL success = glUnmapBuffer(pIBO->elements.buffer.target); |
glBindBuffer(pIBO->elements.buffer.target, 0); |
return( success ); |
} // OpenGLIBOUnmapElements |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOMap(const GLenum target, |
OpenGLIBODataRef pIBO) |
{ |
BOOL success = NO; |
if( target == GL_ELEMENT_ARRAY_BUFFER ) |
{ |
success = OpenGLIBOMapElements(pIBO); |
} // if |
else |
{ |
success = OpenGLIBOMapArray(pIBO); |
} // else |
return( success ); |
} // OpenGLIBOMap |
//--------------------------------------------------------------------------- |
static BOOL OpenGLIBOUnmap(const GLenum target, |
OpenGLIBODataRef pIBO) |
{ |
BOOL success = NO; |
if( target == GL_ELEMENT_ARRAY_BUFFER ) |
{ |
success = OpenGLIBOUnmapElements(pIBO); |
} // if |
else |
{ |
success = OpenGLIBOUnmapElements(pIBO); |
} // else |
return( success ); |
} // OpenGLIBOUnmap |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
//--------------------------------------------------------------------------- |
@implementation OpenGLIBO |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Public - Designated Initializer |
//--------------------------------------------------------------------------- |
- (id) initIBOWithType:(const GLenum)theType |
{ |
self = [super init]; |
if( self ) |
{ |
mpIBO = OpenGLIBOCreate(theType); |
} // if |
return self; |
} // initIBOWithVertices |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Public - Destructor |
//--------------------------------------------------------------------------- |
- (void) dealloc |
{ |
OpenGLIBODelete(mpIBO); |
[super dealloc]; |
} // dealloc |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Public - Accessors |
//--------------------------------------------------------------------------- |
- (void) setVertices:(const GLvoid *)theVertices |
size:(const GLsizeiptr)theSize |
{ |
mpIBO->geometry.vertices.data = theVertices; |
mpIBO->geometry.vertices.size = theSize; |
} // setVertices |
//--------------------------------------------------------------------------- |
- (void) setNormals:(const GLvoid *)theNormals |
size:(const GLsizeiptr)theSize |
offset:(const GLsizeiptr)theOffset |
{ |
mpIBO->geometry.normals.data = theNormals; |
mpIBO->geometry.normals.size = theSize; |
mpIBO->geometry.normals.offset = theOffset; |
} // setNormals |
//--------------------------------------------------------------------------- |
- (void) setElements:(const GLshort *)theElements |
size:(const GLsizeiptr)theSize |
{ |
mpIBO->elements.indices.data = theElements; |
mpIBO->elements.indices.size = theSize; |
} // setElements |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Public - Utilities |
//--------------------------------------------------------------------------- |
- (BOOL) acquire |
{ |
return( OpenGLIBOAcquire(mpIBO) ); |
} // acquire |
//--------------------------------------------------------------------------- |
- (void) bind |
{ |
OpenGLIBOBind(mpIBO); |
} // bind |
//--------------------------------------------------------------------------- |
- (void) unbind |
{ |
OpenGLIBOUnbind(mpIBO); |
} // unbind |
//--------------------------------------------------------------------------- |
// |
// Copy an array of vertices into an acquired IBO. |
// |
//--------------------------------------------------------------------------- |
- (BOOL) copyVertices:(const GLvoid *)theVertices |
size:(const GLsizeiptr)theSize |
{ |
return( OpenGLIBOCopyArray(NO, theVertices, theSize, mpIBO) ); |
} // copyVertices |
//--------------------------------------------------------------------------- |
// |
// Copy an array of normals into an acquired IBO. |
// |
//--------------------------------------------------------------------------- |
- (BOOL) copyNormals:(const GLvoid *)theNormals |
size:(const GLsizeiptr)theSize |
{ |
return( OpenGLIBOCopyArray(YES, theNormals, theSize, mpIBO) ); |
} // copyNormals |
//--------------------------------------------------------------------------- |
// |
// Copy an array of indicies into an acquired IBO. |
// |
//--------------------------------------------------------------------------- |
- (BOOL) copyElements:(const GLshort *)theElements |
size:(const GLsizeiptr)theSize |
{ |
return( OpenGLIBOCopyElements(theElements, theSize, mpIBO) ); |
} // copyElements |
//--------------------------------------------------------------------------- |
- (BOOL) map:(const GLenum)theTarget |
{ |
return( OpenGLIBOMap(theTarget, mpIBO) ); |
} // map |
//--------------------------------------------------------------------------- |
- (BOOL) unmap:(const GLenum)theTarget |
{ |
return( OpenGLIBOUnmap(theTarget, mpIBO) ); |
} // unmap |
//--------------------------------------------------------------------------- |
- (GLvoid *) vertices |
{ |
return( mpIBO->geometry.pointer ); |
} // vertices |
//--------------------------------------------------------------------------- |
- (GLvoid *) normals |
{ |
return( mpIBO->geometry.pointer + mpIBO->geometry.vertices.size ); |
} // normals |
//--------------------------------------------------------------------------- |
- (GLshort *) elements |
{ |
return( mpIBO->elements.pointer ); |
} // elements |
//--------------------------------------------------------------------------- |
@end |
//--------------------------------------------------------------------------- |
//--------------------------------------------------------------------------- |
Copyright © 2011 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2011-06-27