Sources/Classes/Application/Model/OpenGL/Surfaces/Klein Surface/OpenGLKleinSurface.mm
//------------------------------------------------------------------------ |
// |
// File: OpenGLKleinSurface.mm |
// |
// Abstract: Klein surface geometry class |
// Based on the work by Philip Rideout |
// ((C) 2002-2006 3Dlabs Inc.) |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by |
// 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) 2004-2008, 2012 Apple Inc., All rights reserved. |
// |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
#import <cmath> |
#import "GeometryConstants.h" |
#import "Vector3.h" |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
#import "OpenGLKleinSurface.h" |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
static const GLdouble kEpsilon = 0.00001; |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
struct OpenGLKleinVertex |
{ |
Math::Vector3<GLdouble> p[4]; |
Math::Vector3<GLdouble> normal; |
}; |
typedef struct OpenGLKleinVertex OpenGLKleinVertex; |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
static void OpenGLKleinSurfaceCompute(Math::Vector2<GLdouble>& domain, |
Math::Vector3<GLdouble>& range ) |
{ |
GLdouble u = (1.0 - domain.u) * kTwoPi; |
GLdouble v = domain.v * kTwoPi; |
GLdouble p0 = cos(v); |
GLdouble p1 = cos(v + kPi); |
GLdouble q0 = sin(v); |
GLdouble r0 = sin(u); |
GLdouble r1 = 8.0 * r0; |
GLdouble r2 = 1.0 + r0; |
GLdouble s0 = cos(u); |
GLdouble s1 = 3.0 * s0; |
GLdouble s2 = 2.0 - s0; |
GLdouble t0 = s2 * p0; |
GLdouble t1 = s1 * r2; |
GLdouble x0 = t1 + t0 * s0; |
GLdouble y0 = r1 + t0 * r0; |
GLdouble x1 = t1 + s2 * p1; |
GLdouble y1 = r1; |
range.x = u < kPi ? x0 : x1; |
range.y = u < kPi ? y0 : y1; |
range.z = s2 * q0; |
range = range * 0.1; |
range.y = -range.y; |
// Tweak the texture coordinates. |
domain.u *= 4.0; |
} // OpenGLKleinSurfaceCompute |
//------------------------------------------------------------------------- |
// |
// Flip the normals along a segment of the Klein bottle so that we don't |
// need two-sided lighting. |
// |
//------------------------------------------------------------------------- |
static inline GLboolean OpenGLKleinSurfaceFlipNormals(const GLdouble u) |
{ |
return( u < 0.125 ); |
} // OpenGLKleinSurfaceFlipNormals |
//------------------------------------------------------------------------- |
static void OpenGLKleinSurfaceComputeVertex(const GLboolean isFlipped, |
GLdouble du, |
GLdouble dv, |
Math::Vector2<GLdouble>& domain, |
OpenGLKleinVertex& vKlein) |
{ |
GLdouble u = domain.u; |
GLdouble v = domain.v; |
GLdouble w = u + 0.5 * du; |
OpenGLKleinSurfaceCompute(domain, vKlein.p[0]); |
Math::Vector2<GLdouble> z1(w, v); |
OpenGLKleinSurfaceCompute(z1, vKlein.p[1]); |
Math::Vector2<GLdouble> z2(w + du, v); |
OpenGLKleinSurfaceCompute(z2, vKlein.p[3]); |
if( isFlipped ) |
{ |
Math::Vector2<GLdouble> z3(w, v - dv); |
OpenGLKleinSurfaceCompute(z3, vKlein.p[2]); |
} // if |
else |
{ |
Math::Vector2<GLdouble> z4(w, v + dv); |
OpenGLKleinSurfaceCompute(z4, vKlein.p[2]); |
} // else |
} // OpenGLKleinSurfaceComputeVertex |
//------------------------------------------------------------------------- |
static void OpenGLKleinSurfaceSetVertexAttribs(OpenGLKleinVertex& vKlein) |
{ |
GLint tangentLoc = -1; |
GLint binormalLoc = -1; |
Math::Vector3<GLdouble> tangent = vKlein.p[3] - vKlein.p[1]; |
Math::Vector3<GLdouble> binormal = vKlein.p[2] - vKlein.p[1]; |
vKlein.normal = tangent ^ binormal; // Exterior cross product |
if( norm(vKlein.normal) < kEpsilon ) |
{ |
vKlein.normal = vKlein.p[0]; |
} // if |
vKlein.normal = norml(vKlein.normal); |
if( norm(tangent) < kEpsilon ) |
{ |
tangent = binormal ^ vKlein.normal; // Exterior cross product |
} // if |
tangent = norml(tangent); |
glVertexAttrib3dv(tangentLoc, tangent.array); |
binormal = -norml(binormal); |
glVertexAttrib3dv(binormalLoc, binormal.array); |
} // OpenGLKleinSurfaceSetVertexAttribs |
//------------------------------------------------------------------------- |
static void OpenGLKleinSurfaceNewVertex(Math::Vector2<GLdouble>& domain, |
OpenGLKleinVertex& vKlein) |
{ |
glNormal3dv( vKlein.normal.array ); |
glTexCoord2d( domain.s, domain.t ); |
glVertex3dv( vKlein.p[0].array ); |
} // OpenGLKleinSurfaceNewVertex |
//------------------------------------------------------------------------- |
// |
// Send out a normal, texture coordinate, vertex coordinate, and an |
// optional custom attribute. |
// |
//------------------------------------------------------------------------- |
static void OpenGLKleinSurfaceCreateVertex(const GLboolean isFlipped, |
GLdouble du, |
GLdouble dv, |
Math::Vector2<GLdouble>& domain) |
{ |
OpenGLKleinVertex vKlein; |
OpenGLKleinSurfaceComputeVertex(isFlipped, du, dv, domain, vKlein); |
OpenGLKleinSurfaceSetVertexAttribs(vKlein); |
OpenGLKleinSurfaceNewVertex(domain, vKlein); |
} // OpenGLKleinSurfaceCreateVertex |
//------------------------------------------------------------------------- |
static GLuint OpenGLKleinSurfaceCreateDisplayList(const GLsizei theTessellationFactor) |
{ |
GLuint displayList; |
GLint stacks = theTessellationFactor / 2; |
GLdouble u; |
GLdouble v; |
GLdouble du = 1.0 / (GLdouble)theTessellationFactor; |
GLdouble dv = 1.0 / (GLdouble)stacks; |
GLdouble uMax = 1.0 - 0.5 * du; |
GLdouble vMax = 1.0 + 0.5 * dv; |
GLboolean isFlipped = GL_FALSE; |
displayList = glGenLists(1); |
glNewList(displayList, GL_COMPILE); |
for( u = 0.0; u < uMax; u += du ) |
{ |
glBegin(GL_QUAD_STRIP); |
isFlipped = OpenGLKleinSurfaceFlipNormals(u); |
if( OpenGLKleinSurfaceFlipNormals(u) ) |
{ |
for( v = 0.0; v < vMax; v += dv ) |
{ |
Math::Vector2<GLdouble> domain1(u + du, v); |
Math::Vector2<GLdouble> domain2(u, v); |
OpenGLKleinSurfaceCreateVertex(isFlipped, du, dv, domain1); |
OpenGLKleinSurfaceCreateVertex(isFlipped, du, dv, domain2); |
} // for |
} // if |
else |
{ |
for( v = 0.0; v < vMax; v += dv ) |
{ |
Math::Vector2<GLdouble> domain1(u, v); |
Math::Vector2<GLdouble> domain2(u + du, v); |
OpenGLKleinSurfaceCreateVertex(isFlipped, du, dv, domain1); |
OpenGLKleinSurfaceCreateVertex(isFlipped, du, dv, domain2); |
} // for |
} // else |
glEnd(); |
} // for |
glEndList(); |
return displayList; |
} // OpenGLKleinSurfaceCreateDisplayList |
//------------------------------------------------------------------------- |
//------------------------------------------------------------------------ |
@implementation OpenGLKleinSurface |
//------------------------------------------------------------------------ |
- (id) initKleinSurfaceWithTessellationFactor:(const GLsizei)theTessellationFactor |
{ |
self = [super init]; |
if( self ) |
{ |
mnDisplayList = OpenGLKleinSurfaceCreateDisplayList(theTessellationFactor); |
} // if |
return self; |
} // initKleinSurfaceWithTessellationFactor |
//------------------------------------------------------------------------ |
- (void) dealloc |
{ |
// delete the last used display list |
if( mnDisplayList ) |
{ |
glDeleteLists( mnDisplayList, 1 ); |
} // if |
[super dealloc]; |
} // dealloc |
//------------------------------------------------------------------------ |
- (GLuint) displayList |
{ |
return mnDisplayList; |
} // displayList |
//------------------------------------------------------------------------ |
- (void) callList |
{ |
glCallList( mnDisplayList ); |
} // callList |
//------------------------------------------------------------------------ |
@end |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
Copyright © 2013 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2013-01-02